From b20c64f872ac8df8c25470fe095bfda831fb641f Mon Sep 17 00:00:00 2001 From: Lewis Date: Sat, 29 Jun 2024 14:45:38 +0100 Subject: [PATCH 1/9] allow configuring additional url schemes Signed-off-by: Lewis --- config/short-url.php | 11 +++++++++++ src/Classes/Builder.php | 8 ++++++-- tests/Unit/Classes/BuilderTest.php | 26 +++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/config/short-url.php b/config/short-url.php index 3d2c763..bbcf3b9 100644 --- a/config/short-url.php +++ b/config/short-url.php @@ -105,6 +105,17 @@ */ 'enforce_https' => true, + /* + |-------------------------------------------------------------------------- + | Additional URL Schemes + |-------------------------------------------------------------------------- + | + | Here you may specify additional URL schemes to shorten, eg 'mailto://' or + | ones for your own app, eg 'whatsapp://', 'yourapp://' + | + */ + 'additional_url_schemes' => [], + /* |-------------------------------------------------------------------------- | URL Length diff --git a/src/Classes/Builder.php b/src/Classes/Builder.php index 3eca0d4..e2edfbe 100644 --- a/src/Classes/Builder.php +++ b/src/Classes/Builder.php @@ -181,8 +181,12 @@ public function routes(): void */ public function destinationUrl(string $url): self { - if (! Str::startsWith($url, ['http://', 'https://'])) { - throw new ShortURLException('The destination URL must begin with http:// or https://'); + $defaultAllowedPrefixes = ['http://', 'https://']; + $additionalAllowedPrefixes = config('short-url.additional_url_schemes', []); + $allowedPrefixes = array_merge($defaultAllowedPrefixes, $additionalAllowedPrefixes); + + if (! Str::startsWith($url, $allowedPrefixes)) { + throw new ShortURLException('The destination URL must begin with an allowed prefix: ' . implode(', ', $allowedPrefixes)); } $this->destinationUrl = $url; diff --git a/tests/Unit/Classes/BuilderTest.php b/tests/Unit/Classes/BuilderTest.php index 3feeb83..e446b1b 100644 --- a/tests/Unit/Classes/BuilderTest.php +++ b/tests/Unit/Classes/BuilderTest.php @@ -42,7 +42,7 @@ public function exception_is_thrown_in_the_constructor_if_the_config_variables_a public function exception_is_thrown_if_the_destination_url_does_not_begin_with_http_or_https(): void { $this->expectException(ShortURLException::class); - $this->expectExceptionMessage('The destination URL must begin with http:// or https://'); + $this->expectExceptionMessage('The destination URL must begin with an allowed prefix: http://, https://'); $builder = app(Builder::class); $builder->destinationUrl('INVALID'); @@ -609,4 +609,28 @@ public function builder_works_when_the_date_facade_is_set_to_use_carbon_immutabl Date::useDefault(); } + + #[Test] + public function custom_url_schemes_allowed_if_configured(): void + { + Config::set('short-url.additional_url_schemes', ['whatsapp://']); + + $shortUrl = app(Builder::class) + ->destinationUrl('whatsapp://callMe') + ->make(); + + $this->assertSame('whatsapp://callMe', $shortUrl->destination_url); + } + + #[Test] + public function exception_is_thrown_if_invalid_scheme(): void + { + Config::set('short-url.additional_url_schemes', ['whatsapp://']); + + $this->expectException(ShortURLException::class); + $this->expectExceptionMessage('The destination URL must begin with an allowed prefix: http://, https://, whatsapp://'); + + $builder = app(Builder::class); + $builder->destinationUrl('INVALID'); + } } From 984b55ff35cbb3a23235873513a6f71abf2dd368 Mon Sep 17 00:00:00 2001 From: Lewis Date: Sat, 29 Jun 2024 15:01:34 +0100 Subject: [PATCH 2/9] whitespace changes to comply with style Signed-off-by: Lewis --- src/Classes/Builder.php | 4 ++-- tests/Unit/Classes/BuilderTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Classes/Builder.php b/src/Classes/Builder.php index e2edfbe..6e3c31f 100644 --- a/src/Classes/Builder.php +++ b/src/Classes/Builder.php @@ -181,10 +181,10 @@ public function routes(): void */ public function destinationUrl(string $url): self { - $defaultAllowedPrefixes = ['http://', 'https://']; + $defaultAllowedPrefixes = ['http://', 'https://']; $additionalAllowedPrefixes = config('short-url.additional_url_schemes', []); $allowedPrefixes = array_merge($defaultAllowedPrefixes, $additionalAllowedPrefixes); - + if (! Str::startsWith($url, $allowedPrefixes)) { throw new ShortURLException('The destination URL must begin with an allowed prefix: ' . implode(', ', $allowedPrefixes)); } diff --git a/tests/Unit/Classes/BuilderTest.php b/tests/Unit/Classes/BuilderTest.php index e446b1b..7643fe2 100644 --- a/tests/Unit/Classes/BuilderTest.php +++ b/tests/Unit/Classes/BuilderTest.php @@ -614,12 +614,12 @@ public function builder_works_when_the_date_facade_is_set_to_use_carbon_immutabl public function custom_url_schemes_allowed_if_configured(): void { Config::set('short-url.additional_url_schemes', ['whatsapp://']); - + $shortUrl = app(Builder::class) ->destinationUrl('whatsapp://callMe') ->make(); - $this->assertSame('whatsapp://callMe', $shortUrl->destination_url); + $this->assertSame('whatsapp://callMe', $shortUrl->destination_url); } #[Test] From 5569265b20cd0cafc43408c59ac607d97e439aa5 Mon Sep 17 00:00:00 2001 From: Lewis Date: Sat, 29 Jun 2024 15:03:44 +0100 Subject: [PATCH 3/9] whitespace style changes Signed-off-by: Lewis --- src/Classes/Builder.php | 2 +- tests/Unit/Classes/BuilderTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Classes/Builder.php b/src/Classes/Builder.php index 6e3c31f..038a7ef 100644 --- a/src/Classes/Builder.php +++ b/src/Classes/Builder.php @@ -186,7 +186,7 @@ public function destinationUrl(string $url): self $allowedPrefixes = array_merge($defaultAllowedPrefixes, $additionalAllowedPrefixes); if (! Str::startsWith($url, $allowedPrefixes)) { - throw new ShortURLException('The destination URL must begin with an allowed prefix: ' . implode(', ', $allowedPrefixes)); + throw new ShortURLException('The destination URL must begin with an allowed prefix: '. implode(', ', $allowedPrefixes)); } $this->destinationUrl = $url; diff --git a/tests/Unit/Classes/BuilderTest.php b/tests/Unit/Classes/BuilderTest.php index 7643fe2..9cb90c4 100644 --- a/tests/Unit/Classes/BuilderTest.php +++ b/tests/Unit/Classes/BuilderTest.php @@ -618,7 +618,7 @@ public function custom_url_schemes_allowed_if_configured(): void $shortUrl = app(Builder::class) ->destinationUrl('whatsapp://callMe') ->make(); - + $this->assertSame('whatsapp://callMe', $shortUrl->destination_url); } From d6b28cfc63273110e177394b437ade0c62e346dc Mon Sep 17 00:00:00 2001 From: Lewis Date: Sat, 29 Jun 2024 15:04:31 +0100 Subject: [PATCH 4/9] whitespace style change Signed-off-by: Lewis --- src/Classes/Builder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Classes/Builder.php b/src/Classes/Builder.php index 038a7ef..c050325 100644 --- a/src/Classes/Builder.php +++ b/src/Classes/Builder.php @@ -186,7 +186,7 @@ public function destinationUrl(string $url): self $allowedPrefixes = array_merge($defaultAllowedPrefixes, $additionalAllowedPrefixes); if (! Str::startsWith($url, $allowedPrefixes)) { - throw new ShortURLException('The destination URL must begin with an allowed prefix: '. implode(', ', $allowedPrefixes)); + throw new ShortURLException('The destination URL must begin with an allowed prefix: '.implode(', ', $allowedPrefixes)); } $this->destinationUrl = $url; From 49cce8597838da4e5705cb01011b73dde12f8b4b Mon Sep 17 00:00:00 2001 From: Ash Allen Date: Tue, 2 Jul 2024 17:57:32 +0100 Subject: [PATCH 5/9] Rename config field to `allowed_url_schemes`. --- config/short-url.php | 11 +++++++---- src/Classes/Builder.php | 6 ++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/config/short-url.php b/config/short-url.php index bbcf3b9..ba2d0cb 100644 --- a/config/short-url.php +++ b/config/short-url.php @@ -107,14 +107,17 @@ /* |-------------------------------------------------------------------------- - | Additional URL Schemes + | Allowed URL Schemes |-------------------------------------------------------------------------- | - | Here you may specify additional URL schemes to shorten, eg 'mailto://' or - | ones for your own app, eg 'whatsapp://', 'yourapp://' + | Here you may specify the allowed URL schemes to shorten, eg 'mailto://' + | or ones for your own app, eg 'whatsapp://', 'yourapp://'. | */ - 'additional_url_schemes' => [], + 'allowed_url_schemes' => [ + 'http://', + 'https://', + ], /* |-------------------------------------------------------------------------- diff --git a/src/Classes/Builder.php b/src/Classes/Builder.php index c050325..b55df51 100644 --- a/src/Classes/Builder.php +++ b/src/Classes/Builder.php @@ -181,11 +181,9 @@ public function routes(): void */ public function destinationUrl(string $url): self { - $defaultAllowedPrefixes = ['http://', 'https://']; - $additionalAllowedPrefixes = config('short-url.additional_url_schemes', []); - $allowedPrefixes = array_merge($defaultAllowedPrefixes, $additionalAllowedPrefixes); + $allowedPrefixes = config('short-url.allowed_url_schemes'); - if (! Str::startsWith($url, $allowedPrefixes)) { + if (! Str::startsWith($url, config('short-url.allowed_url_schemes'))) { throw new ShortURLException('The destination URL must begin with an allowed prefix: '.implode(', ', $allowedPrefixes)); } From 7c3c676636eceab8f2440a85c60ceafb306474db Mon Sep 17 00:00:00 2001 From: Ash Allen Date: Tue, 2 Jul 2024 17:57:43 +0100 Subject: [PATCH 6/9] Updated tests. --- tests/Unit/Classes/BuilderTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Unit/Classes/BuilderTest.php b/tests/Unit/Classes/BuilderTest.php index 9cb90c4..5447c33 100644 --- a/tests/Unit/Classes/BuilderTest.php +++ b/tests/Unit/Classes/BuilderTest.php @@ -613,7 +613,7 @@ public function builder_works_when_the_date_facade_is_set_to_use_carbon_immutabl #[Test] public function custom_url_schemes_allowed_if_configured(): void { - Config::set('short-url.additional_url_schemes', ['whatsapp://']); + Config::set('short-url.allowed_url_schemes', ['http://', 'https://', 'whatsapp://']); $shortUrl = app(Builder::class) ->destinationUrl('whatsapp://callMe') @@ -625,12 +625,12 @@ public function custom_url_schemes_allowed_if_configured(): void #[Test] public function exception_is_thrown_if_invalid_scheme(): void { - Config::set('short-url.additional_url_schemes', ['whatsapp://']); + Config::set('short-url.allowed_url_schemes', ['https://', 'whatsapp://']); $this->expectException(ShortURLException::class); - $this->expectExceptionMessage('The destination URL must begin with an allowed prefix: http://, https://, whatsapp://'); + $this->expectExceptionMessage('The destination URL must begin with an allowed prefix: https://, whatsapp://'); $builder = app(Builder::class); - $builder->destinationUrl('INVALID'); + $builder->destinationUrl('phpstorm://'); } } From d95b88197aa967ad0cfc5b40add53864e8f05328 Mon Sep 17 00:00:00 2001 From: Ash Allen Date: Tue, 2 Jul 2024 17:57:51 +0100 Subject: [PATCH 7/9] Added validation for the new config field. --- src/Classes/Validation.php | 1 + tests/Unit/Classes/ValidationTest.php | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/Classes/Validation.php b/src/Classes/Validation.php index 2219e91..bc9cab5 100644 --- a/src/Classes/Validation.php +++ b/src/Classes/Validation.php @@ -32,6 +32,7 @@ public function validateConfig(): bool Rule::make('enforce_https')->rules(['required', 'boolean']), Rule::make('forward_query_params')->rules(['required', 'boolean']), Rule::make('default_url')->rules(['nullable', 'string']), + Rule::make('allowed_url_schemes')->rules(['required', 'array']), ], ]); diff --git a/tests/Unit/Classes/ValidationTest.php b/tests/Unit/Classes/ValidationTest.php index e44d32b..5070278 100644 --- a/tests/Unit/Classes/ValidationTest.php +++ b/tests/Unit/Classes/ValidationTest.php @@ -129,4 +129,16 @@ public function exception_is_thrown_if_the_default_url_is_not_a_string(): void $validation = new Validation(); $validation->validateConfig(); } + + #[Test] + public function exception_is_thrown_if_the_allowed_url_schemes_is_not_an_array(): void + { + $this->expectException(ValidationException::class); + $this->expectExceptionMessage('The short-url.allowed_url_schemes field must be an array.'); + + Config::set('short-url.allowed_url_schemes', 'INVALID'); + + $validation = new Validation(); + $validation->validateConfig(); + } } From aa9c894cbb7235091877adeadab8351845698a4a Mon Sep 17 00:00:00 2001 From: Ash Allen Date: Tue, 2 Jul 2024 18:24:18 +0100 Subject: [PATCH 8/9] Updated config documentation. --- config/short-url.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/short-url.php b/config/short-url.php index ba2d0cb..5fbcf7f 100644 --- a/config/short-url.php +++ b/config/short-url.php @@ -110,8 +110,8 @@ | Allowed URL Schemes |-------------------------------------------------------------------------- | - | Here you may specify the allowed URL schemes to shorten, eg 'mailto://' - | or ones for your own app, eg 'whatsapp://', 'yourapp://'. + | Here you may specify the allowed URL schemes to shorten. For example: + | 'mailto://', 'whatsapp://', 'yourapp://'. | */ 'allowed_url_schemes' => [ From c3b3f059edec8748b34f1e73ebd22fa6aeba84ab Mon Sep 17 00:00:00 2001 From: Ash Allen Date: Tue, 2 Jul 2024 18:29:15 +0100 Subject: [PATCH 9/9] Updated documentation. --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 8f10247..af34cc8 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ - [Custom Database Connection](#custom-database-connection) - [Specifying the Key Generator](#specifying-the-key-generator) - [Specifying the User Agent Parser](#specifying-the-user-agent-parser) + - [Specifying the Allowed URL Schemes](#specifying-the-allowed-url-schemes) - [Helper Methods](#helper-methods) - [Visits](#visits) - [Find by URL Key](#find-by-url-key) @@ -632,6 +633,23 @@ To do this, you can define the class to be used in the `short-url.php` config fi You'll just need to ensure that your custom user agent parser class implements the `AshAllenDesign\ShortURL\Interfaces\UserAgentDriver` interface. +#### Specifying the Allowed URL Schemes + +By default, Short URL will allow you to create a shortened URL for any URLs beginning with `http://` or `https://`. + +However, you may want to change this list of allowed URL schemes. For example, this may be to restrict the creation to only `https://` URLs. Or, it may be to allow URLs to be created using other schemes such as `mailto://` or even custom schemes for your own applications. + +To change the list of allowed URL schemes, you can define the list using the `allowed_url_schemes` field in your `short-url.php` config file like so: + +```php +'allowed_url_schemes' => [ + 'http://', + 'https://', + 'mailto://', + 'myapp://', +], +``` + ### Helper Methods #### Visits The ShortURL model includes a relationship (that you can use just like any other Laravel model relation) for getting the