aboutsummaryrefslogtreecommitdiff
path: root/lib/models/Token.php
blob: 63c6ebc832f9284930a896e594e8ffb0cd15b51a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<?php
/**
 * Token.php - Token class
 *
 * @author    Jan-Hendrik Willms <tleilax+studip@gmail.com>
 * @author    Marco Diedrich <mdiedric@uos.de>
 * @license   GPL2 or any later version
 *
 * @property string $id alias column for token
 * @property string $token database column
 * @property string $user_id database column
 * @property int $expiration database column
 * @property int|null $mkdate database column
 * @property User $user belongs_to User
 */
class Token extends SimpleORMap
{
    /**
     * Configures the model
     *
     * @param array $config
     */
    protected static function configure($config = [])
    {
        $config['db_table'] = 'user_token';

        $config['belongs_to']['user'] = [
            'class_name'  => User::class,
            'foreign_key' => 'user_id',
        ];

        // Create new token and ensure token is unique upon store
        $config['registered_callbacks']['before_create'][] = function ($object) {
            do {
                $token = md5(uniqid(__CLASS__, true));
            } while (Token::exists($token));

            $object->token = $token;
        };

        // Ensure tokens are not changed
        $config['registered_callbacks']['before_store'][] = function ($object) {
            if (!$object->isNew() && $object->isFieldDirty('token')) {
                return false;
            }
        };

        parent::configure($config);
    }

    /**
     * Creates a new token.
     *
     * @param integer $duration       Lifetime of the token
     * @param mixed   $user_id        Optional id of the user (defaults to current user)
     * @param bool     $return_object Return the actual token object if true, only the token otherwise (default)
     * @return string|Token the token
     */
    public static function create($duration = 30, $user_id = null, bool $return_object = false)
    {
        $token = new self();
        $token->user_id    = $user_id ?? $GLOBALS['user']->id;
        $token->expiration = strtotime("+{$duration} seconds");
        $token->store();

        return $return_object ? $token : $token->token;
    }

    /**
     * Checks if a token is valid (for a given user).
     *
     * Based on the number of paremters this either returns the id of the user
     * the token belongs to or a boolean if the id of a user was already given.
     *
     * @param  string  $token   Token to check
     * @param  mixed   $user_id Optional id of a user
     * @return mixed  User id of none was given or boolean
     */
    public static function isValid($token, $user_id = null)
    {
        $token = static::find($token);

        // No db entry for token
        if (!$token || $token->isExpired()) {
            return null;
        }

        // Token is valid
        $token_user_id = $token->user_id;
        $token->delete();

        return func_num_args() === 1
             ? $token_user_id
             : $token_user_id === ($user_id ?? $GLOBALS['user']->id);
    }

    /**
     * Returns whether the token is expired
     * @return boolean
     */
    public function isExpired()
    {
        return $this->expiration < time();
    }
}