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
Push — develop ( 7b8120...7d455c )
by Lonnie
22:54 queued 17:12
created
build/scripts/SprintRelease.php 1 patch
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -17,7 +17,7 @@
 block discarded – undo
17 17
 
18 18
 	public function __construct($destination)
19 19
 	{
20
-	    $this->source_path = realpath(BUILDBASE .'../');
20
+		$this->source_path = realpath(BUILDBASE .'../');
21 21
 
22 22
 		if (empty($this->source_path))
23 23
 		{
Please login to merge, or discard this patch.
build/scripts/SubTreeSplit.php 1 patch
Indentation   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -12,12 +12,12 @@
 block discarded – undo
12 12
  */
13 13
 class SubTreeSplit extends BaseBuilder {
14 14
 
15
-    public function run()
16
-    {
15
+	public function run()
16
+	{
17 17
 
18
-    }
18
+	}
19 19
 
20
-    //--------------------------------------------------------------------
20
+	//--------------------------------------------------------------------
21 21
 
22 22
 
23 23
 }
24 24
\ No newline at end of file
Please login to merge, or discard this patch.
index.php 1 patch
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.
myth/Api/Auth/APIAuthentication.php 1 patch
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.
myth/Api/Server/ApiController.php 1 patch
Indentation   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -141,8 +141,8 @@  discard block
 block discarded – undo
141 141
 	 * @var array
142 142
 	 */
143 143
 	protected $codes = array(
144
-        'created'                   => 201,
145
-        'deleted'                   => 200,
144
+		'created'                   => 201,
145
+		'deleted'                   => 200,
146 146
 		'invalid_request'           => 400,
147 147
 		'unsupported_response_type' => 400,
148 148
 		'invalid_scope'             => 400,
@@ -166,32 +166,32 @@  discard block
 block discarded – undo
166 166
 		'not_implemented'           => 501
167 167
 	);
168 168
 
169
-    /**
170
-     * Convert common browser-sent langauge
171
-     * strings to a folder name in the languages folder
172
-     * that we want to use.
173
-     *
174
-     * Primarily used for converting to english when
175
-     * viewing the API in a browser.
176
-     *
177
-     * @var array
178
-     */
179
-    protected $lang_map = [
180
-        'en-us' => 'english',
181
-        'en'    => 'english',
182
-        'eng'   => 'english',
183
-        'en-au' => 'english',
184
-        'en-nz' => 'english',
185
-        'en-za' => 'english',
186
-        'en-tt' => 'english',
187
-        'en-gb' => 'english',
188
-        'en-ca' => 'english',
189
-        'en-ie' => 'english',
190
-        'en-jm' => 'english',
191
-        'en-bz' => 'english',
192
-    ];
193
-
194
-    /**
169
+	/**
170
+	 * Convert common browser-sent langauge
171
+	 * strings to a folder name in the languages folder
172
+	 * that we want to use.
173
+	 *
174
+	 * Primarily used for converting to english when
175
+	 * viewing the API in a browser.
176
+	 *
177
+	 * @var array
178
+	 */
179
+	protected $lang_map = [
180
+		'en-us' => 'english',
181
+		'en'    => 'english',
182
+		'eng'   => 'english',
183
+		'en-au' => 'english',
184
+		'en-nz' => 'english',
185
+		'en-za' => 'english',
186
+		'en-tt' => 'english',
187
+		'en-gb' => 'english',
188
+		'en-ca' => 'english',
189
+		'en-ie' => 'english',
190
+		'en-jm' => 'english',
191
+		'en-bz' => 'english',
192
+	];
193
+
194
+	/**
195 195
 	 * If you wish to override the default authentication
196 196
 	 * library used for authentication, set this to the
197 197
 	 * fully namespaced class name.
@@ -544,7 +544,7 @@  discard block
 block discarded – undo
544 544
 	 */
545 545
 	public function grabVar($name)
546 546
 	{
547
-	    return array_key_exists($name, $this->vars) ? $this->vars[$name] : false;
547
+		return array_key_exists($name, $this->vars) ? $this->vars[$name] : false;
548 548
 	}
549 549
 
550 550
 	//--------------------------------------------------------------------
@@ -757,12 +757,12 @@  discard block
 block discarded – undo
757 757
 				// Remove weight and strip space
758 758
 				list($lang) = explode(';', $lang);
759 759
 
760
-                $lang = strtolower(trim($lang));
760
+				$lang = strtolower(trim($lang));
761 761
 
762
-                if (array_key_exists($lang, $this->lang_map))
763
-                {
764
-                    $lang = $this->lang_map[$lang];
765
-                }
762
+				if (array_key_exists($lang, $this->lang_map))
763
+				{
764
+					$lang = $this->lang_map[$lang];
765
+				}
766 766
 
767 767
 				$return_langs[] = $lang;
768 768
 			}
@@ -782,10 +782,10 @@  discard block
 block discarded – undo
782 782
 	 */
783 783
 	public function detectFields()
784 784
 	{
785
-	    if (! array_key_exists('fields', $_GET))
786
-	    {
787
-		    return;
788
-	    }
785
+		if (! array_key_exists('fields', $_GET))
786
+		{
787
+			return;
788
+		}
789 789
 
790 790
 		$fields = explode(',', $_GET['fields']);
791 791
 
@@ -814,7 +814,7 @@  discard block
 block discarded – undo
814 814
 			return;
815 815
 		}
816 816
 
817
-	    $model = new LogModel();
817
+		$model = new LogModel();
818 818
 
819 819
 		$data = [
820 820
 			'duration' => microtime(true) - $this->start_time,
Please login to merge, or discard this patch.
myth/Auth/AuthTrait.php 1 patch
Indentation   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -1,34 +1,34 @@  discard block
 block discarded – undo
1 1
 <?php namespace Myth\Auth;
2 2
 /**
3
- * Sprint
4
- *
5
- * A set of power tools to enhance the CodeIgniter framework and provide consistent workflow.
6
- *
7
- * Permission is hereby granted, free of charge, to any person obtaining a copy
8
- * of this software and associated documentation files (the "Software"), to deal
9
- * in the Software without restriction, including without limitation the rights
10
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- * copies of the Software, and to permit persons to whom the Software is
12
- * furnished to do so, subject to the following conditions:
13
- *
14
- * The above copyright notice and this permission notice shall be included in
15
- * all copies or substantial portions of the Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- * THE SOFTWARE.
24
- *
25
- * @package     Sprint
26
- * @author      Lonnie Ezell
27
- * @copyright   Copyright 2014-2015, New Myth Media, LLC (http://newmythmedia.com)
28
- * @license     http://opensource.org/licenses/MIT  (MIT)
29
- * @link        http://sprintphp.com
30
- * @since       Version 1.0
31
- */
3
+	 * Sprint
4
+	 *
5
+	 * A set of power tools to enhance the CodeIgniter framework and provide consistent workflow.
6
+	 *
7
+	 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+	 * of this software and associated documentation files (the "Software"), to deal
9
+	 * in the Software without restriction, including without limitation the rights
10
+	 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+	 * copies of the Software, and to permit persons to whom the Software is
12
+	 * furnished to do so, subject to the following conditions:
13
+	 *
14
+	 * The above copyright notice and this permission notice shall be included in
15
+	 * all copies or substantial portions of the Software.
16
+	 *
17
+	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+	 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+	 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+	 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+	 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+	 * THE SOFTWARE.
24
+	 *
25
+	 * @package     Sprint
26
+	 * @author      Lonnie Ezell
27
+	 * @copyright   Copyright 2014-2015, New Myth Media, LLC (http://newmythmedia.com)
28
+	 * @license     http://opensource.org/licenses/MIT  (MIT)
29
+	 * @link        http://sprintphp.com
30
+	 * @since       Version 1.0
31
+	 */
32 32
 
33 33
 trait AuthTrait {
34 34
 
@@ -58,7 +58,7 @@  discard block
 block discarded – undo
58 58
 	 */
59 59
 	public function restrict($uri=null, $return_only=false)
60 60
 	{
61
-	    $this->setupAuthClasses();
61
+		$this->setupAuthClasses();
62 62
 
63 63
 		if ($this->authenticate->isLoggedIn())
64 64
 		{
@@ -108,7 +108,7 @@  discard block
 block discarded – undo
108 108
 	 */
109 109
 	public function restrictToGroups($groups, $uri='')
110 110
 	{
111
-	    $this->setupAuthClasses();
111
+		$this->setupAuthClasses();
112 112
 
113 113
 		if ($this->authenticate->isLoggedIn())
114 114
 		{
@@ -149,7 +149,7 @@  discard block
 block discarded – undo
149 149
 	 */
150 150
 	public function restrictWithPermissions($permissions, $uri='')
151 151
 	{
152
-	    $this->setupAuthClasses();
152
+		$this->setupAuthClasses();
153 153
 
154 154
 		if ($this->authenticate->isLoggedIn())
155 155
 		{
Please login to merge, or discard this patch.
myth/Auth/AuthenticateInterface.php 1 patch
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.
myth/Auth/Flat/FlatGroupsModel.php 1 patch
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.
myth/Auth/LocalAuthentication.php 1 patch
Indentation   +886 added lines, -886 removed lines patch added patch discarded remove patch
@@ -52,892 +52,892 @@
 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
-        // Grab the amount of time to add if the system thinks we're
512
-        // under a distributed brute force attack.
513
-        $dbrute_time = $this->ci->login_model->distributedBruteForceTime();
514
-
515
-        // If this user was found to possibly be under a brute
516
-        // force attack, their account would have been banned
517
-        // for 15 minutes.
518
-        if ($time = isset($_SESSION['bruteBan']) ? $_SESSION['bruteBan'] : false)
519
-        {
520
-            // If the current time is less than the
521
-            // the ban expiration, plus any distributed time
522
-            // then the user can't login just yet.
523
-            if ($time + $dbrute_time > time())
524
-            {
525
-                // The user is banned still...
526
-                $this->error = lang('auth.bruteBan_notice');
527
-                return ($time + $dbrute_time) - time();
528
-            }
529
-
530
-            // Still here? The the ban time is over...
531
-            unset($_SESSION['bruteBan']);
532
-        }
533
-
534
-        // Grab the time of last attempt and
535
-        // determine if we're throttled by amount of time passed.
536
-        $last_time = $this->ci->login_model->lastLoginAttemptTime($email);
537
-
538
-        // Have any attempts been made?
539
-        $attempts = $this->ci->login_model->countLoginAttempts($email);
540
-
541
-        $allowed = config_item('auth.allowed_login_attempts');
542
-
543
-        // We're not throttling if there are 0 attempts or
544
-        // the number is less than or equal to the allowed free attempts
545
-        if ($attempts === 0 || $attempts <= $allowed)
546
-        {
547
-            // Before we can say there's nothing up here,
548
-            // we need to check dbrute time.
549
-            $time_left = $last_time + $dbrute_time - time();
550
-
551
-            if ($time_left > 0)
552
-            {
553
-                return $time_left;
554
-            }
555
-
556
-            return false;
557
-        }
558
-
559
-        // If the number of attempts is excessive (above 100) we need
560
-        // to check the elapsed time of all of these attacks. If they are
561
-        // less than 1 minute it's obvious this is a brute force attack,
562
-        // so we'll set a session flag and block that user for 15 minutes.
563
-        if ($attempts > 100 && $this->ci->login_model->isBruteForced($email))
564
-        {
565
-            $this->error = lang('auth.bruteBan_notice');
566
-
567
-            $ban_time = 60 * 15;    // 15 minutes
568
-            $_SESSION['bruteBan'] = time() + $ban_time;
569
-            return $ban_time;
570
-        }
571
-
572
-        // Get our allowed attempts out of the picture.
573
-        $attempts = $attempts - $allowed;
574
-
575
-        $max_time = config_item('auth.max_throttle_time');
576
-
577
-        $add_time = pow(5, $attempts);
578
-
579
-        if ($add_time > $max_time)
580
-        {
581
-            $add_time = $max_time;
582
-        }
583
-
584
-        $next_time = $last_time + $add_time + $dbrute_time;
585
-
586
-        $current = time();
587
-
588
-        // We are NOT throttled if we are already
589
-        // past the allowed time.
590
-        if ($current > $next_time)
591
-        {
592
-            return false;
593
-        }
594
-
595
-        return $next_time - $current;
596
-    }
597
-
598
-    //--------------------------------------------------------------------
599
-
600
-    /**
601
-     * Sends a password reset link email to the user associated with
602
-     * the passed in $email.
603
-     *
604
-     * @param $email
605
-     * @return mixed
606
-     */
607
-    public function remindUser($email)
608
-    {
609
-        // Emails should NOT be case sensitive.
610
-        $email = strtolower($email);
611
-
612
-        // Is it a valid user?
613
-        $user = $this->user_model->find_by('email', $email);
614
-
615
-        if (! $user)
616
-        {
617
-            $this->error = lang('auth.invalid_email');
618
-            return false;
619
-        }
620
-
621
-        // Generate/store our codes
622
-        $this->ci->load->helper('string');
623
-        $token = random_string('alnum', 24);
624
-        $hash = hash('sha1', config_item('auth.salt') .$token);
625
-
626
-        $result = $this->user_model->update($user->id, ['reset_hash' => $hash]);
627
-
628
-        if (! $result)
629
-        {
630
-            $this->error = $this->user_model->error();
631
-            return false;
632
-        }
633
-
634
-        Events::trigger('didRemindUser', [(array)$user, $token]);
635
-
636
-        return true;
637
-    }
638
-
639
-    //--------------------------------------------------------------------
640
-
641
-    /**
642
-     * Validates the credentials provided and, if valid, resets the password.
643
-     *
644
-     * The $credentials array MUST contain a 'code' key with the string to
645
-     * hash and check against the reset_hash.
646
-     *
647
-     * @param $credentials
648
-     * @param $password
649
-     * @param $passConfirm
650
-     * @return mixed
651
-     */
652
-    public function resetPassword($credentials, $password, $passConfirm)
653
-    {
654
-        if (empty($credentials['code']))
655
-        {
656
-            $this->error = lang('auth.need_reset_code');
657
-            return false;
658
-        }
659
-
660
-        // Generate a hash to match against the table.
661
-        $credentials['reset_hash'] = hash('sha1', config_item('auth.salt') .$credentials['code']);
662
-        unset($credentials['code']);
663
-
664
-        if (! empty($credentials['email']))
665
-        {
666
-            $credentials['email'] = strtolower($credentials['email']);
667
-        }
668
-
669
-        // Is there a matching user?
670
-        $user = $this->user_model->find_by($credentials);
671
-
672
-        if (! $user)
673
-        {
674
-            $this->error = lang('auth.reset_no_user');
675
-            return false;
676
-        }
677
-
678
-        // Update their password and reset their reset_hash
679
-        $data = [
680
-            'password'     => $password,
681
-            'pass_confirm' => $passConfirm,
682
-            'reset_hash'   => null
683
-        ];
684
-
685
-        if (! $this->user_model->update($user->id, $data))
686
-        {
687
-            $this->error = $this->user_model->error();
688
-            return false;
689
-        }
690
-
691
-        Events::trigger('didResetPassword', [(array)$user]);
692
-
693
-        return true;
694
-    }
695
-
696
-    //--------------------------------------------------------------------
697
-
698
-    /**
699
-     * Provides a way for implementations to allow new statuses to be set
700
-     * on the user. The details will vary based upon implementation, but
701
-     * will often allow for banning or suspending users.
702
-     *
703
-     * @param $newStatus
704
-     * @param null $message
705
-     * @return mixed
706
-     */
707
-    public function changeStatus($newStatus, $message=null)
708
-    {
709
-        // todo actually record new users status!
710
-    }
711
-
712
-    //--------------------------------------------------------------------
713
-
714
-    /**
715
-     * Allows the consuming application to pass in a reference to the
716
-     * model that should be used.
717
-     *
718
-     * The model MUST extend Myth\Models\CIDbModel.
719
-     *
720
-     * @param $model
721
-     * @param bool $allow_any_parent
722
-     * @return mixed
723
-     */
724
-    public function useModel($model, $allow_any_parent=false)
725
-    {
726
-        if (! $allow_any_parent && get_parent_class($model) != 'Myth\Models\CIDbModel')
727
-        {
728
-            throw new \RuntimeException('Models passed into LocalAuthenticate MUST extend Myth\Models\CIDbModel');
729
-        }
730
-
731
-        $this->user_model =& $model;
732
-
733
-        return $this;
734
-    }
735
-
736
-    //--------------------------------------------------------------------
737
-
738
-    public function error()
739
-    {
740
-        if (validation_errors())
741
-        {
742
-            return validation_errors();
743
-        }
744
-
745
-        return $this->error;
746
-    }
747
-
748
-    //--------------------------------------------------------------------
749
-
750
-    //--------------------------------------------------------------------
751
-    // Login Records
752
-    //--------------------------------------------------------------------
753
-
754
-    /**
755
-     * Purges all login attempt records from the database.
756
-     *
757
-     * @param $email
758
-     */
759
-    public function purgeLoginAttempts($email)
760
-    {
761
-        // Emails should NOT be case sensitive.
762
-        $email = strtolower($email);
763
-
764
-        $this->ci->login_model->purgeLoginAttempts($email);
765
-
766
-        // @todo record activity of login attempts purge.
767
-        Events::trigger('didPurgeLoginAttempts', [$email]);
768
-    }
769
-
770
-    //--------------------------------------------------------------------
771
-
772
-    /**
773
-     * Purges all remember tokens for a single user. Effectively logs
774
-     * a user out of all devices. Intended to allow users to log themselves
775
-     * out of all devices as a security measure.
776
-     *
777
-     * @param $email
778
-     */
779
-    public function purgeRememberTokens($email)
780
-    {
781
-        // Emails should NOT be case sensitive.
782
-        $email = strtolower($email);
783
-
784
-        $this->ci->login_model->purgeRememberTokens($email);
785
-
786
-        // todo record activity of remember me purges.
787
-        Events::trigger('didPurgeRememberTokens', [$email]);
788
-    }
789
-
790
-    //--------------------------------------------------------------------
791
-
792
-    //--------------------------------------------------------------------
793
-    // Protected Methods
794
-    //--------------------------------------------------------------------
795
-
796
-    /**
797
-     * Check if Allow Persistent Login Cookies is enable
798
-     *
799
-     * @param $user
800
-     */
801
-    protected function rememberUser($user)
802
-    {
803
-        if (! config_item('auth.allow_remembering'))
804
-        {
805
-            log_message('debug', 'Auth library set to refuse "Remember Me" functionality.');
806
-            return false;
807
-        }
808
-
809
-        $this->refreshRememberCookie($user);
810
-    }
811
-
812
-    //--------------------------------------------------------------------
813
-
814
-    /**
815
-     * Invalidates the current rememberme cookie/database entry, creates
816
-     * a new one, stores it and returns the new value.
817
-     *
818
-     * @param $user
819
-     * @param null $token
820
-     * @return mixed
821
-     */
822
-    protected function refreshRememberCookie($user, $token=null)
823
-    {
824
-        $this->ci->load->helper('cookie');
825
-
826
-        // If a token is passed in, we know we're removing the
827
-        // old one.
828
-        if (! empty($token))
829
-        {
830
-            $this->invalidateRememberCookie($user['email'], $token);
831
-        }
832
-
833
-        $new_token = $this->ci->login_model->generateRememberToken($user);
834
-
835
-        // Save the token to the database.
836
-        $data = [
837
-            'email'   => $user['email'],
838
-            'hash'    => sha1(config_item('auth.salt') . $new_token),
839
-            'created' => date('Y-m-d H:i:s')
840
-        ];
841
-
842
-        $this->ci->db->insert('auth_tokens', $data);
843
-
844
-        // Create the cookie
845
-        set_cookie(
846
-            'remember',                             // Cookie Name
847
-            $new_token,                             // Value
848
-            config_item('auth.remember_length'),    // # Seconds until it expires
849
-            config_item('cookie_domain'),
850
-            config_item('cookie_path'),
851
-            config_item('cookie_prefix'),
852
-            false,                                  // Only send over HTTPS?
853
-            true                                    // Hide from Javascript?
854
-        );
855
-
856
-        return $new_token;
857
-    }
858
-
859
-    //--------------------------------------------------------------------
860
-
861
-    /**
862
-     * Deletes any current remember me cookies and database entries.
863
-     *
864
-     * @param $email
865
-     * @param $token
866
-     * @return string The new token (not the hash).
867
-     */
868
-    protected function invalidateRememberCookie($email, $token)
869
-    {
870
-        // Emails should NOT be case sensitive.
871
-        $email = strtolower($email);
872
-
873
-        // Remove from the database
874
-        $this->ci->login_model->deleteRememberToken($email, $token);
875
-
876
-        // Remove the cookie
877
-        delete_cookie(
878
-            'remember',
879
-            config_item('cookie_domain'),
880
-            config_item('cookie_path'),
881
-            config_item('cookie_prefix')
882
-        );
883
-    }
884
-
885
-    //--------------------------------------------------------------------
886
-
887
-    /**
888
-     * Handles the nitty gritty of actually logging our user into the system.
889
-     * Does NOT perform the authentication, just sets the system up so that
890
-     * it knows we're here.
891
-     *
892
-     * @param $user
893
-     */
894
-    protected function loginUser($user)
895
-    {
896
-        // Save the user for later access
897
-        $this->user = $user;
898
-
899
-        // Regenerate the session ID to help protect
900
-        // against session fixation
901
-        $this->ci->session->sess_regenerate();
902
-
903
-        // Let the session know that we're logged in.
904
-        $this->ci->session->set_userdata('logged_in', $user['id']);
905
-
906
-        // Clear our login attempts
907
-        $this->ci->login_model->purgeLoginAttempts($user['email']);
908
-
909
-        // Record a new Login
910
-        $this->ci->login_model->recordLogin($user);
911
-
912
-        // If logged in, ensure cache control
913
-        // headers are in place
914
-        $this->setHeaders();
915
-
916
-        // We'll give a 20% chance to need to do a purge since we
917
-        // don't need to purge THAT often, it's just a maintenance issue.
918
-        // to keep the table from getting out of control.
919
-        if (mt_rand(1, 100) < 20)
920
-        {
921
-            $this->ci->login_model->purgeOldRememberTokens();
922
-        }
923
-    }
924
-
925
-    //--------------------------------------------------------------------
926
-
927
-    /**
928
-     * Sets the headers to ensure that pages are not cached when a user
929
-     * is logged in, helping to protect against logging out and then
930
-     * simply hitting the Back button on the browser and getting private
931
-     * information because the page was loaded from cache.
932
-     */
933
-    protected function setHeaders()
934
-    {
935
-        $this->ci->output->set_header('Cache-Control: no-store, no-cache, must-revalidate');
936
-        $this->ci->output->set_header('Cache-Control: post-check=0, pre-check=0');
937
-        $this->ci->output->set_header('Pragma: no-cache');
938
-    }
939
-
940
-    //--------------------------------------------------------------------
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
+		// Grab the amount of time to add if the system thinks we're
512
+		// under a distributed brute force attack.
513
+		$dbrute_time = $this->ci->login_model->distributedBruteForceTime();
514
+
515
+		// If this user was found to possibly be under a brute
516
+		// force attack, their account would have been banned
517
+		// for 15 minutes.
518
+		if ($time = isset($_SESSION['bruteBan']) ? $_SESSION['bruteBan'] : false)
519
+		{
520
+			// If the current time is less than the
521
+			// the ban expiration, plus any distributed time
522
+			// then the user can't login just yet.
523
+			if ($time + $dbrute_time > time())
524
+			{
525
+				// The user is banned still...
526
+				$this->error = lang('auth.bruteBan_notice');
527
+				return ($time + $dbrute_time) - time();
528
+			}
529
+
530
+			// Still here? The the ban time is over...
531
+			unset($_SESSION['bruteBan']);
532
+		}
533
+
534
+		// Grab the time of last attempt and
535
+		// determine if we're throttled by amount of time passed.
536
+		$last_time = $this->ci->login_model->lastLoginAttemptTime($email);
537
+
538
+		// Have any attempts been made?
539
+		$attempts = $this->ci->login_model->countLoginAttempts($email);
540
+
541
+		$allowed = config_item('auth.allowed_login_attempts');
542
+
543
+		// We're not throttling if there are 0 attempts or
544
+		// the number is less than or equal to the allowed free attempts
545
+		if ($attempts === 0 || $attempts <= $allowed)
546
+		{
547
+			// Before we can say there's nothing up here,
548
+			// we need to check dbrute time.
549
+			$time_left = $last_time + $dbrute_time - time();
550
+
551
+			if ($time_left > 0)
552
+			{
553
+				return $time_left;
554
+			}
555
+
556
+			return false;
557
+		}
558
+
559
+		// If the number of attempts is excessive (above 100) we need
560
+		// to check the elapsed time of all of these attacks. If they are
561
+		// less than 1 minute it's obvious this is a brute force attack,
562
+		// so we'll set a session flag and block that user for 15 minutes.
563
+		if ($attempts > 100 && $this->ci->login_model->isBruteForced($email))
564
+		{
565
+			$this->error = lang('auth.bruteBan_notice');
566
+
567
+			$ban_time = 60 * 15;    // 15 minutes
568
+			$_SESSION['bruteBan'] = time() + $ban_time;
569
+			return $ban_time;
570
+		}
571
+
572
+		// Get our allowed attempts out of the picture.
573
+		$attempts = $attempts - $allowed;
574
+
575
+		$max_time = config_item('auth.max_throttle_time');
576
+
577
+		$add_time = pow(5, $attempts);
578
+
579
+		if ($add_time > $max_time)
580
+		{
581
+			$add_time = $max_time;
582
+		}
583
+
584
+		$next_time = $last_time + $add_time + $dbrute_time;
585
+
586
+		$current = time();
587
+
588
+		// We are NOT throttled if we are already
589
+		// past the allowed time.
590
+		if ($current > $next_time)
591
+		{
592
+			return false;
593
+		}
594
+
595
+		return $next_time - $current;
596
+	}
597
+
598
+	//--------------------------------------------------------------------
599
+
600
+	/**
601
+	 * Sends a password reset link email to the user associated with
602
+	 * the passed in $email.
603
+	 *
604
+	 * @param $email
605
+	 * @return mixed
606
+	 */
607
+	public function remindUser($email)
608
+	{
609
+		// Emails should NOT be case sensitive.
610
+		$email = strtolower($email);
611
+
612
+		// Is it a valid user?
613
+		$user = $this->user_model->find_by('email', $email);
614
+
615
+		if (! $user)
616
+		{
617
+			$this->error = lang('auth.invalid_email');
618
+			return false;
619
+		}
620
+
621
+		// Generate/store our codes
622
+		$this->ci->load->helper('string');
623
+		$token = random_string('alnum', 24);
624
+		$hash = hash('sha1', config_item('auth.salt') .$token);
625
+
626
+		$result = $this->user_model->update($user->id, ['reset_hash' => $hash]);
627
+
628
+		if (! $result)
629
+		{
630
+			$this->error = $this->user_model->error();
631
+			return false;
632
+		}
633
+
634
+		Events::trigger('didRemindUser', [(array)$user, $token]);
635
+
636
+		return true;
637
+	}
638
+
639
+	//--------------------------------------------------------------------
640
+
641
+	/**
642
+	 * Validates the credentials provided and, if valid, resets the password.
643
+	 *
644
+	 * The $credentials array MUST contain a 'code' key with the string to
645
+	 * hash and check against the reset_hash.
646
+	 *
647
+	 * @param $credentials
648
+	 * @param $password
649
+	 * @param $passConfirm
650
+	 * @return mixed
651
+	 */
652
+	public function resetPassword($credentials, $password, $passConfirm)
653
+	{
654
+		if (empty($credentials['code']))
655
+		{
656
+			$this->error = lang('auth.need_reset_code');
657
+			return false;
658
+		}
659
+
660
+		// Generate a hash to match against the table.
661
+		$credentials['reset_hash'] = hash('sha1', config_item('auth.salt') .$credentials['code']);
662
+		unset($credentials['code']);
663
+
664
+		if (! empty($credentials['email']))
665
+		{
666
+			$credentials['email'] = strtolower($credentials['email']);
667
+		}
668
+
669
+		// Is there a matching user?
670
+		$user = $this->user_model->find_by($credentials);
671
+
672
+		if (! $user)
673
+		{
674
+			$this->error = lang('auth.reset_no_user');
675
+			return false;
676
+		}
677
+
678
+		// Update their password and reset their reset_hash
679
+		$data = [
680
+			'password'     => $password,
681
+			'pass_confirm' => $passConfirm,
682
+			'reset_hash'   => null
683
+		];
684
+
685
+		if (! $this->user_model->update($user->id, $data))
686
+		{
687
+			$this->error = $this->user_model->error();
688
+			return false;
689
+		}
690
+
691
+		Events::trigger('didResetPassword', [(array)$user]);
692
+
693
+		return true;
694
+	}
695
+
696
+	//--------------------------------------------------------------------
697
+
698
+	/**
699
+	 * Provides a way for implementations to allow new statuses to be set
700
+	 * on the user. The details will vary based upon implementation, but
701
+	 * will often allow for banning or suspending users.
702
+	 *
703
+	 * @param $newStatus
704
+	 * @param null $message
705
+	 * @return mixed
706
+	 */
707
+	public function changeStatus($newStatus, $message=null)
708
+	{
709
+		// todo actually record new users status!
710
+	}
711
+
712
+	//--------------------------------------------------------------------
713
+
714
+	/**
715
+	 * Allows the consuming application to pass in a reference to the
716
+	 * model that should be used.
717
+	 *
718
+	 * The model MUST extend Myth\Models\CIDbModel.
719
+	 *
720
+	 * @param $model
721
+	 * @param bool $allow_any_parent
722
+	 * @return mixed
723
+	 */
724
+	public function useModel($model, $allow_any_parent=false)
725
+	{
726
+		if (! $allow_any_parent && get_parent_class($model) != 'Myth\Models\CIDbModel')
727
+		{
728
+			throw new \RuntimeException('Models passed into LocalAuthenticate MUST extend Myth\Models\CIDbModel');
729
+		}
730
+
731
+		$this->user_model =& $model;
732
+
733
+		return $this;
734
+	}
735
+
736
+	//--------------------------------------------------------------------
737
+
738
+	public function error()
739
+	{
740
+		if (validation_errors())
741
+		{
742
+			return validation_errors();
743
+		}
744
+
745
+		return $this->error;
746
+	}
747
+
748
+	//--------------------------------------------------------------------
749
+
750
+	//--------------------------------------------------------------------
751
+	// Login Records
752
+	//--------------------------------------------------------------------
753
+
754
+	/**
755
+	 * Purges all login attempt records from the database.
756
+	 *
757
+	 * @param $email
758
+	 */
759
+	public function purgeLoginAttempts($email)
760
+	{
761
+		// Emails should NOT be case sensitive.
762
+		$email = strtolower($email);
763
+
764
+		$this->ci->login_model->purgeLoginAttempts($email);
765
+
766
+		// @todo record activity of login attempts purge.
767
+		Events::trigger('didPurgeLoginAttempts', [$email]);
768
+	}
769
+
770
+	//--------------------------------------------------------------------
771
+
772
+	/**
773
+	 * Purges all remember tokens for a single user. Effectively logs
774
+	 * a user out of all devices. Intended to allow users to log themselves
775
+	 * out of all devices as a security measure.
776
+	 *
777
+	 * @param $email
778
+	 */
779
+	public function purgeRememberTokens($email)
780
+	{
781
+		// Emails should NOT be case sensitive.
782
+		$email = strtolower($email);
783
+
784
+		$this->ci->login_model->purgeRememberTokens($email);
785
+
786
+		// todo record activity of remember me purges.
787
+		Events::trigger('didPurgeRememberTokens', [$email]);
788
+	}
789
+
790
+	//--------------------------------------------------------------------
791
+
792
+	//--------------------------------------------------------------------
793
+	// Protected Methods
794
+	//--------------------------------------------------------------------
795
+
796
+	/**
797
+	 * Check if Allow Persistent Login Cookies is enable
798
+	 *
799
+	 * @param $user
800
+	 */
801
+	protected function rememberUser($user)
802
+	{
803
+		if (! config_item('auth.allow_remembering'))
804
+		{
805
+			log_message('debug', 'Auth library set to refuse "Remember Me" functionality.');
806
+			return false;
807
+		}
808
+
809
+		$this->refreshRememberCookie($user);
810
+	}
811
+
812
+	//--------------------------------------------------------------------
813
+
814
+	/**
815
+	 * Invalidates the current rememberme cookie/database entry, creates
816
+	 * a new one, stores it and returns the new value.
817
+	 *
818
+	 * @param $user
819
+	 * @param null $token
820
+	 * @return mixed
821
+	 */
822
+	protected function refreshRememberCookie($user, $token=null)
823
+	{
824
+		$this->ci->load->helper('cookie');
825
+
826
+		// If a token is passed in, we know we're removing the
827
+		// old one.
828
+		if (! empty($token))
829
+		{
830
+			$this->invalidateRememberCookie($user['email'], $token);
831
+		}
832
+
833
+		$new_token = $this->ci->login_model->generateRememberToken($user);
834
+
835
+		// Save the token to the database.
836
+		$data = [
837
+			'email'   => $user['email'],
838
+			'hash'    => sha1(config_item('auth.salt') . $new_token),
839
+			'created' => date('Y-m-d H:i:s')
840
+		];
841
+
842
+		$this->ci->db->insert('auth_tokens', $data);
843
+
844
+		// Create the cookie
845
+		set_cookie(
846
+			'remember',                             // Cookie Name
847
+			$new_token,                             // Value
848
+			config_item('auth.remember_length'),    // # Seconds until it expires
849
+			config_item('cookie_domain'),
850
+			config_item('cookie_path'),
851
+			config_item('cookie_prefix'),
852
+			false,                                  // Only send over HTTPS?
853
+			true                                    // Hide from Javascript?
854
+		);
855
+
856
+		return $new_token;
857
+	}
858
+
859
+	//--------------------------------------------------------------------
860
+
861
+	/**
862
+	 * Deletes any current remember me cookies and database entries.
863
+	 *
864
+	 * @param $email
865
+	 * @param $token
866
+	 * @return string The new token (not the hash).
867
+	 */
868
+	protected function invalidateRememberCookie($email, $token)
869
+	{
870
+		// Emails should NOT be case sensitive.
871
+		$email = strtolower($email);
872
+
873
+		// Remove from the database
874
+		$this->ci->login_model->deleteRememberToken($email, $token);
875
+
876
+		// Remove the cookie
877
+		delete_cookie(
878
+			'remember',
879
+			config_item('cookie_domain'),
880
+			config_item('cookie_path'),
881
+			config_item('cookie_prefix')
882
+		);
883
+	}
884
+
885
+	//--------------------------------------------------------------------
886
+
887
+	/**
888
+	 * Handles the nitty gritty of actually logging our user into the system.
889
+	 * Does NOT perform the authentication, just sets the system up so that
890
+	 * it knows we're here.
891
+	 *
892
+	 * @param $user
893
+	 */
894
+	protected function loginUser($user)
895
+	{
896
+		// Save the user for later access
897
+		$this->user = $user;
898
+
899
+		// Regenerate the session ID to help protect
900
+		// against session fixation
901
+		$this->ci->session->sess_regenerate();
902
+
903
+		// Let the session know that we're logged in.
904
+		$this->ci->session->set_userdata('logged_in', $user['id']);
905
+
906
+		// Clear our login attempts
907
+		$this->ci->login_model->purgeLoginAttempts($user['email']);
908
+
909
+		// Record a new Login
910
+		$this->ci->login_model->recordLogin($user);
911
+
912
+		// If logged in, ensure cache control
913
+		// headers are in place
914
+		$this->setHeaders();
915
+
916
+		// We'll give a 20% chance to need to do a purge since we
917
+		// don't need to purge THAT often, it's just a maintenance issue.
918
+		// to keep the table from getting out of control.
919
+		if (mt_rand(1, 100) < 20)
920
+		{
921
+			$this->ci->login_model->purgeOldRememberTokens();
922
+		}
923
+	}
924
+
925
+	//--------------------------------------------------------------------
926
+
927
+	/**
928
+	 * Sets the headers to ensure that pages are not cached when a user
929
+	 * is logged in, helping to protect against logging out and then
930
+	 * simply hitting the Back button on the browser and getting private
931
+	 * information because the page was loaded from cache.
932
+	 */
933
+	protected function setHeaders()
934
+	{
935
+		$this->ci->output->set_header('Cache-Control: no-store, no-cache, must-revalidate');
936
+		$this->ci->output->set_header('Cache-Control: post-check=0, pre-check=0');
937
+		$this->ci->output->set_header('Pragma: no-cache');
938
+	}
939
+
940
+	//--------------------------------------------------------------------
941 941
 
942 942
 
943 943
 }
Please login to merge, or discard this patch.