Completed
Push — master ( 14d226...3a0e06 )
by Joas
10:50
created

BackupCodeStorage::getBackupCodesState()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 1
nop 1
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @author Christoph Wurst <[email protected]>
5
 *
6
 * @license GNU AGPL version 3 or any later version
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22
23
namespace OCA\TwoFactorBackupCodes\Service;
24
25
use OCA\TwoFactorBackupCodes\Db\BackupCode;
26
use OCA\TwoFactorBackupCodes\Db\BackupCodeMapper;
27
use OCP\IUser;
28
use OCP\Security\IHasher;
29
use OCP\Security\ISecureRandom;
30
31
class BackupCodeStorage {
32
33
	/** @var BackupCodeMapper */
34
	private $mapper;
35
36
	/** @var IHasher */
37
	private $hasher;
38
39
	/** @var ISecureRandom */
40
	private $random;
41
42
	public function __construct(BackupCodeMapper $mapper, ISecureRandom $random, IHasher $hasher) {
43
		$this->mapper = $mapper;
44
		$this->hasher = $hasher;
45
		$this->random = $random;
46
	}
47
48
	/**
49
	 * @param IUser $user
50
	 * @return string[]
51
	 */
52
	public function createCodes(IUser $user, $number = 10) {
53
		$result = [];
54
55
		// Delete existing ones
56
		$this->mapper->deleteCodes($user);
57
58
		$uid = $user->getUID();
59
		foreach (range(1, min([$number, 20])) as $i) {
60
			$code = $this->random->generate(10, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');
61
62
			$dbCode = new BackupCode();
63
			$dbCode->setUserId($uid);
64
			$dbCode->setCode($this->hasher->hash($code));
65
			$dbCode->setUsed(0);
66
			$this->mapper->insert($dbCode);
67
68
			array_push($result, $code);
69
		}
70
71
		return $result;
72
	}
73
74
	/**
75
	 * @param IUser $user
76
	 * @return bool
77
	 */
78
	public function hasBackupCodes(IUser $user) {
79
		$codes = $this->mapper->getBackupCodes($user);
80
		return count($codes) > 0;
81
	}
82
83
	/**
84
	 * @param IUser $user
85
	 * @return array
86
	 */
87
	public function getBackupCodesState(IUser $user) {
88
		$codes = $this->mapper->getBackupCodes($user);
89
		$total = count($codes);
90
		$used = 0;
91
		array_walk($codes, function (BackupCode $code) use (&$used) {
92
			if (1 === (int) $code->getUsed()) {
93
				$used++;
94
			}
95
		});
96
		return [
97
			'enabled' => $total > 0,
98
			'total' => $total,
99
			'used' => $used,
100
		];
101
	}
102
103
	/**
104
	 * @param IUser $user
105
	 * @param string $code
106
	 * @return bool
107
	 */
108
	public function validateCode(IUser $user, $code) {
109
		$dbCodes = $this->mapper->getBackupCodes($user);
110
111
		foreach ($dbCodes as $dbCode) {
112
			if (0 === (int) $dbCode->getUsed() && $this->hasher->verify($code, $dbCode->getCode())) {
113
				$dbCode->setUsed(1);
114
				$this->mapper->update($dbCode);
115
				return true;
116
			}
117
		}
118
		return false;
119
	}
120
121
}
122