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 (#155)
by
unknown
08:46
created
system/libraries/Pagination.php 1 patch
Indentation   +35 added lines, -35 removed lines patch added patch discarded remove patch
@@ -1,40 +1,40 @@
 block discarded – undo
1 1
 <?php
2 2
 /**
3
- * CodeIgniter
4
- *
5
- * An open source application development framework for PHP
6
- *
7
- * This content is released under the MIT License (MIT)
8
- *
9
- * Copyright (c) 2014 - 2015, British Columbia Institute of Technology
10
- *
11
- * Permission is hereby granted, free of charge, to any person obtaining a copy
12
- * of this software and associated documentation files (the "Software"), to deal
13
- * in the Software without restriction, including without limitation the rights
14
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
- * copies of the Software, and to permit persons to whom the Software is
16
- * furnished to do so, subject to the following conditions:
17
- *
18
- * The above copyright notice and this permission notice shall be included in
19
- * all copies or substantial portions of the Software.
20
- *
21
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
- * THE SOFTWARE.
28
- *
29
- * @package	CodeIgniter
30
- * @author	EllisLab Dev Team
31
- * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
32
- * @copyright	Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
33
- * @license	http://opensource.org/licenses/MIT	MIT License
34
- * @link	http://codeigniter.com
35
- * @since	Version 1.0.0
36
- * @filesource
37
- */
3
+	 * CodeIgniter
4
+	 *
5
+	 * An open source application development framework for PHP
6
+	 *
7
+	 * This content is released under the MIT License (MIT)
8
+	 *
9
+	 * Copyright (c) 2014 - 2015, British Columbia Institute of Technology
10
+	 *
11
+	 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
+	 * of this software and associated documentation files (the "Software"), to deal
13
+	 * in the Software without restriction, including without limitation the rights
14
+	 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+	 * copies of the Software, and to permit persons to whom the Software is
16
+	 * furnished to do so, subject to the following conditions:
17
+	 *
18
+	 * The above copyright notice and this permission notice shall be included in
19
+	 * all copies or substantial portions of the Software.
20
+	 *
21
+	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+	 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+	 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+	 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+	 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
+	 * THE SOFTWARE.
28
+	 *
29
+	 * @package	CodeIgniter
30
+	 * @author	EllisLab Dev Team
31
+	 * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
32
+	 * @copyright	Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
33
+	 * @license	http://opensource.org/licenses/MIT	MIT License
34
+	 * @link	http://codeigniter.com
35
+	 * @since	Version 1.0.0
36
+	 * @filesource
37
+	 */
38 38
 defined('BASEPATH') OR exit('No direct script access allowed');
39 39
 
40 40
 /**
Please login to merge, or discard this patch.
system/libraries/Cache/drivers/Cache_file.php 1 patch
Indentation   +35 added lines, -35 removed lines patch added patch discarded remove patch
@@ -1,40 +1,40 @@
 block discarded – undo
1 1
 <?php
2 2
 /**
3
- * CodeIgniter
4
- *
5
- * An open source application development framework for PHP
6
- *
7
- * This content is released under the MIT License (MIT)
8
- *
9
- * Copyright (c) 2014 - 2015, British Columbia Institute of Technology
10
- *
11
- * Permission is hereby granted, free of charge, to any person obtaining a copy
12
- * of this software and associated documentation files (the "Software"), to deal
13
- * in the Software without restriction, including without limitation the rights
14
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
- * copies of the Software, and to permit persons to whom the Software is
16
- * furnished to do so, subject to the following conditions:
17
- *
18
- * The above copyright notice and this permission notice shall be included in
19
- * all copies or substantial portions of the Software.
20
- *
21
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
- * THE SOFTWARE.
28
- *
29
- * @package	CodeIgniter
30
- * @author	EllisLab Dev Team
31
- * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
32
- * @copyright	Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
33
- * @license	http://opensource.org/licenses/MIT	MIT License
34
- * @link	http://codeigniter.com
35
- * @since	Version 2.0
36
- * @filesource
37
- */
3
+	 * CodeIgniter
4
+	 *
5
+	 * An open source application development framework for PHP
6
+	 *
7
+	 * This content is released under the MIT License (MIT)
8
+	 *
9
+	 * Copyright (c) 2014 - 2015, British Columbia Institute of Technology
10
+	 *
11
+	 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
+	 * of this software and associated documentation files (the "Software"), to deal
13
+	 * in the Software without restriction, including without limitation the rights
14
+	 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+	 * copies of the Software, and to permit persons to whom the Software is
16
+	 * furnished to do so, subject to the following conditions:
17
+	 *
18
+	 * The above copyright notice and this permission notice shall be included in
19
+	 * all copies or substantial portions of the Software.
20
+	 *
21
+	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+	 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+	 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+	 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+	 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
+	 * THE SOFTWARE.
28
+	 *
29
+	 * @package	CodeIgniter
30
+	 * @author	EllisLab Dev Team
31
+	 * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
32
+	 * @copyright	Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
33
+	 * @license	http://opensource.org/licenses/MIT	MIT License
34
+	 * @link	http://codeigniter.com
35
+	 * @since	Version 2.0
36
+	 * @filesource
37
+	 */
38 38
 defined('BASEPATH') OR exit('No direct script access allowed');
39 39
 
40 40
 /**
Please login to merge, or discard this patch.
system/libraries/Parser.php 1 patch
Indentation   +35 added lines, -35 removed lines patch added patch discarded remove patch
@@ -1,40 +1,40 @@
 block discarded – undo
1 1
 <?php
2 2
 /**
3
- * CodeIgniter
4
- *
5
- * An open source application development framework for PHP
6
- *
7
- * This content is released under the MIT License (MIT)
8
- *
9
- * Copyright (c) 2014 - 2015, British Columbia Institute of Technology
10
- *
11
- * Permission is hereby granted, free of charge, to any person obtaining a copy
12
- * of this software and associated documentation files (the "Software"), to deal
13
- * in the Software without restriction, including without limitation the rights
14
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
- * copies of the Software, and to permit persons to whom the Software is
16
- * furnished to do so, subject to the following conditions:
17
- *
18
- * The above copyright notice and this permission notice shall be included in
19
- * all copies or substantial portions of the Software.
20
- *
21
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
- * THE SOFTWARE.
28
- *
29
- * @package	CodeIgniter
30
- * @author	EllisLab Dev Team
31
- * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
32
- * @copyright	Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
33
- * @license	http://opensource.org/licenses/MIT	MIT License
34
- * @link	http://codeigniter.com
35
- * @since	Version 1.0.0
36
- * @filesource
37
- */
3
+	 * CodeIgniter
4
+	 *
5
+	 * An open source application development framework for PHP
6
+	 *
7
+	 * This content is released under the MIT License (MIT)
8
+	 *
9
+	 * Copyright (c) 2014 - 2015, British Columbia Institute of Technology
10
+	 *
11
+	 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
+	 * of this software and associated documentation files (the "Software"), to deal
13
+	 * in the Software without restriction, including without limitation the rights
14
+	 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+	 * copies of the Software, and to permit persons to whom the Software is
16
+	 * furnished to do so, subject to the following conditions:
17
+	 *
18
+	 * The above copyright notice and this permission notice shall be included in
19
+	 * all copies or substantial portions of the Software.
20
+	 *
21
+	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+	 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+	 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+	 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+	 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
+	 * THE SOFTWARE.
28
+	 *
29
+	 * @package	CodeIgniter
30
+	 * @author	EllisLab Dev Team
31
+	 * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
32
+	 * @copyright	Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
33
+	 * @license	http://opensource.org/licenses/MIT	MIT License
34
+	 * @link	http://codeigniter.com
35
+	 * @since	Version 1.0.0
36
+	 * @filesource
37
+	 */
38 38
 defined('BASEPATH') OR exit('No direct script access allowed');
39 39
 
40 40
 /**
Please login to merge, or discard this patch.
myth/Cron/CronManager.php 1 patch
Indentation   +281 added lines, -281 removed lines patch added patch discarded remove patch
@@ -1,34 +1,34 @@  discard block
 block discarded – undo
1 1
 <?php namespace Myth\Cron;
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
 use Myth\Cron\CronTask as CronTask;
34 34
 
@@ -39,257 +39,257 @@  discard block
 block discarded – undo
39 39
  */
40 40
 class CronManager {
41 41
 
42
-    protected static $tasks = [];
43
-
44
-    //--------------------------------------------------------------------
45
-
46
-    /**
47
-     * Schedules a new task in the system.
48
-     *
49
-     * @param $alias
50
-     * @param $time_string
51
-     * @param callable|string $task
52
-     */
53
-    public static function schedule($alias, $time_string, $task)
54
-    {
55
-        // Valid Alias?
56
-        if (! is_string($alias) || empty($alias))
57
-        {
58
-            throw new \RuntimeException( lang('cron.bad_alias') );
59
-        }
60
-
61
-        // Valid TimeString?
62
-        if (! is_string($time_string) || empty($time_string))
63
-        {
64
-            throw new \RuntimeException( lang('cron.bad_timestring') );
65
-        }
66
-
67
-        // Valid Task?
68
-        if (! is_callable($task) && ! is_string($task))
69
-        {
70
-            throw new \RuntimeException( lang('cron.bad_task') . $alias);
71
-        }
72
-
73
-        static::$tasks[$alias] = new CronTask($time_string, $task);
74
-    }
75
-
76
-    //--------------------------------------------------------------------
77
-
78
-    /**
79
-     * Removes a single task from the system.
80
-     *
81
-     * @param $alias
82
-     */
83
-    public static function remove($alias)
84
-    {
85
-        if (empty(static::$tasks[$alias]))
86
-        {
87
-            return null;
88
-        }
89
-
90
-        unset(static::$tasks[$alias]);
91
-
92
-        return true;
93
-    }
94
-
95
-    //--------------------------------------------------------------------
96
-
97
-
98
-    /**
99
-     * Provides an array of all tasks in the system. The format will be
100
-     * like:
101
-     *      [
102
-     *          'alias' => [
103
-     *              'next_run'  => '123456789',
104
-     *              'prev_run'  => '123456789',
105
-     *              'task'  => mixed
106
-     *          ],
107
-     *          ...
108
-     *      ]
109
-     */
110
-    public static function listAll($current_time='now')
111
-    {
112
-        if (! count(static::$tasks))
113
-        {
114
-            return null;
115
-        }
116
-
117
-        $output = array();
118
-
119
-        foreach (static::$tasks as $alias => $task)
120
-        {
121
-            $output[$alias] = [
122
-                'next_run'  => $task->nextRunDate($current_time),
123
-                'prev_run'  => $task->previousRunDate($current_time),
124
-                'task'      => $task->task()
125
-            ];
126
-        }
127
-
128
-        return $output;
129
-    }
130
-
131
-    //--------------------------------------------------------------------
132
-
133
-    /**
134
-     * Gets the task object assigned to an alias.
135
-     *
136
-     * @param $alias
137
-     * @return null|CronTask object
138
-     */
139
-    public static function task($alias)
140
-    {
141
-        if (empty(static::$tasks[$alias]) )
142
-        {
143
-            return null;
144
-        }
145
-
146
-        return static::$tasks[$alias];
147
-    }
148
-
149
-    //--------------------------------------------------------------------
150
-
151
-    /**
152
-     * Returns all tasks currently in the system.
153
-     *
154
-     * @return array
155
-     */
156
-    public static function tasks()
157
-    {
158
-        return count(static::$tasks) ? static::$tasks : null;
159
-    }
160
-
161
-    //--------------------------------------------------------------------
162
-
163
-    /**
164
-     * Runs all tasks scheduled to run right now.
165
-     *
166
-     * Can be limited to a single task by passing it's alias in the first param.
167
-     *
168
-     * Returns the output of all task runs as a single string. Perfect for
169
-     * emailing to users on completion
170
-     *
171
-     * @param null $alias
172
-     * @param bool $force_run
173
-     * @param string $current_time
174
-     * @return string
175
-     */
176
-    public static function run($alias=null, $force_run=false, $current_time='now')
177
-    {
178
-        $tasks = static::$tasks;
179
-
180
-        if (! empty($alias) && isset($tasks[$alias]))
181
-        {
182
-            $tasks = [$alias => $tasks[$alias] ];
183
-        }
184
-
185
-        $output = '';
186
-
187
-        $count = 0; // How many tasks have ran?
188
-
189
-        foreach ($tasks as $alias => $task)
190
-        {
191
-            if ($task->isDue($current_time) || $force_run === true)
192
-            {
193
-                $output .= sprintf( lang('cron.running_task'), $alias);
194
-
195
-                try {
196
-                    $result = self::runTask($alias);
197
-
198
-                    if (is_bool($result))
199
-                    {
200
-                        $output .= $result === true ? lang('done') ."\n" : lang('failed') ."\n";
201
-                    }
202
-                    else if (is_string($result))
203
-                    {
204
-                        $output .= sprintf( lang('cron.done_with_msg'), $result);
205
-                    }
206
-                }
207
-                catch (\Exception $e)
208
-                {
209
-                    $output .= "[Exception] ". $e->getMessage() ."\n";
210
-                }
211
-
212
-                $count++;
213
-            }
214
-            else
215
-            {
216
-                $output .= sprintf( lang('cron.not_scheduled_until'), $alias, $task->nextRunDate() );
217
-            }
218
-        }
219
-
220
-        if (! $count)
221
-        {
222
-            $output .= lang('cron.nothing_scheduled');
223
-        }
224
-
225
-        return $output;
226
-    }
227
-
228
-    //--------------------------------------------------------------------
229
-
230
-    /**
231
-     * Clears all tasks from the system
232
-     */
233
-    public static function reset()
234
-    {
235
-        static::$tasks = [];
236
-    }
237
-
238
-    //--------------------------------------------------------------------
239
-
240
-    //--------------------------------------------------------------------
241
-    // Protected Methods
242
-    //--------------------------------------------------------------------
243
-
244
-    /**
245
-     * Runs a single Task.
246
-     *
247
-     * NOTE: Tasks MUST return a true/false value only.
248
-     *
249
-     * @param $alias
250
-     * @return bool
251
-     */
252
-    protected static function runTask($alias)
253
-    {
254
-        $task = static::$tasks[$alias]->task();
255
-
256
-        $success = false;
257
-
258
-        // If it's a standard callable item,
259
-        // then run it.
260
-        if (is_callable($task))
261
-        {
262
-            $success = call_user_func($task);
263
-        }
264
-
265
-        // Otherwise, if it's a string it should be
266
-        // a library:method string so try to run it.
267
-        else if (is_string($task) && ! empty($task) && strpos($task, ':') !== false)
268
-        {
269
-            list($class, $method) = explode(':', $task);
270
-
271
-            // Let PHP try to autoload it through any available autoloaders
272
-            // (including Composer and user's custom autoloaders). If we
273
-            // don't find it, then assume it's a CI library that we can reach.
274
-            if (class_exists($class)) {
275
-                $class = new $class();
276
-            } else {
277
-                get_instance()->load->library($class);
278
-                $class =& get_instance()->$class;
279
-            }
280
-
281
-            if (! method_exists($class, $method)) {
282
-                log_message('error', "[CRON] Method not found: {$class}::{$method}");
283
-                return $success;
284
-            }
285
-
286
-            // Call the class with our parameters
287
-            $success = $class->{$method}();
288
-        }
289
-
290
-        return $success;
291
-    }
292
-
293
-    //--------------------------------------------------------------------
42
+	protected static $tasks = [];
43
+
44
+	//--------------------------------------------------------------------
45
+
46
+	/**
47
+	 * Schedules a new task in the system.
48
+	 *
49
+	 * @param $alias
50
+	 * @param $time_string
51
+	 * @param callable|string $task
52
+	 */
53
+	public static function schedule($alias, $time_string, $task)
54
+	{
55
+		// Valid Alias?
56
+		if (! is_string($alias) || empty($alias))
57
+		{
58
+			throw new \RuntimeException( lang('cron.bad_alias') );
59
+		}
60
+
61
+		// Valid TimeString?
62
+		if (! is_string($time_string) || empty($time_string))
63
+		{
64
+			throw new \RuntimeException( lang('cron.bad_timestring') );
65
+		}
66
+
67
+		// Valid Task?
68
+		if (! is_callable($task) && ! is_string($task))
69
+		{
70
+			throw new \RuntimeException( lang('cron.bad_task') . $alias);
71
+		}
72
+
73
+		static::$tasks[$alias] = new CronTask($time_string, $task);
74
+	}
75
+
76
+	//--------------------------------------------------------------------
77
+
78
+	/**
79
+	 * Removes a single task from the system.
80
+	 *
81
+	 * @param $alias
82
+	 */
83
+	public static function remove($alias)
84
+	{
85
+		if (empty(static::$tasks[$alias]))
86
+		{
87
+			return null;
88
+		}
89
+
90
+		unset(static::$tasks[$alias]);
91
+
92
+		return true;
93
+	}
94
+
95
+	//--------------------------------------------------------------------
96
+
97
+
98
+	/**
99
+	 * Provides an array of all tasks in the system. The format will be
100
+	 * like:
101
+	 *      [
102
+	 *          'alias' => [
103
+	 *              'next_run'  => '123456789',
104
+	 *              'prev_run'  => '123456789',
105
+	 *              'task'  => mixed
106
+	 *          ],
107
+	 *          ...
108
+	 *      ]
109
+	 */
110
+	public static function listAll($current_time='now')
111
+	{
112
+		if (! count(static::$tasks))
113
+		{
114
+			return null;
115
+		}
116
+
117
+		$output = array();
118
+
119
+		foreach (static::$tasks as $alias => $task)
120
+		{
121
+			$output[$alias] = [
122
+				'next_run'  => $task->nextRunDate($current_time),
123
+				'prev_run'  => $task->previousRunDate($current_time),
124
+				'task'      => $task->task()
125
+			];
126
+		}
127
+
128
+		return $output;
129
+	}
130
+
131
+	//--------------------------------------------------------------------
132
+
133
+	/**
134
+	 * Gets the task object assigned to an alias.
135
+	 *
136
+	 * @param $alias
137
+	 * @return null|CronTask object
138
+	 */
139
+	public static function task($alias)
140
+	{
141
+		if (empty(static::$tasks[$alias]) )
142
+		{
143
+			return null;
144
+		}
145
+
146
+		return static::$tasks[$alias];
147
+	}
148
+
149
+	//--------------------------------------------------------------------
150
+
151
+	/**
152
+	 * Returns all tasks currently in the system.
153
+	 *
154
+	 * @return array
155
+	 */
156
+	public static function tasks()
157
+	{
158
+		return count(static::$tasks) ? static::$tasks : null;
159
+	}
160
+
161
+	//--------------------------------------------------------------------
162
+
163
+	/**
164
+	 * Runs all tasks scheduled to run right now.
165
+	 *
166
+	 * Can be limited to a single task by passing it's alias in the first param.
167
+	 *
168
+	 * Returns the output of all task runs as a single string. Perfect for
169
+	 * emailing to users on completion
170
+	 *
171
+	 * @param null $alias
172
+	 * @param bool $force_run
173
+	 * @param string $current_time
174
+	 * @return string
175
+	 */
176
+	public static function run($alias=null, $force_run=false, $current_time='now')
177
+	{
178
+		$tasks = static::$tasks;
179
+
180
+		if (! empty($alias) && isset($tasks[$alias]))
181
+		{
182
+			$tasks = [$alias => $tasks[$alias] ];
183
+		}
184
+
185
+		$output = '';
186
+
187
+		$count = 0; // How many tasks have ran?
188
+
189
+		foreach ($tasks as $alias => $task)
190
+		{
191
+			if ($task->isDue($current_time) || $force_run === true)
192
+			{
193
+				$output .= sprintf( lang('cron.running_task'), $alias);
194
+
195
+				try {
196
+					$result = self::runTask($alias);
197
+
198
+					if (is_bool($result))
199
+					{
200
+						$output .= $result === true ? lang('done') ."\n" : lang('failed') ."\n";
201
+					}
202
+					else if (is_string($result))
203
+					{
204
+						$output .= sprintf( lang('cron.done_with_msg'), $result);
205
+					}
206
+				}
207
+				catch (\Exception $e)
208
+				{
209
+					$output .= "[Exception] ". $e->getMessage() ."\n";
210
+				}
211
+
212
+				$count++;
213
+			}
214
+			else
215
+			{
216
+				$output .= sprintf( lang('cron.not_scheduled_until'), $alias, $task->nextRunDate() );
217
+			}
218
+		}
219
+
220
+		if (! $count)
221
+		{
222
+			$output .= lang('cron.nothing_scheduled');
223
+		}
224
+
225
+		return $output;
226
+	}
227
+
228
+	//--------------------------------------------------------------------
229
+
230
+	/**
231
+	 * Clears all tasks from the system
232
+	 */
233
+	public static function reset()
234
+	{
235
+		static::$tasks = [];
236
+	}
237
+
238
+	//--------------------------------------------------------------------
239
+
240
+	//--------------------------------------------------------------------
241
+	// Protected Methods
242
+	//--------------------------------------------------------------------
243
+
244
+	/**
245
+	 * Runs a single Task.
246
+	 *
247
+	 * NOTE: Tasks MUST return a true/false value only.
248
+	 *
249
+	 * @param $alias
250
+	 * @return bool
251
+	 */
252
+	protected static function runTask($alias)
253
+	{
254
+		$task = static::$tasks[$alias]->task();
255
+
256
+		$success = false;
257
+
258
+		// If it's a standard callable item,
259
+		// then run it.
260
+		if (is_callable($task))
261
+		{
262
+			$success = call_user_func($task);
263
+		}
264
+
265
+		// Otherwise, if it's a string it should be
266
+		// a library:method string so try to run it.
267
+		else if (is_string($task) && ! empty($task) && strpos($task, ':') !== false)
268
+		{
269
+			list($class, $method) = explode(':', $task);
270
+
271
+			// Let PHP try to autoload it through any available autoloaders
272
+			// (including Composer and user's custom autoloaders). If we
273
+			// don't find it, then assume it's a CI library that we can reach.
274
+			if (class_exists($class)) {
275
+				$class = new $class();
276
+			} else {
277
+				get_instance()->load->library($class);
278
+				$class =& get_instance()->$class;
279
+			}
280
+
281
+			if (! method_exists($class, $method)) {
282
+				log_message('error', "[CRON] Method not found: {$class}::{$method}");
283
+				return $success;
284
+			}
285
+
286
+			// Call the class with our parameters
287
+			$success = $class->{$method}();
288
+		}
289
+
290
+		return $success;
291
+	}
292
+
293
+	//--------------------------------------------------------------------
294 294
 
295 295
 }
Please login to merge, or discard this patch.
myth/Controllers/CLIController.php 1 patch
Indentation   +167 added lines, -167 removed lines patch added patch discarded remove patch
@@ -1,34 +1,34 @@  discard block
 block discarded – undo
1 1
 <?php namespace Myth\Controllers;
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
 use Myth\CLI as CLI;
34 34
 
@@ -41,144 +41,144 @@  discard block
 block discarded – undo
41 41
  */
42 42
 class CLIController extends \CI_Controller {
43 43
 
44
-    /**
45
-     * Holds short descriptions for the public functions in this class.
46
-     * Each 'key' in the array should match the function name.
47
-     *
48
-     * @var array
49
-     */
50
-    protected $descriptions = [];
51
-
52
-    /**
53
-     * Holds long descriptions for the public functions in this class.
54
-     * Each 'key' in the array should match the function name.
55
-     * @var array
56
-     */
57
-    protected $long_descriptions = [];
58
-
59
-    //--------------------------------------------------------------------
60
-
61
-    /**
62
-     * Ensures that we are running on the CLI, and collects basic settings
63
-     * like collecting our command line arguments into a pretty array.
64
-     */
65
-    public function __construct()
66
-    {
67
-        parent::__construct();
68
-
69
-        // Restrict usage to the command line.
70
-        if (! is_cli() )
71
-        {
72
-            show_error( lang('cli_required') );
73
-        }
74
-
75
-        // Make sure the CLI library is loaded and ready.
44
+	/**
45
+	 * Holds short descriptions for the public functions in this class.
46
+	 * Each 'key' in the array should match the function name.
47
+	 *
48
+	 * @var array
49
+	 */
50
+	protected $descriptions = [];
51
+
52
+	/**
53
+	 * Holds long descriptions for the public functions in this class.
54
+	 * Each 'key' in the array should match the function name.
55
+	 * @var array
56
+	 */
57
+	protected $long_descriptions = [];
58
+
59
+	//--------------------------------------------------------------------
60
+
61
+	/**
62
+	 * Ensures that we are running on the CLI, and collects basic settings
63
+	 * like collecting our command line arguments into a pretty array.
64
+	 */
65
+	public function __construct()
66
+	{
67
+		parent::__construct();
68
+
69
+		// Restrict usage to the command line.
70
+		if (! is_cli() )
71
+		{
72
+			show_error( lang('cli_required') );
73
+		}
74
+
75
+		// Make sure the CLI library is loaded and ready.
76 76
 //        CLI::_init();
77
-    }
78
-
79
-    //--------------------------------------------------------------------
80
-
81
-    /**
82
-     * A default index method that all CLI Controllers can share. Will
83
-     * list all of the methods and their short descriptions, if available.
84
-     */
85
-    public function index()
86
-    {
87
-        CLI::new_line();
88
-        CLI::write( lang('cli.available_commands') );
89
-
90
-        $this->sayDescriptions($this->descriptions);
91
-
92
-        CLI::new_line();
93
-    }
94
-
95
-    //--------------------------------------------------------------------
96
-
97
-
98
-    /**
99
-     * Grabs the short description of a command, if it exists.
100
-     *
101
-     * @param null $method
102
-     */
103
-    public function describeMethod($method=null)
104
-    {
105
-        if (empty($this->descriptions[$method]))
106
-        {
107
-            return CLI::error( lang('cli.bad_description') );
108
-        }
109
-
110
-        CLI::write("\t{$this->descriptions[$method]}", 'yellow');
111
-    }
112
-
113
-    //--------------------------------------------------------------------
114
-
115
-    public function longDescribeMethod($method=null)
116
-    {
117
-        if (empty($this->long_descriptions[$method]))
118
-        {
119
-            return CLI::error( lang('cli.no_help') );
120
-        }
121
-
122
-        CLI::write("\t{$this->long_descriptions[$method]}", 'yellow');
123
-    }
124
-
125
-    //--------------------------------------------------------------------
126
-
127
-    //--------------------------------------------------------------------
128
-    // Private Methods
129
-    //--------------------------------------------------------------------
130
-
131
-    protected function sayDescriptions($descriptions)
132
-    {
133
-        $names      = array_keys($descriptions);
134
-        $syntaxes   = array_column($descriptions, 0);
135
-        $descs      = array_column($descriptions, 1);
136
-
137
-        // Pad each item to the same length
138
-        $names      = $this->padArray($names);
139
-        $syntaxes   = $this->padArray($syntaxes);
140
-
141
-        for ($i=0; $i < count($names); $i++)
142
-        {
143
-            $out = CLI::color($names[$i], 'yellow');
144
-
145
-            // The rest of the items stay default color.
146
-            if (isset($syntaxes[$i]))
147
-            {
148
-                $out .= $syntaxes[$i];
149
-            }
150
-
151
-            if (isset($descs[$i]))
152
-            {
153
-                $out .= CLI::wrap($descs[$i], 125, strlen($names[$i]) + strlen($syntaxes[$i]));
154
-            }
155
-
156
-            CLI::write($out);
157
-        }
158
-    }
159
-
160
-    //--------------------------------------------------------------------
161
-
162
-    /**
163
-     * Returns a new array where all of the string elements have
164
-     * been padding with trailling spaces to be the same length.
165
-     *
166
-     * @param array $array
167
-     * @param int $extra // How many extra spaces to add at the end
168
-     * @return array
169
-     */
170
-    protected function padArray($array, $extra=2)
171
-    {
172
-        $max = max(array_map('strlen', $array)) + $extra;
173
-
174
-        foreach ($array as &$item)
175
-        {
176
-            $item = str_pad($item, $max);
177
-        }
178
-
179
-        return $array;
180
-    }
181
-
182
-    //--------------------------------------------------------------------
77
+	}
78
+
79
+	//--------------------------------------------------------------------
80
+
81
+	/**
82
+	 * A default index method that all CLI Controllers can share. Will
83
+	 * list all of the methods and their short descriptions, if available.
84
+	 */
85
+	public function index()
86
+	{
87
+		CLI::new_line();
88
+		CLI::write( lang('cli.available_commands') );
89
+
90
+		$this->sayDescriptions($this->descriptions);
91
+
92
+		CLI::new_line();
93
+	}
94
+
95
+	//--------------------------------------------------------------------
96
+
97
+
98
+	/**
99
+	 * Grabs the short description of a command, if it exists.
100
+	 *
101
+	 * @param null $method
102
+	 */
103
+	public function describeMethod($method=null)
104
+	{
105
+		if (empty($this->descriptions[$method]))
106
+		{
107
+			return CLI::error( lang('cli.bad_description') );
108
+		}
109
+
110
+		CLI::write("\t{$this->descriptions[$method]}", 'yellow');
111
+	}
112
+
113
+	//--------------------------------------------------------------------
114
+
115
+	public function longDescribeMethod($method=null)
116
+	{
117
+		if (empty($this->long_descriptions[$method]))
118
+		{
119
+			return CLI::error( lang('cli.no_help') );
120
+		}
121
+
122
+		CLI::write("\t{$this->long_descriptions[$method]}", 'yellow');
123
+	}
124
+
125
+	//--------------------------------------------------------------------
126
+
127
+	//--------------------------------------------------------------------
128
+	// Private Methods
129
+	//--------------------------------------------------------------------
130
+
131
+	protected function sayDescriptions($descriptions)
132
+	{
133
+		$names      = array_keys($descriptions);
134
+		$syntaxes   = array_column($descriptions, 0);
135
+		$descs      = array_column($descriptions, 1);
136
+
137
+		// Pad each item to the same length
138
+		$names      = $this->padArray($names);
139
+		$syntaxes   = $this->padArray($syntaxes);
140
+
141
+		for ($i=0; $i < count($names); $i++)
142
+		{
143
+			$out = CLI::color($names[$i], 'yellow');
144
+
145
+			// The rest of the items stay default color.
146
+			if (isset($syntaxes[$i]))
147
+			{
148
+				$out .= $syntaxes[$i];
149
+			}
150
+
151
+			if (isset($descs[$i]))
152
+			{
153
+				$out .= CLI::wrap($descs[$i], 125, strlen($names[$i]) + strlen($syntaxes[$i]));
154
+			}
155
+
156
+			CLI::write($out);
157
+		}
158
+	}
159
+
160
+	//--------------------------------------------------------------------
161
+
162
+	/**
163
+	 * Returns a new array where all of the string elements have
164
+	 * been padding with trailling spaces to be the same length.
165
+	 *
166
+	 * @param array $array
167
+	 * @param int $extra // How many extra spaces to add at the end
168
+	 * @return array
169
+	 */
170
+	protected function padArray($array, $extra=2)
171
+	{
172
+		$max = max(array_map('strlen', $array)) + $extra;
173
+
174
+		foreach ($array as &$item)
175
+		{
176
+			$item = str_pad($item, $max);
177
+		}
178
+
179
+		return $array;
180
+	}
181
+
182
+	//--------------------------------------------------------------------
183 183
 
184 184
 }
Please login to merge, or discard this patch.
myth/CIModules/auth/models/Login_model.php 1 patch
Indentation   +381 added lines, -381 removed lines patch added patch discarded remove patch
@@ -1,34 +1,34 @@  discard block
 block discarded – undo
1 1
 <?php
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
 /**
34 34
  * Class Login_model
@@ -41,357 +41,357 @@  discard block
 block discarded – undo
41 41
  */
42 42
 class Login_model extends \Myth\Models\CIDbModel {
43 43
 
44
-    protected $table_name = 'auth_logins';
45
-
46
-    protected $set_created = false;
47
-    protected $set_modified = false;
48
-
49
-    //--------------------------------------------------------------------
50
-
51
-    //--------------------------------------------------------------------
52
-    // Login Attempts
53
-    //--------------------------------------------------------------------
54
-
55
-    /**
56
-     * Records a login attempt. This is used to implement
57
-     * throttling of application, ip address and user login attempts.
58
-     *
59
-     * @param $ip_address
60
-     * @param $user_id
61
-     * @return void
62
-     */
63
-    public function recordLoginAttempt($ip_address, $user_id = null)
64
-    {
65
-        $datetime = date('Y-m-d H:i:s');
66
-
67
-        // log attempt for app
68
-        $data = [
69
-            'type' => 'app',
70
-            'datetime' => $datetime
71
-        ];
72
-
73
-        $this->db->insert('auth_login_attempts', $data);
74
-
75
-        // log attempt for ip address
76
-        if (! empty($ip_address))
77
-        {
78
-            $data = [
79
-                'type' => 'ip',
80
-                'ip_address' => $ip_address,
81
-                'datetime' => $datetime
82
-            ];
83
-
84
-            $this->db->insert('auth_login_attempts', $data);
85
-        }
86
-
87
-        // log attempt for user
88
-        if ($user_id)
89
-        {
90
-            $data = [
91
-                'type' => 'user',
92
-                'user_id' => $user_id,
93
-                'datetime' => $datetime
94
-            ];
95
-
96
-            $this->db->insert('auth_login_attempts', $data);
97
-        }
98
-    }
99
-
100
-    //--------------------------------------------------------------------
101
-
102
-    /**
103
-     * Purges all login attempt records from the database.
104
-     *
105
-     * @param $ip_address
106
-     * @param $user_id
107
-     * @return mixed
108
-     */
109
-    public function purgeLoginAttempts($ip_address, $user_id)
110
-    {
111
-        if ($ip_address)
112
-        {
113
-            $this->db->where('ip_address', $ip_address);
114
-        }
115
-
116
-        if ($user_id)
117
-        {
118
-            $this->db->or_where('user_id', $user_id);
119
-        }
120
-
121
-        return $this->db->delete('auth_login_attempts');
122
-    }
123
-
124
-    //--------------------------------------------------------------------
125
-
126
-    /**
127
-     * Checks to see if how many login attempts have been attempted in the
128
-     * last 60 seconds. If over 100, it is considered to be under a
129
-     * brute force attempt.
130
-     *
131
-     * @param $ip_address
132
-     * @param $user_id
133
-     * @return bool
134
-     */
135
-    public function isBruteForced($ip_address, $user_id)
136
-    {
137
-        $start_time = date('Y-m-d H:i:s', time() - 60);
138
-
139
-        $attempts_ip = $this->db->where('type', 'ip')
140
-                                ->where('ip_address', $ip_address)
141
-                                ->where('datetime >=', $start_time)
142
-                                ->count_all_results('auth_login_attempts');
143
-
144
-        if (! $user_id)
145
-        {
146
-            return $attempts_ip > 100;
147
-        }
148
-
149
-        $attempts_user = $this->db->where('type', 'user')
150
-                                  ->where('user_id', $user_id)
151
-                                  ->where('datetime >=', $start_time)
152
-                                  ->count_all_results('auth_login_attempts');
153
-
154
-        if ($attempts_user > $attempts_ip) 
155
-        {
156
-            return $attempts_user > 100;
157
-        }
158
-        else
159
-        {
160
-            return $attempts_ip > 100;
161
-        }
162
-    }
163
-
164
-    //--------------------------------------------------------------------
165
-
166
-    /**
167
-     * Attempts to determine if the system is under a distributed
168
-     * brute force attack.
169
-     *
170
-     * To determine if we are in under a brute force attack, we first
171
-     * find the average number of bad logins per day that never converted to
172
-     * successful logins over the last 3 months. Then we compare
173
-     * that to the the average number of logins in the past 24 hours.
174
-     *
175
-     * If the number of attempts in the last 24 hours is more than X (see config)
176
-     * times the average, then institute additional throttling.
177
-     *
178
-     * @return int The time to add to any throttling.
179
-     */
180
-    public function distributedBruteForceTime()
181
-    {
182
-        if (! $time = $this->cache->get('dbrutetime'))
183
-        {
184
-            $time = 0;
185
-
186
-            // Compute our daily average over the last 3 months.
187
-            $avg_start_time = date('Y-m-d 00:00:00', strtotime('-3 months'));
188
-
189
-            $query = $this->db->query("SELECT COUNT(*) / COUNT(DISTINCT DATE(`datetime`)) as num_rows FROM `auth_login_attempts` WHERE `type` = 'app' AND `datetime` >= ?", $avg_start_time);
190
-
191
-            if (! $query->num_rows())
192
-            {
193
-                $average = 0;
194
-            }
195
-            else
196
-            {
197
-                $average = $query->row()->num_rows;
198
-            }
199
-
200
-            // Get the total in the last 24 hours
201
-            $today_start_time = date('Y-m-d H:i:s', strtotime('-24 hours'));
202
-
203
-            $attempts = $this->db->where('type', 'app')
204
-                                 ->where('datetime >=', $today_start_time)
205
-                                 ->count_all_results('auth_login_attempts');
206
-
207
-            if ($attempts > (config_item('auth.dbrute_multiplier') * $average))
208
-            {
209
-                $time = config_item('auth.distributed_brute_add_time');
210
-            }
211
-
212
-            // Cache it for 3 hours.
213
-            $this->cache->save('dbrutetime', $time, 60*60*3);
214
-        }
215
-
216
-        return $time;
217
-    }
218
-
219
-    //--------------------------------------------------------------------
220
-
221
-    //--------------------------------------------------------------------
222
-    // Logins
223
-    //--------------------------------------------------------------------
224
-
225
-    /**
226
-     * Records a successful login. This stores in a table so that a
227
-     * history can be pulled up later if needed for security analyses.
228
-     *
229
-     * @param $user
230
-     */
231
-    public function recordLogin($user)
232
-    {
233
-        $data = [
234
-            'user_id'    => (int)$user['id'],
235
-            'datetime'   => date('Y-m-d H:i:s'),
236
-            'ip_address' => $this->input->ip_address()
237
-        ];
238
-
239
-        return $this->db->insert('auth_logins', $data);
240
-    }
241
-
242
-    //--------------------------------------------------------------------
243
-
244
-    //--------------------------------------------------------------------
245
-    // Tokens
246
-    //--------------------------------------------------------------------
247
-
248
-    /**
249
-     * Generates a new token for the rememberme cookie.
250
-     *
251
-     * The token is based on the user's email address (since everyone will have one)
252
-     * with the '@' turned to a '.', followed by a pipe (|) and a random 128-character
253
-     * string with letters and numbers.
254
-     *
255
-     * @param $user
256
-     * @return mixed
257
-     */
258
-    public function generateRememberToken($user)
259
-    {
260
-        $this->load->helper('string');
261
-
262
-        return str_replace('@', '.', $user['email']) .'|' . random_string('alnum', 128);
263
-    }
264
-
265
-    //--------------------------------------------------------------------
266
-
267
-    /**
268
-     * Hashes the token for the Remember Me Functionality.
269
-     *
270
-     * @param $token
271
-     * @return string
272
-     */
273
-    public function hashRememberToken($token)
274
-    {
275
-        return sha1(config_item('auth.salt') . $token);
276
-    }
277
-
278
-    //--------------------------------------------------------------------
279
-
280
-    /**
281
-     * Deletes a single token that matches the email/token combo.
282
-     *
283
-     * @param $email
284
-     * @param $token
285
-     * @return mixed
286
-     */
287
-    public function deleteRememberToken($email, $token)
288
-    {
289
-        $where = [
290
-            'email' => $email,
291
-            'hash'  => $this->hashRememberToken($token)
292
-        ];
293
-
294
-        $this->db->delete('auth_tokens', $where);
295
-    }
296
-
297
-    //--------------------------------------------------------------------
298
-
299
-    /**
300
-     * Removes all persistent login tokens (RememberMe) for a single user
301
-     * across all devices they may have logged in with.
302
-     *
303
-     * @param $email
304
-     * @return mixed
305
-     */
306
-    public function purgeRememberTokens($email)
307
-    {
308
-        return $this->db->delete('auth_tokens', ['email' => $email]);
309
-    }
310
-
311
-    //--------------------------------------------------------------------
312
-
313
-
314
-    /**
315
-     * Purges the 'auth_tokens' table of any records that are too old
316
-     * to be of any use anymore. This equates to 1 week older than
317
-     * the remember_length set in the config file.
318
-     */
319
-    public function purgeOldRememberTokens()
320
-    {
321
-        if (! config_item('auth.allow_remembering'))
322
-        {
323
-            return;
324
-        }
325
-
326
-        $date = time() - config_item('auth.remember_length') - 604800; // 1 week
327
-        $date = date('Y-m-d 00:00:00', $date);
328
-
329
-        $this->db->where('created <=', $date)
330
-                 ->delete('auth_tokens');
331
-    }
332
-
333
-    //--------------------------------------------------------------------
334
-
335
-    /**
336
-     * Gets the timestamp of the last attempted login for this user.
337
-     *
338
-     * @param $ip_address
339
-     * @param $user_id
340
-     * @return int|null
341
-     */
342
-    public function lastLoginAttemptTime($ip_address, $user_id)
343
-    {
344
-        $query = $this->db->where('type', 'ip')
345
-                          ->where('ip_address', $ip_address)
346
-                          ->order_by('datetime', 'desc')
347
-                          ->limit(1)
348
-                          ->get('auth_login_attempts');
349
-
350
-        $last_ip = ! $query->num_rows() ? 0 : strtotime($query->row()->datetime);
351
-
352
-        if (! $user_id)
353
-        {
354
-            return $last_ip;
355
-        }
356
-
357
-        $query = $this->db->where('type', 'user')
358
-                          ->where('user_id', $user_id)
359
-                          ->order_by('datetime', 'desc')
360
-                          ->limit(1)
361
-                          ->get('auth_login_attempts');
362
-
363
-        $last_user = ! $query->num_rows() ? 0 : strtotime($query->row()->datetime);
364
-
365
-        return ($last_user > $last_ip) ? $last_user : $last_ip;
366
-    }
367
-
368
-    //--------------------------------------------------------------------
369
-
370
-    /**
371
-     * Returns the number of failed login attempts for a given type.
372
-     *
373
-     * @param $ip_address
374
-     * @param $user_id
375
-     * @return int
376
-     */
377
-    public function countLoginAttempts($ip_address, $user_id)
378
-    {
379
-        $count_ip = $this->db->where('type', 'ip')
380
-                             ->where('ip_address', $ip_address)
381
-                             ->count_all_results('auth_login_attempts');
382
-
383
-        if (! $user_id)
384
-        {
385
-            return $count_ip;
386
-        }
387
-
388
-        $count_user = $this->db->where('type', 'user')
389
-                               ->where('user_id', $user_id)
390
-                               ->count_all_results('auth_login_attempts');
391
-
392
-        return ($count_user > $count_ip) ? $count_user : $count_ip;
393
-    }
394
-
395
-    //--------------------------------------------------------------------
44
+	protected $table_name = 'auth_logins';
45
+
46
+	protected $set_created = false;
47
+	protected $set_modified = false;
48
+
49
+	//--------------------------------------------------------------------
50
+
51
+	//--------------------------------------------------------------------
52
+	// Login Attempts
53
+	//--------------------------------------------------------------------
54
+
55
+	/**
56
+	 * Records a login attempt. This is used to implement
57
+	 * throttling of application, ip address and user login attempts.
58
+	 *
59
+	 * @param $ip_address
60
+	 * @param $user_id
61
+	 * @return void
62
+	 */
63
+	public function recordLoginAttempt($ip_address, $user_id = null)
64
+	{
65
+		$datetime = date('Y-m-d H:i:s');
66
+
67
+		// log attempt for app
68
+		$data = [
69
+			'type' => 'app',
70
+			'datetime' => $datetime
71
+		];
72
+
73
+		$this->db->insert('auth_login_attempts', $data);
74
+
75
+		// log attempt for ip address
76
+		if (! empty($ip_address))
77
+		{
78
+			$data = [
79
+				'type' => 'ip',
80
+				'ip_address' => $ip_address,
81
+				'datetime' => $datetime
82
+			];
83
+
84
+			$this->db->insert('auth_login_attempts', $data);
85
+		}
86
+
87
+		// log attempt for user
88
+		if ($user_id)
89
+		{
90
+			$data = [
91
+				'type' => 'user',
92
+				'user_id' => $user_id,
93
+				'datetime' => $datetime
94
+			];
95
+
96
+			$this->db->insert('auth_login_attempts', $data);
97
+		}
98
+	}
99
+
100
+	//--------------------------------------------------------------------
101
+
102
+	/**
103
+	 * Purges all login attempt records from the database.
104
+	 *
105
+	 * @param $ip_address
106
+	 * @param $user_id
107
+	 * @return mixed
108
+	 */
109
+	public function purgeLoginAttempts($ip_address, $user_id)
110
+	{
111
+		if ($ip_address)
112
+		{
113
+			$this->db->where('ip_address', $ip_address);
114
+		}
115
+
116
+		if ($user_id)
117
+		{
118
+			$this->db->or_where('user_id', $user_id);
119
+		}
120
+
121
+		return $this->db->delete('auth_login_attempts');
122
+	}
123
+
124
+	//--------------------------------------------------------------------
125
+
126
+	/**
127
+	 * Checks to see if how many login attempts have been attempted in the
128
+	 * last 60 seconds. If over 100, it is considered to be under a
129
+	 * brute force attempt.
130
+	 *
131
+	 * @param $ip_address
132
+	 * @param $user_id
133
+	 * @return bool
134
+	 */
135
+	public function isBruteForced($ip_address, $user_id)
136
+	{
137
+		$start_time = date('Y-m-d H:i:s', time() - 60);
138
+
139
+		$attempts_ip = $this->db->where('type', 'ip')
140
+								->where('ip_address', $ip_address)
141
+								->where('datetime >=', $start_time)
142
+								->count_all_results('auth_login_attempts');
143
+
144
+		if (! $user_id)
145
+		{
146
+			return $attempts_ip > 100;
147
+		}
148
+
149
+		$attempts_user = $this->db->where('type', 'user')
150
+								  ->where('user_id', $user_id)
151
+								  ->where('datetime >=', $start_time)
152
+								  ->count_all_results('auth_login_attempts');
153
+
154
+		if ($attempts_user > $attempts_ip) 
155
+		{
156
+			return $attempts_user > 100;
157
+		}
158
+		else
159
+		{
160
+			return $attempts_ip > 100;
161
+		}
162
+	}
163
+
164
+	//--------------------------------------------------------------------
165
+
166
+	/**
167
+	 * Attempts to determine if the system is under a distributed
168
+	 * brute force attack.
169
+	 *
170
+	 * To determine if we are in under a brute force attack, we first
171
+	 * find the average number of bad logins per day that never converted to
172
+	 * successful logins over the last 3 months. Then we compare
173
+	 * that to the the average number of logins in the past 24 hours.
174
+	 *
175
+	 * If the number of attempts in the last 24 hours is more than X (see config)
176
+	 * times the average, then institute additional throttling.
177
+	 *
178
+	 * @return int The time to add to any throttling.
179
+	 */
180
+	public function distributedBruteForceTime()
181
+	{
182
+		if (! $time = $this->cache->get('dbrutetime'))
183
+		{
184
+			$time = 0;
185
+
186
+			// Compute our daily average over the last 3 months.
187
+			$avg_start_time = date('Y-m-d 00:00:00', strtotime('-3 months'));
188
+
189
+			$query = $this->db->query("SELECT COUNT(*) / COUNT(DISTINCT DATE(`datetime`)) as num_rows FROM `auth_login_attempts` WHERE `type` = 'app' AND `datetime` >= ?", $avg_start_time);
190
+
191
+			if (! $query->num_rows())
192
+			{
193
+				$average = 0;
194
+			}
195
+			else
196
+			{
197
+				$average = $query->row()->num_rows;
198
+			}
199
+
200
+			// Get the total in the last 24 hours
201
+			$today_start_time = date('Y-m-d H:i:s', strtotime('-24 hours'));
202
+
203
+			$attempts = $this->db->where('type', 'app')
204
+								 ->where('datetime >=', $today_start_time)
205
+								 ->count_all_results('auth_login_attempts');
206
+
207
+			if ($attempts > (config_item('auth.dbrute_multiplier') * $average))
208
+			{
209
+				$time = config_item('auth.distributed_brute_add_time');
210
+			}
211
+
212
+			// Cache it for 3 hours.
213
+			$this->cache->save('dbrutetime', $time, 60*60*3);
214
+		}
215
+
216
+		return $time;
217
+	}
218
+
219
+	//--------------------------------------------------------------------
220
+
221
+	//--------------------------------------------------------------------
222
+	// Logins
223
+	//--------------------------------------------------------------------
224
+
225
+	/**
226
+	 * Records a successful login. This stores in a table so that a
227
+	 * history can be pulled up later if needed for security analyses.
228
+	 *
229
+	 * @param $user
230
+	 */
231
+	public function recordLogin($user)
232
+	{
233
+		$data = [
234
+			'user_id'    => (int)$user['id'],
235
+			'datetime'   => date('Y-m-d H:i:s'),
236
+			'ip_address' => $this->input->ip_address()
237
+		];
238
+
239
+		return $this->db->insert('auth_logins', $data);
240
+	}
241
+
242
+	//--------------------------------------------------------------------
243
+
244
+	//--------------------------------------------------------------------
245
+	// Tokens
246
+	//--------------------------------------------------------------------
247
+
248
+	/**
249
+	 * Generates a new token for the rememberme cookie.
250
+	 *
251
+	 * The token is based on the user's email address (since everyone will have one)
252
+	 * with the '@' turned to a '.', followed by a pipe (|) and a random 128-character
253
+	 * string with letters and numbers.
254
+	 *
255
+	 * @param $user
256
+	 * @return mixed
257
+	 */
258
+	public function generateRememberToken($user)
259
+	{
260
+		$this->load->helper('string');
261
+
262
+		return str_replace('@', '.', $user['email']) .'|' . random_string('alnum', 128);
263
+	}
264
+
265
+	//--------------------------------------------------------------------
266
+
267
+	/**
268
+	 * Hashes the token for the Remember Me Functionality.
269
+	 *
270
+	 * @param $token
271
+	 * @return string
272
+	 */
273
+	public function hashRememberToken($token)
274
+	{
275
+		return sha1(config_item('auth.salt') . $token);
276
+	}
277
+
278
+	//--------------------------------------------------------------------
279
+
280
+	/**
281
+	 * Deletes a single token that matches the email/token combo.
282
+	 *
283
+	 * @param $email
284
+	 * @param $token
285
+	 * @return mixed
286
+	 */
287
+	public function deleteRememberToken($email, $token)
288
+	{
289
+		$where = [
290
+			'email' => $email,
291
+			'hash'  => $this->hashRememberToken($token)
292
+		];
293
+
294
+		$this->db->delete('auth_tokens', $where);
295
+	}
296
+
297
+	//--------------------------------------------------------------------
298
+
299
+	/**
300
+	 * Removes all persistent login tokens (RememberMe) for a single user
301
+	 * across all devices they may have logged in with.
302
+	 *
303
+	 * @param $email
304
+	 * @return mixed
305
+	 */
306
+	public function purgeRememberTokens($email)
307
+	{
308
+		return $this->db->delete('auth_tokens', ['email' => $email]);
309
+	}
310
+
311
+	//--------------------------------------------------------------------
312
+
313
+
314
+	/**
315
+	 * Purges the 'auth_tokens' table of any records that are too old
316
+	 * to be of any use anymore. This equates to 1 week older than
317
+	 * the remember_length set in the config file.
318
+	 */
319
+	public function purgeOldRememberTokens()
320
+	{
321
+		if (! config_item('auth.allow_remembering'))
322
+		{
323
+			return;
324
+		}
325
+
326
+		$date = time() - config_item('auth.remember_length') - 604800; // 1 week
327
+		$date = date('Y-m-d 00:00:00', $date);
328
+
329
+		$this->db->where('created <=', $date)
330
+				 ->delete('auth_tokens');
331
+	}
332
+
333
+	//--------------------------------------------------------------------
334
+
335
+	/**
336
+	 * Gets the timestamp of the last attempted login for this user.
337
+	 *
338
+	 * @param $ip_address
339
+	 * @param $user_id
340
+	 * @return int|null
341
+	 */
342
+	public function lastLoginAttemptTime($ip_address, $user_id)
343
+	{
344
+		$query = $this->db->where('type', 'ip')
345
+						  ->where('ip_address', $ip_address)
346
+						  ->order_by('datetime', 'desc')
347
+						  ->limit(1)
348
+						  ->get('auth_login_attempts');
349
+
350
+		$last_ip = ! $query->num_rows() ? 0 : strtotime($query->row()->datetime);
351
+
352
+		if (! $user_id)
353
+		{
354
+			return $last_ip;
355
+		}
356
+
357
+		$query = $this->db->where('type', 'user')
358
+						  ->where('user_id', $user_id)
359
+						  ->order_by('datetime', 'desc')
360
+						  ->limit(1)
361
+						  ->get('auth_login_attempts');
362
+
363
+		$last_user = ! $query->num_rows() ? 0 : strtotime($query->row()->datetime);
364
+
365
+		return ($last_user > $last_ip) ? $last_user : $last_ip;
366
+	}
367
+
368
+	//--------------------------------------------------------------------
369
+
370
+	/**
371
+	 * Returns the number of failed login attempts for a given type.
372
+	 *
373
+	 * @param $ip_address
374
+	 * @param $user_id
375
+	 * @return int
376
+	 */
377
+	public function countLoginAttempts($ip_address, $user_id)
378
+	{
379
+		$count_ip = $this->db->where('type', 'ip')
380
+							 ->where('ip_address', $ip_address)
381
+							 ->count_all_results('auth_login_attempts');
382
+
383
+		if (! $user_id)
384
+		{
385
+			return $count_ip;
386
+		}
387
+
388
+		$count_user = $this->db->where('type', 'user')
389
+							   ->where('user_id', $user_id)
390
+							   ->count_all_results('auth_login_attempts');
391
+
392
+		return ($count_user > $count_ip) ? $count_user : $count_ip;
393
+	}
394
+
395
+	//--------------------------------------------------------------------
396 396
 
397 397
 }
Please login to merge, or discard this patch.
myth/Auth/AuthenticateInterface.php 1 patch
Indentation   +221 added lines, -221 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
 /**
34 34
  * Class AuthenticateInterface
@@ -42,197 +42,197 @@  discard block
 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 null $ip_address
221
-     * @param null $user_id
222
-     */
223
-    public function purgeLoginAttempts($ip_address = null, $user_id = null);
224
-
225
-    //--------------------------------------------------------------------
226
-
227
-    /**
228
-     * Purges all remember tokens for a single user. Effectively logs
229
-     * a user out of all devices. Intended to allow users to log themselves
230
-     * out of all devices as a security measure.
231
-     *
232
-     * @param $email
233
-     */
234
-    public function purgeRememberTokens($email);
235
-
236
-    //--------------------------------------------------------------------
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 null $ip_address
221
+	 * @param null $user_id
222
+	 */
223
+	public function purgeLoginAttempts($ip_address = null, $user_id = null);
224
+
225
+	//--------------------------------------------------------------------
226
+
227
+	/**
228
+	 * Purges all remember tokens for a single user. Effectively logs
229
+	 * a user out of all devices. Intended to allow users to log themselves
230
+	 * out of all devices as a security measure.
231
+	 *
232
+	 * @param $email
233
+	 */
234
+	public function purgeRememberTokens($email);
235
+
236
+	//--------------------------------------------------------------------
237 237
 
238 238
 }
Please login to merge, or discard this patch.
myth/Auth/LocalAuthentication.php 1 patch
Indentation   +908 added lines, -908 removed lines patch added patch discarded remove patch
@@ -52,915 +52,915 @@
 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
-            $this->user = null;
111
-            return $user;
112
-        }       
113
-
114
-        $this->loginUser($user);
115
-
116
-        if ($remember)
117
-        {
118
-            $this->rememberUser($user);
119
-        }
120
-
121
-        Events::trigger('didLogin', [$user]);
122
-
123
-        return true;
124
-    }
125
-
126
-    //--------------------------------------------------------------------
127
-
128
-    /**
129
-     * Validates user login information without logging them in.
130
-     *
131
-     * $credentials is an array of key/value pairs needed to log the user in.
132
-     * This is often email/password, or username/password.
133
-     *
134
-     * @param $credentials
135
-     * @param bool $return_user
136
-     * @return mixed
137
-     */
138
-    public function validate($credentials, $return_user=false)
139
-    {
140
-        // Can't validate without a password.
141
-        if (empty($credentials['password']) || count($credentials) < 2)
142
-        {
143
-            return null;
144
-        }
145
-
146
-        $password = $credentials['password'];
147
-        unset($credentials['password']);
148
-
149
-        // We should only be allowed 1 single other credential to
150
-        // test against.
151
-        if (count($credentials) > 1)
152
-        {
153
-            $this->error = lang('auth.too_many_credentials');
154
-            return false;
155
-        }
156
-
157
-        // Ensure that the fields are allowed validation fields
158
-        if (! in_array(key($credentials), config_item('auth.valid_fields')) )
159
-        {
160
-            $this->error = lang('auth.invalid_credentials');
161
-            return false;
162
-        }
163
-
164
-        // We do not want to force case-sensitivity on things
165
-        // like username and email for usability sake.
166
-        if (! empty($credentials['email']))
167
-        {
168
-            $credentials['email'] = strtolower($credentials['email']);
169
-        }
170
-
171
-        // Can we find a user with those credentials?
172
-        $user = $this->user_model->as_array()
173
-                                 ->where($credentials)
174
-                                 ->first();
175
-
176
-        // If the user is throttled due to too many invalid logins
177
-        // or the system is under attack, kick them back.
178
-
179
-        // If throttling time is above zero, we can't allow
180
-        // logins now.
181
-        $time = (int)$this->isThrottled($user);
182
-        if ($time > 0)
183
-        {
184
-            $this->error = sprintf(lang('auth.throttled'), $time);
185
-            return false;
186
-        }
187
-
188
-        // Get ip address
189
-        $ip_address = $this->ci->input->ip_address();
190
-
191
-        if (! $user)
192
-        {
193
-            $this->error = lang('auth.invalid_user');
194
-            $this->ci->login_model->recordLoginAttempt($ip_address);
195
-            return false;
196
-        }
197
-
198
-        // Now, try matching the passwords.
199
-        $result =  password_verify($password, $user['password_hash']);
200
-
201
-        if (! $result)
202
-        {
203
-            $this->error = lang('auth.invalid_password');
204
-            $this->ci->login_model->recordLoginAttempt($ip_address, $user['id']);
205
-            return false;
206
-        }
207
-
208
-        // Check to see if the password needs to be rehashed.
209
-        // This would be due to the hash algorithm or hash
210
-        // cost changing since the last time that a user
211
-        // logged in.
212
-        if (password_needs_rehash($user['password_hash'], PASSWORD_DEFAULT, ['cost' => config_item('auth.hash_cost')] ))
213
-        {
214
-            $new_hash = Password::hashPassword($password);
215
-            $this->user_model->skip_validation()
216
-                             ->update($user['id'], ['password_hash' => $new_hash]);
217
-            unset($new_hash);
218
-        }
219
-
220
-        // Is the user active?
221
-        if (! $user['active'])
222
-        {
223
-            $this->error = lang('auth.inactive_account');
224
-            return false;
225
-        }
226
-
227
-        return $return_user ? $user : true;
228
-    }
229
-
230
-    //--------------------------------------------------------------------
231
-
232
-    /**
233
-     * Logs a user out and removes all session information.
234
-     *
235
-     * @return mixed
236
-     */
237
-    public function logout()
238
-    {
239
-        $this->ci->load->helper('cookie');
240
-
241
-        if (! Events::trigger('beforeLogout', [$this->user]))
242
-        {
243
-            return false;
244
-        }
245
-
246
-        // Destroy the session data - but ensure a session is still
247
-        // available for flash messages, etc.
248
-        if (isset($_SESSION))
249
-        {
250
-            foreach ( $_SESSION as $key => $value )
251
-            {
252
-                $_SESSION[ $key ] = NULL;
253
-                unset( $_SESSION[ $key ] );
254
-            }
255
-        }
256
-        // Also, regenerate the session ID for a touch of added safety.
257
-        $this->ci->session->sess_regenerate(true);
258
-
259
-        // Take care of any rememberme functionality.
260
-        if (config_item('auth.allow_remembering'))
261
-        {
262
-            $token = get_cookie('remember');
263
-
264
-            $this->invalidateRememberCookie($this->user['email'], $token);
265
-        }
266
-    }
267
-
268
-    //--------------------------------------------------------------------
269
-
270
-    /**
271
-     * Checks whether a user is logged in or not.
272
-     *
273
-     * @return bool
274
-     */
275
-    public function isLoggedIn()
276
-    {
277
-        $id = $this->ci->session->userdata('logged_in');
278
-
279
-        if (! $id)
280
-        {
281
-            return false;
282
-        }
283
-
284
-        // If the user var hasn't been filled in, we need to fill it in,
285
-        // since this method will typically be used as the only method
286
-        // to determine whether a user is logged in or not.
287
-        if (! $this->user)
288
-        {
289
-            $this->user = $this->user_model->as_array()
290
-                                           ->find_by('id', (int)$id);
291
-
292
-            if (empty($this->user))
293
-            {
294
-                return false;
295
-            }
296
-        }
297
-
298
-        // If logged in, ensure cache control
299
-        // headers are in place
300
-        $this->setHeaders();
301
-
302
-        return true;
303
-    }
304
-
305
-    //--------------------------------------------------------------------
306
-
307
-    /**
308
-     * Attempts to log a user in based on the "remember me" cookie.
309
-     *
310
-     * @return bool
311
-     */
312
-    public function viaRemember()
313
-    {
314
-        if (! config_item('auth.allow_remembering'))
315
-        {
316
-            return false;
317
-        }
318
-
319
-        $this->ci->load->helper('cookie');
320
-
321
-        if (! $token = get_cookie('remember'))
322
-        {
323
-            return false;
324
-        }
325
-
326
-        // Attempt to match the token against our auth_tokens table.
327
-        $query = $this->ci->db->where('hash', $this->ci->login_model->hashRememberToken($token))
328
-                              ->get('auth_tokens');
329
-
330
-        if (! $query->num_rows())
331
-        {
332
-            return false;
333
-        }
334
-
335
-        // Grab the user
336
-        $email = $query->row()->email;
337
-
338
-        $user = $this->user_model->as_array()
339
-                                 ->find_by('email', $email);
340
-
341
-        $this->loginUser($user);
342
-
343
-        // We only want our remember me tokens to be valid
344
-        // for a single use.
345
-        $this->refreshRememberCookie($user, $token);
346
-
347
-        return true;
348
-    }
349
-
350
-    //--------------------------------------------------------------------
351
-
352
-    /**
353
-     * Registers a new user and handles activation method.
354
-     *
355
-     * @param $user_data
356
-     * @return bool
357
-     */
358
-    public function registerUser($user_data)
359
-    {
360
-        // Anything special needed for Activation?
361
-        $method = config_item('auth.activation_method');
362
-
363
-        $user_data['active'] = $method == 'auto' ? 1 : 0;
364
-
365
-        // If via email, we need to generate a hash
366
-        $this->ci->load->helper('string');
367
-        $token = random_string('alnum', 24);
368
-        $user_data['activate_hash'] = hash('sha1', config_item('auth.salt') . $token);
369
-
370
-        // Email should NOT be case sensitive.
371
-        if (! empty($user_data['email']))
372
-        {
373
-            $user_data['email'] = strtolower($user_data['email']);
374
-        }
375
-
376
-        // Save the user
377
-        if (! $id = $this->user_model->insert($user_data))
378
-        {
379
-            $this->error = $this->user_model->error();
380
-            return false;
381
-        }
382
-
383
-        $data = [
384
-            'user_id' => $id,
385
-            'email'   => $user_data['email'],
386
-            'token'   => $token,
387
-            'method'  => $method
388
-        ];
389
-
390
-        Events::trigger('didRegisterUser', [$data]);
391
-
392
-        return true;
393
-    }
394
-
395
-    //--------------------------------------------------------------------
396
-
397
-    /**
398
-     * Used to verify the user values and activate a user so they can
399
-     * visit the site.
400
-     *
401
-     * @param $data
402
-     * @return bool
403
-     */
404
-    public function activateUser($data)
405
-    {
406
-        $post = [
407
-            'email'         => $data['email'],
408
-            'activate_hash' => hash('sha1', config_item('auth.salt') . $data['code'])
409
-        ];
410
-
411
-        $user = $this->user_model->where($post)
412
-                                 ->first();
413
-
414
-        if (! $user) {
415
-            $this->error = $this->user_model->error() ? $this->user_model->error() : lang('auth.activate_no_user');
416
-
417
-            return false;
418
-        }
419
-
420
-        if (! $this->user_model->update($user->id, ['active' => 1, 'activate_hash' => null]))
421
-        {
422
-            $this->error = $this->user_model->error();
423
-            return false;
424
-        }
425
-
426
-        Events::trigger('didActivate', [(array)$user]);
427
-
428
-        return true;
429
-    }
430
-
431
-    //--------------------------------------------------------------------
432
-
433
-    /**
434
-     * Used to allow manual activation of a user with a known ID.
435
-     *
436
-     * @param $id
437
-     * @return bool
438
-     */
439
-    public function activateUserById($id)
440
-    {
441
-        if (! $this->user_model->update($id, ['active' => 1, 'activate_hash' => null]))
442
-        {
443
-            $this->error = $this->user_model->error();
444
-            return false;
445
-        }
446
-
447
-        Events::trigger('didActivate', [$this->user_model->as_array()->find($id)]);
448
-
449
-        return true;
450
-    }
451
-
452
-    //--------------------------------------------------------------------
453
-
454
-    /**
455
-     * Grabs the current user object. Returns NULL if nothing found.
456
-     *
457
-     * @return array|null
458
-     */
459
-    public function user()
460
-    {
461
-        return $this->user;
462
-    }
463
-
464
-    //--------------------------------------------------------------------
465
-
466
-    /**
467
-     * A convenience method to grab the current user's ID.
468
-     *
469
-     * @return int|null
470
-     */
471
-    public function id()
472
-    {
473
-        if (! is_array($this->user) || empty($this->user['id']))
474
-        {
475
-            return null;
476
-        }
477
-
478
-        return (int)$this->user['id'];
479
-    }
480
-
481
-    //--------------------------------------------------------------------
482
-
483
-    /**
484
-     * Checks to see if the user is currently being throttled.
485
-     *
486
-     *  - If they are NOT, will return FALSE.
487
-     *  - If they ARE, will return the number of seconds until they can try again.
488
-     *
489
-     * @param $user
490
-     * @return mixed
491
-     */
492
-    public function isThrottled($user)
493
-    {
494
-        // Not throttling? Get outta here!
495
-        if (! config_item('auth.allow_throttling'))
496
-        {
497
-            return false;
498
-        }
499
-
500
-        // Get user_id
501
-        $user_id = $user ? $user['id'] : null;
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
+			$this->user = null;
111
+			return $user;
112
+		}       
113
+
114
+		$this->loginUser($user);
115
+
116
+		if ($remember)
117
+		{
118
+			$this->rememberUser($user);
119
+		}
120
+
121
+		Events::trigger('didLogin', [$user]);
122
+
123
+		return true;
124
+	}
125
+
126
+	//--------------------------------------------------------------------
127
+
128
+	/**
129
+	 * Validates user login information without logging them in.
130
+	 *
131
+	 * $credentials is an array of key/value pairs needed to log the user in.
132
+	 * This is often email/password, or username/password.
133
+	 *
134
+	 * @param $credentials
135
+	 * @param bool $return_user
136
+	 * @return mixed
137
+	 */
138
+	public function validate($credentials, $return_user=false)
139
+	{
140
+		// Can't validate without a password.
141
+		if (empty($credentials['password']) || count($credentials) < 2)
142
+		{
143
+			return null;
144
+		}
145
+
146
+		$password = $credentials['password'];
147
+		unset($credentials['password']);
148
+
149
+		// We should only be allowed 1 single other credential to
150
+		// test against.
151
+		if (count($credentials) > 1)
152
+		{
153
+			$this->error = lang('auth.too_many_credentials');
154
+			return false;
155
+		}
156
+
157
+		// Ensure that the fields are allowed validation fields
158
+		if (! in_array(key($credentials), config_item('auth.valid_fields')) )
159
+		{
160
+			$this->error = lang('auth.invalid_credentials');
161
+			return false;
162
+		}
163
+
164
+		// We do not want to force case-sensitivity on things
165
+		// like username and email for usability sake.
166
+		if (! empty($credentials['email']))
167
+		{
168
+			$credentials['email'] = strtolower($credentials['email']);
169
+		}
170
+
171
+		// Can we find a user with those credentials?
172
+		$user = $this->user_model->as_array()
173
+								 ->where($credentials)
174
+								 ->first();
175
+
176
+		// If the user is throttled due to too many invalid logins
177
+		// or the system is under attack, kick them back.
178
+
179
+		// If throttling time is above zero, we can't allow
180
+		// logins now.
181
+		$time = (int)$this->isThrottled($user);
182
+		if ($time > 0)
183
+		{
184
+			$this->error = sprintf(lang('auth.throttled'), $time);
185
+			return false;
186
+		}
187
+
188
+		// Get ip address
189
+		$ip_address = $this->ci->input->ip_address();
190
+
191
+		if (! $user)
192
+		{
193
+			$this->error = lang('auth.invalid_user');
194
+			$this->ci->login_model->recordLoginAttempt($ip_address);
195
+			return false;
196
+		}
197
+
198
+		// Now, try matching the passwords.
199
+		$result =  password_verify($password, $user['password_hash']);
200
+
201
+		if (! $result)
202
+		{
203
+			$this->error = lang('auth.invalid_password');
204
+			$this->ci->login_model->recordLoginAttempt($ip_address, $user['id']);
205
+			return false;
206
+		}
207
+
208
+		// Check to see if the password needs to be rehashed.
209
+		// This would be due to the hash algorithm or hash
210
+		// cost changing since the last time that a user
211
+		// logged in.
212
+		if (password_needs_rehash($user['password_hash'], PASSWORD_DEFAULT, ['cost' => config_item('auth.hash_cost')] ))
213
+		{
214
+			$new_hash = Password::hashPassword($password);
215
+			$this->user_model->skip_validation()
216
+							 ->update($user['id'], ['password_hash' => $new_hash]);
217
+			unset($new_hash);
218
+		}
219
+
220
+		// Is the user active?
221
+		if (! $user['active'])
222
+		{
223
+			$this->error = lang('auth.inactive_account');
224
+			return false;
225
+		}
226
+
227
+		return $return_user ? $user : true;
228
+	}
229
+
230
+	//--------------------------------------------------------------------
231
+
232
+	/**
233
+	 * Logs a user out and removes all session information.
234
+	 *
235
+	 * @return mixed
236
+	 */
237
+	public function logout()
238
+	{
239
+		$this->ci->load->helper('cookie');
240
+
241
+		if (! Events::trigger('beforeLogout', [$this->user]))
242
+		{
243
+			return false;
244
+		}
245
+
246
+		// Destroy the session data - but ensure a session is still
247
+		// available for flash messages, etc.
248
+		if (isset($_SESSION))
249
+		{
250
+			foreach ( $_SESSION as $key => $value )
251
+			{
252
+				$_SESSION[ $key ] = NULL;
253
+				unset( $_SESSION[ $key ] );
254
+			}
255
+		}
256
+		// Also, regenerate the session ID for a touch of added safety.
257
+		$this->ci->session->sess_regenerate(true);
258
+
259
+		// Take care of any rememberme functionality.
260
+		if (config_item('auth.allow_remembering'))
261
+		{
262
+			$token = get_cookie('remember');
263
+
264
+			$this->invalidateRememberCookie($this->user['email'], $token);
265
+		}
266
+	}
267
+
268
+	//--------------------------------------------------------------------
269
+
270
+	/**
271
+	 * Checks whether a user is logged in or not.
272
+	 *
273
+	 * @return bool
274
+	 */
275
+	public function isLoggedIn()
276
+	{
277
+		$id = $this->ci->session->userdata('logged_in');
278
+
279
+		if (! $id)
280
+		{
281
+			return false;
282
+		}
283
+
284
+		// If the user var hasn't been filled in, we need to fill it in,
285
+		// since this method will typically be used as the only method
286
+		// to determine whether a user is logged in or not.
287
+		if (! $this->user)
288
+		{
289
+			$this->user = $this->user_model->as_array()
290
+										   ->find_by('id', (int)$id);
291
+
292
+			if (empty($this->user))
293
+			{
294
+				return false;
295
+			}
296
+		}
297
+
298
+		// If logged in, ensure cache control
299
+		// headers are in place
300
+		$this->setHeaders();
301
+
302
+		return true;
303
+	}
304
+
305
+	//--------------------------------------------------------------------
306
+
307
+	/**
308
+	 * Attempts to log a user in based on the "remember me" cookie.
309
+	 *
310
+	 * @return bool
311
+	 */
312
+	public function viaRemember()
313
+	{
314
+		if (! config_item('auth.allow_remembering'))
315
+		{
316
+			return false;
317
+		}
318
+
319
+		$this->ci->load->helper('cookie');
320
+
321
+		if (! $token = get_cookie('remember'))
322
+		{
323
+			return false;
324
+		}
325
+
326
+		// Attempt to match the token against our auth_tokens table.
327
+		$query = $this->ci->db->where('hash', $this->ci->login_model->hashRememberToken($token))
328
+							  ->get('auth_tokens');
329
+
330
+		if (! $query->num_rows())
331
+		{
332
+			return false;
333
+		}
334
+
335
+		// Grab the user
336
+		$email = $query->row()->email;
337
+
338
+		$user = $this->user_model->as_array()
339
+								 ->find_by('email', $email);
340
+
341
+		$this->loginUser($user);
342
+
343
+		// We only want our remember me tokens to be valid
344
+		// for a single use.
345
+		$this->refreshRememberCookie($user, $token);
346
+
347
+		return true;
348
+	}
349
+
350
+	//--------------------------------------------------------------------
351
+
352
+	/**
353
+	 * Registers a new user and handles activation method.
354
+	 *
355
+	 * @param $user_data
356
+	 * @return bool
357
+	 */
358
+	public function registerUser($user_data)
359
+	{
360
+		// Anything special needed for Activation?
361
+		$method = config_item('auth.activation_method');
362
+
363
+		$user_data['active'] = $method == 'auto' ? 1 : 0;
364
+
365
+		// If via email, we need to generate a hash
366
+		$this->ci->load->helper('string');
367
+		$token = random_string('alnum', 24);
368
+		$user_data['activate_hash'] = hash('sha1', config_item('auth.salt') . $token);
369
+
370
+		// Email should NOT be case sensitive.
371
+		if (! empty($user_data['email']))
372
+		{
373
+			$user_data['email'] = strtolower($user_data['email']);
374
+		}
375
+
376
+		// Save the user
377
+		if (! $id = $this->user_model->insert($user_data))
378
+		{
379
+			$this->error = $this->user_model->error();
380
+			return false;
381
+		}
382
+
383
+		$data = [
384
+			'user_id' => $id,
385
+			'email'   => $user_data['email'],
386
+			'token'   => $token,
387
+			'method'  => $method
388
+		];
389
+
390
+		Events::trigger('didRegisterUser', [$data]);
391
+
392
+		return true;
393
+	}
394
+
395
+	//--------------------------------------------------------------------
396
+
397
+	/**
398
+	 * Used to verify the user values and activate a user so they can
399
+	 * visit the site.
400
+	 *
401
+	 * @param $data
402
+	 * @return bool
403
+	 */
404
+	public function activateUser($data)
405
+	{
406
+		$post = [
407
+			'email'         => $data['email'],
408
+			'activate_hash' => hash('sha1', config_item('auth.salt') . $data['code'])
409
+		];
410
+
411
+		$user = $this->user_model->where($post)
412
+								 ->first();
413
+
414
+		if (! $user) {
415
+			$this->error = $this->user_model->error() ? $this->user_model->error() : lang('auth.activate_no_user');
416
+
417
+			return false;
418
+		}
419
+
420
+		if (! $this->user_model->update($user->id, ['active' => 1, 'activate_hash' => null]))
421
+		{
422
+			$this->error = $this->user_model->error();
423
+			return false;
424
+		}
425
+
426
+		Events::trigger('didActivate', [(array)$user]);
427
+
428
+		return true;
429
+	}
430
+
431
+	//--------------------------------------------------------------------
432
+
433
+	/**
434
+	 * Used to allow manual activation of a user with a known ID.
435
+	 *
436
+	 * @param $id
437
+	 * @return bool
438
+	 */
439
+	public function activateUserById($id)
440
+	{
441
+		if (! $this->user_model->update($id, ['active' => 1, 'activate_hash' => null]))
442
+		{
443
+			$this->error = $this->user_model->error();
444
+			return false;
445
+		}
446
+
447
+		Events::trigger('didActivate', [$this->user_model->as_array()->find($id)]);
448
+
449
+		return true;
450
+	}
451
+
452
+	//--------------------------------------------------------------------
453
+
454
+	/**
455
+	 * Grabs the current user object. Returns NULL if nothing found.
456
+	 *
457
+	 * @return array|null
458
+	 */
459
+	public function user()
460
+	{
461
+		return $this->user;
462
+	}
463
+
464
+	//--------------------------------------------------------------------
465
+
466
+	/**
467
+	 * A convenience method to grab the current user's ID.
468
+	 *
469
+	 * @return int|null
470
+	 */
471
+	public function id()
472
+	{
473
+		if (! is_array($this->user) || empty($this->user['id']))
474
+		{
475
+			return null;
476
+		}
477
+
478
+		return (int)$this->user['id'];
479
+	}
480
+
481
+	//--------------------------------------------------------------------
482
+
483
+	/**
484
+	 * Checks to see if the user is currently being throttled.
485
+	 *
486
+	 *  - If they are NOT, will return FALSE.
487
+	 *  - If they ARE, will return the number of seconds until they can try again.
488
+	 *
489
+	 * @param $user
490
+	 * @return mixed
491
+	 */
492
+	public function isThrottled($user)
493
+	{
494
+		// Not throttling? Get outta here!
495
+		if (! config_item('auth.allow_throttling'))
496
+		{
497
+			return false;
498
+		}
499
+
500
+		// Get user_id
501
+		$user_id = $user ? $user['id'] : null;
502 502
         
503
-        // Get ip address
504
-        $ip_address = $this->ci->input->ip_address();
505
-
506
-        // Have any attempts been made?
507
-        $attempts = $this->ci->login_model->countLoginAttempts($ip_address, $user_id);
508
-
509
-        // Grab the amount of time to add if the system thinks we're
510
-        // under a distributed brute force attack.
511
-        // Affect users that have at least 1 failure login attempt
512
-        $dbrute_time = ($attempts === 0) ? 0 : $this->ci->login_model->distributedBruteForceTime();
513
-
514
-        // If this user was found to possibly be under a brute
515
-        // force attack, their account would have been banned
516
-        // for 15 minutes.
517
-        if ($time = isset($_SESSION['bruteBan']) ? $_SESSION['bruteBan'] : false)
518
-        {
519
-            // If the current time is less than the
520
-            // the ban expiration, plus any distributed time
521
-            // then the user can't login just yet.
522
-            if ($time + $dbrute_time > time())
523
-            {
524
-                // The user is banned still...
525
-                $this->error = lang('auth.bruteBan_notice');
526
-                return ($time + $dbrute_time) - time();
527
-            }
528
-
529
-            // Still here? The the ban time is over...
530
-            unset($_SESSION['bruteBan']);
531
-        }
532
-
533
-        // Grab the time of last attempt and
534
-        // determine if we're throttled by amount of time passed.
535
-        $last_time = $this->ci->login_model->lastLoginAttemptTime($ip_address, $user_id);
536
-
537
-        $allowed = config_item('auth.allowed_login_attempts');
538
-
539
-        // We're not throttling if there are 0 attempts or
540
-        // the number is less than or equal to the allowed free attempts
541
-        if ($attempts === 0 || $attempts < $allowed)
542
-        {
543
-            // Before we can say there's nothing up here,
544
-            // we need to check dbrute time.
545
-            $time_left = $last_time + $dbrute_time - time();
546
-
547
-            if ($time_left > 0)
548
-            {
549
-                return $time_left;
550
-            }
551
-
552
-            return false;
553
-        }
554
-
555
-        // If the number of attempts is excessive (above 100) we need
556
-        // to check the elapsed time of all of these attacks. If they are
557
-        // less than 1 minute it's obvious this is a brute force attack,
558
-        // so we'll set a session flag and block that user for 15 minutes.
559
-        if ($attempts > 100 && $this->ci->login_model->isBruteForced($ip_address, $user_id))
560
-        {
561
-            $this->error = lang('auth.bruteBan_notice');
562
-
563
-            $ban_time = 60 * 15;    // 15 minutes
564
-            $_SESSION['bruteBan'] = time() + $ban_time;
565
-            return $ban_time;
566
-        }
567
-
568
-        // Get our allowed attempts out of the picture.
569
-        $attempts = $attempts - $allowed;
570
-
571
-        $max_time = config_item('auth.max_throttle_time');
572
-
573
-        $add_time = 5 * pow(2, $attempts);
574
-
575
-        if ($add_time > $max_time)
576
-        {
577
-            $add_time = $max_time;
578
-        }
579
-
580
-        $next_time = $last_time + $add_time + $dbrute_time;
581
-
582
-        $current = time();
583
-
584
-        // We are NOT throttled if we are already
585
-        // past the allowed time.
586
-        if ($current > $next_time)
587
-        {
588
-            return false;
589
-        }
590
-
591
-        return $next_time - $current;
592
-    }
593
-
594
-    //--------------------------------------------------------------------
595
-
596
-    /**
597
-     * Sends a password reset link email to the user associated with
598
-     * the passed in $email.
599
-     *
600
-     * @param $email
601
-     * @return mixed
602
-     */
603
-    public function remindUser($email)
604
-    {
605
-        // Emails should NOT be case sensitive.
606
-        $email = strtolower($email);
607
-
608
-        // Is it a valid user?
609
-        $user = $this->user_model->find_by('email', $email);
610
-
611
-        if (! $user)
612
-        {
613
-            $this->error = lang('auth.invalid_email');
614
-            return false;
615
-        }
616
-
617
-        // Generate/store our codes
618
-        $this->ci->load->helper('string');
619
-        $token = random_string('alnum', 24);
620
-        $hash = hash('sha1', config_item('auth.salt') .$token);
621
-
622
-        $result = $this->user_model->update($user->id, ['reset_hash' => $hash]);
623
-
624
-        if (! $result)
625
-        {
626
-            $this->error = $this->user_model->error();
627
-            return false;
628
-        }
629
-
630
-        Events::trigger('didRemindUser', [(array)$user, $token]);
631
-
632
-        return true;
633
-    }
634
-
635
-    //--------------------------------------------------------------------
636
-
637
-    /**
638
-     * Validates the credentials provided and, if valid, resets the password.
639
-     *
640
-     * The $credentials array MUST contain a 'code' key with the string to
641
-     * hash and check against the reset_hash.
642
-     *
643
-     * @param $credentials
644
-     * @param $password
645
-     * @param $passConfirm
646
-     * @return mixed
647
-     */
648
-    public function resetPassword($credentials, $password, $passConfirm)
649
-    {
650
-        if (empty($credentials['code']))
651
-        {
652
-            $this->error = lang('auth.need_reset_code');
653
-            return false;
654
-        }
655
-
656
-        // Generate a hash to match against the table.
657
-        $reset_hash = hash('sha1', config_item('auth.salt') .$credentials['code']);
658
-        unset($credentials['code']);
659
-
660
-        if (! empty($credentials['email']))
661
-        {
662
-            $credentials['email'] = strtolower($credentials['email']);
663
-        }
664
-
665
-        // Is there a matching user?
666
-        $user = $this->user_model->as_array()
667
-                                 ->where($credentials)
668
-                                 ->first();
669
-
670
-        // If throttling time is above zero, we can't allow
671
-        // logins now.
672
-        $time = (int)$this->isThrottled($user);
673
-        if ($time > 0)
674
-        {
675
-            $this->error = sprintf(lang('auth.throttled'), $time);
676
-            return false;
677
-        }
678
-
679
-        // Get ip address
680
-        $ip_address = $this->ci->input->ip_address();
681
-
682
-        if (! $user)
683
-        {
684
-            $this->error = lang('auth.reset_no_user');
685
-            $this->ci->login_model->recordLoginAttempt($ip_address);
686
-            return false;
687
-        }
688
-
689
-        // Is generated reset_hash string matches one from the table?
690
-        if ($reset_hash !== $user['reset_hash'])
691
-        {
692
-            $this->error = lang('auth.reset_no_user');
693
-            $this->ci->login_model->recordLoginAttempt($ip_address, $user['id']);
694
-            return false;
695
-        }
696
-
697
-        // Update their password and reset their reset_hash
698
-        $data = [
699
-            'password'     => $password,
700
-            'pass_confirm' => $passConfirm,
701
-            'reset_hash'   => null
702
-        ];
703
-
704
-        if (! $this->user_model->update($user['id'], $data))
705
-        {
706
-            $this->error = $this->user_model->error();
707
-            return false;
708
-        }
709
-
710
-        // Clear our login attempts
711
-        $this->ci->login_model->purgeLoginAttempts($ip_address, $user['id']);
712
-
713
-        Events::trigger('didResetPassword', [$user]);
714
-
715
-        return true;
716
-    }
717
-
718
-    //--------------------------------------------------------------------
719
-
720
-    /**
721
-     * Provides a way for implementations to allow new statuses to be set
722
-     * on the user. The details will vary based upon implementation, but
723
-     * will often allow for banning or suspending users.
724
-     *
725
-     * @param $newStatus
726
-     * @param null $message
727
-     * @return mixed
728
-     */
729
-    public function changeStatus($newStatus, $message=null)
730
-    {
731
-        // todo actually record new users status!
732
-    }
733
-
734
-    //--------------------------------------------------------------------
735
-
736
-    /**
737
-     * Allows the consuming application to pass in a reference to the
738
-     * model that should be used.
739
-     *
740
-     * The model MUST extend Myth\Models\CIDbModel.
741
-     *
742
-     * @param $model
743
-     * @param bool $allow_any_parent
744
-     * @return mixed
745
-     */
746
-    public function useModel($model, $allow_any_parent=false)
747
-    {
748
-        if (! $allow_any_parent && get_parent_class($model) != 'Myth\Models\CIDbModel')
749
-        {
750
-            throw new \RuntimeException('Models passed into LocalAuthenticate MUST extend Myth\Models\CIDbModel');
751
-        }
752
-
753
-        $this->user_model =& $model;
754
-
755
-        return $this;
756
-    }
757
-
758
-    //--------------------------------------------------------------------
759
-
760
-    public function error()
761
-    {
762
-        if (validation_errors())
763
-        {
764
-            return validation_errors();
765
-        }
766
-
767
-        return $this->error;
768
-    }
769
-
770
-    //--------------------------------------------------------------------
771
-
772
-    //--------------------------------------------------------------------
773
-    // Login Records
774
-    //--------------------------------------------------------------------
775
-
776
-    /**
777
-     * Purges all login attempt records from the database.
778
-     *
779
-     * @param null $ip_address
780
-     * @param null $user_id
781
-     */
782
-    public function purgeLoginAttempts($ip_address = null, $user_id = null)
783
-    {
784
-        $this->ci->login_model->purgeLoginAttempts($ip_address, $user_id);
785
-
786
-        // @todo record activity of login attempts purge.
787
-        Events::trigger('didPurgeLoginAttempts', [$email]);
788
-    }
789
-
790
-    //--------------------------------------------------------------------
791
-
792
-    /**
793
-     * Purges all remember tokens for a single user. Effectively logs
794
-     * a user out of all devices. Intended to allow users to log themselves
795
-     * out of all devices as a security measure.
796
-     *
797
-     * @param $email
798
-     */
799
-    public function purgeRememberTokens($email)
800
-    {
801
-        // Emails should NOT be case sensitive.
802
-        $email = strtolower($email);
803
-
804
-        $this->ci->login_model->purgeRememberTokens($email);
805
-
806
-        // todo record activity of remember me purges.
807
-        Events::trigger('didPurgeRememberTokens', [$email]);
808
-    }
809
-
810
-    //--------------------------------------------------------------------
811
-
812
-    //--------------------------------------------------------------------
813
-    // Protected Methods
814
-    //--------------------------------------------------------------------
815
-
816
-    /**
817
-     * Check if Allow Persistent Login Cookies is enable
818
-     *
819
-     * @param $user
820
-     */
821
-    protected function rememberUser($user)
822
-    {
823
-        if (! config_item('auth.allow_remembering'))
824
-        {
825
-            log_message('debug', 'Auth library set to refuse "Remember Me" functionality.');
826
-            return false;
827
-        }
828
-
829
-        $this->refreshRememberCookie($user);
830
-    }
831
-
832
-    //--------------------------------------------------------------------
833
-
834
-    /**
835
-     * Invalidates the current rememberme cookie/database entry, creates
836
-     * a new one, stores it and returns the new value.
837
-     *
838
-     * @param $user
839
-     * @param null $token
840
-     * @return mixed
841
-     */
842
-    protected function refreshRememberCookie($user, $token=null)
843
-    {
844
-        $this->ci->load->helper('cookie');
845
-
846
-        // If a token is passed in, we know we're removing the
847
-        // old one.
848
-        if (! empty($token))
849
-        {
850
-            $this->invalidateRememberCookie($user['email'], $token);
851
-        }
852
-
853
-        $new_token = $this->ci->login_model->generateRememberToken($user);
854
-
855
-        // Save the token to the database.
856
-        $data = [
857
-            'email'   => $user['email'],
858
-            'hash'    => sha1(config_item('auth.salt') . $new_token),
859
-            'created' => date('Y-m-d H:i:s')
860
-        ];
861
-
862
-        $this->ci->db->insert('auth_tokens', $data);
863
-
864
-        // Create the cookie
865
-        set_cookie(
866
-            'remember',                             // Cookie Name
867
-            $new_token,                             // Value
868
-            config_item('auth.remember_length'),    // # Seconds until it expires
869
-            config_item('cookie_domain'),
870
-            config_item('cookie_path'),
871
-            config_item('cookie_prefix'),
872
-            false,                                  // Only send over HTTPS?
873
-            true                                    // Hide from Javascript?
874
-        );
875
-
876
-        return $new_token;
877
-    }
878
-
879
-    //--------------------------------------------------------------------
880
-
881
-    /**
882
-     * Deletes any current remember me cookies and database entries.
883
-     *
884
-     * @param $email
885
-     * @param $token
886
-     * @return string The new token (not the hash).
887
-     */
888
-    protected function invalidateRememberCookie($email, $token)
889
-    {
890
-        // Emails should NOT be case sensitive.
891
-        $email = strtolower($email);
892
-
893
-        // Remove from the database
894
-        $this->ci->login_model->deleteRememberToken($email, $token);
895
-
896
-        // Remove the cookie
897
-        delete_cookie(
898
-            'remember',
899
-            config_item('cookie_domain'),
900
-            config_item('cookie_path'),
901
-            config_item('cookie_prefix')
902
-        );
903
-    }
904
-
905
-    //--------------------------------------------------------------------
906
-
907
-    /**
908
-     * Handles the nitty gritty of actually logging our user into the system.
909
-     * Does NOT perform the authentication, just sets the system up so that
910
-     * it knows we're here.
911
-     *
912
-     * @param $user
913
-     */
914
-    protected function loginUser($user)
915
-    {
916
-        // Save the user for later access
917
-        $this->user = $user;
918
-
919
-        // Get ip address
920
-        $ip_address = $this->ci->input->ip_address();
921
-
922
-        // Regenerate the session ID to help protect
923
-        // against session fixation
924
-        $this->ci->session->sess_regenerate();
925
-
926
-        // Let the session know that we're logged in.
927
-        $this->ci->session->set_userdata('logged_in', $user['id']);
928
-
929
-        // Clear our login attempts
930
-        $this->ci->login_model->purgeLoginAttempts($ip_address, $user['id']);
931
-
932
-        // Record a new Login
933
-        $this->ci->login_model->recordLogin($user);
934
-
935
-        // If logged in, ensure cache control
936
-        // headers are in place
937
-        $this->setHeaders();
938
-
939
-        // We'll give a 20% chance to need to do a purge since we
940
-        // don't need to purge THAT often, it's just a maintenance issue.
941
-        // to keep the table from getting out of control.
942
-        if (mt_rand(1, 100) < 20)
943
-        {
944
-            $this->ci->login_model->purgeOldRememberTokens();
945
-        }
946
-    }
947
-
948
-    //--------------------------------------------------------------------
949
-
950
-    /**
951
-     * Sets the headers to ensure that pages are not cached when a user
952
-     * is logged in, helping to protect against logging out and then
953
-     * simply hitting the Back button on the browser and getting private
954
-     * information because the page was loaded from cache.
955
-     */
956
-    protected function setHeaders()
957
-    {
958
-        $this->ci->output->set_header('Cache-Control: no-store, no-cache, must-revalidate');
959
-        $this->ci->output->set_header('Cache-Control: post-check=0, pre-check=0');
960
-        $this->ci->output->set_header('Pragma: no-cache');
961
-    }
962
-
963
-    //--------------------------------------------------------------------
503
+		// Get ip address
504
+		$ip_address = $this->ci->input->ip_address();
505
+
506
+		// Have any attempts been made?
507
+		$attempts = $this->ci->login_model->countLoginAttempts($ip_address, $user_id);
508
+
509
+		// Grab the amount of time to add if the system thinks we're
510
+		// under a distributed brute force attack.
511
+		// Affect users that have at least 1 failure login attempt
512
+		$dbrute_time = ($attempts === 0) ? 0 : $this->ci->login_model->distributedBruteForceTime();
513
+
514
+		// If this user was found to possibly be under a brute
515
+		// force attack, their account would have been banned
516
+		// for 15 minutes.
517
+		if ($time = isset($_SESSION['bruteBan']) ? $_SESSION['bruteBan'] : false)
518
+		{
519
+			// If the current time is less than the
520
+			// the ban expiration, plus any distributed time
521
+			// then the user can't login just yet.
522
+			if ($time + $dbrute_time > time())
523
+			{
524
+				// The user is banned still...
525
+				$this->error = lang('auth.bruteBan_notice');
526
+				return ($time + $dbrute_time) - time();
527
+			}
528
+
529
+			// Still here? The the ban time is over...
530
+			unset($_SESSION['bruteBan']);
531
+		}
532
+
533
+		// Grab the time of last attempt and
534
+		// determine if we're throttled by amount of time passed.
535
+		$last_time = $this->ci->login_model->lastLoginAttemptTime($ip_address, $user_id);
536
+
537
+		$allowed = config_item('auth.allowed_login_attempts');
538
+
539
+		// We're not throttling if there are 0 attempts or
540
+		// the number is less than or equal to the allowed free attempts
541
+		if ($attempts === 0 || $attempts < $allowed)
542
+		{
543
+			// Before we can say there's nothing up here,
544
+			// we need to check dbrute time.
545
+			$time_left = $last_time + $dbrute_time - time();
546
+
547
+			if ($time_left > 0)
548
+			{
549
+				return $time_left;
550
+			}
551
+
552
+			return false;
553
+		}
554
+
555
+		// If the number of attempts is excessive (above 100) we need
556
+		// to check the elapsed time of all of these attacks. If they are
557
+		// less than 1 minute it's obvious this is a brute force attack,
558
+		// so we'll set a session flag and block that user for 15 minutes.
559
+		if ($attempts > 100 && $this->ci->login_model->isBruteForced($ip_address, $user_id))
560
+		{
561
+			$this->error = lang('auth.bruteBan_notice');
562
+
563
+			$ban_time = 60 * 15;    // 15 minutes
564
+			$_SESSION['bruteBan'] = time() + $ban_time;
565
+			return $ban_time;
566
+		}
567
+
568
+		// Get our allowed attempts out of the picture.
569
+		$attempts = $attempts - $allowed;
570
+
571
+		$max_time = config_item('auth.max_throttle_time');
572
+
573
+		$add_time = 5 * pow(2, $attempts);
574
+
575
+		if ($add_time > $max_time)
576
+		{
577
+			$add_time = $max_time;
578
+		}
579
+
580
+		$next_time = $last_time + $add_time + $dbrute_time;
581
+
582
+		$current = time();
583
+
584
+		// We are NOT throttled if we are already
585
+		// past the allowed time.
586
+		if ($current > $next_time)
587
+		{
588
+			return false;
589
+		}
590
+
591
+		return $next_time - $current;
592
+	}
593
+
594
+	//--------------------------------------------------------------------
595
+
596
+	/**
597
+	 * Sends a password reset link email to the user associated with
598
+	 * the passed in $email.
599
+	 *
600
+	 * @param $email
601
+	 * @return mixed
602
+	 */
603
+	public function remindUser($email)
604
+	{
605
+		// Emails should NOT be case sensitive.
606
+		$email = strtolower($email);
607
+
608
+		// Is it a valid user?
609
+		$user = $this->user_model->find_by('email', $email);
610
+
611
+		if (! $user)
612
+		{
613
+			$this->error = lang('auth.invalid_email');
614
+			return false;
615
+		}
616
+
617
+		// Generate/store our codes
618
+		$this->ci->load->helper('string');
619
+		$token = random_string('alnum', 24);
620
+		$hash = hash('sha1', config_item('auth.salt') .$token);
621
+
622
+		$result = $this->user_model->update($user->id, ['reset_hash' => $hash]);
623
+
624
+		if (! $result)
625
+		{
626
+			$this->error = $this->user_model->error();
627
+			return false;
628
+		}
629
+
630
+		Events::trigger('didRemindUser', [(array)$user, $token]);
631
+
632
+		return true;
633
+	}
634
+
635
+	//--------------------------------------------------------------------
636
+
637
+	/**
638
+	 * Validates the credentials provided and, if valid, resets the password.
639
+	 *
640
+	 * The $credentials array MUST contain a 'code' key with the string to
641
+	 * hash and check against the reset_hash.
642
+	 *
643
+	 * @param $credentials
644
+	 * @param $password
645
+	 * @param $passConfirm
646
+	 * @return mixed
647
+	 */
648
+	public function resetPassword($credentials, $password, $passConfirm)
649
+	{
650
+		if (empty($credentials['code']))
651
+		{
652
+			$this->error = lang('auth.need_reset_code');
653
+			return false;
654
+		}
655
+
656
+		// Generate a hash to match against the table.
657
+		$reset_hash = hash('sha1', config_item('auth.salt') .$credentials['code']);
658
+		unset($credentials['code']);
659
+
660
+		if (! empty($credentials['email']))
661
+		{
662
+			$credentials['email'] = strtolower($credentials['email']);
663
+		}
664
+
665
+		// Is there a matching user?
666
+		$user = $this->user_model->as_array()
667
+								 ->where($credentials)
668
+								 ->first();
669
+
670
+		// If throttling time is above zero, we can't allow
671
+		// logins now.
672
+		$time = (int)$this->isThrottled($user);
673
+		if ($time > 0)
674
+		{
675
+			$this->error = sprintf(lang('auth.throttled'), $time);
676
+			return false;
677
+		}
678
+
679
+		// Get ip address
680
+		$ip_address = $this->ci->input->ip_address();
681
+
682
+		if (! $user)
683
+		{
684
+			$this->error = lang('auth.reset_no_user');
685
+			$this->ci->login_model->recordLoginAttempt($ip_address);
686
+			return false;
687
+		}
688
+
689
+		// Is generated reset_hash string matches one from the table?
690
+		if ($reset_hash !== $user['reset_hash'])
691
+		{
692
+			$this->error = lang('auth.reset_no_user');
693
+			$this->ci->login_model->recordLoginAttempt($ip_address, $user['id']);
694
+			return false;
695
+		}
696
+
697
+		// Update their password and reset their reset_hash
698
+		$data = [
699
+			'password'     => $password,
700
+			'pass_confirm' => $passConfirm,
701
+			'reset_hash'   => null
702
+		];
703
+
704
+		if (! $this->user_model->update($user['id'], $data))
705
+		{
706
+			$this->error = $this->user_model->error();
707
+			return false;
708
+		}
709
+
710
+		// Clear our login attempts
711
+		$this->ci->login_model->purgeLoginAttempts($ip_address, $user['id']);
712
+
713
+		Events::trigger('didResetPassword', [$user]);
714
+
715
+		return true;
716
+	}
717
+
718
+	//--------------------------------------------------------------------
719
+
720
+	/**
721
+	 * Provides a way for implementations to allow new statuses to be set
722
+	 * on the user. The details will vary based upon implementation, but
723
+	 * will often allow for banning or suspending users.
724
+	 *
725
+	 * @param $newStatus
726
+	 * @param null $message
727
+	 * @return mixed
728
+	 */
729
+	public function changeStatus($newStatus, $message=null)
730
+	{
731
+		// todo actually record new users status!
732
+	}
733
+
734
+	//--------------------------------------------------------------------
735
+
736
+	/**
737
+	 * Allows the consuming application to pass in a reference to the
738
+	 * model that should be used.
739
+	 *
740
+	 * The model MUST extend Myth\Models\CIDbModel.
741
+	 *
742
+	 * @param $model
743
+	 * @param bool $allow_any_parent
744
+	 * @return mixed
745
+	 */
746
+	public function useModel($model, $allow_any_parent=false)
747
+	{
748
+		if (! $allow_any_parent && get_parent_class($model) != 'Myth\Models\CIDbModel')
749
+		{
750
+			throw new \RuntimeException('Models passed into LocalAuthenticate MUST extend Myth\Models\CIDbModel');
751
+		}
752
+
753
+		$this->user_model =& $model;
754
+
755
+		return $this;
756
+	}
757
+
758
+	//--------------------------------------------------------------------
759
+
760
+	public function error()
761
+	{
762
+		if (validation_errors())
763
+		{
764
+			return validation_errors();
765
+		}
766
+
767
+		return $this->error;
768
+	}
769
+
770
+	//--------------------------------------------------------------------
771
+
772
+	//--------------------------------------------------------------------
773
+	// Login Records
774
+	//--------------------------------------------------------------------
775
+
776
+	/**
777
+	 * Purges all login attempt records from the database.
778
+	 *
779
+	 * @param null $ip_address
780
+	 * @param null $user_id
781
+	 */
782
+	public function purgeLoginAttempts($ip_address = null, $user_id = null)
783
+	{
784
+		$this->ci->login_model->purgeLoginAttempts($ip_address, $user_id);
785
+
786
+		// @todo record activity of login attempts purge.
787
+		Events::trigger('didPurgeLoginAttempts', [$email]);
788
+	}
789
+
790
+	//--------------------------------------------------------------------
791
+
792
+	/**
793
+	 * Purges all remember tokens for a single user. Effectively logs
794
+	 * a user out of all devices. Intended to allow users to log themselves
795
+	 * out of all devices as a security measure.
796
+	 *
797
+	 * @param $email
798
+	 */
799
+	public function purgeRememberTokens($email)
800
+	{
801
+		// Emails should NOT be case sensitive.
802
+		$email = strtolower($email);
803
+
804
+		$this->ci->login_model->purgeRememberTokens($email);
805
+
806
+		// todo record activity of remember me purges.
807
+		Events::trigger('didPurgeRememberTokens', [$email]);
808
+	}
809
+
810
+	//--------------------------------------------------------------------
811
+
812
+	//--------------------------------------------------------------------
813
+	// Protected Methods
814
+	//--------------------------------------------------------------------
815
+
816
+	/**
817
+	 * Check if Allow Persistent Login Cookies is enable
818
+	 *
819
+	 * @param $user
820
+	 */
821
+	protected function rememberUser($user)
822
+	{
823
+		if (! config_item('auth.allow_remembering'))
824
+		{
825
+			log_message('debug', 'Auth library set to refuse "Remember Me" functionality.');
826
+			return false;
827
+		}
828
+
829
+		$this->refreshRememberCookie($user);
830
+	}
831
+
832
+	//--------------------------------------------------------------------
833
+
834
+	/**
835
+	 * Invalidates the current rememberme cookie/database entry, creates
836
+	 * a new one, stores it and returns the new value.
837
+	 *
838
+	 * @param $user
839
+	 * @param null $token
840
+	 * @return mixed
841
+	 */
842
+	protected function refreshRememberCookie($user, $token=null)
843
+	{
844
+		$this->ci->load->helper('cookie');
845
+
846
+		// If a token is passed in, we know we're removing the
847
+		// old one.
848
+		if (! empty($token))
849
+		{
850
+			$this->invalidateRememberCookie($user['email'], $token);
851
+		}
852
+
853
+		$new_token = $this->ci->login_model->generateRememberToken($user);
854
+
855
+		// Save the token to the database.
856
+		$data = [
857
+			'email'   => $user['email'],
858
+			'hash'    => sha1(config_item('auth.salt') . $new_token),
859
+			'created' => date('Y-m-d H:i:s')
860
+		];
861
+
862
+		$this->ci->db->insert('auth_tokens', $data);
863
+
864
+		// Create the cookie
865
+		set_cookie(
866
+			'remember',                             // Cookie Name
867
+			$new_token,                             // Value
868
+			config_item('auth.remember_length'),    // # Seconds until it expires
869
+			config_item('cookie_domain'),
870
+			config_item('cookie_path'),
871
+			config_item('cookie_prefix'),
872
+			false,                                  // Only send over HTTPS?
873
+			true                                    // Hide from Javascript?
874
+		);
875
+
876
+		return $new_token;
877
+	}
878
+
879
+	//--------------------------------------------------------------------
880
+
881
+	/**
882
+	 * Deletes any current remember me cookies and database entries.
883
+	 *
884
+	 * @param $email
885
+	 * @param $token
886
+	 * @return string The new token (not the hash).
887
+	 */
888
+	protected function invalidateRememberCookie($email, $token)
889
+	{
890
+		// Emails should NOT be case sensitive.
891
+		$email = strtolower($email);
892
+
893
+		// Remove from the database
894
+		$this->ci->login_model->deleteRememberToken($email, $token);
895
+
896
+		// Remove the cookie
897
+		delete_cookie(
898
+			'remember',
899
+			config_item('cookie_domain'),
900
+			config_item('cookie_path'),
901
+			config_item('cookie_prefix')
902
+		);
903
+	}
904
+
905
+	//--------------------------------------------------------------------
906
+
907
+	/**
908
+	 * Handles the nitty gritty of actually logging our user into the system.
909
+	 * Does NOT perform the authentication, just sets the system up so that
910
+	 * it knows we're here.
911
+	 *
912
+	 * @param $user
913
+	 */
914
+	protected function loginUser($user)
915
+	{
916
+		// Save the user for later access
917
+		$this->user = $user;
918
+
919
+		// Get ip address
920
+		$ip_address = $this->ci->input->ip_address();
921
+
922
+		// Regenerate the session ID to help protect
923
+		// against session fixation
924
+		$this->ci->session->sess_regenerate();
925
+
926
+		// Let the session know that we're logged in.
927
+		$this->ci->session->set_userdata('logged_in', $user['id']);
928
+
929
+		// Clear our login attempts
930
+		$this->ci->login_model->purgeLoginAttempts($ip_address, $user['id']);
931
+
932
+		// Record a new Login
933
+		$this->ci->login_model->recordLogin($user);
934
+
935
+		// If logged in, ensure cache control
936
+		// headers are in place
937
+		$this->setHeaders();
938
+
939
+		// We'll give a 20% chance to need to do a purge since we
940
+		// don't need to purge THAT often, it's just a maintenance issue.
941
+		// to keep the table from getting out of control.
942
+		if (mt_rand(1, 100) < 20)
943
+		{
944
+			$this->ci->login_model->purgeOldRememberTokens();
945
+		}
946
+	}
947
+
948
+	//--------------------------------------------------------------------
949
+
950
+	/**
951
+	 * Sets the headers to ensure that pages are not cached when a user
952
+	 * is logged in, helping to protect against logging out and then
953
+	 * simply hitting the Back button on the browser and getting private
954
+	 * information because the page was loaded from cache.
955
+	 */
956
+	protected function setHeaders()
957
+	{
958
+		$this->ci->output->set_header('Cache-Control: no-store, no-cache, must-revalidate');
959
+		$this->ci->output->set_header('Cache-Control: post-check=0, pre-check=0');
960
+		$this->ci->output->set_header('Pragma: no-cache');
961
+	}
962
+
963
+	//--------------------------------------------------------------------
964 964
 
965 965
 
966 966
 }
Please login to merge, or discard this patch.