Skip to content

Commit

Permalink
- added "session_key" config
Browse files Browse the repository at this point in the history
- added "allowed_utm_parameter"  config
- added tests
  • Loading branch information
toni-suarez committed Jun 21, 2024
1 parent fc75d66 commit 1db3a61
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 4 deletions.
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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'
],
];
```

Expand Down
11 changes: 9 additions & 2 deletions src/UtmParameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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();
}

Expand Down
28 changes: 27 additions & 1 deletion src/config/utm-parameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'
],
];
95 changes: 95 additions & 0 deletions tests/UtmParameterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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'=> '<span onclick="alert(\'alert\')">google</span>',
'utm_medium' => 'cpc<script>alert(1)</script>',
'utm_campaign' => '<script href="x" onload="alert(1)">',
'utm_content' => '<img src="x" onerror="alert(1)">',
'utm_term' => '%3Cscript%3Ealert(1)%3C%2Fscript%3E',
'utm_sql_injection' => '" OR 1=1; --',
'utm_html_tag' => '<b>bold</b>',
'utm_<html onclick="alert(\'alert\')">_tag' => '<b>bold</b>',
'utm_" OR 1=1; --' => '<b>bold</b>',
];

$request = Request::create('/test', 'GET', $parameters);
app(UtmParameter::class)->boot($request);

$source = UtmParameter::get('source');
$this->assertEquals('&lt;span onclick=&quot;alert(&#039;alert&#039;)&quot;&gt;google&lt;/span&gt;', $source);

$medium = UtmParameter::get('medium');
$this->assertEquals('cpc&lt;script&gt;alert(1)&lt;/script&gt;', $medium);

$campaign = UtmParameter::get('campaign');
$this->assertEquals('&lt;script href=&quot;x&quot; onload=&quot;alert(1)&quot;&gt;', $campaign);

$content = UtmParameter::get('content');
$this->assertEquals('&lt;img src=&quot;x&quot; onerror=&quot;alert(1)&quot;&gt;', $content);

$term = UtmParameter::get('term');
$this->assertEquals('%3Cscript%3Ealert(1)%3C%2Fscript%3E', $term);

$sql = UtmParameter::get('sql_injection');
$this->assertNull($sql);

$html = UtmParameter::get('html_tag');
$this->assertNull($html);

$randomKey = UtmParameter::get('utm_&lt;html onclick=&quot;alert(&#039;alert&#039;)&quot;&gt;_tag');
$this->assertNull($randomKey);

$randomSqlKey = UtmParameter::get('utm_&quot; OR 1=1; --');
$this->assertNull($randomSqlKey);
}
}

0 comments on commit 1db3a61

Please sign in to comment.