GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — develop (#145)
by
unknown
09:16 queued 03:08
created
index.php 4 patches
Indentation   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -57,29 +57,29 @@  discard block
 block discarded – undo
57 57
  */
58 58
 	$domain = ! empty($_SERVER['HTTP_HOST']) ? strtolower($_SERVER['HTTP_HOST']) : 'cli';
59 59
 
60
-    /**
61
-     * A simple method to automatically determine the environment that
62
-     * the script is running on. Modify to support your needs.
63
-     *
64
-     * To handle Travis-ci testing, we check for an environment
65
-     * variable called TRAVIS which is set in the .travis.yml file.
66
-     * This allows a database-specific setup for Travis testing.
67
-     */
68
-    if (isset($_ENV['TRAVIS']))
69
-    {
70
-        define('ENVIRONMENT', 'travis');
71
-    }
72
-    else if (isset($_ENV['TESTING']))
73
-    {
74
-	    define('ENVIRONMENT', 'testing');
75
-    }
76
-    else if (strpos($domain, '.dev') !== false || $domain == 'cli')
77
-    {
78
-        define('ENVIRONMENT', 'development');
79
-    }
80
-    else {
81
-        define('ENVIRONMENT', 'production');
82
-    }
60
+	/**
61
+	 * A simple method to automatically determine the environment that
62
+	 * the script is running on. Modify to support your needs.
63
+	 *
64
+	 * To handle Travis-ci testing, we check for an environment
65
+	 * variable called TRAVIS which is set in the .travis.yml file.
66
+	 * This allows a database-specific setup for Travis testing.
67
+	 */
68
+	if (isset($_ENV['TRAVIS']))
69
+	{
70
+		define('ENVIRONMENT', 'travis');
71
+	}
72
+	else if (isset($_ENV['TESTING']))
73
+	{
74
+		define('ENVIRONMENT', 'testing');
75
+	}
76
+	else if (strpos($domain, '.dev') !== false || $domain == 'cli')
77
+	{
78
+		define('ENVIRONMENT', 'development');
79
+	}
80
+	else {
81
+		define('ENVIRONMENT', 'production');
82
+	}
83 83
 
84 84
 /*
85 85
  *---------------------------------------------------------------
@@ -92,7 +92,7 @@  discard block
 block discarded – undo
92 92
 switch (ENVIRONMENT)
93 93
 {
94 94
 	case 'development':
95
-    case 'travis':
95
+	case 'travis':
96 96
 	case 'testing':
97 97
 		error_reporting(-1);
98 98
 		ini_set('display_errors', 1);
@@ -150,7 +150,7 @@  discard block
 block discarded – undo
150 150
  * Include the path if the folder is not in the same directory
151 151
  * as this file.
152 152
  */
153
-    $myth_folder = 'myth';
153
+	$myth_folder = 'myth';
154 154
 
155 155
 /*
156 156
  *---------------------------------------------------------------
@@ -267,8 +267,8 @@  discard block
 block discarded – undo
267 267
 	// Name of the "system folder"
268 268
 	define('SYSDIR', trim(strrchr(trim(BASEPATH, '/'), '/'), '/'));
269 269
 
270
-    // Path to the myth folder
271
-    define('MYTHPATH', rtrim( str_replace('\\', '/', $myth_folder), '/ ') .'/' );
270
+	// Path to the myth folder
271
+	define('MYTHPATH', rtrim( str_replace('\\', '/', $myth_folder), '/ ') .'/' );
272 272
 
273 273
 	// The path to the "application" folder
274 274
 	if (is_dir($application_folder))
Please login to merge, or discard this patch.
Switch Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -92,7 +92,7 @@
 block discarded – undo
92 92
 switch (ENVIRONMENT)
93 93
 {
94 94
 	case 'development':
95
-    case 'travis':
95
+    	case 'travis':
96 96
 	case 'testing':
97 97
 		error_reporting(-1);
98 98
 		ini_set('display_errors', 1);
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -268,7 +268,7 @@
 block discarded – undo
268 268
 	define('SYSDIR', trim(strrchr(trim(BASEPATH, '/'), '/'), '/'));
269 269
 
270 270
     // Path to the myth folder
271
-    define('MYTHPATH', rtrim( str_replace('\\', '/', $myth_folder), '/ ') .'/' );
271
+    define('MYTHPATH', rtrim(str_replace('\\', '/', $myth_folder), '/ ').'/');
272 272
 
273 273
 	// The path to the "application" folder
274 274
 	if (is_dir($application_folder))
Please login to merge, or discard this patch.
Braces   +9 added lines, -18 removed lines patch added patch discarded remove patch
@@ -68,16 +68,13 @@  discard block
 block discarded – undo
68 68
     if (isset($_ENV['TRAVIS']))
69 69
     {
70 70
         define('ENVIRONMENT', 'travis');
71
-    }
72
-    else if (isset($_ENV['TESTING']))
71
+    } else if (isset($_ENV['TESTING']))
73 72
     {
74 73
 	    define('ENVIRONMENT', 'testing');
75
-    }
76
-    else if (strpos($domain, '.dev') !== false || $domain == 'cli')
74
+    } else if (strpos($domain, '.dev') !== false || $domain == 'cli')
77 75
     {
78 76
         define('ENVIRONMENT', 'development');
79
-    }
80
-    else {
77
+    } else {
81 78
         define('ENVIRONMENT', 'production');
82 79
     }
83 80
 
@@ -103,8 +100,7 @@  discard block
 block discarded – undo
103 100
 		if (version_compare(PHP_VERSION, '5.3', '>='))
104 101
 		{
105 102
 			error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED);
106
-		}
107
-		else
103
+		} else
108 104
 		{
109 105
 			error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_USER_NOTICE);
110 106
 		}
@@ -235,8 +231,7 @@  discard block
 block discarded – undo
235 231
 	if (($_temp = realpath($system_path)) !== FALSE)
236 232
 	{
237 233
 		$system_path = $_temp.'/';
238
-	}
239
-	else
234
+	} else
240 235
 	{
241 236
 		// Ensure there's a trailing slash
242 237
 		$system_path = rtrim($system_path, '/').'/';
@@ -279,8 +274,7 @@  discard block
 block discarded – undo
279 274
 		}
280 275
 
281 276
 		define('APPPATH', $application_folder.DIRECTORY_SEPARATOR);
282
-	}
283
-	else
277
+	} else
284 278
 	{
285 279
 		if ( ! is_dir(BASEPATH.$application_folder.DIRECTORY_SEPARATOR))
286 280
 		{
@@ -298,14 +292,12 @@  discard block
 block discarded – undo
298 292
 		if ( ! empty($view_folder) && is_dir(APPPATH.$view_folder.DIRECTORY_SEPARATOR))
299 293
 		{
300 294
 			$view_folder = APPPATH.$view_folder;
301
-		}
302
-		elseif ( ! is_dir(APPPATH.'views'.DIRECTORY_SEPARATOR))
295
+		} elseif ( ! is_dir(APPPATH.'views'.DIRECTORY_SEPARATOR))
303 296
 		{
304 297
 			header('HTTP/1.1 503 Service Unavailable.', TRUE, 503);
305 298
 			echo 'Your view folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF;
306 299
 			exit(3); // EXIT_CONFIG
307
-		}
308
-		else
300
+		} else
309 301
 		{
310 302
 			$view_folder = APPPATH.'views';
311 303
 		}
@@ -314,8 +306,7 @@  discard block
 block discarded – undo
314 306
 	if (($_temp = realpath($view_folder)) !== FALSE)
315 307
 	{
316 308
 		$view_folder = $_temp.DIRECTORY_SEPARATOR;
317
-	}
318
-	else
309
+	} else
319 310
 	{
320 311
 		$view_folder = rtrim($view_folder, '/\\').DIRECTORY_SEPARATOR;
321 312
 	}
Please login to merge, or discard this patch.
myth/Api/Auth/APIAuthentication.php 3 patches
Indentation   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -74,7 +74,7 @@  discard block
 block discarded – undo
74 74
 	 */
75 75
 	public function setRealm($realm)
76 76
 	{
77
-	    $this->realm = $realm;
77
+		$this->realm = $realm;
78 78
 		return $this;
79 79
 	}
80 80
 
@@ -116,7 +116,7 @@  discard block
 block discarded – undo
116 116
 			'password'  => $password
117 117
 		];
118 118
 
119
-	    $user = $this->validate($data, true);
119
+		$user = $this->validate($data, true);
120 120
 
121 121
 		$this->user = $user;
122 122
 
@@ -272,7 +272,7 @@  discard block
 block discarded – undo
272 272
 	 */
273 273
 	public function checkIPBlacklist()
274 274
 	{
275
-	    $blacklist = explode(',', config_item('api.ip_blacklist'));
275
+		$blacklist = explode(',', config_item('api.ip_blacklist'));
276 276
 
277 277
 		array_walk($blacklist, function (&$item, $key) {
278 278
 			$item = trim($item);
Please login to merge, or discard this patch.
Spacing   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -41,7 +41,7 @@  discard block
 block discarded – undo
41 41
 
42 42
 	//--------------------------------------------------------------------
43 43
 
44
-	public function __construct($ci=null)
44
+	public function __construct($ci = null)
45 45
 	{
46 46
 		parent::__construct($ci);
47 47
 
@@ -107,7 +107,7 @@  discard block
 block discarded – undo
107 107
 		// so request authorization by the client.
108 108
 		if (empty($username) || empty($password))
109 109
 		{
110
-			$this->ci->output->set_header('WWW-Authenticate: Basic realm="'. config_item('api.realm') .'"');
110
+			$this->ci->output->set_header('WWW-Authenticate: Basic realm="'.config_item('api.realm').'"');
111 111
 			return false;
112 112
 		}
113 113
 
@@ -157,7 +157,7 @@  discard block
 block discarded – undo
157 157
 		// No digest string? Then you're done. Go home.
158 158
 		if (empty($digest_string))
159 159
 		{
160
-			$this->ci->output->set_header( sprintf('WWW-Authenticate: Digest realm="%s", nonce="%s", opaque="%s"', config_item('api.realm'), $nonce, $opaque) );
160
+			$this->ci->output->set_header(sprintf('WWW-Authenticate: Digest realm="%s", nonce="%s", opaque="%s"', config_item('api.realm'), $nonce, $opaque));
161 161
 			return false;
162 162
 		}
163 163
 
@@ -167,18 +167,18 @@  discard block
 block discarded – undo
167 167
 		preg_match_all('@(username|nonce|uri|nc|cnonce|qop|response)=[\'"]?([^\'",]+)@', $digest_string, $matches);
168 168
 		$digest = (empty($matches[1]) || empty($matches[2])) ? array() : array_combine($matches[1], $matches[2]);
169 169
 
170
-		if (! array_key_exists('username', $digest))
170
+		if ( ! array_key_exists('username', $digest))
171 171
 		{
172
-			$this->ci->output->set_header( sprintf('WWW-Authenticate: Digest realm="%s", nonce="%s", opaque="%s"', config_item('api.realm'), $nonce, $opaque) );
172
+			$this->ci->output->set_header(sprintf('WWW-Authenticate: Digest realm="%s", nonce="%s", opaque="%s"', config_item('api.realm'), $nonce, $opaque));
173 173
 			return false;
174 174
 		}
175 175
 
176 176
 		// Grab the user that corresponds to that "username"
177 177
 		// exact field determined in the api config file - api.auth_field setting.
178
-		$user = $this->user_model->as_array()->find_by( config_item('api.auth_field'), $digest['username'] );
179
-		if (!  $user)
178
+		$user = $this->user_model->as_array()->find_by(config_item('api.auth_field'), $digest['username']);
179
+		if ( ! $user)
180 180
 		{
181
-			$this->ci->output->set_header( sprintf('WWW-Authenticate: Digest realm="%s", nonce="%s", opaque="%s"', config_item('api.realm'), $nonce, $opaque) );
181
+			$this->ci->output->set_header(sprintf('WWW-Authenticate: Digest realm="%s", nonce="%s", opaque="%s"', config_item('api.realm'), $nonce, $opaque));
182 182
 			return false;
183 183
 		}
184 184
 
@@ -187,16 +187,16 @@  discard block
 block discarded – undo
187 187
 
188 188
 		if ($digest['qop'] == 'auth')
189 189
 		{
190
-			$A2 = md5( strtoupper( $_SERVER['REQUEST_METHOD'] ) .':'. $digest['uri'] );
190
+			$A2 = md5(strtoupper($_SERVER['REQUEST_METHOD']).':'.$digest['uri']);
191 191
 		} else {
192 192
 			$body = file_get_contents('php://input');
193
-			$A2 = md5( strtoupper( $_SERVER['REQUEST_METHOD'] ) .':'. $digest['uri'] .':'. md5($body) );
193
+			$A2 = md5(strtoupper($_SERVER['REQUEST_METHOD']).':'.$digest['uri'].':'.md5($body));
194 194
 		}
195
-		$valid_response = md5($A1 .':'. $digest['nonce'].':'. $digest['nc'] .':'. $digest['cnonce'] .':'. $digest['qop'] .':'. $A2);
195
+		$valid_response = md5($A1.':'.$digest['nonce'].':'.$digest['nc'].':'.$digest['cnonce'].':'.$digest['qop'].':'.$A2);
196 196
 
197 197
 		if ($digest['response'] != $valid_response)
198 198
 		{
199
-			$this->ci->output->set_header( sprintf('WWW-Authenticate: Digest realm="%s", nonce="%s", opaque="%s"', config_item('api.realm'), $nonce, $opaque) );
199
+			$this->ci->output->set_header(sprintf('WWW-Authenticate: Digest realm="%s", nonce="%s", opaque="%s"', config_item('api.realm'), $nonce, $opaque));
200 200
 			return false;
201 201
 		}
202 202
 
@@ -233,7 +233,7 @@  discard block
 block discarded – undo
233 233
 				break;
234 234
 		}
235 235
 
236
-		if (! $user)
236
+		if ( ! $user)
237 237
 		{
238 238
 			$this->user = null;
239 239
 			return $user;
@@ -246,7 +246,7 @@  discard block
 block discarded – undo
246 246
 
247 247
 		// If throttling time is above zero, we can't allow
248 248
 		// logins now.
249
-		if ($time = (int)$this->isThrottled($user['email']) > 0)
249
+		if ($time = (int) $this->isThrottled($user['email']) > 0)
250 250
 		{
251 251
 			$this->error = sprintf(lang('api.throttled'), $time);
252 252
 			return false;
@@ -274,13 +274,13 @@  discard block
 block discarded – undo
274 274
 	{
275 275
 	    $blacklist = explode(',', config_item('api.ip_blacklist'));
276 276
 
277
-		array_walk($blacklist, function (&$item, $key) {
277
+		array_walk($blacklist, function(&$item, $key) {
278 278
 			$item = trim($item);
279 279
 		});
280 280
 
281 281
 		if (in_array($this->ci->input->ip_address(), $blacklist))
282 282
 		{
283
-			throw new \Exception( lang('api.ip_denied'), 401);
283
+			throw new \Exception(lang('api.ip_denied'), 401);
284 284
 		}
285 285
 
286 286
 		return true;
@@ -299,13 +299,13 @@  discard block
 block discarded – undo
299 299
 
300 300
 		array_push($whitelist, '127.0.0.1', '0.0.0.0');
301 301
 
302
-		array_walk($whitelist, function (&$item, $key) {
302
+		array_walk($whitelist, function(&$item, $key) {
303 303
 			$item = trim($item);
304 304
 		});
305 305
 
306
-		if (! in_array($this->ci->input->ip_address(), $whitelist))
306
+		if ( ! in_array($this->ci->input->ip_address(), $whitelist))
307 307
 		{
308
-			throw new \Exception( lang('api.ip_denied'), 401);
308
+			throw new \Exception(lang('api.ip_denied'), 401);
309 309
 		}
310 310
 
311 311
 		return true;
@@ -362,9 +362,9 @@  discard block
 block discarded – undo
362 362
 	 *
363 363
 	 * @return bool|mixed|void
364 364
 	 */
365
-	public function login($credentials, $remember=false)
365
+	public function login($credentials, $remember = false)
366 366
 	{
367
-		throw new \BadMethodCallException( lang('api.unused_method') );
367
+		throw new \BadMethodCallException(lang('api.unused_method'));
368 368
 	}
369 369
 
370 370
 	//--------------------------------------------------------------------
@@ -379,7 +379,7 @@  discard block
 block discarded – undo
379 379
 	 */
380 380
 	public function logout()
381 381
 	{
382
-		throw new \BadMethodCallException( lang('api.unused_method') );
382
+		throw new \BadMethodCallException(lang('api.unused_method'));
383 383
 	}
384 384
 
385 385
 	//--------------------------------------------------------------------
Please login to merge, or discard this patch.
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -145,8 +145,7 @@
 block discarded – undo
145 145
 		if ($this->ci->input->server('PHP_AUTH_DIGEST'))
146 146
 		{
147 147
 			$digest_string = $this->ci->input->server('PHP_AUTH_DIGEST');
148
-		}
149
-		elseif ($this->ci->input->server('HTTP_AUTHORIZATION'))
148
+		} elseif ($this->ci->input->server('HTTP_AUTHORIZATION'))
150 149
 		{
151 150
 			$digest_string = $this->ci->input->server('HTTP_AUTHORIZATION');
152 151
 		}
Please login to merge, or discard this patch.
myth/Api/Server/LogModel.php 1 patch
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -55,11 +55,11 @@
 block discarded – undo
55 55
 		$time = date('Y-m-d H:00:00');
56 56
 
57 57
 		$query = $this->db->select('id')
58
-						  ->where('user_id', (int)$user_id)
58
+						  ->where('user_id', (int) $user_id)
59 59
 						  ->where('created_on >=', $time)
60 60
 						  ->get($this->table_name);
61 61
 
62
-		return (int)$query->num_rows();
62
+		return (int) $query->num_rows();
63 63
 	}
64 64
 
65 65
 	//--------------------------------------------------------------------
Please login to merge, or discard this patch.
myth/Auth/AuthenticateInterface.php 2 patches
Indentation   +191 added lines, -191 removed lines patch added patch discarded remove patch
@@ -42,196 +42,196 @@
 block discarded – undo
42 42
  */
43 43
 interface AuthenticateInterface {
44 44
 
45
-    /**
46
-     * Attempt to log a user into the system.
47
-     *
48
-     * $credentials is an array of key/value pairs needed to log the user in.
49
-     * This is often email/password, or username/password.
50
-     *
51
-     * @param $credentials
52
-     * @param bool $remember
53
-     */
54
-    public function login($credentials, $remember=false);
55
-
56
-    //--------------------------------------------------------------------
57
-
58
-    /**
59
-     * Validates user login information without logging them in.
60
-     *
61
-     * $credentials is an array of key/value pairs needed to log the user in.
62
-     * This is often email/password, or username/password.
63
-     *
64
-     * @param $credentials
65
-     * @param bool $return_user
66
-     * @return mixed
67
-     */
68
-    public function validate($credentials, $return_user=false);
69
-
70
-    //--------------------------------------------------------------------
71
-
72
-    /**
73
-     * Logs a user out and removes all session information.
74
-     *
75
-     * @return mixed
76
-     */
77
-    public function logout();
78
-
79
-    //--------------------------------------------------------------------
80
-
81
-    /**
82
-     * Checks whether a user is logged in or not.
83
-     *
84
-     * @return bool
85
-     */
86
-    public function isLoggedIn();
87
-
88
-    //--------------------------------------------------------------------
89
-
90
-    /**
91
-     * Attempts to log a user in based on the "remember me" cookie.
92
-     *
93
-     * @return bool
94
-     */
95
-    public function viaRemember();
96
-
97
-    //--------------------------------------------------------------------
98
-
99
-    /**
100
-     * Registers a new user and handles activation method.
101
-     *
102
-     * @param $user_data
103
-     * @return bool
104
-     */
105
-    public function registerUser($user_data);
106
-
107
-    //--------------------------------------------------------------------
108
-
109
-    /**
110
-     * Used to verify the user values and activate a user so they can
111
-     * visit the site.
112
-     *
113
-     * @param $data
114
-     * @return bool
115
-     */
116
-    public function activateUser($data);
117
-
118
-    //--------------------------------------------------------------------
119
-
120
-    /**
121
-     * Used to allow manual activation of a user with a known ID.
122
-     *
123
-     * @param $id
124
-     * @return bool
125
-     */
126
-    public function activateUserById($id);
127
-
128
-    //--------------------------------------------------------------------
129
-
130
-    /**
131
-     * Grabs the current user object. Returns NULL if nothing found.
132
-     *
133
-     * @return array|null
134
-     */
135
-    public function user();
136
-
137
-    //--------------------------------------------------------------------
138
-
139
-    /**
140
-     * A convenience method to grab the current user's ID.
141
-     *
142
-     * @return int|null
143
-     */
144
-    public function id();
145
-
146
-    //--------------------------------------------------------------------
147
-
148
-    /**
149
-     * Tells the system to start throttling a user. This may vary by implementation,
150
-     * but will often add additional time before another login is allowed.
151
-     *
152
-     * @param $email
153
-     * @return mixed
154
-     */
155
-    public function isThrottled($email);
156
-
157
-    //--------------------------------------------------------------------
158
-
159
-    /**
160
-     * Sends a password reminder email to the user associated with
161
-     * the passed in $email.
162
-     *
163
-     * @param $email
164
-     * @return mixed
165
-     */
166
-    public function remindUser($email);
167
-
168
-    //--------------------------------------------------------------------
169
-
170
-    /**
171
-     * Validates the credentials provided and, if valid, resets the password.
172
-     *
173
-     * @param $credentials
174
-     * @param $password
175
-     * @param $passConfirm
176
-     * @return mixed
177
-     */
178
-    public function resetPassword($credentials, $password, $passConfirm);
179
-
180
-    //--------------------------------------------------------------------
181
-
182
-    /**
183
-     * Provides a way for implementations to allow new statuses to be set
184
-     * on the user. The details will vary based upon implementation, but
185
-     * will often allow for banning or suspending users.
186
-     *
187
-     * @param $newStatus
188
-     * @param null $message
189
-     * @return mixed
190
-     */
191
-    public function changeStatus($newStatus, $message=null);
192
-
193
-    //--------------------------------------------------------------------
194
-
195
-    /**
196
-     * Allows the consuming application to pass in a reference to the
197
-     * model that should be used.
198
-     *
199
-     * The model MUST extend Myth\Models\CIDbModel.
200
-     *
201
-     * @param $model
202
-     * @return mixed
203
-     */
204
-    public function useModel($model);
205
-
206
-    //--------------------------------------------------------------------
207
-
208
-    /**
209
-     * Returns the current error string.
210
-     *
211
-     * @return mixed
212
-     */
213
-    public function error();
214
-
215
-    //--------------------------------------------------------------------
216
-
217
-    /**
218
-     * Purges all login attempt records from the database.
219
-     *
220
-     * @param $email
221
-     */
222
-    public function purgeLoginAttempts($email);
223
-
224
-    //--------------------------------------------------------------------
225
-
226
-    /**
227
-     * Purges all remember tokens for a single user. Effectively logs
228
-     * a user out of all devices. Intended to allow users to log themselves
229
-     * out of all devices as a security measure.
230
-     *
231
-     * @param $email
232
-     */
233
-    public function purgeRememberTokens($email);
234
-
235
-    //--------------------------------------------------------------------
45
+	/**
46
+	 * Attempt to log a user into the system.
47
+	 *
48
+	 * $credentials is an array of key/value pairs needed to log the user in.
49
+	 * This is often email/password, or username/password.
50
+	 *
51
+	 * @param $credentials
52
+	 * @param bool $remember
53
+	 */
54
+	public function login($credentials, $remember=false);
55
+
56
+	//--------------------------------------------------------------------
57
+
58
+	/**
59
+	 * Validates user login information without logging them in.
60
+	 *
61
+	 * $credentials is an array of key/value pairs needed to log the user in.
62
+	 * This is often email/password, or username/password.
63
+	 *
64
+	 * @param $credentials
65
+	 * @param bool $return_user
66
+	 * @return mixed
67
+	 */
68
+	public function validate($credentials, $return_user=false);
69
+
70
+	//--------------------------------------------------------------------
71
+
72
+	/**
73
+	 * Logs a user out and removes all session information.
74
+	 *
75
+	 * @return mixed
76
+	 */
77
+	public function logout();
78
+
79
+	//--------------------------------------------------------------------
80
+
81
+	/**
82
+	 * Checks whether a user is logged in or not.
83
+	 *
84
+	 * @return bool
85
+	 */
86
+	public function isLoggedIn();
87
+
88
+	//--------------------------------------------------------------------
89
+
90
+	/**
91
+	 * Attempts to log a user in based on the "remember me" cookie.
92
+	 *
93
+	 * @return bool
94
+	 */
95
+	public function viaRemember();
96
+
97
+	//--------------------------------------------------------------------
98
+
99
+	/**
100
+	 * Registers a new user and handles activation method.
101
+	 *
102
+	 * @param $user_data
103
+	 * @return bool
104
+	 */
105
+	public function registerUser($user_data);
106
+
107
+	//--------------------------------------------------------------------
108
+
109
+	/**
110
+	 * Used to verify the user values and activate a user so they can
111
+	 * visit the site.
112
+	 *
113
+	 * @param $data
114
+	 * @return bool
115
+	 */
116
+	public function activateUser($data);
117
+
118
+	//--------------------------------------------------------------------
119
+
120
+	/**
121
+	 * Used to allow manual activation of a user with a known ID.
122
+	 *
123
+	 * @param $id
124
+	 * @return bool
125
+	 */
126
+	public function activateUserById($id);
127
+
128
+	//--------------------------------------------------------------------
129
+
130
+	/**
131
+	 * Grabs the current user object. Returns NULL if nothing found.
132
+	 *
133
+	 * @return array|null
134
+	 */
135
+	public function user();
136
+
137
+	//--------------------------------------------------------------------
138
+
139
+	/**
140
+	 * A convenience method to grab the current user's ID.
141
+	 *
142
+	 * @return int|null
143
+	 */
144
+	public function id();
145
+
146
+	//--------------------------------------------------------------------
147
+
148
+	/**
149
+	 * Tells the system to start throttling a user. This may vary by implementation,
150
+	 * but will often add additional time before another login is allowed.
151
+	 *
152
+	 * @param $email
153
+	 * @return mixed
154
+	 */
155
+	public function isThrottled($email);
156
+
157
+	//--------------------------------------------------------------------
158
+
159
+	/**
160
+	 * Sends a password reminder email to the user associated with
161
+	 * the passed in $email.
162
+	 *
163
+	 * @param $email
164
+	 * @return mixed
165
+	 */
166
+	public function remindUser($email);
167
+
168
+	//--------------------------------------------------------------------
169
+
170
+	/**
171
+	 * Validates the credentials provided and, if valid, resets the password.
172
+	 *
173
+	 * @param $credentials
174
+	 * @param $password
175
+	 * @param $passConfirm
176
+	 * @return mixed
177
+	 */
178
+	public function resetPassword($credentials, $password, $passConfirm);
179
+
180
+	//--------------------------------------------------------------------
181
+
182
+	/**
183
+	 * Provides a way for implementations to allow new statuses to be set
184
+	 * on the user. The details will vary based upon implementation, but
185
+	 * will often allow for banning or suspending users.
186
+	 *
187
+	 * @param $newStatus
188
+	 * @param null $message
189
+	 * @return mixed
190
+	 */
191
+	public function changeStatus($newStatus, $message=null);
192
+
193
+	//--------------------------------------------------------------------
194
+
195
+	/**
196
+	 * Allows the consuming application to pass in a reference to the
197
+	 * model that should be used.
198
+	 *
199
+	 * The model MUST extend Myth\Models\CIDbModel.
200
+	 *
201
+	 * @param $model
202
+	 * @return mixed
203
+	 */
204
+	public function useModel($model);
205
+
206
+	//--------------------------------------------------------------------
207
+
208
+	/**
209
+	 * Returns the current error string.
210
+	 *
211
+	 * @return mixed
212
+	 */
213
+	public function error();
214
+
215
+	//--------------------------------------------------------------------
216
+
217
+	/**
218
+	 * Purges all login attempt records from the database.
219
+	 *
220
+	 * @param $email
221
+	 */
222
+	public function purgeLoginAttempts($email);
223
+
224
+	//--------------------------------------------------------------------
225
+
226
+	/**
227
+	 * Purges all remember tokens for a single user. Effectively logs
228
+	 * a user out of all devices. Intended to allow users to log themselves
229
+	 * out of all devices as a security measure.
230
+	 *
231
+	 * @param $email
232
+	 */
233
+	public function purgeRememberTokens($email);
234
+
235
+	//--------------------------------------------------------------------
236 236
 
237 237
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -51,7 +51,7 @@  discard block
 block discarded – undo
51 51
      * @param $credentials
52 52
      * @param bool $remember
53 53
      */
54
-    public function login($credentials, $remember=false);
54
+    public function login($credentials, $remember = false);
55 55
 
56 56
     //--------------------------------------------------------------------
57 57
 
@@ -65,7 +65,7 @@  discard block
 block discarded – undo
65 65
      * @param bool $return_user
66 66
      * @return mixed
67 67
      */
68
-    public function validate($credentials, $return_user=false);
68
+    public function validate($credentials, $return_user = false);
69 69
 
70 70
     //--------------------------------------------------------------------
71 71
 
@@ -188,7 +188,7 @@  discard block
 block discarded – undo
188 188
      * @param null $message
189 189
      * @return mixed
190 190
      */
191
-    public function changeStatus($newStatus, $message=null);
191
+    public function changeStatus($newStatus, $message = null);
192 192
 
193 193
     //--------------------------------------------------------------------
194 194
 
Please login to merge, or discard this patch.
myth/Auth/AuthorizeInterface.php 1 patch
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -30,7 +30,7 @@  discard block
 block discarded – undo
30 30
  * @since       Version 1.0
31 31
  */
32 32
 
33
-interface AuthorizeInterface  {
33
+interface AuthorizeInterface {
34 34
 
35 35
 	/**
36 36
 	 * Returns the latest error string.
@@ -150,7 +150,7 @@  discard block
 block discarded – undo
150 150
 	 *
151 151
 	 * @return mixed
152 152
 	 */
153
-	public function createGroup($name, $description='');
153
+	public function createGroup($name, $description = '');
154 154
 
155 155
 	//--------------------------------------------------------------------
156 156
 
@@ -174,7 +174,7 @@  discard block
 block discarded – undo
174 174
 	 *
175 175
 	 * @return mixed
176 176
 	 */
177
-	public function updateGroup($id, $name, $description='');
177
+	public function updateGroup($id, $name, $description = '');
178 178
 
179 179
 	//--------------------------------------------------------------------
180 180
 
@@ -210,7 +210,7 @@  discard block
 block discarded – undo
210 210
 	 *
211 211
 	 * @return mixed
212 212
 	 */
213
-	public function createPermission($name, $description='');
213
+	public function createPermission($name, $description = '');
214 214
 
215 215
 	//--------------------------------------------------------------------
216 216
 
@@ -234,7 +234,7 @@  discard block
 block discarded – undo
234 234
 	 *
235 235
 	 * @return bool
236 236
 	 */
237
-	public function updatePermission($id, $name, $description='');
237
+	public function updatePermission($id, $name, $description = '');
238 238
 
239 239
 	//--------------------------------------------------------------------
240 240
 
Please login to merge, or discard this patch.
myth/Auth/Flat/FlatGroupsModel.php 2 patches
Indentation   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -85,10 +85,10 @@  discard block
 block discarded – undo
85 85
 	 */
86 86
 	public function addUserToGroup($user_id, $group_id)
87 87
 	{
88
-	    $data = [
89
-		    'user_id'   => (int)$user_id,
90
-		    'group_id'  => (int)$group_id
91
-	    ];
88
+		$data = [
89
+			'user_id'   => (int)$user_id,
90
+			'group_id'  => (int)$group_id
91
+		];
92 92
 
93 93
 		return $this->db->insert('auth_groups_users', $data);
94 94
 	}
@@ -105,10 +105,10 @@  discard block
 block discarded – undo
105 105
 	 */
106 106
 	public function removeUserFromGroup($user_id, $group_id)
107 107
 	{
108
-	    return $this->where([
109
-		    'user_id' => (int)$user_id,
110
-		    'group_id' => (int)$group_id
111
-	    ])->delete('auth_groups_users');
108
+		return $this->where([
109
+			'user_id' => (int)$user_id,
110
+			'group_id' => (int)$group_id
111
+		])->delete('auth_groups_users');
112 112
 	}
113 113
 
114 114
 	//--------------------------------------------------------------------
@@ -122,8 +122,8 @@  discard block
 block discarded – undo
122 122
 	 */
123 123
 	public function removeUserFromAllGroups($user_id)
124 124
 	{
125
-	    return $this->db->where('user_id', (int)$user_id)
126
-		                ->delete('auth_groups_users');
125
+		return $this->db->where('user_id', (int)$user_id)
126
+						->delete('auth_groups_users');
127 127
 	}
128 128
 
129 129
 	//--------------------------------------------------------------------
@@ -137,11 +137,11 @@  discard block
 block discarded – undo
137 137
 	 */
138 138
 	public function getGroupsForUser($user_id)
139 139
 	{
140
-	    return $this->select('auth_groups_users.*, auth_groups.name, auth_groups.description')
141
-		            ->join('auth_groups_users', 'auth_groups_users.group_id = auth_groups.id', 'left')
142
-		            ->where('user_id', $user_id)
143
-		            ->as_array()
144
-		            ->find_all();
140
+		return $this->select('auth_groups_users.*, auth_groups.name, auth_groups.description')
141
+					->join('auth_groups_users', 'auth_groups_users.group_id = auth_groups.id', 'left')
142
+					->where('user_id', $user_id)
143
+					->as_array()
144
+					->find_all();
145 145
 	}
146 146
 
147 147
 	//--------------------------------------------------------------------
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
 			'group_id'      => (int)$group_id
161 161
 		];
162 162
 
163
-	    return $this->db->insert('auth_groups_permissions', $data);
163
+		return $this->db->insert('auth_groups_permissions', $data);
164 164
 	}
165 165
 
166 166
 	//--------------------------------------------------------------------
@@ -176,10 +176,10 @@  discard block
 block discarded – undo
176 176
 	 */
177 177
 	public function removePermissionFromGroup($permission_id, $group_id)
178 178
 	{
179
-	    return $this->db->where([
180
-		    'permission_id' => $permission_id,
181
-		    'group_id'      => $group_id
182
-	    ])->delete('auth_groups_permissions');
179
+		return $this->db->where([
180
+			'permission_id' => $permission_id,
181
+			'group_id'      => $group_id
182
+		])->delete('auth_groups_permissions');
183 183
 	}
184 184
 
185 185
 	//--------------------------------------------------------------------
@@ -193,8 +193,8 @@  discard block
 block discarded – undo
193 193
 	 */
194 194
 	public function removePermissionFromAllGroups($permission_id)
195 195
 	{
196
-	    return $this->db->where('permission_id', $permission_id)
197
-		                ->delete('auth_groups_permissions');
196
+		return $this->db->where('permission_id', $permission_id)
197
+						->delete('auth_groups_permissions');
198 198
 	}
199 199
 
200 200
 	//--------------------------------------------------------------------
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -86,8 +86,8 @@  discard block
 block discarded – undo
86 86
 	public function addUserToGroup($user_id, $group_id)
87 87
 	{
88 88
 	    $data = [
89
-		    'user_id'   => (int)$user_id,
90
-		    'group_id'  => (int)$group_id
89
+		    'user_id'   => (int) $user_id,
90
+		    'group_id'  => (int) $group_id
91 91
 	    ];
92 92
 
93 93
 		return $this->db->insert('auth_groups_users', $data);
@@ -106,8 +106,8 @@  discard block
 block discarded – undo
106 106
 	public function removeUserFromGroup($user_id, $group_id)
107 107
 	{
108 108
 	    return $this->where([
109
-		    'user_id' => (int)$user_id,
110
-		    'group_id' => (int)$group_id
109
+		    'user_id' => (int) $user_id,
110
+		    'group_id' => (int) $group_id
111 111
 	    ])->delete('auth_groups_users');
112 112
 	}
113 113
 
@@ -122,7 +122,7 @@  discard block
 block discarded – undo
122 122
 	 */
123 123
 	public function removeUserFromAllGroups($user_id)
124 124
 	{
125
-	    return $this->db->where('user_id', (int)$user_id)
125
+	    return $this->db->where('user_id', (int) $user_id)
126 126
 		                ->delete('auth_groups_users');
127 127
 	}
128 128
 
@@ -156,8 +156,8 @@  discard block
 block discarded – undo
156 156
 	public function addPermissionToGroup($permission_id, $group_id)
157 157
 	{
158 158
 		$data = [
159
-			'permission_id' => (int)$permission_id,
160
-			'group_id'      => (int)$group_id
159
+			'permission_id' => (int) $permission_id,
160
+			'group_id'      => (int) $group_id
161 161
 		];
162 162
 
163 163
 	    return $this->db->insert('auth_groups_permissions', $data);
Please login to merge, or discard this patch.
myth/Auth/Flat/FlatPermissionsModel.php 1 patch
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -84,11 +84,11 @@
 block discarded – undo
84 84
 	{
85 85
 		$permissions = $this->join('auth_groups_permissions', 'auth_groups_permissions.permission_id = auth_permissions.id', 'inner')
86 86
 							->join('auth_groups_users', 'auth_groups_users.group_id = auth_groups_permissions.group_id', 'inner')
87
-							->where('auth_groups_users.user_id', (int)$user_id)
87
+							->where('auth_groups_users.user_id', (int) $user_id)
88 88
 							->as_array()
89 89
 							->find_all();
90 90
 
91
-		if (! $permissions)
91
+		if ( ! $permissions)
92 92
 		{
93 93
 			return false;
94 94
 		}
Please login to merge, or discard this patch.
myth/Auth/LocalAuthentication.php 3 patches
Spacing   +60 added lines, -60 removed lines patch added patch discarded remove patch
@@ -62,21 +62,21 @@  discard block
 block discarded – undo
62 62
 
63 63
     //--------------------------------------------------------------------
64 64
 
65
-    public function __construct( $ci=null )
65
+    public function __construct($ci = null)
66 66
     {
67 67
         if ($ci)
68 68
         {
69
-            $this->ci= $ci;
69
+            $this->ci = $ci;
70 70
         }
71 71
         else
72 72
         {
73
-            $this->ci =& get_instance();
73
+            $this->ci = & get_instance();
74 74
         }
75 75
 
76 76
         // Get our compatibility password file loaded up.
77
-        if (! function_exists('password_hash'))
77
+        if ( ! function_exists('password_hash'))
78 78
         {
79
-            require_once dirname(__FILE__) .'password.php';
79
+            require_once dirname(__FILE__).'password.php';
80 80
         }
81 81
 
82 82
         if (empty($this->ci->session))
@@ -101,18 +101,18 @@  discard block
 block discarded – undo
101 101
      * @param bool  $remember
102 102
      * @return bool|mixed
103 103
      */
104
-    public function login($credentials, $remember=false)
104
+    public function login($credentials, $remember = false)
105 105
     {
106 106
         $user = $this->validate($credentials, true);
107 107
 
108
-        if (! $user)
108
+        if ( ! $user)
109 109
         {
110 110
 	        // We need to send an error even if no
111 111
 	        // user was found!
112 112
 	        $this->error = lang('auth.invalid_user');
113 113
 
114 114
 	        // If an email is present, log the attempt
115
-	        if (! empty($credentials['email']) )
115
+	        if ( ! empty($credentials['email']))
116 116
 	        {
117 117
 		        $this->ci->login_model->recordLoginAttempt($credentials['email']);
118 118
 	        }
@@ -128,7 +128,7 @@  discard block
 block discarded – undo
128 128
 
129 129
         // If throttling time is above zero, we can't allow
130 130
         // logins now.
131
-        $time = (int)$this->isThrottled($user['email']);
131
+        $time = (int) $this->isThrottled($user['email']);
132 132
         if ($time > 0)
133 133
         {
134 134
             $this->error = sprintf(lang('auth.throttled'), $time);
@@ -159,7 +159,7 @@  discard block
 block discarded – undo
159 159
      * @param bool $return_user
160 160
      * @return mixed
161 161
      */
162
-    public function validate($credentials, $return_user=false)
162
+    public function validate($credentials, $return_user = false)
163 163
     {
164 164
         // Can't validate without a password.
165 165
         if (empty($credentials['password']) || count($credentials) < 2)
@@ -179,7 +179,7 @@  discard block
 block discarded – undo
179 179
 	    }
180 180
 
181 181
         // Ensure that the fields are allowed validation fields
182
-	    if (! in_array(key($credentials), config_item('auth.valid_fields')) )
182
+	    if ( ! in_array(key($credentials), config_item('auth.valid_fields')))
183 183
 	    {
184 184
 		    $this->error = lang('auth.invalid_credentials');
185 185
 		    return false;
@@ -187,7 +187,7 @@  discard block
 block discarded – undo
187 187
 
188 188
         // We do not want to force case-sensitivity on things
189 189
         // like username and email for usability sake.
190
-        if (! empty($credentials['email']))
190
+        if ( ! empty($credentials['email']))
191 191
         {
192 192
             $credentials['email'] = strtolower($credentials['email']);
193 193
         }
@@ -197,16 +197,16 @@  discard block
 block discarded – undo
197 197
                                  ->where($credentials)
198 198
                                  ->first();
199 199
 
200
-        if (! $user)
200
+        if ( ! $user)
201 201
         {
202 202
             $this->error = lang('auth.invalid_user');
203 203
             return false;
204 204
         }
205 205
 
206 206
         // Now, try matching the passwords.
207
-        $result =  password_verify($password, $user['password_hash']);
207
+        $result = password_verify($password, $user['password_hash']);
208 208
 
209
-        if (! $result)
209
+        if ( ! $result)
210 210
         {
211 211
             $this->error = lang('auth.invalid_password');
212 212
             $this->ci->login_model->recordLoginAttempt($user['email']);
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
         // This would be due to the hash algorithm or hash
218 218
         // cost changing since the last time that a user
219 219
         // logged in.
220
-        if (password_needs_rehash($user['password_hash'], PASSWORD_DEFAULT, ['cost' => config_item('auth.hash_cost')] ))
220
+        if (password_needs_rehash($user['password_hash'], PASSWORD_DEFAULT, ['cost' => config_item('auth.hash_cost')]))
221 221
         {
222 222
             $new_hash = Password::hashPassword($password);
223 223
             $this->user_model->skip_validation()
@@ -226,7 +226,7 @@  discard block
 block discarded – undo
226 226
         }
227 227
 
228 228
         // Is the user active?
229
-        if (! $user['active'])
229
+        if ( ! $user['active'])
230 230
         {
231 231
             $this->error = lang('auth.inactive_account');
232 232
             return false;
@@ -246,7 +246,7 @@  discard block
 block discarded – undo
246 246
     {
247 247
         $this->ci->load->helper('cookie');
248 248
 
249
-        if (! Events::trigger('beforeLogout', [$this->user]))
249
+        if ( ! Events::trigger('beforeLogout', [$this->user]))
250 250
         {
251 251
             return false;
252 252
         }
@@ -255,10 +255,10 @@  discard block
 block discarded – undo
255 255
         // available for flash messages, etc.
256 256
         if (isset($_SESSION))
257 257
         {
258
-            foreach ( $_SESSION as $key => $value )
258
+            foreach ($_SESSION as $key => $value)
259 259
             {
260
-                $_SESSION[ $key ] = NULL;
261
-                unset( $_SESSION[ $key ] );
260
+                $_SESSION[$key] = NULL;
261
+                unset($_SESSION[$key]);
262 262
             }
263 263
         }
264 264
         // Also, regenerate the session ID for a touch of added safety.
@@ -284,7 +284,7 @@  discard block
 block discarded – undo
284 284
     {
285 285
         $id = $this->ci->session->userdata('logged_in');
286 286
 
287
-        if (! $id)
287
+        if ( ! $id)
288 288
         {
289 289
             return false;
290 290
         }
@@ -292,10 +292,10 @@  discard block
 block discarded – undo
292 292
         // If the user var hasn't been filled in, we need to fill it in,
293 293
         // since this method will typically be used as the only method
294 294
         // to determine whether a user is logged in or not.
295
-        if (! $this->user)
295
+        if ( ! $this->user)
296 296
         {
297 297
             $this->user = $this->user_model->as_array()
298
-                                           ->find_by('id', (int)$id);
298
+                                           ->find_by('id', (int) $id);
299 299
 
300 300
             if (empty($this->user))
301 301
             {
@@ -319,14 +319,14 @@  discard block
 block discarded – undo
319 319
      */
320 320
     public function viaRemember()
321 321
     {
322
-        if (! config_item('auth.allow_remembering'))
322
+        if ( ! config_item('auth.allow_remembering'))
323 323
         {
324 324
             return false;
325 325
         }
326 326
 
327 327
         $this->ci->load->helper('cookie');
328 328
 
329
-        if (! $token = get_cookie('remember'))
329
+        if ( ! $token = get_cookie('remember'))
330 330
         {
331 331
             return false;
332 332
         }
@@ -335,7 +335,7 @@  discard block
 block discarded – undo
335 335
         $query = $this->ci->db->where('hash', $this->ci->login_model->hashRememberToken($token))
336 336
                               ->get('auth_tokens');
337 337
 
338
-        if (! $query->num_rows())
338
+        if ( ! $query->num_rows())
339 339
         {
340 340
             return false;
341 341
         }
@@ -373,16 +373,16 @@  discard block
 block discarded – undo
373 373
         // If via email, we need to generate a hash
374 374
         $this->ci->load->helper('string');
375 375
         $token = random_string('alnum', 24);
376
-        $user_data['activate_hash'] = hash('sha1', config_item('auth.salt') . $token);
376
+        $user_data['activate_hash'] = hash('sha1', config_item('auth.salt').$token);
377 377
 
378 378
         // Email should NOT be case sensitive.
379
-        if (! empty($user_data['email']))
379
+        if ( ! empty($user_data['email']))
380 380
         {
381 381
             $user_data['email'] = strtolower($user_data['email']);
382 382
         }
383 383
 
384 384
         // Save the user
385
-        if (! $id = $this->user_model->insert($user_data))
385
+        if ( ! $id = $this->user_model->insert($user_data))
386 386
         {
387 387
             $this->error = $this->user_model->error();
388 388
             return false;
@@ -413,25 +413,25 @@  discard block
 block discarded – undo
413 413
     {
414 414
         $post = [
415 415
             'email'         => $data['email'],
416
-            'activate_hash' => hash('sha1', config_item('auth.salt') . $data['code'])
416
+            'activate_hash' => hash('sha1', config_item('auth.salt').$data['code'])
417 417
         ];
418 418
 
419 419
         $user = $this->user_model->where($post)
420 420
                                  ->first();
421 421
 
422
-        if (! $user) {
422
+        if ( ! $user) {
423 423
             $this->error = $this->user_model->error() ? $this->user_model->error() : lang('auth.activate_no_user');
424 424
 
425 425
             return false;
426 426
         }
427 427
 
428
-        if (! $this->user_model->update($user->id, ['active' => 1, 'activate_hash' => null]))
428
+        if ( ! $this->user_model->update($user->id, ['active' => 1, 'activate_hash' => null]))
429 429
         {
430 430
             $this->error = $this->user_model->error();
431 431
             return false;
432 432
         }
433 433
 
434
-        Events::trigger('didActivate', [(array)$user]);
434
+        Events::trigger('didActivate', [(array) $user]);
435 435
 
436 436
         return true;
437 437
     }
@@ -446,7 +446,7 @@  discard block
 block discarded – undo
446 446
      */
447 447
     public function activateUserById($id)
448 448
     {
449
-        if (! $this->user_model->update($id, ['active' => 1, 'activate_hash' => null]))
449
+        if ( ! $this->user_model->update($id, ['active' => 1, 'activate_hash' => null]))
450 450
         {
451 451
             $this->error = $this->user_model->error();
452 452
             return false;
@@ -478,12 +478,12 @@  discard block
 block discarded – undo
478 478
      */
479 479
     public function id()
480 480
     {
481
-        if (! is_array($this->user) || empty($this->user['id']))
481
+        if ( ! is_array($this->user) || empty($this->user['id']))
482 482
         {
483 483
             return null;
484 484
         }
485 485
 
486
-        return (int)$this->user['id'];
486
+        return (int) $this->user['id'];
487 487
     }
488 488
 
489 489
     //--------------------------------------------------------------------
@@ -500,7 +500,7 @@  discard block
 block discarded – undo
500 500
     public function isThrottled($email)
501 501
     {
502 502
         // Not throttling? Get outta here!
503
-        if (! config_item('auth.allow_throttling'))
503
+        if ( ! config_item('auth.allow_throttling'))
504 504
         {
505 505
             return false;
506 506
         }
@@ -564,7 +564,7 @@  discard block
 block discarded – undo
564 564
         {
565 565
             $this->error = lang('auth.bruteBan_notice');
566 566
 
567
-            $ban_time = 60 * 15;    // 15 minutes
567
+            $ban_time = 60 * 15; // 15 minutes
568 568
             $_SESSION['bruteBan'] = time() + $ban_time;
569 569
             return $ban_time;
570 570
         }
@@ -612,7 +612,7 @@  discard block
 block discarded – undo
612 612
         // Is it a valid user?
613 613
         $user = $this->user_model->find_by('email', $email);
614 614
 
615
-        if (! $user)
615
+        if ( ! $user)
616 616
         {
617 617
             $this->error = lang('auth.invalid_email');
618 618
             return false;
@@ -621,17 +621,17 @@  discard block
 block discarded – undo
621 621
         // Generate/store our codes
622 622
         $this->ci->load->helper('string');
623 623
         $token = random_string('alnum', 24);
624
-        $hash = hash('sha1', config_item('auth.salt') .$token);
624
+        $hash = hash('sha1', config_item('auth.salt').$token);
625 625
 
626 626
         $result = $this->user_model->update($user->id, ['reset_hash' => $hash]);
627 627
 
628
-        if (! $result)
628
+        if ( ! $result)
629 629
         {
630 630
             $this->error = $this->user_model->error();
631 631
             return false;
632 632
         }
633 633
 
634
-        Events::trigger('didRemindUser', [(array)$user, $token]);
634
+        Events::trigger('didRemindUser', [(array) $user, $token]);
635 635
 
636 636
         return true;
637 637
     }
@@ -658,10 +658,10 @@  discard block
 block discarded – undo
658 658
         }
659 659
 
660 660
         // Generate a hash to match against the table.
661
-        $credentials['reset_hash'] = hash('sha1', config_item('auth.salt') .$credentials['code']);
661
+        $credentials['reset_hash'] = hash('sha1', config_item('auth.salt').$credentials['code']);
662 662
         unset($credentials['code']);
663 663
 
664
-        if (! empty($credentials['email']))
664
+        if ( ! empty($credentials['email']))
665 665
         {
666 666
             $credentials['email'] = strtolower($credentials['email']);
667 667
         }
@@ -669,7 +669,7 @@  discard block
 block discarded – undo
669 669
         // Is there a matching user?
670 670
         $user = $this->user_model->find_by($credentials);
671 671
 
672
-        if (! $user)
672
+        if ( ! $user)
673 673
         {
674 674
             $this->error = lang('auth.reset_no_user');
675 675
             return false;
@@ -682,13 +682,13 @@  discard block
 block discarded – undo
682 682
             'reset_hash'   => null
683 683
         ];
684 684
 
685
-        if (! $this->user_model->update($user->id, $data))
685
+        if ( ! $this->user_model->update($user->id, $data))
686 686
         {
687 687
             $this->error = $this->user_model->error();
688 688
             return false;
689 689
         }
690 690
 
691
-        Events::trigger('didResetPassword', [(array)$user]);
691
+        Events::trigger('didResetPassword', [(array) $user]);
692 692
 
693 693
         return true;
694 694
     }
@@ -704,7 +704,7 @@  discard block
 block discarded – undo
704 704
      * @param null $message
705 705
      * @return mixed
706 706
      */
707
-    public function changeStatus($newStatus, $message=null)
707
+    public function changeStatus($newStatus, $message = null)
708 708
     {
709 709
         // todo actually record new users status!
710 710
     }
@@ -721,14 +721,14 @@  discard block
 block discarded – undo
721 721
      * @param bool $allow_any_parent
722 722
      * @return mixed
723 723
      */
724
-    public function useModel($model, $allow_any_parent=false)
724
+    public function useModel($model, $allow_any_parent = false)
725 725
     {
726
-        if (! $allow_any_parent && get_parent_class($model) != 'Myth\Models\CIDbModel')
726
+        if ( ! $allow_any_parent && get_parent_class($model) != 'Myth\Models\CIDbModel')
727 727
         {
728 728
             throw new \RuntimeException('Models passed into LocalAuthenticate MUST extend Myth\Models\CIDbModel');
729 729
         }
730 730
 
731
-        $this->user_model =& $model;
731
+        $this->user_model = & $model;
732 732
 
733 733
         return $this;
734 734
     }
@@ -800,7 +800,7 @@  discard block
 block discarded – undo
800 800
      */
801 801
     protected function rememberUser($user)
802 802
     {
803
-        if (! config_item('auth.allow_remembering'))
803
+        if ( ! config_item('auth.allow_remembering'))
804 804
         {
805 805
             log_message('debug', 'Auth library set to refuse "Remember Me" functionality.');
806 806
             return false;
@@ -819,13 +819,13 @@  discard block
 block discarded – undo
819 819
      * @param null $token
820 820
      * @return mixed
821 821
      */
822
-    protected function refreshRememberCookie($user, $token=null)
822
+    protected function refreshRememberCookie($user, $token = null)
823 823
     {
824 824
         $this->ci->load->helper('cookie');
825 825
 
826 826
         // If a token is passed in, we know we're removing the
827 827
         // old one.
828
-        if (! empty($token))
828
+        if ( ! empty($token))
829 829
         {
830 830
             $this->invalidateRememberCookie($user['email'], $token);
831 831
         }
@@ -835,7 +835,7 @@  discard block
 block discarded – undo
835 835
         // Save the token to the database.
836 836
         $data = [
837 837
             'email'   => $user['email'],
838
-            'hash'    => sha1(config_item('auth.salt') . $new_token),
838
+            'hash'    => sha1(config_item('auth.salt').$new_token),
839 839
             'created' => date('Y-m-d H:i:s')
840 840
         ];
841 841
 
@@ -843,13 +843,13 @@  discard block
 block discarded – undo
843 843
 
844 844
         // Create the cookie
845 845
         set_cookie(
846
-            'remember',                             // Cookie Name
847
-            $new_token,                             // Value
848
-            config_item('auth.remember_length'),    // # Seconds until it expires
846
+            'remember', // Cookie Name
847
+            $new_token, // Value
848
+            config_item('auth.remember_length'), // # Seconds until it expires
849 849
             config_item('cookie_domain'),
850 850
             config_item('cookie_path'),
851 851
             config_item('cookie_prefix'),
852
-            false,                                  // Only send over HTTPS?
852
+            false, // Only send over HTTPS?
853 853
             true                                    // Hide from Javascript?
854 854
         );
855 855
 
Please login to merge, or discard this patch.
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -253,8 +253,7 @@
 block discarded – undo
253 253
             {
254 254
                 $this->vars[$k] = $escape ? esc($v, $context, $this->escaper) : $v;
255 255
             }
256
-        }
257
-        else
256
+        } else
258 257
         {
259 258
             $this->vars[$name] = $escape ? esc($value, $context, $this->escaper) : $value;
260 259
         }
Please login to merge, or discard this patch.
Indentation   +887 added lines, -887 removed lines patch added patch discarded remove patch
@@ -52,893 +52,893 @@
 block discarded – undo
52 52
  */
53 53
 class LocalAuthentication implements AuthenticateInterface {
54 54
 
55
-    protected $ci;
56
-
57
-    protected $user = null;
58
-
59
-    public $user_model = null;
60
-
61
-    public $error = null;
62
-
63
-    //--------------------------------------------------------------------
64
-
65
-    public function __construct( $ci=null )
66
-    {
67
-        if ($ci)
68
-        {
69
-            $this->ci= $ci;
70
-        }
71
-        else
72
-        {
73
-            $this->ci =& get_instance();
74
-        }
75
-
76
-        // Get our compatibility password file loaded up.
77
-        if (! function_exists('password_hash'))
78
-        {
79
-            require_once dirname(__FILE__) .'password.php';
80
-        }
81
-
82
-        if (empty($this->ci->session))
83
-        {
84
-            $this->ci->load->library('session');
85
-        }
86
-
87
-        $this->ci->config->load('auth');
88
-        $this->ci->load->model('auth/login_model');
89
-        $this->ci->load->language('auth/auth');
90
-    }
91
-
92
-    //--------------------------------------------------------------------
93
-
94
-    /**
95
-     * Attempt to log a user into the system.
96
-     *
97
-     * $credentials is an array of key/value pairs needed to log the user in.
98
-     * This is often email/password, or username/password.
99
-     *
100
-     * @param array $credentials
101
-     * @param bool  $remember
102
-     * @return bool|mixed
103
-     */
104
-    public function login($credentials, $remember=false)
105
-    {
106
-        $user = $this->validate($credentials, true);
107
-
108
-        if (! $user)
109
-        {
110
-	        // We need to send an error even if no
111
-	        // user was found!
112
-	        $this->error = lang('auth.invalid_user');
113
-
114
-	        // If an email is present, log the attempt
115
-	        if (! empty($credentials['email']) )
116
-	        {
117
-		        $this->ci->login_model->recordLoginAttempt($credentials['email']);
118
-	        }
119
-
120
-            $this->user = null;
121
-            return $user;
122
-        }
123
-
124
-        // If the user is throttled due to too many invalid logins
125
-        // or the system is under attack, kick them back.
126
-        // We need to test for this after validation because we
127
-        // don't want it to affect a valid login.
128
-
129
-        // If throttling time is above zero, we can't allow
130
-        // logins now.
131
-        $time = (int)$this->isThrottled($user['email']);
132
-        if ($time > 0)
133
-        {
134
-            $this->error = sprintf(lang('auth.throttled'), $time);
135
-            return false;
136
-        }
137
-
138
-        $this->loginUser($user);
139
-
140
-        if ($remember)
141
-        {
142
-            $this->rememberUser($user);
143
-        }
144
-
145
-        Events::trigger('didLogin', [$user]);
146
-
147
-        return true;
148
-    }
149
-
150
-    //--------------------------------------------------------------------
151
-
152
-    /**
153
-     * Validates user login information without logging them in.
154
-     *
155
-     * $credentials is an array of key/value pairs needed to log the user in.
156
-     * This is often email/password, or username/password.
157
-     *
158
-     * @param $credentials
159
-     * @param bool $return_user
160
-     * @return mixed
161
-     */
162
-    public function validate($credentials, $return_user=false)
163
-    {
164
-        // Can't validate without a password.
165
-        if (empty($credentials['password']) || count($credentials) < 2)
166
-        {
167
-            return null;
168
-        }
169
-
170
-        $password = $credentials['password'];
171
-        unset($credentials['password']);
172
-
173
-	    // We should only be allowed 1 single other credential to
174
-	    // test against.
175
-	    if (count($credentials) > 1)
176
-	    {
177
-		    $this->error = lang('auth.too_many_credentials');
178
-		    return false;
179
-	    }
180
-
181
-        // Ensure that the fields are allowed validation fields
182
-	    if (! in_array(key($credentials), config_item('auth.valid_fields')) )
183
-	    {
184
-		    $this->error = lang('auth.invalid_credentials');
185
-		    return false;
186
-	    }
187
-
188
-        // We do not want to force case-sensitivity on things
189
-        // like username and email for usability sake.
190
-        if (! empty($credentials['email']))
191
-        {
192
-            $credentials['email'] = strtolower($credentials['email']);
193
-        }
194
-
195
-        // Can we find a user with those credentials?
196
-        $user = $this->user_model->as_array()
197
-                                 ->where($credentials)
198
-                                 ->first();
199
-
200
-        if (! $user)
201
-        {
202
-            $this->error = lang('auth.invalid_user');
203
-            return false;
204
-        }
205
-
206
-        // Now, try matching the passwords.
207
-        $result =  password_verify($password, $user['password_hash']);
208
-
209
-        if (! $result)
210
-        {
211
-            $this->error = lang('auth.invalid_password');
212
-            $this->ci->login_model->recordLoginAttempt($user['email']);
213
-            return false;
214
-        }
215
-
216
-        // Check to see if the password needs to be rehashed.
217
-        // This would be due to the hash algorithm or hash
218
-        // cost changing since the last time that a user
219
-        // logged in.
220
-        if (password_needs_rehash($user['password_hash'], PASSWORD_DEFAULT, ['cost' => config_item('auth.hash_cost')] ))
221
-        {
222
-            $new_hash = Password::hashPassword($password);
223
-            $this->user_model->skip_validation()
224
-                             ->update($user['id'], ['password_hash' => $new_hash]);
225
-            unset($new_hash);
226
-        }
227
-
228
-        // Is the user active?
229
-        if (! $user['active'])
230
-        {
231
-            $this->error = lang('auth.inactive_account');
232
-            return false;
233
-        }
234
-
235
-        return $return_user ? $user : true;
236
-    }
237
-
238
-    //--------------------------------------------------------------------
239
-
240
-    /**
241
-     * Logs a user out and removes all session information.
242
-     *
243
-     * @return mixed
244
-     */
245
-    public function logout()
246
-    {
247
-        $this->ci->load->helper('cookie');
248
-
249
-        if (! Events::trigger('beforeLogout', [$this->user]))
250
-        {
251
-            return false;
252
-        }
253
-
254
-        // Destroy the session data - but ensure a session is still
255
-        // available for flash messages, etc.
256
-        if (isset($_SESSION))
257
-        {
258
-            foreach ( $_SESSION as $key => $value )
259
-            {
260
-                $_SESSION[ $key ] = NULL;
261
-                unset( $_SESSION[ $key ] );
262
-            }
263
-        }
264
-        // Also, regenerate the session ID for a touch of added safety.
265
-        $this->ci->session->sess_regenerate(true);
266
-
267
-        // Take care of any rememberme functionality.
268
-        if (config_item('auth.allow_remembering'))
269
-        {
270
-            $token = get_cookie('remember');
271
-
272
-            $this->invalidateRememberCookie($this->user['email'], $token);
273
-        }
274
-    }
275
-
276
-    //--------------------------------------------------------------------
277
-
278
-    /**
279
-     * Checks whether a user is logged in or not.
280
-     *
281
-     * @return bool
282
-     */
283
-    public function isLoggedIn()
284
-    {
285
-        $id = $this->ci->session->userdata('logged_in');
286
-
287
-        if (! $id)
288
-        {
289
-            return false;
290
-        }
291
-
292
-        // If the user var hasn't been filled in, we need to fill it in,
293
-        // since this method will typically be used as the only method
294
-        // to determine whether a user is logged in or not.
295
-        if (! $this->user)
296
-        {
297
-            $this->user = $this->user_model->as_array()
298
-                                           ->find_by('id', (int)$id);
299
-
300
-            if (empty($this->user))
301
-            {
302
-                return false;
303
-            }
304
-        }
305
-
306
-        // If logged in, ensure cache control
307
-        // headers are in place
308
-        $this->setHeaders();
309
-
310
-        return true;
311
-    }
312
-
313
-    //--------------------------------------------------------------------
314
-
315
-    /**
316
-     * Attempts to log a user in based on the "remember me" cookie.
317
-     *
318
-     * @return bool
319
-     */
320
-    public function viaRemember()
321
-    {
322
-        if (! config_item('auth.allow_remembering'))
323
-        {
324
-            return false;
325
-        }
326
-
327
-        $this->ci->load->helper('cookie');
328
-
329
-        if (! $token = get_cookie('remember'))
330
-        {
331
-            return false;
332
-        }
333
-
334
-        // Attempt to match the token against our auth_tokens table.
335
-        $query = $this->ci->db->where('hash', $this->ci->login_model->hashRememberToken($token))
336
-                              ->get('auth_tokens');
337
-
338
-        if (! $query->num_rows())
339
-        {
340
-            return false;
341
-        }
342
-
343
-        // Grab the user
344
-        $email = $query->row()->email;
345
-
346
-        $user = $this->user_model->as_array()
347
-                                 ->find_by('email', $email);
348
-
349
-        $this->loginUser($user);
350
-
351
-        // We only want our remember me tokens to be valid
352
-        // for a single use.
353
-        $this->refreshRememberCookie($user, $token);
354
-
355
-        return true;
356
-    }
357
-
358
-    //--------------------------------------------------------------------
359
-
360
-    /**
361
-     * Registers a new user and handles activation method.
362
-     *
363
-     * @param $user_data
364
-     * @return bool
365
-     */
366
-    public function registerUser($user_data)
367
-    {
368
-        // Anything special needed for Activation?
369
-        $method = config_item('auth.activation_method');
370
-
371
-        $user_data['active'] = $method == 'auto' ? 1 : 0;
372
-
373
-        // If via email, we need to generate a hash
374
-        $this->ci->load->helper('string');
375
-        $token = random_string('alnum', 24);
376
-        $user_data['activate_hash'] = hash('sha1', config_item('auth.salt') . $token);
377
-
378
-        // Email should NOT be case sensitive.
379
-        if (! empty($user_data['email']))
380
-        {
381
-            $user_data['email'] = strtolower($user_data['email']);
382
-        }
383
-
384
-        // Save the user
385
-        if (! $id = $this->user_model->insert($user_data))
386
-        {
387
-            $this->error = $this->user_model->error();
388
-            return false;
389
-        }
390
-
391
-        $data = [
392
-            'user_id' => $id,
393
-            'email'   => $user_data['email'],
394
-            'token'   => $token,
395
-            'method'  => $method
396
-        ];
397
-
398
-        Events::trigger('didRegisterUser', [$data]);
399
-
400
-        return true;
401
-    }
402
-
403
-    //--------------------------------------------------------------------
404
-
405
-    /**
406
-     * Used to verify the user values and activate a user so they can
407
-     * visit the site.
408
-     *
409
-     * @param $data
410
-     * @return bool
411
-     */
412
-    public function activateUser($data)
413
-    {
414
-        $post = [
415
-            'email'         => $data['email'],
416
-            'activate_hash' => hash('sha1', config_item('auth.salt') . $data['code'])
417
-        ];
418
-
419
-        $user = $this->user_model->where($post)
420
-                                 ->first();
421
-
422
-        if (! $user) {
423
-            $this->error = $this->user_model->error() ? $this->user_model->error() : lang('auth.activate_no_user');
424
-
425
-            return false;
426
-        }
427
-
428
-        if (! $this->user_model->update($user->id, ['active' => 1, 'activate_hash' => null]))
429
-        {
430
-            $this->error = $this->user_model->error();
431
-            return false;
432
-        }
433
-
434
-        Events::trigger('didActivate', [(array)$user]);
435
-
436
-        return true;
437
-    }
438
-
439
-    //--------------------------------------------------------------------
440
-
441
-    /**
442
-     * Used to allow manual activation of a user with a known ID.
443
-     *
444
-     * @param $id
445
-     * @return bool
446
-     */
447
-    public function activateUserById($id)
448
-    {
449
-        if (! $this->user_model->update($id, ['active' => 1, 'activate_hash' => null]))
450
-        {
451
-            $this->error = $this->user_model->error();
452
-            return false;
453
-        }
454
-
455
-        Events::trigger('didActivate', [$this->user_model->as_array()->find($id)]);
456
-
457
-        return true;
458
-    }
459
-
460
-    //--------------------------------------------------------------------
461
-
462
-    /**
463
-     * Grabs the current user object. Returns NULL if nothing found.
464
-     *
465
-     * @return array|null
466
-     */
467
-    public function user()
468
-    {
469
-        return $this->user;
470
-    }
471
-
472
-    //--------------------------------------------------------------------
473
-
474
-    /**
475
-     * A convenience method to grab the current user's ID.
476
-     *
477
-     * @return int|null
478
-     */
479
-    public function id()
480
-    {
481
-        if (! is_array($this->user) || empty($this->user['id']))
482
-        {
483
-            return null;
484
-        }
485
-
486
-        return (int)$this->user['id'];
487
-    }
488
-
489
-    //--------------------------------------------------------------------
490
-
491
-    /**
492
-     * Checks to see if the user is currently being throttled.
493
-     *
494
-     *  - If they are NOT, will return FALSE.
495
-     *  - If they ARE, will return the number of seconds until they can try again.
496
-     *
497
-     * @param $email
498
-     * @return mixed
499
-     */
500
-    public function isThrottled($email)
501
-    {
502
-        // Not throttling? Get outta here!
503
-        if (! config_item('auth.allow_throttling'))
504
-        {
505
-            return false;
506
-        }
507
-
508
-        // Emails should NOT be case sensitive.
509
-        $email = strtolower($email);
510
-
511
-        // Have any attempts been made?
512
-        $attempts = $this->ci->login_model->countLoginAttempts($email);
513
-
514
-        // Grab the amount of time to add if the system thinks we're
515
-        // under a distributed brute force attack.
516
-        // Affect users that have at least 1 failure login attempt
517
-        $dbrute_time = ($attempts === 0) ? 0 : $this->ci->login_model->distributedBruteForceTime();
518
-
519
-        // If this user was found to possibly be under a brute
520
-        // force attack, their account would have been banned
521
-        // for 15 minutes.
522
-        if ($time = isset($_SESSION['bruteBan']) ? $_SESSION['bruteBan'] : false)
523
-        {
524
-            // If the current time is less than the
525
-            // the ban expiration, plus any distributed time
526
-            // then the user can't login just yet.
527
-            if ($time + $dbrute_time > time())
528
-            {
529
-                // The user is banned still...
530
-                $this->error = lang('auth.bruteBan_notice');
531
-                return ($time + $dbrute_time) - time();
532
-            }
533
-
534
-            // Still here? The the ban time is over...
535
-            unset($_SESSION['bruteBan']);
536
-        }
537
-
538
-        // Grab the time of last attempt and
539
-        // determine if we're throttled by amount of time passed.
540
-        $last_time = $this->ci->login_model->lastLoginAttemptTime($email);
541
-
542
-        $allowed = config_item('auth.allowed_login_attempts');
543
-
544
-        // We're not throttling if there are 0 attempts or
545
-        // the number is less than or equal to the allowed free attempts
546
-        if ($attempts === 0 || $attempts <= $allowed)
547
-        {
548
-            // Before we can say there's nothing up here,
549
-            // we need to check dbrute time.
550
-            $time_left = $last_time + $dbrute_time - time();
551
-
552
-            if ($time_left > 0)
553
-            {
554
-                return $time_left;
555
-            }
556
-
557
-            return false;
558
-        }
559
-
560
-        // If the number of attempts is excessive (above 100) we need
561
-        // to check the elapsed time of all of these attacks. If they are
562
-        // less than 1 minute it's obvious this is a brute force attack,
563
-        // so we'll set a session flag and block that user for 15 minutes.
564
-        if ($attempts > 100 && $this->ci->login_model->isBruteForced($email))
565
-        {
566
-            $this->error = lang('auth.bruteBan_notice');
567
-
568
-            $ban_time = 60 * 15;    // 15 minutes
569
-            $_SESSION['bruteBan'] = time() + $ban_time;
570
-            return $ban_time;
571
-        }
572
-
573
-        // Get our allowed attempts out of the picture.
574
-        $attempts = $attempts - $allowed;
575
-
576
-        $max_time = config_item('auth.max_throttle_time');
577
-
578
-        $add_time = pow(5, $attempts);
579
-
580
-        if ($add_time > $max_time)
581
-        {
582
-            $add_time = $max_time;
583
-        }
584
-
585
-        $next_time = $last_time + $add_time + $dbrute_time;
586
-
587
-        $current = time();
588
-
589
-        // We are NOT throttled if we are already
590
-        // past the allowed time.
591
-        if ($current > $next_time)
592
-        {
593
-            return false;
594
-        }
595
-
596
-        return $next_time - $current;
597
-    }
598
-
599
-    //--------------------------------------------------------------------
600
-
601
-    /**
602
-     * Sends a password reset link email to the user associated with
603
-     * the passed in $email.
604
-     *
605
-     * @param $email
606
-     * @return mixed
607
-     */
608
-    public function remindUser($email)
609
-    {
610
-        // Emails should NOT be case sensitive.
611
-        $email = strtolower($email);
612
-
613
-        // Is it a valid user?
614
-        $user = $this->user_model->find_by('email', $email);
615
-
616
-        if (! $user)
617
-        {
618
-            $this->error = lang('auth.invalid_email');
619
-            return false;
620
-        }
621
-
622
-        // Generate/store our codes
623
-        $this->ci->load->helper('string');
624
-        $token = random_string('alnum', 24);
625
-        $hash = hash('sha1', config_item('auth.salt') .$token);
626
-
627
-        $result = $this->user_model->update($user->id, ['reset_hash' => $hash]);
628
-
629
-        if (! $result)
630
-        {
631
-            $this->error = $this->user_model->error();
632
-            return false;
633
-        }
634
-
635
-        Events::trigger('didRemindUser', [(array)$user, $token]);
636
-
637
-        return true;
638
-    }
639
-
640
-    //--------------------------------------------------------------------
641
-
642
-    /**
643
-     * Validates the credentials provided and, if valid, resets the password.
644
-     *
645
-     * The $credentials array MUST contain a 'code' key with the string to
646
-     * hash and check against the reset_hash.
647
-     *
648
-     * @param $credentials
649
-     * @param $password
650
-     * @param $passConfirm
651
-     * @return mixed
652
-     */
653
-    public function resetPassword($credentials, $password, $passConfirm)
654
-    {
655
-        if (empty($credentials['code']))
656
-        {
657
-            $this->error = lang('auth.need_reset_code');
658
-            return false;
659
-        }
660
-
661
-        // Generate a hash to match against the table.
662
-        $credentials['reset_hash'] = hash('sha1', config_item('auth.salt') .$credentials['code']);
663
-        unset($credentials['code']);
664
-
665
-        if (! empty($credentials['email']))
666
-        {
667
-            $credentials['email'] = strtolower($credentials['email']);
668
-        }
669
-
670
-        // Is there a matching user?
671
-        $user = $this->user_model->find_by($credentials);
672
-
673
-        if (! $user)
674
-        {
675
-            $this->error = lang('auth.reset_no_user');
676
-            return false;
677
-        }
678
-
679
-        // Update their password and reset their reset_hash
680
-        $data = [
681
-            'password'     => $password,
682
-            'pass_confirm' => $passConfirm,
683
-            'reset_hash'   => null
684
-        ];
685
-
686
-        if (! $this->user_model->update($user->id, $data))
687
-        {
688
-            $this->error = $this->user_model->error();
689
-            return false;
690
-        }
691
-
692
-        Events::trigger('didResetPassword', [(array)$user]);
693
-
694
-        return true;
695
-    }
696
-
697
-    //--------------------------------------------------------------------
698
-
699
-    /**
700
-     * Provides a way for implementations to allow new statuses to be set
701
-     * on the user. The details will vary based upon implementation, but
702
-     * will often allow for banning or suspending users.
703
-     *
704
-     * @param $newStatus
705
-     * @param null $message
706
-     * @return mixed
707
-     */
708
-    public function changeStatus($newStatus, $message=null)
709
-    {
710
-        // todo actually record new users status!
711
-    }
712
-
713
-    //--------------------------------------------------------------------
714
-
715
-    /**
716
-     * Allows the consuming application to pass in a reference to the
717
-     * model that should be used.
718
-     *
719
-     * The model MUST extend Myth\Models\CIDbModel.
720
-     *
721
-     * @param $model
722
-     * @param bool $allow_any_parent
723
-     * @return mixed
724
-     */
725
-    public function useModel($model, $allow_any_parent=false)
726
-    {
727
-        if (! $allow_any_parent && get_parent_class($model) != 'Myth\Models\CIDbModel')
728
-        {
729
-            throw new \RuntimeException('Models passed into LocalAuthenticate MUST extend Myth\Models\CIDbModel');
730
-        }
731
-
732
-        $this->user_model =& $model;
733
-
734
-        return $this;
735
-    }
736
-
737
-    //--------------------------------------------------------------------
738
-
739
-    public function error()
740
-    {
741
-        if (validation_errors())
742
-        {
743
-            return validation_errors();
744
-        }
745
-
746
-        return $this->error;
747
-    }
748
-
749
-    //--------------------------------------------------------------------
750
-
751
-    //--------------------------------------------------------------------
752
-    // Login Records
753
-    //--------------------------------------------------------------------
754
-
755
-    /**
756
-     * Purges all login attempt records from the database.
757
-     *
758
-     * @param $email
759
-     */
760
-    public function purgeLoginAttempts($email)
761
-    {
762
-        // Emails should NOT be case sensitive.
763
-        $email = strtolower($email);
764
-
765
-        $this->ci->login_model->purgeLoginAttempts($email);
766
-
767
-        // @todo record activity of login attempts purge.
768
-        Events::trigger('didPurgeLoginAttempts', [$email]);
769
-    }
770
-
771
-    //--------------------------------------------------------------------
772
-
773
-    /**
774
-     * Purges all remember tokens for a single user. Effectively logs
775
-     * a user out of all devices. Intended to allow users to log themselves
776
-     * out of all devices as a security measure.
777
-     *
778
-     * @param $email
779
-     */
780
-    public function purgeRememberTokens($email)
781
-    {
782
-        // Emails should NOT be case sensitive.
783
-        $email = strtolower($email);
784
-
785
-        $this->ci->login_model->purgeRememberTokens($email);
786
-
787
-        // todo record activity of remember me purges.
788
-        Events::trigger('didPurgeRememberTokens', [$email]);
789
-    }
790
-
791
-    //--------------------------------------------------------------------
792
-
793
-    //--------------------------------------------------------------------
794
-    // Protected Methods
795
-    //--------------------------------------------------------------------
796
-
797
-    /**
798
-     * Check if Allow Persistent Login Cookies is enable
799
-     *
800
-     * @param $user
801
-     */
802
-    protected function rememberUser($user)
803
-    {
804
-        if (! config_item('auth.allow_remembering'))
805
-        {
806
-            log_message('debug', 'Auth library set to refuse "Remember Me" functionality.');
807
-            return false;
808
-        }
809
-
810
-        $this->refreshRememberCookie($user);
811
-    }
812
-
813
-    //--------------------------------------------------------------------
814
-
815
-    /**
816
-     * Invalidates the current rememberme cookie/database entry, creates
817
-     * a new one, stores it and returns the new value.
818
-     *
819
-     * @param $user
820
-     * @param null $token
821
-     * @return mixed
822
-     */
823
-    protected function refreshRememberCookie($user, $token=null)
824
-    {
825
-        $this->ci->load->helper('cookie');
826
-
827
-        // If a token is passed in, we know we're removing the
828
-        // old one.
829
-        if (! empty($token))
830
-        {
831
-            $this->invalidateRememberCookie($user['email'], $token);
832
-        }
833
-
834
-        $new_token = $this->ci->login_model->generateRememberToken($user);
835
-
836
-        // Save the token to the database.
837
-        $data = [
838
-            'email'   => $user['email'],
839
-            'hash'    => sha1(config_item('auth.salt') . $new_token),
840
-            'created' => date('Y-m-d H:i:s')
841
-        ];
842
-
843
-        $this->ci->db->insert('auth_tokens', $data);
844
-
845
-        // Create the cookie
846
-        set_cookie(
847
-            'remember',                             // Cookie Name
848
-            $new_token,                             // Value
849
-            config_item('auth.remember_length'),    // # Seconds until it expires
850
-            config_item('cookie_domain'),
851
-            config_item('cookie_path'),
852
-            config_item('cookie_prefix'),
853
-            false,                                  // Only send over HTTPS?
854
-            true                                    // Hide from Javascript?
855
-        );
856
-
857
-        return $new_token;
858
-    }
859
-
860
-    //--------------------------------------------------------------------
861
-
862
-    /**
863
-     * Deletes any current remember me cookies and database entries.
864
-     *
865
-     * @param $email
866
-     * @param $token
867
-     * @return string The new token (not the hash).
868
-     */
869
-    protected function invalidateRememberCookie($email, $token)
870
-    {
871
-        // Emails should NOT be case sensitive.
872
-        $email = strtolower($email);
873
-
874
-        // Remove from the database
875
-        $this->ci->login_model->deleteRememberToken($email, $token);
876
-
877
-        // Remove the cookie
878
-        delete_cookie(
879
-            'remember',
880
-            config_item('cookie_domain'),
881
-            config_item('cookie_path'),
882
-            config_item('cookie_prefix')
883
-        );
884
-    }
885
-
886
-    //--------------------------------------------------------------------
887
-
888
-    /**
889
-     * Handles the nitty gritty of actually logging our user into the system.
890
-     * Does NOT perform the authentication, just sets the system up so that
891
-     * it knows we're here.
892
-     *
893
-     * @param $user
894
-     */
895
-    protected function loginUser($user)
896
-    {
897
-        // Save the user for later access
898
-        $this->user = $user;
899
-
900
-        // Regenerate the session ID to help protect
901
-        // against session fixation
902
-        $this->ci->session->sess_regenerate();
903
-
904
-        // Let the session know that we're logged in.
905
-        $this->ci->session->set_userdata('logged_in', $user['id']);
906
-
907
-        // Clear our login attempts
908
-        $this->ci->login_model->purgeLoginAttempts($user['email']);
909
-
910
-        // Record a new Login
911
-        $this->ci->login_model->recordLogin($user);
912
-
913
-        // If logged in, ensure cache control
914
-        // headers are in place
915
-        $this->setHeaders();
916
-
917
-        // We'll give a 20% chance to need to do a purge since we
918
-        // don't need to purge THAT often, it's just a maintenance issue.
919
-        // to keep the table from getting out of control.
920
-        if (mt_rand(1, 100) < 20)
921
-        {
922
-            $this->ci->login_model->purgeOldRememberTokens();
923
-        }
924
-    }
925
-
926
-    //--------------------------------------------------------------------
927
-
928
-    /**
929
-     * Sets the headers to ensure that pages are not cached when a user
930
-     * is logged in, helping to protect against logging out and then
931
-     * simply hitting the Back button on the browser and getting private
932
-     * information because the page was loaded from cache.
933
-     */
934
-    protected function setHeaders()
935
-    {
936
-        $this->ci->output->set_header('Cache-Control: no-store, no-cache, must-revalidate');
937
-        $this->ci->output->set_header('Cache-Control: post-check=0, pre-check=0');
938
-        $this->ci->output->set_header('Pragma: no-cache');
939
-    }
940
-
941
-    //--------------------------------------------------------------------
55
+	protected $ci;
56
+
57
+	protected $user = null;
58
+
59
+	public $user_model = null;
60
+
61
+	public $error = null;
62
+
63
+	//--------------------------------------------------------------------
64
+
65
+	public function __construct( $ci=null )
66
+	{
67
+		if ($ci)
68
+		{
69
+			$this->ci= $ci;
70
+		}
71
+		else
72
+		{
73
+			$this->ci =& get_instance();
74
+		}
75
+
76
+		// Get our compatibility password file loaded up.
77
+		if (! function_exists('password_hash'))
78
+		{
79
+			require_once dirname(__FILE__) .'password.php';
80
+		}
81
+
82
+		if (empty($this->ci->session))
83
+		{
84
+			$this->ci->load->library('session');
85
+		}
86
+
87
+		$this->ci->config->load('auth');
88
+		$this->ci->load->model('auth/login_model');
89
+		$this->ci->load->language('auth/auth');
90
+	}
91
+
92
+	//--------------------------------------------------------------------
93
+
94
+	/**
95
+	 * Attempt to log a user into the system.
96
+	 *
97
+	 * $credentials is an array of key/value pairs needed to log the user in.
98
+	 * This is often email/password, or username/password.
99
+	 *
100
+	 * @param array $credentials
101
+	 * @param bool  $remember
102
+	 * @return bool|mixed
103
+	 */
104
+	public function login($credentials, $remember=false)
105
+	{
106
+		$user = $this->validate($credentials, true);
107
+
108
+		if (! $user)
109
+		{
110
+			// We need to send an error even if no
111
+			// user was found!
112
+			$this->error = lang('auth.invalid_user');
113
+
114
+			// If an email is present, log the attempt
115
+			if (! empty($credentials['email']) )
116
+			{
117
+				$this->ci->login_model->recordLoginAttempt($credentials['email']);
118
+			}
119
+
120
+			$this->user = null;
121
+			return $user;
122
+		}
123
+
124
+		// If the user is throttled due to too many invalid logins
125
+		// or the system is under attack, kick them back.
126
+		// We need to test for this after validation because we
127
+		// don't want it to affect a valid login.
128
+
129
+		// If throttling time is above zero, we can't allow
130
+		// logins now.
131
+		$time = (int)$this->isThrottled($user['email']);
132
+		if ($time > 0)
133
+		{
134
+			$this->error = sprintf(lang('auth.throttled'), $time);
135
+			return false;
136
+		}
137
+
138
+		$this->loginUser($user);
139
+
140
+		if ($remember)
141
+		{
142
+			$this->rememberUser($user);
143
+		}
144
+
145
+		Events::trigger('didLogin', [$user]);
146
+
147
+		return true;
148
+	}
149
+
150
+	//--------------------------------------------------------------------
151
+
152
+	/**
153
+	 * Validates user login information without logging them in.
154
+	 *
155
+	 * $credentials is an array of key/value pairs needed to log the user in.
156
+	 * This is often email/password, or username/password.
157
+	 *
158
+	 * @param $credentials
159
+	 * @param bool $return_user
160
+	 * @return mixed
161
+	 */
162
+	public function validate($credentials, $return_user=false)
163
+	{
164
+		// Can't validate without a password.
165
+		if (empty($credentials['password']) || count($credentials) < 2)
166
+		{
167
+			return null;
168
+		}
169
+
170
+		$password = $credentials['password'];
171
+		unset($credentials['password']);
172
+
173
+		// We should only be allowed 1 single other credential to
174
+		// test against.
175
+		if (count($credentials) > 1)
176
+		{
177
+			$this->error = lang('auth.too_many_credentials');
178
+			return false;
179
+		}
180
+
181
+		// Ensure that the fields are allowed validation fields
182
+		if (! in_array(key($credentials), config_item('auth.valid_fields')) )
183
+		{
184
+			$this->error = lang('auth.invalid_credentials');
185
+			return false;
186
+		}
187
+
188
+		// We do not want to force case-sensitivity on things
189
+		// like username and email for usability sake.
190
+		if (! empty($credentials['email']))
191
+		{
192
+			$credentials['email'] = strtolower($credentials['email']);
193
+		}
194
+
195
+		// Can we find a user with those credentials?
196
+		$user = $this->user_model->as_array()
197
+								 ->where($credentials)
198
+								 ->first();
199
+
200
+		if (! $user)
201
+		{
202
+			$this->error = lang('auth.invalid_user');
203
+			return false;
204
+		}
205
+
206
+		// Now, try matching the passwords.
207
+		$result =  password_verify($password, $user['password_hash']);
208
+
209
+		if (! $result)
210
+		{
211
+			$this->error = lang('auth.invalid_password');
212
+			$this->ci->login_model->recordLoginAttempt($user['email']);
213
+			return false;
214
+		}
215
+
216
+		// Check to see if the password needs to be rehashed.
217
+		// This would be due to the hash algorithm or hash
218
+		// cost changing since the last time that a user
219
+		// logged in.
220
+		if (password_needs_rehash($user['password_hash'], PASSWORD_DEFAULT, ['cost' => config_item('auth.hash_cost')] ))
221
+		{
222
+			$new_hash = Password::hashPassword($password);
223
+			$this->user_model->skip_validation()
224
+							 ->update($user['id'], ['password_hash' => $new_hash]);
225
+			unset($new_hash);
226
+		}
227
+
228
+		// Is the user active?
229
+		if (! $user['active'])
230
+		{
231
+			$this->error = lang('auth.inactive_account');
232
+			return false;
233
+		}
234
+
235
+		return $return_user ? $user : true;
236
+	}
237
+
238
+	//--------------------------------------------------------------------
239
+
240
+	/**
241
+	 * Logs a user out and removes all session information.
242
+	 *
243
+	 * @return mixed
244
+	 */
245
+	public function logout()
246
+	{
247
+		$this->ci->load->helper('cookie');
248
+
249
+		if (! Events::trigger('beforeLogout', [$this->user]))
250
+		{
251
+			return false;
252
+		}
253
+
254
+		// Destroy the session data - but ensure a session is still
255
+		// available for flash messages, etc.
256
+		if (isset($_SESSION))
257
+		{
258
+			foreach ( $_SESSION as $key => $value )
259
+			{
260
+				$_SESSION[ $key ] = NULL;
261
+				unset( $_SESSION[ $key ] );
262
+			}
263
+		}
264
+		// Also, regenerate the session ID for a touch of added safety.
265
+		$this->ci->session->sess_regenerate(true);
266
+
267
+		// Take care of any rememberme functionality.
268
+		if (config_item('auth.allow_remembering'))
269
+		{
270
+			$token = get_cookie('remember');
271
+
272
+			$this->invalidateRememberCookie($this->user['email'], $token);
273
+		}
274
+	}
275
+
276
+	//--------------------------------------------------------------------
277
+
278
+	/**
279
+	 * Checks whether a user is logged in or not.
280
+	 *
281
+	 * @return bool
282
+	 */
283
+	public function isLoggedIn()
284
+	{
285
+		$id = $this->ci->session->userdata('logged_in');
286
+
287
+		if (! $id)
288
+		{
289
+			return false;
290
+		}
291
+
292
+		// If the user var hasn't been filled in, we need to fill it in,
293
+		// since this method will typically be used as the only method
294
+		// to determine whether a user is logged in or not.
295
+		if (! $this->user)
296
+		{
297
+			$this->user = $this->user_model->as_array()
298
+										   ->find_by('id', (int)$id);
299
+
300
+			if (empty($this->user))
301
+			{
302
+				return false;
303
+			}
304
+		}
305
+
306
+		// If logged in, ensure cache control
307
+		// headers are in place
308
+		$this->setHeaders();
309
+
310
+		return true;
311
+	}
312
+
313
+	//--------------------------------------------------------------------
314
+
315
+	/**
316
+	 * Attempts to log a user in based on the "remember me" cookie.
317
+	 *
318
+	 * @return bool
319
+	 */
320
+	public function viaRemember()
321
+	{
322
+		if (! config_item('auth.allow_remembering'))
323
+		{
324
+			return false;
325
+		}
326
+
327
+		$this->ci->load->helper('cookie');
328
+
329
+		if (! $token = get_cookie('remember'))
330
+		{
331
+			return false;
332
+		}
333
+
334
+		// Attempt to match the token against our auth_tokens table.
335
+		$query = $this->ci->db->where('hash', $this->ci->login_model->hashRememberToken($token))
336
+							  ->get('auth_tokens');
337
+
338
+		if (! $query->num_rows())
339
+		{
340
+			return false;
341
+		}
342
+
343
+		// Grab the user
344
+		$email = $query->row()->email;
345
+
346
+		$user = $this->user_model->as_array()
347
+								 ->find_by('email', $email);
348
+
349
+		$this->loginUser($user);
350
+
351
+		// We only want our remember me tokens to be valid
352
+		// for a single use.
353
+		$this->refreshRememberCookie($user, $token);
354
+
355
+		return true;
356
+	}
357
+
358
+	//--------------------------------------------------------------------
359
+
360
+	/**
361
+	 * Registers a new user and handles activation method.
362
+	 *
363
+	 * @param $user_data
364
+	 * @return bool
365
+	 */
366
+	public function registerUser($user_data)
367
+	{
368
+		// Anything special needed for Activation?
369
+		$method = config_item('auth.activation_method');
370
+
371
+		$user_data['active'] = $method == 'auto' ? 1 : 0;
372
+
373
+		// If via email, we need to generate a hash
374
+		$this->ci->load->helper('string');
375
+		$token = random_string('alnum', 24);
376
+		$user_data['activate_hash'] = hash('sha1', config_item('auth.salt') . $token);
377
+
378
+		// Email should NOT be case sensitive.
379
+		if (! empty($user_data['email']))
380
+		{
381
+			$user_data['email'] = strtolower($user_data['email']);
382
+		}
383
+
384
+		// Save the user
385
+		if (! $id = $this->user_model->insert($user_data))
386
+		{
387
+			$this->error = $this->user_model->error();
388
+			return false;
389
+		}
390
+
391
+		$data = [
392
+			'user_id' => $id,
393
+			'email'   => $user_data['email'],
394
+			'token'   => $token,
395
+			'method'  => $method
396
+		];
397
+
398
+		Events::trigger('didRegisterUser', [$data]);
399
+
400
+		return true;
401
+	}
402
+
403
+	//--------------------------------------------------------------------
404
+
405
+	/**
406
+	 * Used to verify the user values and activate a user so they can
407
+	 * visit the site.
408
+	 *
409
+	 * @param $data
410
+	 * @return bool
411
+	 */
412
+	public function activateUser($data)
413
+	{
414
+		$post = [
415
+			'email'         => $data['email'],
416
+			'activate_hash' => hash('sha1', config_item('auth.salt') . $data['code'])
417
+		];
418
+
419
+		$user = $this->user_model->where($post)
420
+								 ->first();
421
+
422
+		if (! $user) {
423
+			$this->error = $this->user_model->error() ? $this->user_model->error() : lang('auth.activate_no_user');
424
+
425
+			return false;
426
+		}
427
+
428
+		if (! $this->user_model->update($user->id, ['active' => 1, 'activate_hash' => null]))
429
+		{
430
+			$this->error = $this->user_model->error();
431
+			return false;
432
+		}
433
+
434
+		Events::trigger('didActivate', [(array)$user]);
435
+
436
+		return true;
437
+	}
438
+
439
+	//--------------------------------------------------------------------
440
+
441
+	/**
442
+	 * Used to allow manual activation of a user with a known ID.
443
+	 *
444
+	 * @param $id
445
+	 * @return bool
446
+	 */
447
+	public function activateUserById($id)
448
+	{
449
+		if (! $this->user_model->update($id, ['active' => 1, 'activate_hash' => null]))
450
+		{
451
+			$this->error = $this->user_model->error();
452
+			return false;
453
+		}
454
+
455
+		Events::trigger('didActivate', [$this->user_model->as_array()->find($id)]);
456
+
457
+		return true;
458
+	}
459
+
460
+	//--------------------------------------------------------------------
461
+
462
+	/**
463
+	 * Grabs the current user object. Returns NULL if nothing found.
464
+	 *
465
+	 * @return array|null
466
+	 */
467
+	public function user()
468
+	{
469
+		return $this->user;
470
+	}
471
+
472
+	//--------------------------------------------------------------------
473
+
474
+	/**
475
+	 * A convenience method to grab the current user's ID.
476
+	 *
477
+	 * @return int|null
478
+	 */
479
+	public function id()
480
+	{
481
+		if (! is_array($this->user) || empty($this->user['id']))
482
+		{
483
+			return null;
484
+		}
485
+
486
+		return (int)$this->user['id'];
487
+	}
488
+
489
+	//--------------------------------------------------------------------
490
+
491
+	/**
492
+	 * Checks to see if the user is currently being throttled.
493
+	 *
494
+	 *  - If they are NOT, will return FALSE.
495
+	 *  - If they ARE, will return the number of seconds until they can try again.
496
+	 *
497
+	 * @param $email
498
+	 * @return mixed
499
+	 */
500
+	public function isThrottled($email)
501
+	{
502
+		// Not throttling? Get outta here!
503
+		if (! config_item('auth.allow_throttling'))
504
+		{
505
+			return false;
506
+		}
507
+
508
+		// Emails should NOT be case sensitive.
509
+		$email = strtolower($email);
510
+
511
+		// Have any attempts been made?
512
+		$attempts = $this->ci->login_model->countLoginAttempts($email);
513
+
514
+		// Grab the amount of time to add if the system thinks we're
515
+		// under a distributed brute force attack.
516
+		// Affect users that have at least 1 failure login attempt
517
+		$dbrute_time = ($attempts === 0) ? 0 : $this->ci->login_model->distributedBruteForceTime();
518
+
519
+		// If this user was found to possibly be under a brute
520
+		// force attack, their account would have been banned
521
+		// for 15 minutes.
522
+		if ($time = isset($_SESSION['bruteBan']) ? $_SESSION['bruteBan'] : false)
523
+		{
524
+			// If the current time is less than the
525
+			// the ban expiration, plus any distributed time
526
+			// then the user can't login just yet.
527
+			if ($time + $dbrute_time > time())
528
+			{
529
+				// The user is banned still...
530
+				$this->error = lang('auth.bruteBan_notice');
531
+				return ($time + $dbrute_time) - time();
532
+			}
533
+
534
+			// Still here? The the ban time is over...
535
+			unset($_SESSION['bruteBan']);
536
+		}
537
+
538
+		// Grab the time of last attempt and
539
+		// determine if we're throttled by amount of time passed.
540
+		$last_time = $this->ci->login_model->lastLoginAttemptTime($email);
541
+
542
+		$allowed = config_item('auth.allowed_login_attempts');
543
+
544
+		// We're not throttling if there are 0 attempts or
545
+		// the number is less than or equal to the allowed free attempts
546
+		if ($attempts === 0 || $attempts <= $allowed)
547
+		{
548
+			// Before we can say there's nothing up here,
549
+			// we need to check dbrute time.
550
+			$time_left = $last_time + $dbrute_time - time();
551
+
552
+			if ($time_left > 0)
553
+			{
554
+				return $time_left;
555
+			}
556
+
557
+			return false;
558
+		}
559
+
560
+		// If the number of attempts is excessive (above 100) we need
561
+		// to check the elapsed time of all of these attacks. If they are
562
+		// less than 1 minute it's obvious this is a brute force attack,
563
+		// so we'll set a session flag and block that user for 15 minutes.
564
+		if ($attempts > 100 && $this->ci->login_model->isBruteForced($email))
565
+		{
566
+			$this->error = lang('auth.bruteBan_notice');
567
+
568
+			$ban_time = 60 * 15;    // 15 minutes
569
+			$_SESSION['bruteBan'] = time() + $ban_time;
570
+			return $ban_time;
571
+		}
572
+
573
+		// Get our allowed attempts out of the picture.
574
+		$attempts = $attempts - $allowed;
575
+
576
+		$max_time = config_item('auth.max_throttle_time');
577
+
578
+		$add_time = pow(5, $attempts);
579
+
580
+		if ($add_time > $max_time)
581
+		{
582
+			$add_time = $max_time;
583
+		}
584
+
585
+		$next_time = $last_time + $add_time + $dbrute_time;
586
+
587
+		$current = time();
588
+
589
+		// We are NOT throttled if we are already
590
+		// past the allowed time.
591
+		if ($current > $next_time)
592
+		{
593
+			return false;
594
+		}
595
+
596
+		return $next_time - $current;
597
+	}
598
+
599
+	//--------------------------------------------------------------------
600
+
601
+	/**
602
+	 * Sends a password reset link email to the user associated with
603
+	 * the passed in $email.
604
+	 *
605
+	 * @param $email
606
+	 * @return mixed
607
+	 */
608
+	public function remindUser($email)
609
+	{
610
+		// Emails should NOT be case sensitive.
611
+		$email = strtolower($email);
612
+
613
+		// Is it a valid user?
614
+		$user = $this->user_model->find_by('email', $email);
615
+
616
+		if (! $user)
617
+		{
618
+			$this->error = lang('auth.invalid_email');
619
+			return false;
620
+		}
621
+
622
+		// Generate/store our codes
623
+		$this->ci->load->helper('string');
624
+		$token = random_string('alnum', 24);
625
+		$hash = hash('sha1', config_item('auth.salt') .$token);
626
+
627
+		$result = $this->user_model->update($user->id, ['reset_hash' => $hash]);
628
+
629
+		if (! $result)
630
+		{
631
+			$this->error = $this->user_model->error();
632
+			return false;
633
+		}
634
+
635
+		Events::trigger('didRemindUser', [(array)$user, $token]);
636
+
637
+		return true;
638
+	}
639
+
640
+	//--------------------------------------------------------------------
641
+
642
+	/**
643
+	 * Validates the credentials provided and, if valid, resets the password.
644
+	 *
645
+	 * The $credentials array MUST contain a 'code' key with the string to
646
+	 * hash and check against the reset_hash.
647
+	 *
648
+	 * @param $credentials
649
+	 * @param $password
650
+	 * @param $passConfirm
651
+	 * @return mixed
652
+	 */
653
+	public function resetPassword($credentials, $password, $passConfirm)
654
+	{
655
+		if (empty($credentials['code']))
656
+		{
657
+			$this->error = lang('auth.need_reset_code');
658
+			return false;
659
+		}
660
+
661
+		// Generate a hash to match against the table.
662
+		$credentials['reset_hash'] = hash('sha1', config_item('auth.salt') .$credentials['code']);
663
+		unset($credentials['code']);
664
+
665
+		if (! empty($credentials['email']))
666
+		{
667
+			$credentials['email'] = strtolower($credentials['email']);
668
+		}
669
+
670
+		// Is there a matching user?
671
+		$user = $this->user_model->find_by($credentials);
672
+
673
+		if (! $user)
674
+		{
675
+			$this->error = lang('auth.reset_no_user');
676
+			return false;
677
+		}
678
+
679
+		// Update their password and reset their reset_hash
680
+		$data = [
681
+			'password'     => $password,
682
+			'pass_confirm' => $passConfirm,
683
+			'reset_hash'   => null
684
+		];
685
+
686
+		if (! $this->user_model->update($user->id, $data))
687
+		{
688
+			$this->error = $this->user_model->error();
689
+			return false;
690
+		}
691
+
692
+		Events::trigger('didResetPassword', [(array)$user]);
693
+
694
+		return true;
695
+	}
696
+
697
+	//--------------------------------------------------------------------
698
+
699
+	/**
700
+	 * Provides a way for implementations to allow new statuses to be set
701
+	 * on the user. The details will vary based upon implementation, but
702
+	 * will often allow for banning or suspending users.
703
+	 *
704
+	 * @param $newStatus
705
+	 * @param null $message
706
+	 * @return mixed
707
+	 */
708
+	public function changeStatus($newStatus, $message=null)
709
+	{
710
+		// todo actually record new users status!
711
+	}
712
+
713
+	//--------------------------------------------------------------------
714
+
715
+	/**
716
+	 * Allows the consuming application to pass in a reference to the
717
+	 * model that should be used.
718
+	 *
719
+	 * The model MUST extend Myth\Models\CIDbModel.
720
+	 *
721
+	 * @param $model
722
+	 * @param bool $allow_any_parent
723
+	 * @return mixed
724
+	 */
725
+	public function useModel($model, $allow_any_parent=false)
726
+	{
727
+		if (! $allow_any_parent && get_parent_class($model) != 'Myth\Models\CIDbModel')
728
+		{
729
+			throw new \RuntimeException('Models passed into LocalAuthenticate MUST extend Myth\Models\CIDbModel');
730
+		}
731
+
732
+		$this->user_model =& $model;
733
+
734
+		return $this;
735
+	}
736
+
737
+	//--------------------------------------------------------------------
738
+
739
+	public function error()
740
+	{
741
+		if (validation_errors())
742
+		{
743
+			return validation_errors();
744
+		}
745
+
746
+		return $this->error;
747
+	}
748
+
749
+	//--------------------------------------------------------------------
750
+
751
+	//--------------------------------------------------------------------
752
+	// Login Records
753
+	//--------------------------------------------------------------------
754
+
755
+	/**
756
+	 * Purges all login attempt records from the database.
757
+	 *
758
+	 * @param $email
759
+	 */
760
+	public function purgeLoginAttempts($email)
761
+	{
762
+		// Emails should NOT be case sensitive.
763
+		$email = strtolower($email);
764
+
765
+		$this->ci->login_model->purgeLoginAttempts($email);
766
+
767
+		// @todo record activity of login attempts purge.
768
+		Events::trigger('didPurgeLoginAttempts', [$email]);
769
+	}
770
+
771
+	//--------------------------------------------------------------------
772
+
773
+	/**
774
+	 * Purges all remember tokens for a single user. Effectively logs
775
+	 * a user out of all devices. Intended to allow users to log themselves
776
+	 * out of all devices as a security measure.
777
+	 *
778
+	 * @param $email
779
+	 */
780
+	public function purgeRememberTokens($email)
781
+	{
782
+		// Emails should NOT be case sensitive.
783
+		$email = strtolower($email);
784
+
785
+		$this->ci->login_model->purgeRememberTokens($email);
786
+
787
+		// todo record activity of remember me purges.
788
+		Events::trigger('didPurgeRememberTokens', [$email]);
789
+	}
790
+
791
+	//--------------------------------------------------------------------
792
+
793
+	//--------------------------------------------------------------------
794
+	// Protected Methods
795
+	//--------------------------------------------------------------------
796
+
797
+	/**
798
+	 * Check if Allow Persistent Login Cookies is enable
799
+	 *
800
+	 * @param $user
801
+	 */
802
+	protected function rememberUser($user)
803
+	{
804
+		if (! config_item('auth.allow_remembering'))
805
+		{
806
+			log_message('debug', 'Auth library set to refuse "Remember Me" functionality.');
807
+			return false;
808
+		}
809
+
810
+		$this->refreshRememberCookie($user);
811
+	}
812
+
813
+	//--------------------------------------------------------------------
814
+
815
+	/**
816
+	 * Invalidates the current rememberme cookie/database entry, creates
817
+	 * a new one, stores it and returns the new value.
818
+	 *
819
+	 * @param $user
820
+	 * @param null $token
821
+	 * @return mixed
822
+	 */
823
+	protected function refreshRememberCookie($user, $token=null)
824
+	{
825
+		$this->ci->load->helper('cookie');
826
+
827
+		// If a token is passed in, we know we're removing the
828
+		// old one.
829
+		if (! empty($token))
830
+		{
831
+			$this->invalidateRememberCookie($user['email'], $token);
832
+		}
833
+
834
+		$new_token = $this->ci->login_model->generateRememberToken($user);
835
+
836
+		// Save the token to the database.
837
+		$data = [
838
+			'email'   => $user['email'],
839
+			'hash'    => sha1(config_item('auth.salt') . $new_token),
840
+			'created' => date('Y-m-d H:i:s')
841
+		];
842
+
843
+		$this->ci->db->insert('auth_tokens', $data);
844
+
845
+		// Create the cookie
846
+		set_cookie(
847
+			'remember',                             // Cookie Name
848
+			$new_token,                             // Value
849
+			config_item('auth.remember_length'),    // # Seconds until it expires
850
+			config_item('cookie_domain'),
851
+			config_item('cookie_path'),
852
+			config_item('cookie_prefix'),
853
+			false,                                  // Only send over HTTPS?
854
+			true                                    // Hide from Javascript?
855
+		);
856
+
857
+		return $new_token;
858
+	}
859
+
860
+	//--------------------------------------------------------------------
861
+
862
+	/**
863
+	 * Deletes any current remember me cookies and database entries.
864
+	 *
865
+	 * @param $email
866
+	 * @param $token
867
+	 * @return string The new token (not the hash).
868
+	 */
869
+	protected function invalidateRememberCookie($email, $token)
870
+	{
871
+		// Emails should NOT be case sensitive.
872
+		$email = strtolower($email);
873
+
874
+		// Remove from the database
875
+		$this->ci->login_model->deleteRememberToken($email, $token);
876
+
877
+		// Remove the cookie
878
+		delete_cookie(
879
+			'remember',
880
+			config_item('cookie_domain'),
881
+			config_item('cookie_path'),
882
+			config_item('cookie_prefix')
883
+		);
884
+	}
885
+
886
+	//--------------------------------------------------------------------
887
+
888
+	/**
889
+	 * Handles the nitty gritty of actually logging our user into the system.
890
+	 * Does NOT perform the authentication, just sets the system up so that
891
+	 * it knows we're here.
892
+	 *
893
+	 * @param $user
894
+	 */
895
+	protected function loginUser($user)
896
+	{
897
+		// Save the user for later access
898
+		$this->user = $user;
899
+
900
+		// Regenerate the session ID to help protect
901
+		// against session fixation
902
+		$this->ci->session->sess_regenerate();
903
+
904
+		// Let the session know that we're logged in.
905
+		$this->ci->session->set_userdata('logged_in', $user['id']);
906
+
907
+		// Clear our login attempts
908
+		$this->ci->login_model->purgeLoginAttempts($user['email']);
909
+
910
+		// Record a new Login
911
+		$this->ci->login_model->recordLogin($user);
912
+
913
+		// If logged in, ensure cache control
914
+		// headers are in place
915
+		$this->setHeaders();
916
+
917
+		// We'll give a 20% chance to need to do a purge since we
918
+		// don't need to purge THAT often, it's just a maintenance issue.
919
+		// to keep the table from getting out of control.
920
+		if (mt_rand(1, 100) < 20)
921
+		{
922
+			$this->ci->login_model->purgeOldRememberTokens();
923
+		}
924
+	}
925
+
926
+	//--------------------------------------------------------------------
927
+
928
+	/**
929
+	 * Sets the headers to ensure that pages are not cached when a user
930
+	 * is logged in, helping to protect against logging out and then
931
+	 * simply hitting the Back button on the browser and getting private
932
+	 * information because the page was loaded from cache.
933
+	 */
934
+	protected function setHeaders()
935
+	{
936
+		$this->ci->output->set_header('Cache-Control: no-store, no-cache, must-revalidate');
937
+		$this->ci->output->set_header('Cache-Control: post-check=0, pre-check=0');
938
+		$this->ci->output->set_header('Pragma: no-cache');
939
+	}
940
+
941
+	//--------------------------------------------------------------------
942 942
 
943 943
 
944 944
 }
Please login to merge, or discard this patch.
myth/Auth/Password.php 3 patches
Indentation   +321 added lines, -321 removed lines patch added patch discarded remove patch
@@ -51,325 +51,325 @@
 block discarded – undo
51 51
  */
52 52
 class Password {
53 53
 
54
-    /**
55
-     * A standardized method for hasing a password before storing
56
-     * in the database.
57
-     *
58
-     * @param $password
59
-     * @return bool|mixed|string
60
-     */
61
-    public static function hashPassword($password)
62
-    {
63
-        if (! config_item('auth.hash_cost'))
64
-        {
65
-            get_instance()->load->config('auth');
66
-        }
67
-
68
-        return password_hash($password, PASSWORD_DEFAULT, ['cost' => config_item('auth.hash_cost')]);
69
-    }
70
-
71
-    //--------------------------------------------------------------------
72
-
73
-    /**
74
-     * Determines the number of entropy bits a password has based on
75
-     *
76
-     *
77
-     * @param $password
78
-     * @param bool $repeatcalc
79
-     * @return int
80
-     */
81
-    public static function getNISTNumBits($password, $repeatcalc = false)
82
-    {
83
-        $y = strlen($password);
84
-        if ($repeatcalc)
85
-        {
86
-            // Variant on NIST rules to reduce long sequences of repeated characters.
87
-            $result = 0;
88
-            $charmult = array_fill(0, 256, 1);
89
-            for ($x = 0; $x < $y; $x++)
90
-            {
91
-                $tempchr = ord(substr($password, $x, 1));
92
-                if ($x > 19)  $result += $charmult[$tempchr];
93
-                else if ($x > 7)  $result += $charmult[$tempchr] * 1.5;
94
-                else if ($x > 0)  $result += $charmult[$tempchr] * 2;
95
-                else  $result += 4;
96
-
97
-                $charmult[$tempchr] *= 0.75;
98
-            }
99
-
100
-            return $result;
101
-        }
102
-        else
103
-        {
104
-            if ($y > 20)  return 4 + (7 * 2) + (12 * 1.5) + $y - 20;
105
-            if ($y > 8)  return 4 + (7 * 2) + (($y - 8) * 1.5);
106
-            if ($y > 1)  return 4 + (($y - 1) * 2);
107
-
108
-            return ($y == 1 ? 4 : 0);
109
-        }
110
-    }
111
-
112
-    //--------------------------------------------------------------------
113
-
114
-    /**
115
-     * Determines whether a password is strong enough to use. You should check
116
-     * the password against this method and reject it if the password is not
117
-     * strong enough.
118
-     *
119
-     * The following guidelines come from the author's tests against 10.4 million actual passwords
120
-     * ( see post: http://cubicspot.blogspot.com/2012/01/how-to-calculate-password-strength-part.html )
121
-     * and represents the suggested minimum entropy bits for different types of sites:
122
-     *
123
-     *      - 18 bits of entropy = minimum for ANY website.
124
-     *      - 25 bits of entropy = minimum for a general purpose web service used relatively widely (e.g. Hotmail).
125
-     *      - 30 bits of entropy = minimum for a web service with business critical applications (e.g. SAAS).
126
-     *      - 40 bits of entropy = minimum for a bank or other financial service.
127
-     *
128
-     * The algorithm is based upon a modified version of the NIST rules which suggest the following:
129
-     *
130
-     *      - The first byte counts as 4 bits.
131
-     *      - The next 7 bytes count as 2 bits each.
132
-     *      - The next 12 bytes count as 1.5 bits each.
133
-     *      - Anything beyond that counts as 1 bit each.
134
-     *      - Mixed case + non-alphanumeric = up to 6 extra bits.
135
-     *
136
-     * @param string    $password   - The password to check
137
-     * @param int       $minbits    - Minimum "entropy bits" that is allowed
138
-     * @param bool      $usedict    - Should we check the password against a 300,000 word English dictionary?
139
-     * @param int       $minwordlen -
140
-     * @return bool
141
-     */
142
-    public static function isStrongPassword($password, $minbits = 18, $usedict = false, $minwordlen = 4)
143
-    {
144
-        // NIST password strength rules allow up to 6 extra bits for mixed case and non-alphabetic.
145
-        $upper = false;
146
-        $lower = false;
147
-        $numeric = false;
148
-        $other = false;
149
-        $space = false;
150
-        $y = strlen($password);
151
-        for ($x = 0; $x < $y; $x++)
152
-        {
153
-            $tempchr = ord(substr($password, $x, 1));
154
-            if ($tempchr >= ord("A") && $tempchr <= ord("Z"))  $upper = true;
155
-            else if ($tempchr >= ord("a") && $tempchr <= ord("z"))  $lower = true;
156
-            else if ($tempchr >= ord("0") && $tempchr <= ord("9"))  $numeric = true;
157
-            else if ($tempchr == ord(" "))  $space = true;
158
-            else  $other = true;
159
-        }
160
-        $extrabits = ($upper && $lower && $other ? ($numeric ? 6 : 5) : ($numeric && !$upper && !$lower ? ($other ? -2 : -6) : 0));
161
-        if (!$space)  $extrabits -= 2;
162
-        else if (count(explode(" ", preg_replace('/\s+/', " ", $password))) > 3)  $extrabits++;
163
-        $result = self::getNISTNumBits($password, true) + $extrabits;
164
-
165
-        $password = strtolower($password);
166
-        $revpassword = strrev($password);
167
-        $numbits = self::getNISTNumBits($password) + $extrabits;
168
-        if ($result > $numbits)  $result = $numbits;
169
-
170
-        // Remove QWERTY strings.
171
-        $qwertystrs = array(
172
-            "1234567890-qwertyuiopasdfghjkl;zxcvbnm,./",
173
-            "1qaz2wsx3edc4rfv5tgb6yhn7ujm8ik,9ol.0p;/-['=]:?_{\"+}",
174
-            "1qaz2wsx3edc4rfv5tgb6yhn7ujm8ik9ol0p",
175
-            "qazwsxedcrfvtgbyhnujmik,ol.p;/-['=]:?_{\"+}",
176
-            "qazwsxedcrfvtgbyhnujmikolp",
177
-            "]\"/=[;.-pl,0okm9ijn8uhb7ygv6tfc5rdx4esz3wa2q1",
178
-            "pl0okm9ijn8uhb7ygv6tfc5rdx4esz3wa2q1",
179
-            "]\"/[;.pl,okmijnuhbygvtfcrdxeszwaq",
180
-            "plokmijnuhbygvtfcrdxeszwaq",
181
-            "014725836914702583697894561230258/369*+-*/",
182
-            "abcdefghijklmnopqrstuvwxyz"
183
-        );
184
-        foreach ($qwertystrs as $qwertystr)
185
-        {
186
-            $qpassword = $password;
187
-            $qrevpassword = $revpassword;
188
-            $z = 6;
189
-            do
190
-            {
191
-                $y = strlen($qwertystr) - $z;
192
-                for ($x = 0; $x < $y; $x++)
193
-                {
194
-                    $str = substr($qwertystr, $x, $z);
195
-                    $qpassword = str_replace($str, "*", $qpassword);
196
-                    $qrevpassword = str_replace($str, "*", $qrevpassword);
197
-                }
198
-
199
-                $z--;
200
-            } while ($z > 2);
201
-
202
-            $numbits = self::getNISTNumBits($qpassword) + $extrabits;
203
-            if ($result > $numbits)  $result = $numbits;
204
-            $numbits = self::getNISTNumBits($qrevpassword) + $extrabits;
205
-            if ($result > $numbits)  $result = $numbits;
206
-
207
-            if ($result < $minbits)  return false;
208
-        }
209
-
210
-        if ($usedict && $result >= $minbits)
211
-        {
212
-            $passwords = array();
213
-
214
-            // Add keyboard shifting password variants.
215
-            $keyboardmap_down_noshift = array(
216
-                "z" => "", "x" => "", "c" => "", "v" => "", "b" => "", "n" => "", "m" => "", "," => "", "." => "", "/" => "", "<" => "", ">" => "", "?" => ""
217
-            );
218
-            if ($password == str_replace(array_keys($keyboardmap_down_noshift), array_values($keyboardmap_down_noshift), $password))
219
-            {
220
-                $keyboardmap_downright = array(
221
-                    "a" => "z",
222
-                    "q" => "a",
223
-                    "1" => "q",
224
-                    "s" => "x",
225
-                    "w" => "s",
226
-                    "2" => "w",
227
-                    "d" => "c",
228
-                    "e" => "d",
229
-                    "3" => "e",
230
-                    "f" => "v",
231
-                    "r" => "f",
232
-                    "4" => "r",
233
-                    "g" => "b",
234
-                    "t" => "g",
235
-                    "5" => "t",
236
-                    "h" => "n",
237
-                    "y" => "h",
238
-                    "6" => "y",
239
-                    "j" => "m",
240
-                    "u" => "j",
241
-                    "7" => "u",
242
-                    "i" => "k",
243
-                    "8" => "i",
244
-                    "o" => "l",
245
-                    "9" => "o",
246
-                    "0" => "p",
247
-                );
248
-
249
-                $keyboardmap_downleft = array(
250
-                    "2" => "q",
251
-                    "w" => "a",
252
-                    "3" => "w",
253
-                    "s" => "z",
254
-                    "e" => "s",
255
-                    "4" => "e",
256
-                    "d" => "x",
257
-                    "r" => "d",
258
-                    "5" => "r",
259
-                    "f" => "c",
260
-                    "t" => "f",
261
-                    "6" => "t",
262
-                    "g" => "v",
263
-                    "y" => "g",
264
-                    "7" => "y",
265
-                    "h" => "b",
266
-                    "u" => "h",
267
-                    "8" => "u",
268
-                    "j" => "n",
269
-                    "i" => "j",
270
-                    "9" => "i",
271
-                    "k" => "m",
272
-                    "o" => "k",
273
-                    "0" => "o",
274
-                    "p" => "l",
275
-                    "-" => "p",
276
-                );
277
-
278
-                $password2 = str_replace(array_keys($keyboardmap_downright), array_values($keyboardmap_downright), $password);
279
-                $passwords[] = $password2;
280
-                $passwords[] = strrev($password2);
281
-
282
-                $password2 = str_replace(array_keys($keyboardmap_downleft), array_values($keyboardmap_downleft), $password);
283
-                $passwords[] = $password2;
284
-                $passwords[] = strrev($password2);
285
-            }
286
-
287
-            // Deal with LEET-Speak substitutions.
288
-            $leetspeakmap = array(
289
-                "@" => "a",
290
-                "!" => "i",
291
-                "$" => "s",
292
-                "1" => "i",
293
-                "2" => "z",
294
-                "3" => "e",
295
-                "4" => "a",
296
-                "5" => "s",
297
-                "6" => "g",
298
-                "7" => "t",
299
-                "8" => "b",
300
-                "9" => "g",
301
-                "0" => "o"
302
-            );
303
-
304
-            $password2 = str_replace(array_keys($leetspeakmap), array_values($leetspeakmap), $password);
305
-            $passwords[] = $password2;
306
-            $passwords[] = strrev($password2);
307
-
308
-            $leetspeakmap["1"] = "l";
309
-            $password3 = str_replace(array_keys($leetspeakmap), array_values($leetspeakmap), $password);
310
-            if ($password3 != $password2)
311
-            {
312
-                $passwords[] = $password3;
313
-                $passwords[] = strrev($password3);
314
-            }
315
-
316
-            // Process the password, while looking for words in the dictionary.
317
-            $a = ord("a");
318
-            $z = ord("z");
319
-            $data = file_get_contents(DICTIONARY_PATH);
320
-            foreach ($passwords as $num => $password)
321
-            {
322
-                $y = strlen($password);
323
-                for ($x = 0; $x < $y; $x++)
324
-                {
325
-                    $tempchr = ord(substr($password, $x, 1));
326
-                    if ($tempchr >= $a && $tempchr <= $z)
327
-                    {
328
-                        for ($x2 = $x + 1; $x2 < $y; $x2++)
329
-                        {
330
-                            $tempchr = ord(substr($password, $x2, 1));
331
-                            if ($tempchr < $a || $tempchr > $z)  break;
332
-                        }
333
-
334
-                        $found = false;
335
-                        while (!$found && $x2 - $x >= $minwordlen)
336
-                        {
337
-                            $word = "/\\n" . substr($password, $x, $minwordlen);
338
-                            for ($x3 = $x + $minwordlen; $x3 < $x2; $x3++)  $word .= "(" . $password{$x3};
339
-                            for ($x3 = $x + $minwordlen; $x3 < $x2; $x3++)  $word .= ")?";
340
-                            $word .= "\\n/";
341
-
342
-                            preg_match_all($word, $data, $matches);
343
-                            if (!count($matches[0]))
344
-                            {
345
-                                $password{$x} = "*";
346
-                                $x++;
347
-                                $numbits = self::getNISTNumBits(substr($password, 0, $x)) + $extrabits;
348
-                                if ($numbits >= $minbits)  $found = true;
349
-                            }
350
-                            else
351
-                            {
352
-                                foreach ($matches[0] as $match)
353
-                                {
354
-                                    $password2 = str_replace(trim($match), "*", $password);
355
-                                    $numbits = self::getNISTNumBits($password2) + $extrabits;
356
-                                    if ($result > $numbits)  $result = $numbits;
357
-
358
-                                    if ($result < $minbits)  return false;
359
-                                }
360
-
361
-                                $found = true;
362
-                            }
363
-                        }
364
-
365
-                        if ($found)  break;
366
-
367
-                        $x = $x2 - 1;
368
-                    }
369
-                }
370
-            }
371
-        }
372
-
373
-        return $result >= $minbits;
374
-    }
54
+	/**
55
+	 * A standardized method for hasing a password before storing
56
+	 * in the database.
57
+	 *
58
+	 * @param $password
59
+	 * @return bool|mixed|string
60
+	 */
61
+	public static function hashPassword($password)
62
+	{
63
+		if (! config_item('auth.hash_cost'))
64
+		{
65
+			get_instance()->load->config('auth');
66
+		}
67
+
68
+		return password_hash($password, PASSWORD_DEFAULT, ['cost' => config_item('auth.hash_cost')]);
69
+	}
70
+
71
+	//--------------------------------------------------------------------
72
+
73
+	/**
74
+	 * Determines the number of entropy bits a password has based on
75
+	 *
76
+	 *
77
+	 * @param $password
78
+	 * @param bool $repeatcalc
79
+	 * @return int
80
+	 */
81
+	public static function getNISTNumBits($password, $repeatcalc = false)
82
+	{
83
+		$y = strlen($password);
84
+		if ($repeatcalc)
85
+		{
86
+			// Variant on NIST rules to reduce long sequences of repeated characters.
87
+			$result = 0;
88
+			$charmult = array_fill(0, 256, 1);
89
+			for ($x = 0; $x < $y; $x++)
90
+			{
91
+				$tempchr = ord(substr($password, $x, 1));
92
+				if ($x > 19)  $result += $charmult[$tempchr];
93
+				else if ($x > 7)  $result += $charmult[$tempchr] * 1.5;
94
+				else if ($x > 0)  $result += $charmult[$tempchr] * 2;
95
+				else  $result += 4;
96
+
97
+				$charmult[$tempchr] *= 0.75;
98
+			}
99
+
100
+			return $result;
101
+		}
102
+		else
103
+		{
104
+			if ($y > 20)  return 4 + (7 * 2) + (12 * 1.5) + $y - 20;
105
+			if ($y > 8)  return 4 + (7 * 2) + (($y - 8) * 1.5);
106
+			if ($y > 1)  return 4 + (($y - 1) * 2);
107
+
108
+			return ($y == 1 ? 4 : 0);
109
+		}
110
+	}
111
+
112
+	//--------------------------------------------------------------------
113
+
114
+	/**
115
+	 * Determines whether a password is strong enough to use. You should check
116
+	 * the password against this method and reject it if the password is not
117
+	 * strong enough.
118
+	 *
119
+	 * The following guidelines come from the author's tests against 10.4 million actual passwords
120
+	 * ( see post: http://cubicspot.blogspot.com/2012/01/how-to-calculate-password-strength-part.html )
121
+	 * and represents the suggested minimum entropy bits for different types of sites:
122
+	 *
123
+	 *      - 18 bits of entropy = minimum for ANY website.
124
+	 *      - 25 bits of entropy = minimum for a general purpose web service used relatively widely (e.g. Hotmail).
125
+	 *      - 30 bits of entropy = minimum for a web service with business critical applications (e.g. SAAS).
126
+	 *      - 40 bits of entropy = minimum for a bank or other financial service.
127
+	 *
128
+	 * The algorithm is based upon a modified version of the NIST rules which suggest the following:
129
+	 *
130
+	 *      - The first byte counts as 4 bits.
131
+	 *      - The next 7 bytes count as 2 bits each.
132
+	 *      - The next 12 bytes count as 1.5 bits each.
133
+	 *      - Anything beyond that counts as 1 bit each.
134
+	 *      - Mixed case + non-alphanumeric = up to 6 extra bits.
135
+	 *
136
+	 * @param string    $password   - The password to check
137
+	 * @param int       $minbits    - Minimum "entropy bits" that is allowed
138
+	 * @param bool      $usedict    - Should we check the password against a 300,000 word English dictionary?
139
+	 * @param int       $minwordlen -
140
+	 * @return bool
141
+	 */
142
+	public static function isStrongPassword($password, $minbits = 18, $usedict = false, $minwordlen = 4)
143
+	{
144
+		// NIST password strength rules allow up to 6 extra bits for mixed case and non-alphabetic.
145
+		$upper = false;
146
+		$lower = false;
147
+		$numeric = false;
148
+		$other = false;
149
+		$space = false;
150
+		$y = strlen($password);
151
+		for ($x = 0; $x < $y; $x++)
152
+		{
153
+			$tempchr = ord(substr($password, $x, 1));
154
+			if ($tempchr >= ord("A") && $tempchr <= ord("Z"))  $upper = true;
155
+			else if ($tempchr >= ord("a") && $tempchr <= ord("z"))  $lower = true;
156
+			else if ($tempchr >= ord("0") && $tempchr <= ord("9"))  $numeric = true;
157
+			else if ($tempchr == ord(" "))  $space = true;
158
+			else  $other = true;
159
+		}
160
+		$extrabits = ($upper && $lower && $other ? ($numeric ? 6 : 5) : ($numeric && !$upper && !$lower ? ($other ? -2 : -6) : 0));
161
+		if (!$space)  $extrabits -= 2;
162
+		else if (count(explode(" ", preg_replace('/\s+/', " ", $password))) > 3)  $extrabits++;
163
+		$result = self::getNISTNumBits($password, true) + $extrabits;
164
+
165
+		$password = strtolower($password);
166
+		$revpassword = strrev($password);
167
+		$numbits = self::getNISTNumBits($password) + $extrabits;
168
+		if ($result > $numbits)  $result = $numbits;
169
+
170
+		// Remove QWERTY strings.
171
+		$qwertystrs = array(
172
+			"1234567890-qwertyuiopasdfghjkl;zxcvbnm,./",
173
+			"1qaz2wsx3edc4rfv5tgb6yhn7ujm8ik,9ol.0p;/-['=]:?_{\"+}",
174
+			"1qaz2wsx3edc4rfv5tgb6yhn7ujm8ik9ol0p",
175
+			"qazwsxedcrfvtgbyhnujmik,ol.p;/-['=]:?_{\"+}",
176
+			"qazwsxedcrfvtgbyhnujmikolp",
177
+			"]\"/=[;.-pl,0okm9ijn8uhb7ygv6tfc5rdx4esz3wa2q1",
178
+			"pl0okm9ijn8uhb7ygv6tfc5rdx4esz3wa2q1",
179
+			"]\"/[;.pl,okmijnuhbygvtfcrdxeszwaq",
180
+			"plokmijnuhbygvtfcrdxeszwaq",
181
+			"014725836914702583697894561230258/369*+-*/",
182
+			"abcdefghijklmnopqrstuvwxyz"
183
+		);
184
+		foreach ($qwertystrs as $qwertystr)
185
+		{
186
+			$qpassword = $password;
187
+			$qrevpassword = $revpassword;
188
+			$z = 6;
189
+			do
190
+			{
191
+				$y = strlen($qwertystr) - $z;
192
+				for ($x = 0; $x < $y; $x++)
193
+				{
194
+					$str = substr($qwertystr, $x, $z);
195
+					$qpassword = str_replace($str, "*", $qpassword);
196
+					$qrevpassword = str_replace($str, "*", $qrevpassword);
197
+				}
198
+
199
+				$z--;
200
+			} while ($z > 2);
201
+
202
+			$numbits = self::getNISTNumBits($qpassword) + $extrabits;
203
+			if ($result > $numbits)  $result = $numbits;
204
+			$numbits = self::getNISTNumBits($qrevpassword) + $extrabits;
205
+			if ($result > $numbits)  $result = $numbits;
206
+
207
+			if ($result < $minbits)  return false;
208
+		}
209
+
210
+		if ($usedict && $result >= $minbits)
211
+		{
212
+			$passwords = array();
213
+
214
+			// Add keyboard shifting password variants.
215
+			$keyboardmap_down_noshift = array(
216
+				"z" => "", "x" => "", "c" => "", "v" => "", "b" => "", "n" => "", "m" => "", "," => "", "." => "", "/" => "", "<" => "", ">" => "", "?" => ""
217
+			);
218
+			if ($password == str_replace(array_keys($keyboardmap_down_noshift), array_values($keyboardmap_down_noshift), $password))
219
+			{
220
+				$keyboardmap_downright = array(
221
+					"a" => "z",
222
+					"q" => "a",
223
+					"1" => "q",
224
+					"s" => "x",
225
+					"w" => "s",
226
+					"2" => "w",
227
+					"d" => "c",
228
+					"e" => "d",
229
+					"3" => "e",
230
+					"f" => "v",
231
+					"r" => "f",
232
+					"4" => "r",
233
+					"g" => "b",
234
+					"t" => "g",
235
+					"5" => "t",
236
+					"h" => "n",
237
+					"y" => "h",
238
+					"6" => "y",
239
+					"j" => "m",
240
+					"u" => "j",
241
+					"7" => "u",
242
+					"i" => "k",
243
+					"8" => "i",
244
+					"o" => "l",
245
+					"9" => "o",
246
+					"0" => "p",
247
+				);
248
+
249
+				$keyboardmap_downleft = array(
250
+					"2" => "q",
251
+					"w" => "a",
252
+					"3" => "w",
253
+					"s" => "z",
254
+					"e" => "s",
255
+					"4" => "e",
256
+					"d" => "x",
257
+					"r" => "d",
258
+					"5" => "r",
259
+					"f" => "c",
260
+					"t" => "f",
261
+					"6" => "t",
262
+					"g" => "v",
263
+					"y" => "g",
264
+					"7" => "y",
265
+					"h" => "b",
266
+					"u" => "h",
267
+					"8" => "u",
268
+					"j" => "n",
269
+					"i" => "j",
270
+					"9" => "i",
271
+					"k" => "m",
272
+					"o" => "k",
273
+					"0" => "o",
274
+					"p" => "l",
275
+					"-" => "p",
276
+				);
277
+
278
+				$password2 = str_replace(array_keys($keyboardmap_downright), array_values($keyboardmap_downright), $password);
279
+				$passwords[] = $password2;
280
+				$passwords[] = strrev($password2);
281
+
282
+				$password2 = str_replace(array_keys($keyboardmap_downleft), array_values($keyboardmap_downleft), $password);
283
+				$passwords[] = $password2;
284
+				$passwords[] = strrev($password2);
285
+			}
286
+
287
+			// Deal with LEET-Speak substitutions.
288
+			$leetspeakmap = array(
289
+				"@" => "a",
290
+				"!" => "i",
291
+				"$" => "s",
292
+				"1" => "i",
293
+				"2" => "z",
294
+				"3" => "e",
295
+				"4" => "a",
296
+				"5" => "s",
297
+				"6" => "g",
298
+				"7" => "t",
299
+				"8" => "b",
300
+				"9" => "g",
301
+				"0" => "o"
302
+			);
303
+
304
+			$password2 = str_replace(array_keys($leetspeakmap), array_values($leetspeakmap), $password);
305
+			$passwords[] = $password2;
306
+			$passwords[] = strrev($password2);
307
+
308
+			$leetspeakmap["1"] = "l";
309
+			$password3 = str_replace(array_keys($leetspeakmap), array_values($leetspeakmap), $password);
310
+			if ($password3 != $password2)
311
+			{
312
+				$passwords[] = $password3;
313
+				$passwords[] = strrev($password3);
314
+			}
315
+
316
+			// Process the password, while looking for words in the dictionary.
317
+			$a = ord("a");
318
+			$z = ord("z");
319
+			$data = file_get_contents(DICTIONARY_PATH);
320
+			foreach ($passwords as $num => $password)
321
+			{
322
+				$y = strlen($password);
323
+				for ($x = 0; $x < $y; $x++)
324
+				{
325
+					$tempchr = ord(substr($password, $x, 1));
326
+					if ($tempchr >= $a && $tempchr <= $z)
327
+					{
328
+						for ($x2 = $x + 1; $x2 < $y; $x2++)
329
+						{
330
+							$tempchr = ord(substr($password, $x2, 1));
331
+							if ($tempchr < $a || $tempchr > $z)  break;
332
+						}
333
+
334
+						$found = false;
335
+						while (!$found && $x2 - $x >= $minwordlen)
336
+						{
337
+							$word = "/\\n" . substr($password, $x, $minwordlen);
338
+							for ($x3 = $x + $minwordlen; $x3 < $x2; $x3++)  $word .= "(" . $password{$x3};
339
+							for ($x3 = $x + $minwordlen; $x3 < $x2; $x3++)  $word .= ")?";
340
+							$word .= "\\n/";
341
+
342
+							preg_match_all($word, $data, $matches);
343
+							if (!count($matches[0]))
344
+							{
345
+								$password{$x} = "*";
346
+								$x++;
347
+								$numbits = self::getNISTNumBits(substr($password, 0, $x)) + $extrabits;
348
+								if ($numbits >= $minbits)  $found = true;
349
+							}
350
+							else
351
+							{
352
+								foreach ($matches[0] as $match)
353
+								{
354
+									$password2 = str_replace(trim($match), "*", $password);
355
+									$numbits = self::getNISTNumBits($password2) + $extrabits;
356
+									if ($result > $numbits)  $result = $numbits;
357
+
358
+									if ($result < $minbits)  return false;
359
+								}
360
+
361
+								$found = true;
362
+							}
363
+						}
364
+
365
+						if ($found)  break;
366
+
367
+						$x = $x2 - 1;
368
+					}
369
+				}
370
+			}
371
+		}
372
+
373
+		return $result >= $minbits;
374
+	}
375 375
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -30,7 +30,7 @@  discard block
 block discarded – undo
30 30
  * @since       Version 1.0
31 31
  */
32 32
 
33
-define('DICTIONARY_PATH', dirname(__FILE__) .'/dictionary.txt');
33
+define('DICTIONARY_PATH', dirname(__FILE__).'/dictionary.txt');
34 34
 
35 35
 /**
36 36
  * Class Password
@@ -60,7 +60,7 @@  discard block
 block discarded – undo
60 60
      */
61 61
     public static function hashPassword($password)
62 62
     {
63
-        if (! config_item('auth.hash_cost'))
63
+        if ( ! config_item('auth.hash_cost'))
64 64
         {
65 65
             get_instance()->load->config('auth');
66 66
         }
@@ -157,8 +157,8 @@  discard block
 block discarded – undo
157 157
             else if ($tempchr == ord(" "))  $space = true;
158 158
             else  $other = true;
159 159
         }
160
-        $extrabits = ($upper && $lower && $other ? ($numeric ? 6 : 5) : ($numeric && !$upper && !$lower ? ($other ? -2 : -6) : 0));
161
-        if (!$space)  $extrabits -= 2;
160
+        $extrabits = ($upper && $lower && $other ? ($numeric ? 6 : 5) : ($numeric && ! $upper && ! $lower ? ($other ? -2 : -6) : 0));
161
+        if ( ! $space)  $extrabits -= 2;
162 162
         else if (count(explode(" ", preg_replace('/\s+/', " ", $password))) > 3)  $extrabits++;
163 163
         $result = self::getNISTNumBits($password, true) + $extrabits;
164 164
 
@@ -332,15 +332,15 @@  discard block
 block discarded – undo
332 332
                         }
333 333
 
334 334
                         $found = false;
335
-                        while (!$found && $x2 - $x >= $minwordlen)
335
+                        while ( ! $found && $x2 - $x >= $minwordlen)
336 336
                         {
337
-                            $word = "/\\n" . substr($password, $x, $minwordlen);
338
-                            for ($x3 = $x + $minwordlen; $x3 < $x2; $x3++)  $word .= "(" . $password{$x3};
337
+                            $word = "/\\n".substr($password, $x, $minwordlen);
338
+                            for ($x3 = $x + $minwordlen; $x3 < $x2; $x3++)  $word .= "(".$password{$x3};
339 339
                             for ($x3 = $x + $minwordlen; $x3 < $x2; $x3++)  $word .= ")?";
340 340
                             $word .= "\\n/";
341 341
 
342 342
                             preg_match_all($word, $data, $matches);
343
-                            if (!count($matches[0]))
343
+                            if ( ! count($matches[0]))
344 344
                             {
345 345
                                 $password{$x} = "*";
346 346
                                 $x++;
Please login to merge, or discard this patch.
Braces   +69 added lines, -29 removed lines patch added patch discarded remove patch
@@ -89,21 +89,31 @@  discard block
 block discarded – undo
89 89
             for ($x = 0; $x < $y; $x++)
90 90
             {
91 91
                 $tempchr = ord(substr($password, $x, 1));
92
-                if ($x > 19)  $result += $charmult[$tempchr];
93
-                else if ($x > 7)  $result += $charmult[$tempchr] * 1.5;
94
-                else if ($x > 0)  $result += $charmult[$tempchr] * 2;
95
-                else  $result += 4;
92
+                if ($x > 19) {
93
+                	$result += $charmult[$tempchr];
94
+                } else if ($x > 7) {
95
+                	$result += $charmult[$tempchr] * 1.5;
96
+                } else if ($x > 0) {
97
+                	$result += $charmult[$tempchr] * 2;
98
+                } else {
99
+                	$result += 4;
100
+                }
96 101
 
97 102
                 $charmult[$tempchr] *= 0.75;
98 103
             }
99 104
 
100 105
             return $result;
101
-        }
102
-        else
106
+        } else
103 107
         {
104
-            if ($y > 20)  return 4 + (7 * 2) + (12 * 1.5) + $y - 20;
105
-            if ($y > 8)  return 4 + (7 * 2) + (($y - 8) * 1.5);
106
-            if ($y > 1)  return 4 + (($y - 1) * 2);
108
+            if ($y > 20) {
109
+            	return 4 + (7 * 2) + (12 * 1.5) + $y - 20;
110
+            }
111
+            if ($y > 8) {
112
+            	return 4 + (7 * 2) + (($y - 8) * 1.5);
113
+            }
114
+            if ($y > 1) {
115
+            	return 4 + (($y - 1) * 2);
116
+            }
107 117
 
108 118
             return ($y == 1 ? 4 : 0);
109 119
         }
@@ -151,21 +161,32 @@  discard block
 block discarded – undo
151 161
         for ($x = 0; $x < $y; $x++)
152 162
         {
153 163
             $tempchr = ord(substr($password, $x, 1));
154
-            if ($tempchr >= ord("A") && $tempchr <= ord("Z"))  $upper = true;
155
-            else if ($tempchr >= ord("a") && $tempchr <= ord("z"))  $lower = true;
156
-            else if ($tempchr >= ord("0") && $tempchr <= ord("9"))  $numeric = true;
157
-            else if ($tempchr == ord(" "))  $space = true;
158
-            else  $other = true;
164
+            if ($tempchr >= ord("A") && $tempchr <= ord("Z")) {
165
+            	$upper = true;
166
+            } else if ($tempchr >= ord("a") && $tempchr <= ord("z")) {
167
+            	$lower = true;
168
+            } else if ($tempchr >= ord("0") && $tempchr <= ord("9")) {
169
+            	$numeric = true;
170
+            } else if ($tempchr == ord(" ")) {
171
+            	$space = true;
172
+            } else {
173
+            	$other = true;
174
+            }
159 175
         }
160 176
         $extrabits = ($upper && $lower && $other ? ($numeric ? 6 : 5) : ($numeric && !$upper && !$lower ? ($other ? -2 : -6) : 0));
161
-        if (!$space)  $extrabits -= 2;
162
-        else if (count(explode(" ", preg_replace('/\s+/', " ", $password))) > 3)  $extrabits++;
177
+        if (!$space) {
178
+        	$extrabits -= 2;
179
+        } else if (count(explode(" ", preg_replace('/\s+/', " ", $password))) > 3) {
180
+        	$extrabits++;
181
+        }
163 182
         $result = self::getNISTNumBits($password, true) + $extrabits;
164 183
 
165 184
         $password = strtolower($password);
166 185
         $revpassword = strrev($password);
167 186
         $numbits = self::getNISTNumBits($password) + $extrabits;
168
-        if ($result > $numbits)  $result = $numbits;
187
+        if ($result > $numbits) {
188
+        	$result = $numbits;
189
+        }
169 190
 
170 191
         // Remove QWERTY strings.
171 192
         $qwertystrs = array(
@@ -200,11 +221,17 @@  discard block
 block discarded – undo
200 221
             } while ($z > 2);
201 222
 
202 223
             $numbits = self::getNISTNumBits($qpassword) + $extrabits;
203
-            if ($result > $numbits)  $result = $numbits;
224
+            if ($result > $numbits) {
225
+            	$result = $numbits;
226
+            }
204 227
             $numbits = self::getNISTNumBits($qrevpassword) + $extrabits;
205
-            if ($result > $numbits)  $result = $numbits;
228
+            if ($result > $numbits) {
229
+            	$result = $numbits;
230
+            }
206 231
 
207
-            if ($result < $minbits)  return false;
232
+            if ($result < $minbits) {
233
+            	return false;
234
+            }
208 235
         }
209 236
 
210 237
         if ($usedict && $result >= $minbits)
@@ -328,15 +355,21 @@  discard block
 block discarded – undo
328 355
                         for ($x2 = $x + 1; $x2 < $y; $x2++)
329 356
                         {
330 357
                             $tempchr = ord(substr($password, $x2, 1));
331
-                            if ($tempchr < $a || $tempchr > $z)  break;
358
+                            if ($tempchr < $a || $tempchr > $z) {
359
+                            	break;
360
+                            }
332 361
                         }
333 362
 
334 363
                         $found = false;
335 364
                         while (!$found && $x2 - $x >= $minwordlen)
336 365
                         {
337 366
                             $word = "/\\n" . substr($password, $x, $minwordlen);
338
-                            for ($x3 = $x + $minwordlen; $x3 < $x2; $x3++)  $word .= "(" . $password{$x3};
339
-                            for ($x3 = $x + $minwordlen; $x3 < $x2; $x3++)  $word .= ")?";
367
+                            for ($x3 = $x + $minwordlen; $x3 < $x2; $x3++) {
368
+                            	$word .= "(" . $password{$x3};
369
+                            }
370
+                            for ($x3 = $x + $minwordlen; $x3 < $x2; $x3++) {
371
+                            	$word .= ")?";
372
+                            }
340 373
                             $word .= "\\n/";
341 374
 
342 375
                             preg_match_all($word, $data, $matches);
@@ -345,24 +378,31 @@  discard block
 block discarded – undo
345 378
                                 $password{$x} = "*";
346 379
                                 $x++;
347 380
                                 $numbits = self::getNISTNumBits(substr($password, 0, $x)) + $extrabits;
348
-                                if ($numbits >= $minbits)  $found = true;
349
-                            }
350
-                            else
381
+                                if ($numbits >= $minbits) {
382
+                                	$found = true;
383
+                                }
384
+                            } else
351 385
                             {
352 386
                                 foreach ($matches[0] as $match)
353 387
                                 {
354 388
                                     $password2 = str_replace(trim($match), "*", $password);
355 389
                                     $numbits = self::getNISTNumBits($password2) + $extrabits;
356
-                                    if ($result > $numbits)  $result = $numbits;
390
+                                    if ($result > $numbits) {
391
+                                    	$result = $numbits;
392
+                                    }
357 393
 
358
-                                    if ($result < $minbits)  return false;
394
+                                    if ($result < $minbits) {
395
+                                    	return false;
396
+                                    }
359 397
                                 }
360 398
 
361 399
                                 $found = true;
362 400
                             }
363 401
                         }
364 402
 
365
-                        if ($found)  break;
403
+                        if ($found) {
404
+                        	break;
405
+                        }
366 406
 
367 407
                         $x = $x2 - 1;
368 408
                     }
Please login to merge, or discard this patch.