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 diff --git a/config/short-url.php b/config/short-url.php index 3d2c763..5fbcf7f 100644 --- a/config/short-url.php +++ b/config/short-url.php @@ -105,6 +105,20 @@ */ 'enforce_https' => true, + /* + |-------------------------------------------------------------------------- + | Allowed URL Schemes + |-------------------------------------------------------------------------- + | + | Here you may specify the allowed URL schemes to shorten. For example: + | 'mailto://', 'whatsapp://', 'yourapp://'. + | + */ + 'allowed_url_schemes' => [ + 'http://', + 'https://', + ], + /* |-------------------------------------------------------------------------- | URL Length diff --git a/src/Classes/Builder.php b/src/Classes/Builder.php index 3eca0d4..b55df51 100644 --- a/src/Classes/Builder.php +++ b/src/Classes/Builder.php @@ -181,8 +181,10 @@ 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://'); + $allowedPrefixes = config('short-url.allowed_url_schemes'); + + if (! Str::startsWith($url, config('short-url.allowed_url_schemes'))) { + throw new ShortURLException('The destination URL must begin with an allowed prefix: '.implode(', ', $allowedPrefixes)); } $this->destinationUrl = $url; 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/BuilderTest.php b/tests/Unit/Classes/BuilderTest.php index 3feeb83..5447c33 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.allowed_url_schemes', ['http://', 'https://', '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.allowed_url_schemes', ['https://', 'whatsapp://']); + + $this->expectException(ShortURLException::class); + $this->expectExceptionMessage('The destination URL must begin with an allowed prefix: https://, whatsapp://'); + + $builder = app(Builder::class); + $builder->destinationUrl('phpstorm://'); + } } 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(); + } }