Passed
Pull Request — master (#216)
by Christoph
20:19
created

AProvider::getPersonalSettings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @author Christoph Wurst <[email protected]>
7
 *
8
 * Nextcloud - Two-factor Gateway
9
 *
10
 * This code is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License, version 3,
12
 * as published by the Free Software Foundation.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License, version 3,
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
21
 *
22
 */
23
24
namespace OCA\TwoFactorGateway\Provider;
25
26
use OCA\TwoFactorGateway\Exception\SmsTransmissionException;
27
use OCA\TwoFactorGateway\PhoneNumberMask;
28
use OCA\TwoFactorGateway\Service\Gateway\IGateway;
29
use OCA\TwoFactorGateway\Service\StateStorage;
30
use OCA\TwoFactorGateway\Settings\PersonalSettings;
31
use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings;
32
use OCP\Authentication\TwoFactorAuth\IProvider;
33
use OCP\Authentication\TwoFactorAuth\IProvidesPersonalSettings;
34
use OCP\IL10N;
35
use OCP\ISession;
36
use OCP\IUser;
37
use OCP\Security\ISecureRandom;
38
use OCP\Template;
39
40
abstract class AProvider implements IProvider, IProvidesPersonalSettings {
41
42
	const STATE_DISABLED = 0;
43
	const STATE_START_VERIFICATION = 1;
44
	const STATE_VERIFYING = 2;
45
	const STATE_ENABLED = 3;
46
47
	/** @var string */
48
	protected $gatewayName;
49
50
	/** @var IGateway */
51
	protected $gateway;
52
53
	/** @var StateStorage */
54
	protected $stateStorage;
55
56
	/** @var ISession */
57
	protected $session;
58
59
	/** @var ISecureRandom */
60
	protected $secureRandom;
61
62
	/** @var IL10N */
63
	protected $l10n;
64
65
	private function getSessionKey() {
66
		return "twofactor_gateway_" . $this->gatewayName . "_secret";
67
	}
68
69
	public function __construct(string $gatewayId,
70
								IGateway $gateway,
71
								StateStorage $stateStorage,
72
								ISession $session,
73
								ISecureRandom $secureRandom,
74
								IL10N $l10n) {
75
		$this->gateway = $gateway;
76
		$this->gatewayName = $gatewayId;
77
		$this->stateStorage = $stateStorage;
78
		$this->session = $session;
79
		$this->secureRandom = $secureRandom;
80
		$this->l10n = $l10n;
81
	}
82
83
	/**
84
	 * Get unique identifier of this 2FA provider
85
	 */
86
	public function getId(): string {
87
		return "gateway_$this->gatewayName";
88
	}
89
90
	private function getSecret(): string {
91
		if ($this->session->exists($this->getSessionKey())) {
92
			return $this->session->get($this->getSessionKey());
93
		}
94
95
		$secret = $this->secureRandom->generate(6, ISecureRandom::CHAR_DIGITS);
96
		$this->session->set($this->getSessionKey(), $secret);
97
98
		return $secret;
99
	}
100
101
	/**
102
	 * Get the template for rending the 2FA provider view
103
	 */
104
	public function getTemplate(IUser $user): Template {
105
		$secret = $this->getSecret();
106
107
		try {
108
			$identifier = $this->stateStorage->get($user, $this->gatewayName)->getIdentifier();
109
			$this->gateway->send(
110
				$user,
111
				$identifier,
0 ignored issues
show
Bug introduced by
It seems like $identifier can also be of type null; however, parameter $identifier of OCA\TwoFactorGateway\Ser...ateway\IGateway::send() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

111
				/** @scrutinizer ignore-type */ $identifier,
Loading history...
112
				$this->l10n->t('%s is your Nextcloud authentication code', [
113
					$secret
114
				])
115
			);
116
		} catch (SmsTransmissionException $ex) {
117
			return new Template('twofactor_gateway', 'error');
118
		}
119
120
		$tmpl = new Template('twofactor_gateway', 'challenge');
121
		$tmpl->assign('phone', PhoneNumberMask::maskNumber($identifier));
0 ignored issues
show
Bug introduced by
It seems like $identifier can also be of type null; however, parameter $number of OCA\TwoFactorGateway\PhoneNumberMask::maskNumber() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

121
		$tmpl->assign('phone', PhoneNumberMask::maskNumber(/** @scrutinizer ignore-type */ $identifier));
Loading history...
122
		return $tmpl;
123
	}
124
125
	/**
126
	 * Verify the given challenge
127
	 */
128
	public function verifyChallenge(IUser $user, string $challenge): bool {
129
		$valid = $this->session->exists($this->getSessionKey())
130
			&& $this->session->get($this->getSessionKey()) === $challenge;
131
132
		if ($valid) {
133
			$this->session->remove($this->getSessionKey());
134
		}
135
136
		return $valid;
137
	}
138
139
	/**
140
	 * Decides whether 2FA is enabled for the given user
141
	 */
142
	public function isTwoFactorAuthEnabledForUser(IUser $user): bool {
143
		return $this->stateStorage->get($user, $this->gatewayName)->getState() === self::STATE_ENABLED;
144
	}
145
146
	public function getPersonalSettings(IUser $user): IPersonalProviderSettings {
147
		return new PersonalSettings($this->gatewayName);
148
	}
149
150
}
151