1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
<?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\Plugins\UsersManager;
use Exception;
use Piwik\Db;
use Piwik\Option;
use Piwik\Piwik;
use Piwik\SettingsPiwik;
/**
* Manage Piwik users
*
*/
class UsersManager extends \Piwik\Plugin
{
const PASSWORD_MIN_LENGTH = 6;
const PASSWORD_MAX_LENGTH = 80;
/**
* @see Piwik\Plugin::registerEvents
*/
public function registerEvents()
{
return array(
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
'SitesManager.deleteSite.end' => 'deleteSite',
'Tracker.Cache.getSiteAttributes' => 'recordAdminUsersInCache',
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
'Platform.initialized' => 'onPlatformInitialized',
'CronArchive.getTokenAuth' => 'getCronArchiveTokenAuth'
);
}
public function onPlatformInitialized()
{
$lastSeenTimeLogger = new LastSeenTimeLogger();
$lastSeenTimeLogger->logCurrentUserLastSeenTime();
}
/**
* Hooks when a website tracker cache is flushed (website/user updated, cache deleted, or empty cache)
* Will record in the tracker config file the list of Admin token_auth for this website. This
* will be used when the Tracking API is used with setIp(), setForceDateTime(), setVisitorId(), etc.
*
* @param $attributes
* @param $idSite
* @return void
*/
public function recordAdminUsersInCache(&$attributes, $idSite)
{
// add the 'hosts' entry in the website array
$users = API::getInstance()->getUsersWithSiteAccess($idSite, 'admin');
$tokens = array();
foreach ($users as $user) {
$tokens[] = $user['token_auth'];
}
$attributes['admin_token_auth'] = $tokens;
}
public function getCronArchiveTokenAuth(&$tokens)
{
$model = new Model();
$superUsers = $model->getUsersHavingSuperUserAccess();
foreach($superUsers as $superUser) {
$tokens[] = $superUser['token_auth'];
}
}
/**
* Delete user preferences associated with a particular site
*/
public function deleteSite($idSite)
{
Option::deleteLike('%\_' . API::PREFERENCE_DEFAULT_REPORT, $idSite);
}
/**
* Return list of plug-in specific JavaScript files to be imported by the asset manager
*
* @see Piwik\AssetManager
*/
public function getJsFiles(&$jsFiles)
{
$jsFiles[] = "plugins/UsersManager/javascripts/usersManager.js";
$jsFiles[] = "plugins/UsersManager/javascripts/usersSettings.js";
$jsFiles[] = "plugins/UsersManager/javascripts/giveViewAccess.js";
}
/**
* Get CSS files
*/
public function getStylesheetFiles(&$stylesheets)
{
$stylesheets[] = "plugins/UsersManager/stylesheets/usersManager.less";
}
/**
* Returns true if the password is complex enough (at least 6 characters and max 26 characters)
*
* @param $input string
* @return bool
*/
public static function isValidPasswordString($input)
{
if (!SettingsPiwik::isUserCredentialsSanityCheckEnabled()
&& !empty($input)
) {
return true;
}
$l = strlen($input);
return $l >= self::PASSWORD_MIN_LENGTH && $l <= self::PASSWORD_MAX_LENGTH;
}
public static function checkPassword($password)
{
/**
* Triggered before core password validator check password.
*
* This event exists for enable option to create custom password validation rules.
* It can be used to validate password (length, used chars etc) and to notify about checking password.
*
* **Example**
*
* Piwik::addAction('UsersManager.checkPassword', function ($password) {
* if (strlen($password) < 10) {
* throw new Exception('Password is too short.');
* }
* });
*
* @param string $password Checking password in plain text.
*/
Piwik::postEvent('UsersManager.checkPassword', array($password));
if (!self::isValidPasswordString($password)) {
throw new Exception(Piwik::translate('UsersManager_ExceptionInvalidPassword', array(self::PASSWORD_MIN_LENGTH,
self::PASSWORD_MAX_LENGTH)));
}
}
public static function getPasswordHash($password)
{
// if change here, should also edit the installation process
// to change how the root pwd is saved in the config file
return md5($password);
}
/**
* Checks the password hash length. Used as a sanity check.
*
* @param string $passwordHash The password hash to check.
* @param string $exceptionMessage Message of the exception thrown.
* @throws Exception if the password hash length is incorrect.
*/
public static function checkPasswordHash($passwordHash, $exceptionMessage)
{
if (strlen($passwordHash) != 32) { // MD5 hash length
throw new Exception($exceptionMessage);
}
}
public function getClientSideTranslationKeys(&$translationKeys)
{
$translationKeys[] = "General_OrCancel";
$translationKeys[] = "General_Save";
$translationKeys[] = "General_Done";
$translationKeys[] = "UsersManager_DeleteConfirm";
$translationKeys[] = "UsersManager_ConfirmGrantSuperUserAccess";
$translationKeys[] = "UsersManager_ConfirmProhibitOtherUsersSuperUserAccess";
$translationKeys[] = "UsersManager_ConfirmProhibitMySuperUserAccess";
$translationKeys[] = "UsersManager_ExceptionUserHasViewAccessAlready";
$translationKeys[] = "UsersManager_ExceptionNoValueForUsernameOrEmail";
}
}
|