Otp::createInstance()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.7085

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 4
cts 7
cp 0.5714
rs 9.8666
c 0
b 0
f 0
cc 3
nc 3
nop 1
crap 3.7085
1
<?php
2
/**
3
 * @link https://github.com/vuongxuongminh/yii2-mfa
4
 * @copyright Copyright (c) 2019 Vuong Xuong Minh
5
 * @license [New BSD License](http://www.opensource.org/licenses/bsd-license.php)
6
 */
7
8
namespace vxm\mfa;
9
10
use yii\base\BaseObject;
11
use yii\base\NotSupportedException;
12
13
use OTPHP\HOTP;
14
use OTPHP\TOTP;
15
16
use ParagonIE\ConstantTime\Base32;
17
18
/**
19
 * Class Otp support generate and validate by given secret key.
20
 *
21
 * @author Vuong Minh <[email protected]>
22
 * @since 1.0.0
23
 */
24
class Otp extends BaseObject
25
{
26
    /**
27
     * TOTP is a time based one-time password. It lives only for a few seconds (the period). You just have to be sure that the clock of your server and your device are synchronized. This is the most common OTP.
28
     */
29
    const TOTP = 0;
30
31
    /**
32
     * HOTP is a counter based one-time password. Every time a password is used, the counter is updated. You have to verify that the server and the device are synchronized.
33
     */
34
    const HOTP = 1;
35
36
    /**
37
     * @var string type of otp
38
     *
39
     * @see self::HOTP
40
     * @see self::TOTP
41
     */
42
    public $type = self::TOTP;
43
44
    /**
45
     * @var int otp digits. Default the number is 6
46
     */
47
    public $digits = 6;
48
49
    /**
50
     * @var string digest algorithm. Default is 'sha1' you can use any algorithm listed by hash_algos(). Note that most applications only support md5, sha1, sha256 and sha512.
51
     */
52
    public $digest = 'sha1';
53
54
    /**
55
     * @var string the template of qr code uri server. Please note that this URI MUST contain a placeholder {PROVISIONING_URI} for the OTP Provisioning URI.
56
     */
57
    public $qrCodeUriTemplate = 'https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl={PROVISIONING_URI}';
58
59
    /**
60
     * Generate an otp digits.
61
     *
62
     * @param string $secretKey the secret key use to generate an otp
63
     * @return string an otp generated by secret key given.
64
     *
65
     * @throws NotSupportedException
66
     */
67 4
    public function generate(string $secretKey)
68
    {
69 4
        return $this->createInstance($secretKey)->now();
70
    }
71
72
    /**
73
     * Validate an otp digits.
74
     *
75
     * @param string $secretKey the secret key use to validate an otp.
76
     * @param string $otp need to verify
77
     * @return bool weather an otp given is valid
78
     *
79
     * @throws NotSupportedException
80
     */
81 3
    public function validate(string $secretKey, string $otp)
82
    {
83 3
        return $this->createInstance($secretKey)->verify($otp);
84
    }
85
86
    /**
87
     * Get qr code for authenticator like google authenticator.
88
     *
89
     * @param string $secretKey the secret key an authenticator use to generating an otp.
90
     * @param array $params list of information use to show on an authenticator app.
91
     *
92
     * Example:
93
     * ```php
94
     * ['issuer' => 'VXM', 'label' => '[email protected]', 'image' => 'https://google.com']
95
     * ```
96
     * @return string the qr code uri
97
     * @throws NotSupportedException
98
     */
99 3
    public function getQrCodeUri(string $secretKey, array $params)
100
    {
101 3
        $instance = $this->createInstance($secretKey);
102
103 3
        foreach ($params as $param => $value) {
104 2
            $instance->setParameter($param, $value);
105
        }
106
107 3
        return $instance->getQrCodeUri($this->qrCodeUriTemplate);
108
    }
109
110
    /**
111
     * Create an otp instance.
112
     *
113
     * @param string $secretKey the secret key use to create an otp instance.
114
     *
115
     * @return HOTP|TOTP an object instance for generate and validate otp.
116
     * @throws NotSupportedException
117
     */
118 8
    protected function createInstance(string $secretKey)
119
    {
120 8
        $secretKey = Base32::encodeUpper($secretKey);
121
122 8
        if ($this->type === self::TOTP) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $this->type (string) and self::TOTP (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
123 8
            return TOTP::create($secretKey, 30, $this->digest, $this->digits);
124
        } elseif ($this->type === self::HOTP) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $this->type (string) and self::HOTP (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
125
            return HOTP::create($secretKey, 0, $this->digest, $this->digits);
126
        } else {
127
            throw new NotSupportedException("An otp type: `{$this->type}` is not supported!");
128
        }
129
    }
130
131
}
132