Passed
Push — master ( fae04d...859641 )
by Artem
01:45
created

CodeManager::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Prozorov\DataVerification;
6
7
use Prozorov\DataVerification\Exceptions\{LimitException, VerificationException};
8
use Prozorov\DataVerification\Models\Code;
9
use Prozorov\DataVerification\Types\Address;
10
11
class CodeManager
12
{
13
    /**
14
     * @var Configuration $config
15
     */
16
    protected $config;
17
18 10
    public function __construct(Configuration $config)
19
    {
20 10
        $this->config = $config;
21 10
    }
22
23
    /**
24
     * generate.
25
     *
26
     * @access	public
27
     * @param	Address	$address
28
     * @param	array  	$data    	Default: null
29
     * @param	string 	$fakeCode	Default: null
30
     * @return	Code
31
     */
32 6
    public function generate(Address $address, array $data = null, string $fakeCode = null): Code
33
    {
34 6
        $this->checkCreationLimit($address);
35
36 4
        $verificationCode = md5((string) strtotime('now'));
37
38 4
        $code = new Code();
39 4
        $code->setVerificationCode($verificationCode)
40 4
            ->setOneTimePass($this->generateOTP($fakeCode))
41 4
            ->setAddress($address);
42
43 4
        if (!empty($data)) {
44 3
            $code->setVerificationData($data);
45
        }
46
47 4
        $this->config->getCodeRepo()->save($code);
48
49 4
        return $code;
50
    }
51
52
    /**
53
     * verify.
54
     *
55
     * @access	public
56
     * @param	string	$verificationCode	
57
     * @param	string	$pass            	
58
     * @return	Code
59
     */
60 5
    public function verify(string $verificationCode, string $pass): Code
61
    {
62 5
        $seconds = $this->config->getPasswordValidationPeriod();
63
64 5
        $createdAfter = (new \Datetime())->sub(new \DateInterval('PT'.$seconds.'S'));
65 5
        $code = $this->config->getCodeRepo()->getOneUnvalidatedByCode($verificationCode, $createdAfter);
66
67 5
        if (!$code) {
68 1
            throw new \OutOfBoundsException('Данные не найдены');
69
        }
70
71 4
        if ($code->getOneTimePass() !== $pass) {
72 1
            $code->incrementAttempts();
73 1
            throw new VerificationException('Некорректно указан код');
74
        }
75
76 3
        if ($this->config->getAttempts() <= $code->getAttempts()) {
77 1
            throw new LimitException('Превышен лимит');
78
        }
79
80 2
        $code->setValidated();
81
        
82 2
        $this->config->getCodeRepo()->save($code);
83
84 2
        return $code;
85
    }
86
87
    /**
88
     * generateOTP.
89
     *
90
     * @access	protected
91
     * @param	string	$fakeCode	Default: null
92
     * @return	string
93
     */
94 4
    protected function generateOTP(string $fakeCode = null): string
95
    {
96 4
        if (! empty($fakeCode)) {
97 1
            return $fakeCode;
98
        }
99
100 3
        $symbols = $this->config->getAllowedSymbols();
101 3
        $length = $this->config->getPassLength();
102 3
        $otp = '';
103
104 3
        for ($i = 1; $i <= $length; $i++) {
105 3
            $otp .= $symbols[rand(0, (count($symbols) - 1))];
106
        }
107
108 3
        return $otp;
109
    }
110
111
    /**
112
     * checkCreationLimit.
113
     *
114
     * @access	protected
115
     * @param	Address	$address	
116
     * @return	void
117
     */
118 6
    protected function checkCreationLimit(Address $address): void
119
    {
120 6
        $threshold = $this->config->getCreationCodeThreshold();
121
122 6
        $createdAfter = (new \Datetime())->sub(new \DateInterval('PT'.$threshold.'S'));
123
124 6
        if ($this->config->getCodeRepo()->getLastCodeForAddress($address, $createdAfter)) {
125 1
            throw new LimitException('Превышен лимит');
126
        }
127
128 5
        $createdAfter = (new \Datetime())->sub(new \DateInterval('PT3600S'));
129
130 5
        $attempts = $this->config->getCodeRepo()->getCodesCountForAddress($address, $createdAfter);
131
132 5
        if ($attempts > 0) {
133 2
            $limitPerHour = $this->config->getLimitPerHour();
134
135 2
            if ($limitPerHour < $attempts) {
136 1
                throw new LimitException('Превышен лимит обращений в час');
137
            }
138
        }
139 4
    }
140
}
141