Completed
Push — development ( b06117...356f74 )
by Thomas
17s
created

htdocs/lib2/login.class.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/***************************************************************************
3
 * for license information see LICENSE.md
4
 *  This class provides access to the login user data. Informations are
5
 *  stored in a cookie.
6
 *  Methods:
7
 *    verify()        validate the login-session (automatically invoked)
8
 *    try_login()     try to login with the given user/password
9
 *    logout()        logout the user
10
 *  Properties:
11
 *    userid          Integer 0 if no login, userid otherwise
12
 *    username        String username or ''
13
 *  !! See also lib/login.class.php. !!
14
 ***************************************************************************/
15
16
use OcLegacy\Util\PasswordCrypt;
17
18
define('LOGIN_UNKNOWN_ERROR', -1);     // unknown error occurred
19
define('LOGIN_OK', 0);                 // login succeeded
20
define('LOGIN_BADUSERPW', 1);          // bad username or password
21
define('LOGIN_TOOMUCHLOGINS', 2);      // too many logins in short time
22
define('LOGIN_USERNOTACTIVE', 3);      // the userAccount locked
23
define('LOGIN_EMPTY_USERPASSWORD', 4); // given username/password was empty
24
define('LOGIN_LOGOUT_OK', 5);          // logout was successful
25
26
// login times in seconds
27
define('LOGIN_TIME', 60 * 60);
28
define('LOGIN_TIME_PERMANENT', 90 * 24 * 60 * 60);
29
30
$login = new login();
31
32
class login
33
{
34
    /**
35
     * @var int
36
     */
37
    public $userid = 0;
38
    /**
39
     * @var mixed|string
40
     */
41
    public $username = '';
42
    /**
43
     * @var string
44
     */
45
    public $lastlogin = '';
46
    /**
47
     * @var bool
48
     */
49
    public $permanent = false;
50
    /**
51
     * @var mixed|string
52
     */
53
    public $sessionid = '';
54
    /**
55
     * @var bool
56
     */
57
    public $verified = false;
58
    /**
59
     * @var int
60
     */
61
    public $admin = 0;
62
63
    /**
64
     * login constructor.
65
     */
66 View Code Duplication
    public function __construct()
67
    {
68
        global $cookie;
69
70
        // TODO good input evaluation
71
        if ($cookie->is_set('userid') && $cookie->is_set('username')) {
72
            $this->userid = (int) $cookie->get('userid');
73
            $this->username = $cookie->get('username');
74
            $this->permanent = (($cookie->get('permanent') + 0) == 1);
75
            $this->lastlogin = $cookie->get('lastlogin');
76
            $this->sessionid = $cookie->get('sessionid');
77
            // $this->admin = $cookie->get('admin')+0;   nonsense
78
            $this->verified = false;
79
80
            $this->verify();
81
        } else {
82
            $this->pClear();
83
        }
84
    }
85
86 View Code Duplication
    public function pClear()
87
    {
88
        // set to no valid login
89
        $this->userid = 0;
90
        $this->username = '';
91
        $this->permanent = false;
92
        $this->lastlogin = '';
93
        $this->sessionid = '';
94
        $this->admin = 0;
95
        $this->verified = true;
96
97
        $this->pStoreCookie();
98
    }
99
100 View Code Duplication
    public function pStoreCookie()
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
101
    {
102
        global $cookie;
103
        $cookie->set('userid', (int) $this->userid);
104
        $cookie->set('username', $this->username);
105
        $cookie->set('permanent', ($this->permanent === true ? 1 : 0));
106
        $cookie->set('lastlogin', $this->lastlogin);
107
        $cookie->set('sessionid', $this->sessionid);
108
    }
109
110
    /**
111
     */
112
    public function verify()
113
    {
114
        global $opt;
115
116
        if ($this->verified == true) {
117
            return;
118
        }
119
120
        if ($this->userid == 0) {
121
            $this->pClear();
122
123
            return;
124
        }
125
126
        if ($this->checkLoginsCount() === false) {
127
            $this->pClear();
128
129
            return;
130
        }
131
132
        $min_lastlogin = date('Y-m-d H:i:s', time() - LOGIN_TIME);
133
        $min_lastlogin_permanent = date('Y-m-d H:i:s', time() - LOGIN_TIME_PERMANENT);
134
135
        $rs = sqlf(
136
            "
137
            SELECT
138
                `sys_sessions`.`last_login`,
139
                `user`.`admin`,
140
                `user`.`username`
141
            FROM &db.`sys_sessions`, &db.`user`
142
            WHERE `sys_sessions`.`user_id`=`user`.`user_id`
143
            AND `user`.`is_active_flag`= 1
144
            AND `sys_sessions`.`uuid`='&1'
145
            AND `sys_sessions`.`user_id`='&2'
146
            AND
147
                (
148
                  (`sys_sessions`.`permanent`=1
149
                   AND `sys_sessions`.`last_login`>'&3')
150
                OR
151
                  (`sys_sessions`.`permanent`=0 AND `sys_sessions`.`last_login`>'&4')
152
                )",
153
            $this->sessionid,
154
            $this->userid,
155
            $min_lastlogin_permanent,
156
            $min_lastlogin
157
        );
158
159
        // sys_session.last_login controls the automatic logout of users at the OC website.
160
        // user.last_login gives the overall last login date, including OKAPI logins.
161
162
        if ($rUser = sql_fetch_assoc($rs)) {
163 View Code Duplication
            if ((($this->permanent == true) && (strtotime($rUser['last_login']) + LOGIN_TIME_PERMANENT / 2 < time())) ||
164
                (($this->permanent == false) && (strtotime($rUser['last_login']) + LOGIN_TIME / 2 < time()))
165
            ) {
166
                sqlf(
167
                    "UPDATE `sys_sessions` SET `sys_sessions`.`last_login`=NOW()
168
                     WHERE `sys_sessions`.`uuid`='&1' AND `sys_sessions`.`user_id`='&2'",
169
                    $this->sessionid,
170
                    $this->userid
171
                );
172
                $rUser['last_login'] = date('Y-m-d H:i:s');
173
            }
174
175
            if (isset($opt['template']['locale'])) {
176
                sqlf(
177
                    "UPDATE `user` SET `last_login`=NOW(), `language`='&2', `language_guessed`=0, `domain`='&3'
178
                     WHERE `user_id`='&1'",
179
                    $this->userid,
180
                    $opt['template']['locale'],
181
                    $opt['page']['domain']
182
                );
183
            } else {
184
                sqlf("UPDATE `user` SET `last_login`=NOW() WHERE `user_id`='&1'", $this->userid);
185
            }
186
187
            $this->lastlogin = $rUser['last_login'];
188
            $this->username = $rUser['username'];
189
            $this->admin = $rUser['admin'];
190
            $this->verified = true;
191
        } else {
192
            // prevent brute force
193
            sql("INSERT INTO `sys_logins` (`remote_addr`, `success`) VALUES ('&1', 0)", $_SERVER['REMOTE_ADDR']);
194
195
            $this->pClear();
196
        }
197
        sql_free_result($rs);
198
199
        $this->pStoreCookie();
200
    }
201
202
    /**
203
     * @param $user
204
     * @param $password
205
     * @param $permanent
206
     * @return int
207
     */
208
    public function try_login($user, $password, $permanent)
209
    {
210
        if ($password == '') {
211
            return LOGIN_EMPTY_USERPASSWORD;
212
        }
213
214
        $encryptedPassword = PasswordCrypt::encryptPassword($password);
215
216
        return $this->try_login_encrypted($user, $encryptedPassword, $permanent);
217
    }
218
219
    /**
220
     * @return bool
221
     */
222
    public function checkLoginsCount()
223
    {
224
        global $opt;
225
226
        // cleanup old entries
227
        // (execute only every 50 search calls)
228 View Code Duplication
        if (mt_rand(1, 50) === 1) {
229
            sqlf("DELETE FROM `sys_logins` WHERE `date_created`<'&1'", date('Y-m-d H:i:s', time() - 3600));
230
        }
231
232
        // check the number of logins in the last hour ...
233
        $loginAttemptsCount = sqlf_value(
234
            "
235
            SELECT COUNT(*) `count`
236
            FROM `sys_logins`
237
            WHERE `remote_addr`='&1'
238
            AND `date_created`>'&2'",
239
            0,
240
            $_SERVER['REMOTE_ADDR'],
241
            date('Y-m-d H:i:s', time() - 3600)
242
        );
243
244
        return !($loginAttemptsCount > $opt['page']['max_logins_per_hour']);
245
    }
246
247
    /**
248
     * @param $user
249
     * @param $encryptedPassword
250
     * @param $permanent
251
     * @return int
252
     */
253
    public function try_login_encrypted($user, $encryptedPassword, $permanent)
254
    {
255
        $this->pClear();
256
257
        if ($user == '' || $encryptedPassword == '') {
258
            return LOGIN_EMPTY_USERPASSWORD;
259
        }
260
261
        if ($this->checkLoginsCount() == false) {
262
            return LOGIN_TOOMUCHLOGINS;
263
        }
264
265
        // delete old sessions
266
        $min_lastlogin_permanent = date('Y-m-d H:i:s', time() - LOGIN_TIME_PERMANENT);
267
        sqlf("DELETE FROM `sys_sessions` WHERE `last_login`<'&1'", $min_lastlogin_permanent);
268
269
        // compare $user with email and username, if both matches use email
270
        $rsUser = sqlf(
271
            "SELECT `user_id`, `username`, 2 AS `prio`, `is_active_flag`, `permanent_login_flag`, `admin`
272
             FROM `user` WHERE `username`='&1' AND `password`='&2'
273
             UNION
274
             SELECT `user_id`, `username`, 1 AS `prio`, `is_active_flag`, `permanent_login_flag`, `admin`
275
             FROM `user`WHERE `email`='&1' AND `password`='&2' ORDER BY `prio` ASC LIMIT 1",
276
            $user,
277
            $encryptedPassword
278
        );
279
        $rUser = sql_fetch_assoc($rsUser);
280
        sql_free_result($rsUser);
281
282
        if ($permanent == null) {
283
            $permanent = ($rUser['permanent_login_flag'] == 1);
284
        }
285
286
        if ($rUser) {
287
            // ok, there is a valid login
288
            if ($rUser['is_active_flag'] != 0) {
289
                // begin session
290
                $uuid = self::create_sessionid();
291
                sqlf(
292
                    "INSERT INTO `sys_sessions` (`uuid`, `user_id`, `permanent`)
293
                      VALUES ('&1', '&2', '&3')",
294
                    $uuid,
295
                    $rUser['user_id'],
296
                    ($permanent != false ? 1 : 0)
297
                );
298
                $this->userid = (int) $rUser['user_id'];
299
                $this->username = $rUser['username'];
300
                $this->permanent = $permanent;
301
                $this->lastlogin = date('Y-m-d H:i:s');
302
                $this->sessionid = $uuid;
303
                $this->admin = $rUser['admin'];
304
                $this->verified = true;
305
306
                $retval = LOGIN_OK;
307
            } else {
308
                $retval = LOGIN_USERNOTACTIVE;
309
            }
310
        } else {
311
            // sorry, bad login
312
            $retval = LOGIN_BADUSERPW;
313
        }
314
315
        sqlf(
316
            "INSERT INTO `sys_logins` (`remote_addr`, `success`) VALUES ('&1', '&2')",
317
            $_SERVER['REMOTE_ADDR'],
318
            ($rUser === false ? 0 : 1)
319
        );
320
321
        // store to cookie
322
        $this->pStoreCookie();
323
324
        return $retval;
325
    }
326
327
    /**
328
     * login for cronjobs, command line tools ...
329
     *
330
     * @param $username
331
     * @return bool
332
     */
333
    public function system_login($username)
334
    {
335
        $this->pClear();
336
        if ($username != '') {
337
            $rs = sql(
338
                "SELECT `user_id`,`username`,`admin` FROM `user`
339
                 WHERE `username`='&1' AND `is_active_flag`",
340
                $username
341
            );
342
            if ($rUser = sql_fetch_assoc($rs)) {
343
                $this->username = $rUser['username'];
344
                $this->userid = (int) $rUser['user_id'];
345
                $this->admin = $rUser['admin'];
346
                $this->verified = true;
347
                sqlf("UPDATE `user` SET `user`.`last_login`=NOW() WHERE `user`.`user_id`='&1'", $this->userid);
348
            }
349
            sql_free_result($rs);
350
        }
351
352
        return ($this->userid > 0);
353
    }
354
355
    /**
356
     * @return string
357
     */
358
    private static function create_sessionid()
359
    {
360
        return sprintf(
361
            '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
362
            mt_rand(0, 0xffff),
363
            mt_rand(0, 0xffff),
364
            mt_rand(0, 0xffff),
365
            mt_rand(0, 0xffff),
366
            mt_rand(0, 0xffff),
367
            mt_rand(0, 0xffff),
368
            mt_rand(0, 0xffff),
369
            mt_rand(0, 0xffff)
370
        );
371
    }
372
373
    /**
374
     * @return mixed|string
375
     */
376
    public function getUserCountry()
377
    {
378
        global $opt, $cookie;
379
380
        // language specified in cookie?
381 View Code Duplication
        if ($cookie->is_set('usercountry')) {
382
            $sCountry = $cookie->get('usercountry', null);
383
            if ($sCountry != null) {
384
                return $sCountry;
385
            }
386
        }
387
388
389
390
        // user specified a country?
391
        if ($this->userid != 0) {
392
            $sCountry = sql_value("SELECT `country` FROM `user` WHERE `user_id`='&1'", null, $this->userid);
393
            if ($sCountry != null) {
394
                return $sCountry;
395
            }
396
        }
397
398
        // default country of this language
399
        //
400
        // disabled: produces unexpected results on multi-domains without translation,
401
        // and will confusingly switch country when switching language  -- following 3.9.2015
402
        //
403
        // if (isset($opt['locale'][$opt['template']['locale']]['country']))
404
        //    return $opt['locale'][$opt['template']['locale']]['country'];
405
406
        // default country of installation (or domain)
407
        return $opt['template']['default']['country'];
408
    }
409
410
    public function logout()
411
    {
412
        if ($this->userid != 0) {
413
            sqlf("DELETE FROM `sys_sessions` WHERE `uuid`='&1' AND `user_id`='&2'", $this->sessionid, $this->userid);
414
        }
415
416
        $this->pClear();
417
    }
418
419
    /**
420
     * @param int|bool $privilege
421
     * @return bool
422
     */
423 View Code Duplication
    public function hasAdminPriv($privilege = false)
424
    {
425
        if ($privilege === false) {
426
            return $this->admin != 0;
427
        }
428
429
        return ($this->admin & $privilege) == $privilege;
430
    }
431
432
    /**
433
     * @return bool
434
     */
435
    public function listingAdmin()
436
    {
437
        global $opt;
438
439
        return $this->hasAdminPriv(ADMIN_LISTING) && $opt['logic']['admin']['enable_listing_admins'];
440
    }
441
442
    /**
443
     * @return bool
444
     */
445
    public function logged_in()
446
    {
447
        return $this->userid > 0;
448
    }
449
}
450