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' => '