Completed
Push — master ( 365b59...c70c47 )
by Matze
06:43
created

OneTimePassword::getData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 1
crap 1
1
<?php
2
3
namespace BrainExe\Core\Authentication\TOTP;
4
5
use BrainExe\Core\Annotations\Service;
6
use BrainExe\Core\Application\UserException;
7
use BrainExe\Core\Authentication\Exception\UserNotFoundException;
8
use BrainExe\Core\Authentication\UserProvider;
9
use BrainExe\Core\Authentication\UserVO;
10
use BrainExe\Core\EventDispatcher\EventDispatcher;
11
use BrainExe\Core\Mail\SendMailEvent;
12
use BrainExe\Core\Util\IdGenerator;
13
14
/**
15
 * @Service
16
 */
17
class OneTimePassword
18
{
19
20
    const SECRET_LENGTH = 16;
21
22
    /**
23
     * @var UserProvider
24
     */
25
    private $userProvider;
26
27
    /**
28
     * @var TOTP
29
     */
30
    private $totp;
31
32
    /**
33
     * @var EventDispatcher
34
     */
35
    private $dispatcher;
36
37
    /**
38
     * @var IdGenerator
39
     */
40
    private $idGenerator;
41
42
    /**
43
     * @param UserProvider $databaseUserProvider
44
     * @param TOTP $totp
45
     * @param EventDispatcher $dispatcher
46
     * @param IdGenerator $idGenerator
47
     */
48 9
    public function __construct(
49
        UserProvider $databaseUserProvider,
50
        TOTP $totp,
51
        EventDispatcher $dispatcher,
52
        IdGenerator $idGenerator
53
    ) {
54 9
        $this->userProvider = $databaseUserProvider;
55 9
        $this->totp         = $totp;
56 9
        $this->dispatcher   = $dispatcher;
57 9
        $this->idGenerator  = $idGenerator;
58 9
    }
59
60
    /**
61
     * @param UserVO $userVo
62
     * @return Data
63
     */
64 1
    public function generateSecret(UserVO $userVo)
65
    {
66 1
        $secret = $this->idGenerator->generateRandomId(self::SECRET_LENGTH);
67
68 1
        $userVo->one_time_secret = $secret;
69 1
        $this->userProvider->setUserProperty($userVo, 'one_time_secret');
70
71 1
        return $this->getData($secret);
72
    }
73
74
    /**
75
     * @param $secret
76
     * @return Data
77
     */
78 1
    public function getData($secret)
79
    {
80 1
        $url = $this->totp->getUri($secret);
81
82 1
        $data = new Data();
83 1
        $data->secret = $secret;
84 1
        $data->url    = $url;
85
86 1
        return $data;
87
    }
88
89
    /**
90
     * @param UserVO $userVo
91
     * @param string $givenToken
92
     * @throws UserException
93
     */
94 4
    public function verifyOneTimePassword(UserVO $userVo, $givenToken)
95
    {
96 4
        if (empty($userVo->one_time_secret)) {
97 1
            throw new UserException(_("No one time secret requested"));
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal No one time secret requested does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
98
        }
99
100 3
        if (empty($givenToken)) {
101 1
            throw new UserException(_("No one time token given"));
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal No one time token given does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
102
        }
103
104 2
        $verified = $this->totp->verify($userVo->one_time_secret, $givenToken);
105
106 2
        if (!$verified) {
107 1
            throw new UserException(sprintf(_('Invalid token: "%s"!'), $givenToken));
108
        }
109 1
    }
110
111
    /**
112
     * @param UserVO $userVo
113
     */
114 1
    public function deleteOneTimeSecret(UserVO $userVo)
115
    {
116 1
        $userVo->one_time_secret = null;
117
118 1
        $this->userProvider->setUserProperty($userVo, 'one_time_secret');
119 1
    }
120
121
    /**
122
     * @param string $userName
123
     * @throws UserException
124
     */
125 3
    public function sendCodeViaMail($userName)
126
    {
127
        try {
128 3
            $user = $this->userProvider->loadUserByUsername($userName);
129
130 2
            if (empty($user->email)) {
131 1
                throw new UserException(_('No email address defined for this user'));
132
            }
133 1
            $code = $this->totp->current($user->one_time_secret);
134
135 1
            $event = new SendMailEvent($user->email, $code, $code);
136 1
            $this->dispatcher->dispatchEvent($event);
137 2
        } catch (UserNotFoundException $e) {
138 1
            throw new UserException(_('Invalid username'));
139
        }
140 1
    }
141
}
142