Skip to content

Commit

Permalink
fixes matomo-org#6824 Hash the fingerprint with the website ID to mak…
Browse files Browse the repository at this point in the history
…e it different on each website for a given user + tests
  • Loading branch information
mattab committed Dec 8, 2014
1 parent ca873b3 commit 38c5b33
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 2 deletions.
6 changes: 6 additions & 0 deletions config/global.ini.php
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,12 @@

[Tracker]

; Piwik uses "Privacy by default" model. When one of your users visit multiple of your websites tracked in this Piwik,
; Piwik will create for this user a fingerprint that will be different across the multiple websites.
; If you want to track unique users across websites (for example when using the InterSites plugin) you may set this setting to 0.
; Note: setting this to 0 reduces your users' privacy.
enable_fingerprinting_across_websites = 0

; Piwik uses first party cookies by default. If set to 1,
; the visit ID cookie will be set on the Piwik server domain as well
; this is useful when you want to do cross websites analysis
Expand Down
9 changes: 8 additions & 1 deletion core/Tracker/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/
namespace Piwik\Tracker;

use Piwik\Config;
use Piwik\Tracker;
use Piwik\DeviceDetectorFactory;
use Piwik\SettingsPiwik;
Expand All @@ -16,10 +17,11 @@ class Settings
{
const OS_BOT = 'BOT';

function __construct(Request $request, $ip)
function __construct(Request $request, $ip, $isSameFingerprintsAcrossWebsites)
{
$this->request = $request;
$this->ipAddress = $ip;
$this->isSameFingerprintsAcrossWebsites = $isSameFingerprintsAcrossWebsites;
$this->configId = null;
}

Expand Down Expand Up @@ -110,8 +112,13 @@ protected function getConfigHash($os, $browserName, $browserVersion, $plugin_Fla
. $browserLang
. $salt;

if(!$this->isSameFingerprintsAcrossWebsites) {
$configString .= $this->request->getIdSite();
}

$hash = md5($configString, $raw_output = true);

return substr($hash, 0, Tracker::LENGTH_BINARY_ID);
}

}
3 changes: 2 additions & 1 deletion core/Tracker/Visit.php
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,8 @@ protected function getVisitorIp()
protected function getSettingsObject()
{
if (is_null($this->userSettings)) {
$this->userSettings = new Settings( $this->request, $this->getVisitorIp() );
$isSameFingerprintAcrossWebsites = (bool)Config::getInstance()->Tracker['enable_fingerprinting_across_websites'];
$this->userSettings = new Settings( $this->request, $this->getVisitorIp(), $isSameFingerprintAcrossWebsites );
}

return $this->userSettings;
Expand Down
159 changes: 159 additions & 0 deletions tests/PHPUnit/Integration/Tracker/SettingsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/

namespace Piwik\Tests\Integration\Tracker;

use Piwik\Tests\Framework\Fixture;
use Piwik\Tracker\Cache;
use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
use Piwik\Tracker\Request;
use Piwik\Tracker\Settings;

/**
* @group SettingsTest
* @group TrackerVisitSettingsTest
* @group Tracker
*/
class SettingsTest extends IntegrationTestCase
{
/**
* @var string
*/
protected $ip = '123.30.30.30';

public function setUp()
{
parent::setUp();

Fixture::createWebsite('2014-01-01 00:00:00');
Fixture::createWebsite('2014-01-01 00:00:00');
Cache::deleteTrackerCache();

$_SERVER['HTTP_USER_AGENT'] = '';
}

public function test_getConfigId_isSame()
{
$settings1 = $this->makeSettings(array('idsite' => 1));
$settings2 = $this->makeSettings(array('idsite' => 1));

$this->assertEquals($settings1->getConfigId(), $settings2->getConfigId());
}


public function test_getConfigId_isSame_whenConfiguredUserHasSameFingerprintAcrossWebsites()
{
$isSameFingerprintAcrossWebsites = true;

$settingsSite1 = $this->makeSettings(array('idsite' => 1), $isSameFingerprintAcrossWebsites);
$settingsSite2 = $this->makeSettings(array('idsite' => 2), $isSameFingerprintAcrossWebsites);

$this->assertEquals($settingsSite1->getConfigId(), $settingsSite2->getConfigId());
}

public function test_getConfigId_isDifferent_whenConfiguredUserHasDifferentFingerprintAcrossWebsites()
{
$isSameFingerprintAcrossWebsites = false;

$settingsSite1 = $this->makeSettings(array('idsite' => 1), $isSameFingerprintAcrossWebsites);
$settingsSite2 = $this->makeSettings(array('idsite' => 2), $isSameFingerprintAcrossWebsites);

$this->assertNotSame($settingsSite1->getConfigId(), $settingsSite2->getConfigId());
}

public function test_getConfigId_isSame_whenBrowserSamebutDifferentUserAgent()
{
$settingsFirefox = $this->makeSettings(array('ua' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10; rv:33.0) Gecko/20100101 Firefox/33.0'));
$settingsSlightlyDifferentUserAgent = $this->makeSettings(array('ua' => 'Mozilla/5.0 (Macintosh; Extra; string; here; Hello; world; Intel Mac OS X 10_10; rv:33.0) Gecko/20100101 Firefox/33.0'));

$this->assertSame($settingsSlightlyDifferentUserAgent->getConfigId(), $settingsFirefox->getConfigId());
}

public function test_getConfigId_isDifferent_whenBrowserChanges()
{
$settingsFirefox = $this->makeSettings(array('ua' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10; rv:33.0) Gecko/20100101 Firefox/33.0'));
$settingsChrome = $this->makeSettings(array('ua' => 'Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19 '));

$this->assertNotSame($settingsChrome->getConfigId(), $settingsFirefox->getConfigId());
}

public function test_getConfigId_isDifferent_whenOSChanges()
{
$settingsFirefoxMac = $this->makeSettings(array('ua' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10; rv:33.0) Gecko/20100101 Firefox/33.0'));
$settingsFirefoxLinux = $this->makeSettings(array('ua' => 'Mozilla/5.0 (Linux; rv:33.0) Gecko/20100101 Firefox/33.0'));

$this->assertNotSame($settingsFirefoxLinux->getConfigId(), $settingsFirefoxMac->getConfigId());
}

public function test_getConfigId_isDifferent_whenPluginChanges()
{
$params = array(
'pdf' => 1,
'cookie' => 1,
'fla' => 0,
'idsite' => 1,
);
$settingsWithoutFlash = $this->makeSettings($params);

// activate flash
$params['fla'] = 1;
$settingsWithFlash = $this->makeSettings($params);

$this->assertNotSame($settingsWithoutFlash->getConfigId(), $settingsWithFlash->getConfigId());
}

public function test_getConfigId_isDifferent_whenIPIsAnonimised()
{
$settingsIpIsNotAnon = $this->makeSettings(array(), true, '125.1.55.55');
$settingsIpIsAnon = $this->makeSettings(array(), true, '125.1.0.0');

$this->assertNotSame($settingsIpIsNotAnon->getConfigId(), $settingsIpIsAnon->getConfigId());
}

public function test_getConfigId_isSame_whenIPIsAnonimisedAndBothSame()
{
$settingsIpIsNotAnon = $this->makeSettings(array(), true, '125.2.0.0');
$settingsIpIsAnon = $this->makeSettings(array(), true, '125.2.0.0');

$this->assertSame($settingsIpIsNotAnon->getConfigId(), $settingsIpIsAnon->getConfigId());
}

/**
* @param $params array
* @param $isSameFingerprintAcrossWebsites
* @param $ip
* @return Settings
*/
protected function makeSettings($params, $isSameFingerprintAcrossWebsites = false, $ip = null)
{
if(is_null($ip)) {
$ip = $this->ip;
}
$requestSite1 = $this->makeRequest($params);
$settingsSite1 = new Settings($requestSite1, $ip, $isSameFingerprintAcrossWebsites);
return $settingsSite1;
}

/**
* @param $extraParams array
* @return array
*/
private function makeRequest($extraParams)
{
// default
$params = array(
'pdf' => 1,
'cookie' => 1,
'fla' => 0,
'idsite' => 1,
);
$params = array_merge($params, $extraParams);
$request = new Request($params);
return $request;
}
}

0 comments on commit 38c5b33

Please sign in to comment.