Skip to content

Commit 810df09

Browse files
committed
Added basic implementation of "Validator" class.
1 parent cf09b91 commit 810df09

File tree

5 files changed

+305
-119
lines changed

5 files changed

+305
-119
lines changed

phpunit.xml

+4-6
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@
44
<file>tests/essentials/test-autoloader.php</file>
55
<file>tests/essentials/test-base-32.php</file>
66
</testsuite>
7+
<testsuite name="qr-generators">
8+
<file>tests/qr-generators/test-google-qr.php</file>
9+
</testsuite>
710
<testsuite name="elements">
811
<file>tests/elements/test-secret.php</file>
912
<file>tests/elements/test-account.php</file>
1013
<file>tests/elements/test-account-manager.php</file>
11-
</testsuite>
12-
<testsuite name="qr-generators">
13-
<file>tests/qr-generators/test-google-qr.php</file>
14-
</testsuite>
15-
<testsuite name="authenticator">
16-
14+
<file>tests/elements/test-validator.php</file>
1715
</testsuite>
1816
</testsuites>
1917
<filter>

readme.md

+13-6
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,18 @@ $qrUrl = $qr->getUrl($account); // Possible Without Storage Location
229229

230230
QR codes are generated only once, when the location is initially requested, but you can always regenerate them if something goes wrong using the "regenerate" method. Also, keep in mind that, using the "generate" method before requesting QR code's location may improve overall performance if implemented correctly.
231231

232-
### Example 11 - Authenticator
232+
### Example 11 - Validator
233233

234-
...
234+
Validating provided 6-digit codes is extremely simple, you just need to instantiate the validator and utilize the "isCodeValid" method.
235+
236+
```php
237+
$validator = Jocic\GoogleAuthenticator\Validator();
238+
239+
if (!$validator->isCodeValid($code, $account))
240+
{
241+
// Handle Invalid Code
242+
}
243+
```
235244

236245
## Installation
237246

@@ -249,17 +258,15 @@ composer require jocic/google-authenticator dev-master
249258
Following unit tests are available:
250259

251260
* **Essentials** - Tests for library's essentials ex. Autoloader, Base 32 encoder, etc.
252-
* **Elements** - Tests for library's core elements ex. Secret, Account, etc.
253261
* **QR Generators** - Tests for available QR code generators in the library.
254-
* **Authenticator** - Tests for authenticator's methods.
262+
* **Elements** - Tests for library's core elements ex. Secret, Account, etc.
255263

256264
You can execute them easily from the terminal like in the example below.
257265

258266
```bash
259267
bash ./scripts/phpunit.sh --testsuite essentials
260-
bash ./scripts/phpunit.sh --testsuite elements
261268
bash ./scripts/phpunit.sh --testsuite qr-generators
262-
bash ./scripts/phpunit.sh --testsuite authenticator
269+
bash ./scripts/phpunit.sh --testsuite elements
263270
```
264271

265272
Please don’t forget to install necessary dependencies before attempting to do the God's work above. They may be important.

source/Jocic/GoogleAuthenticator/GoogleAuthenticatorInterface.php

-86
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
<?php
2+
3+
/*******************************************************************\
4+
|* Author: Djordje Jocic *|
5+
|* Year: 2018 *|
6+
|* License: MIT License (MIT) *|
7+
|* =============================================================== *|
8+
|* Personal Website: http://www.djordjejocic.com/ *|
9+
|* =============================================================== *|
10+
|* Permission is hereby granted, free of charge, to any person *|
11+
|* obtaining a copy of this software and associated documentation *|
12+
|* files (the "Software"), to deal in the Software without *|
13+
|* restriction, including without limitation the rights to use, *|
14+
|* copy, modify, merge, publish, distribute, sublicense, and/or *|
15+
|* sell copies of the Software, and to permit persons to whom the *|
16+
|* Software is furnished to do so, subject to the following *|
17+
|* conditions. *|
18+
|* --------------------------------------------------------------- *|
19+
|* The above copyright notice and this permission notice shall be *|
20+
|* included in all copies or substantial portions of the Software. *|
21+
|* --------------------------------------------------------------- *|
22+
|* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *|
23+
|* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES *|
24+
|* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *|
25+
|* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *|
26+
|* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, *|
27+
|* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, RISING *|
28+
|* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *|
29+
|* OTHER DEALINGS IN THE SOFTWARE. *|
30+
\*******************************************************************/
31+
32+
namespace Jocic\GoogleAuthenticator;
33+
34+
use Jocic\GoogleAuthenticator\Encoders\Base\Base32;
35+
36+
/**
37+
* <i>Validator</i> class is used for generating QR codes, and validating
38+
* provided one-time passwords.
39+
*
40+
* @author Djordje Jocic <office@djordjejocic.com>
41+
* @copyright 2018 All Rights Reserved
42+
* @version 1.0.0
43+
*/
44+
45+
class Validator implements ValidatorInterface
46+
{
47+
/******************\
48+
|* CORE CONSTANTS *|
49+
\******************/
50+
51+
// CORE CONSTANTS GO HERE
52+
53+
/******************\
54+
|* CORE VARIABLES *|
55+
\******************/
56+
57+
// CORE VARIABLES GO HERE
58+
59+
/*******************\
60+
|* MAGIC FUNCTIONS *|
61+
\*******************/
62+
63+
// MAGIC FUNCTIONS GO HERE
64+
65+
/***************\
66+
|* GET METHODS *|
67+
\***************/
68+
69+
/**
70+
* Returns previous code generated for the account.
71+
*
72+
* @author Djordje Jocic <office@djordjejocic.com>
73+
* @copyright 2018 All Rights Reserved
74+
* @version 1.0.0
75+
*
76+
* @param string $account
77+
* Account that should be used for code generation.
78+
* @return string
79+
* 6-digit code that was valid in the previous cycle.
80+
*/
81+
82+
public function getPreviousCode($account)
83+
{
84+
// Logic
85+
86+
return $this->generateCode($account->getAccountSecret(), -1);
87+
}
88+
89+
/**
90+
* Returns current code generated for the account.
91+
*
92+
* @author Djordje Jocic <office@djordjejocic.com>
93+
* @copyright 2018 All Rights Reserved
94+
* @version 1.0.0
95+
*
96+
* @param string $account
97+
* Account that should be used for code generation.
98+
* @return string
99+
* 6-digit code that is valid in the current cycle.
100+
*/
101+
102+
public function getCurrentCode($account)
103+
{
104+
// Logic
105+
106+
return $this->generateCode($account->getAccountSecret(), 0);
107+
}
108+
109+
/**
110+
* Returns next code generated for the account.
111+
*
112+
* @author Djordje Jocic <office@djordjejocic.com>
113+
* @copyright 2018 All Rights Reserved
114+
* @version 1.0.0
115+
*
116+
* @param string $account
117+
* Account that should be used for code generation.
118+
* @return string
119+
* 6-digit code that is going to be valid in the next cycle.
120+
*/
121+
122+
public function getNextCode($account)
123+
{
124+
// Logic
125+
126+
return $this->generateCode($account->getAccountSecret(), 1);
127+
}
128+
129+
/***************\
130+
|* SET METHODS *|
131+
\***************/
132+
133+
// SET METHODS GO HERE
134+
135+
/****************\
136+
|* CORE METHODS *|
137+
\****************/
138+
139+
// CORE METHODS GO HERE
140+
141+
/*****************\
142+
|* CHECK METHODS *|
143+
\*****************/
144+
145+
/**
146+
* Returns previous code generated for the account.
147+
*
148+
* @author Djordje Jocic <office@djordjejocic.com>
149+
* @copyright 2018 All Rights Reserved
150+
* @version 1.0.0
151+
*
152+
* @param integer $code
153+
* Six-digit code that should be used for validation.
154+
* @param string $account
155+
* Account that should be used for code validation.
156+
* @return bool
157+
* Value <i>TRUE</i> if the provide code is valid, and vice versa.
158+
*/
159+
160+
public function isCodeValid($code, $account)
161+
{
162+
// Logic
163+
164+
return ( $this->getPreviousCode($account) == $code
165+
|| $this->getCurrentCode($account) == $code
166+
|| $this->getNextCode($account) == $code);
167+
}
168+
169+
/*****************\
170+
|* OTHER METHODS *|
171+
\*****************/
172+
173+
/**
174+
* Returns previous code generated for the account.
175+
*
176+
* Note: This method will be refactored as it is not good.
177+
*
178+
* @author Djordje Jocic <office@djordjejocic.com>
179+
* @copyright 2018 All Rights Reserved
180+
* @version 1.0.0
181+
*
182+
* @param object $secret
183+
* Secret object that should be used for code generation.
184+
* @param string $offset
185+
* Offset of the time slice.
186+
* @param string $codeLength
187+
* Length of the generated code.
188+
* @return string
189+
* Generated 6-digit code.
190+
*/
191+
192+
private function generateCode($secret, $offset, $codeLength = 6)
193+
{
194+
// Core Variables
195+
196+
$encoder = new Base32();
197+
$binarySecret = $encoder->decode($secret->getValue());
198+
199+
// Primary Algorithm Variables
200+
201+
$timeSlice = floor(time() / 30) + $offset;
202+
$timePacked = (chr(0) . chr(0) . chr(0) . chr(0) . pack("N*", $timeSlice));
203+
$timeHmac = hash_hmac("sha1", $timePacked, $binarySecret, true);
204+
205+
// Secondary Algorithm Variables
206+
207+
$offset = ord(substr($timeHmac, -1)) & 0x0F;
208+
$hashPart = substr($timeHmac, $offset, 4);
209+
$moduo = pow(10, $codeLength);
210+
$bitMask = 0x7;
211+
$code = null;
212+
213+
// Step 1 - Generate Bit Mask
214+
215+
for ($i = 0; $i <= $codeLength; $i ++)
216+
{
217+
$bitMask = ($bitMask << 4) | 0x0F;
218+
}
219+
220+
// Step 2 - Generate Code
221+
222+
$code = unpack("N", $hashPart);
223+
224+
if (isset($code[1]))
225+
{
226+
$code = $code[1] & $bitMask;
227+
228+
return str_pad(($code % $moduo), $codeLength, "0", STR_PAD_LEFT);
229+
}
230+
231+
return "0";
232+
}
233+
}
234+
235+
?>

0 commit comments

Comments
 (0)