diff --git a/README.md b/README.md index 32f7a9b..352adf3 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,33 @@ return [ * you can customize this key to avoid conflicts. * Simply provide your preferred key name as a string value. */ - 'session_key' => 'utm' + 'session_key' => 'utm', + + /* + * Allowed UTM Parameters (default: ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'utm_campaign_id']) + * + * This setting defines the UTM parameters that are allowed within your application. + * + * In this array, you can specify a list of allowed UTM parameter names. Each parameter should be listed as a string. + * Only parameters from this list will be stored and processed in the session. + * and any parameter without the 'utm_' prefix will be ignored regardless of its inclusion in this list. + * + * Example: To only allow the basic UTM parameters (source, medium, and campaign), you could update the array like this: + * + * 'allowed_utm_parameters' => [ + * 'utm_source', + * 'utm_medium', + * 'utm_campaign', + * ], + */ + 'allowed_utm_parameters' => [ + 'utm_source', + 'utm_medium', + 'utm_campaign', + 'utm_term', + 'utm_content', + 'utm_campaign_id' + ], ]; ``` diff --git a/src/UtmParameter.php b/src/UtmParameter.php index 01a7002..c99a327 100644 --- a/src/UtmParameter.php +++ b/src/UtmParameter.php @@ -144,8 +144,8 @@ public static function contains(string $key, string $value) */ public static function clear() { - app(UtmParameter::class)->parameters = null; session()->forget(app(UtmParameter::class)->sessionKey); + app(UtmParameter::class)->parameters = null; return true; } @@ -156,9 +156,16 @@ public static function clear() */ protected static function getParameter(Request $request) { + $allowedKeys = config('utm-parameter.allowed_utm_parameters', [ + 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content' + ]); + return collect($request->all()) ->filter(fn ($value, $key) => substr($key, 0, 4) === 'utm_') - ->map(fn ($value) => htmlspecialchars($value, ENT_QUOTES, 'UTF-8')) + ->filter(fn ($value, $key) => in_array($key, $allowedKeys)) + ->mapWithKeys(fn ($value, $key) => [ + htmlspecialchars($key, ENT_QUOTES, 'UTF-8') => htmlspecialchars($value, ENT_QUOTES, 'UTF-8') + ]) ->toArray(); } diff --git a/src/config/utm-parameter.php b/src/config/utm-parameter.php index 1820930..0e5fb44 100644 --- a/src/config/utm-parameter.php +++ b/src/config/utm-parameter.php @@ -20,5 +20,31 @@ * you can customize this key to avoid conflicts. * Simply provide your preferred key name as a string value. */ - 'session_key' => 'utm' + 'session_key' => 'utm', + + /* + * Allowed UTM Parameters (default: ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'utm_campaign_id']) + * + * This setting defines the UTM parameters that are allowed within your application. + * + * In this array, you can specify a list of allowed UTM parameter names. Each parameter should be listed as a string. + * Only parameters from this list will be stored and processed in the session. + * and any parameter without the 'utm_' prefix will be ignored regardless of its inclusion in this list. + * + * Example: To only allow the basic UTM parameters (source, medium, and campaign), you could update the array like this: + * + * 'allowed_utm_parameters' => [ + * 'utm_source', + * 'utm_medium', + * 'utm_campaign', + * ], + */ + 'allowed_utm_parameters' => [ + 'utm_source', + 'utm_medium', + 'utm_campaign', + 'utm_term', + 'utm_content', + 'utm_campaign_id' + ], ]; diff --git a/tests/UtmParameterTest.php b/tests/UtmParameterTest.php index de127ee..9044ecf 100644 --- a/tests/UtmParameterTest.php +++ b/tests/UtmParameterTest.php @@ -32,6 +32,16 @@ public function setUp(): void session([$this->sessionKey => $parameters]); } + public function tearDown() : void + { + session()->forget($this->sessionKey); + + Config::set('utm-parameter.override_utm_parameters', null); + Config::set('utm-parameter.session_key', null); + + parent::tearDown(); + } + public function test_it_should_be_bound_in_the_app() { $utm = app(UtmParameter::class); @@ -343,4 +353,89 @@ public function test_it_should_keep_existing_parameters_while_browsing() $source = UtmParameter::get('source'); $this->assertEquals('google', $source); } + + public function test_it_should_only_use_utm_parameters_in_the_allowed_list() + { + session()->forget($this->sessionKey); + Config::set('utm-parameter.override_utm_parameters', true); + Config::set('utm-parameter.allowed_utm_parameters', ['utm_source', 'utm_medium']); + + $parameters = [ + 'utm_source'=> 'newsletter', + 'utm_medium' => 'email', + 'utm_campaign' => 'not-allowed' + ]; + + $request = Request::create('/test', 'GET', $parameters); + app(UtmParameter::class)->boot($request); + + $source = UtmParameter::get('source'); + $this->assertEquals('newsletter', $source); + $this->assertIsNotInt($source); + $this->assertNotEmpty($source); + + $medium = UtmParameter::get('medium'); + $this->assertEquals('email', $medium); + $this->assertIsNotInt($medium); + $this->assertNotEmpty($medium); + + $campaign = UtmParameter::get('campaign'); + $this->assertNull($campaign); + $this->assertEmpty($campaign); + + $term = UtmParameter::get('term'); + $this->assertNull($term); + $this->assertEmpty($term); + + $utm_campaign_id = UtmParameter::get('utm_campaign_id'); + $this->assertNull($utm_campaign_id); + $this->assertEmpty($utm_campaign_id); + } + + public function test_it_should_sanitize_utm_parameter() + { + Config::set('utm-parameter.override_utm_parameters', true); + + $parameters = [ + 'utm_source'=> 'google', + 'utm_medium' => 'cpc', + 'utm_campaign' => '