Completed
Push — master ( 580028...d7e9e8 )
by Charles
02:19
created

Token::generate()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 42
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 42
rs 8.439
cc 5
eloc 27
nc 7
nop 2
1
<?php
2
3
namespace yrc\api\models;
4
5
use Base32\Base32;
6
use yrc\api\models\TokenKeyPair;
7
use Yii;
8
9
/**
10
 * Abstract class for generating and storing tokens
11
 * @class Token
12
 */
13
abstract class Token extends \yrc\redis\ActiveRecord
14
{
15
    /**
16
     * This is our default token lifespan
17
     * @const TOKEN_EXPIRATION_TIME
18
     */
19
    const TOKEN_EXPIRATION_TIME = '+15 minutes';
20
21
    /**
22
     * @inheritdoc
23
     */
24
    public function attributes()
25
    {
26
        return [
27
            'id',
28
            'user_id',
29
            'access_token',
30
            'refresh_token',
31
            'ikm',
32
            'client_public',
33
            'crypt_id',
34
            'expires_at'
35
        ];
36
    }
37
38
    /**
39
     * Returns the token key pair object
40
     * @return TokenKeyPair
41
     */
42
    public function getCryptToken()
43
    {
44
        return TokenKeyPair::find(['id' => $this->crypt_id])->one();
45
    }
46
47
    /**
48
     * Generates a new auth and refresh token pair
49
     * @param int $userId
50
     * @param bool $pubkey
51
     * @return array
52
     */
53
    public static function generate($userId = null, $pubkey = null)
54
    {
55
        $model = null;
56
        $user = Yii::$app->yrc->userClass::findOne(['id' => $userId]);
57
        if ($user === null) {
58
            throw new \yii\base\Exception('Invalid user');
59
        }
60
       
61
        $token = new static;
62
        $token->user_id = $userId;
63
        $token->access_token = \str_replace('=', '', Base32::encode(\random_bytes(32)));
64
        $token->refresh_token = \str_replace('=', '', Base32::encode(\random_bytes(32)));
65
        $token->ikm =  \base64_encode(\random_bytes(32));
66
        $token->expires_at = \strtotime(static::TOKEN_EXPIRATION_TIME);
67
68
        // Prevent encrypted sessions from being downgraded
69
        $token->client_public = $pubkey;
70
71
        if ($pubkey !== null) {
72
            $model = TokenKeyPair::generate();
73
            $token->crypt_id = $model->id;
74
        }
75
76
        if ($token->save()) {
77
            $tokens = $token->attributes;
78
            if ($model !== null) {
79
                $tokens['crypt'] = [
80
                    'public' => \base64_encode($model->getBoxPublicKey()),
81
                    'signing' => \base64_encode($model->getSignPublicKey()),
82
                    'signature' => \base64_encode(\Sodium\crypto_sign(
83
                        $model->getBoxPublicKey(),
84
                        \base64_decode($model->secret_sign_kp)
85
                    )),
86
                    'hash' => $model->hash
87
                ];
88
            }
89
90
            return $tokens;
91
        }
92
            
93
        throw new \yii\base\Exception(Yii::t('yrc', 'Token failed to save'));
94
    }
95
}