SetupService::startSetup()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 11
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 3
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @author Christoph Wurst <[email protected]>
7
 *
8
 * @license GNU AGPL version 3 or any later version
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License as
12
 * published by the Free Software Foundation, either version 3 of the
13
 * License, or (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 */
24
25
namespace OCA\TwoFactorGateway\Service;
26
27
use Exception;
28
use OCA\TwoFactorGateway\Exception\IdentifierMissingException;
29
use OCA\TwoFactorGateway\Exception\SmsTransmissionException;
30
use OCA\TwoFactorGateway\Exception\VerificationException;
31
use OCA\TwoFactorGateway\Exception\VerificationTransmissionException;
32
use OCA\TwoFactorGateway\Provider\Factory;
33
use OCA\TwoFactorGateway\Provider\State;
34
use OCA\TwoFactorGateway\Service\Gateway\Factory as GatewayFactory;
35
use OCP\Authentication\TwoFactorAuth\IRegistry;
36
use OCP\IUser;
37
use OCP\Security\ISecureRandom;
38
39
class SetupService {
40
41
	/** @var StateStorage */
42
	private $stateStorage;
43
44
	/** @var GatewayFactory */
45
	private $gatewayFactory;
46
47
	/** @var Factory */
48
	private $providerFactory;
49
50
	/** @var ISecureRandom */
51
	private $random;
52
53
	/** @var IRegistry */
54
	private $providerRegistry;
55
56
	public function __construct(StateStorage $stateStorage,
57
		GatewayFactory $gatewayFactory,
58
		Factory $providerFactory,
59
		ISecureRandom $random,
60
		IRegistry $providerRegistry) {
61
		$this->stateStorage = $stateStorage;
62
		$this->gatewayFactory = $gatewayFactory;
63
		$this->providerFactory = $providerFactory;
64
		$this->random = $random;
65
		$this->providerRegistry = $providerRegistry;
66
	}
67
68
	public function getState(IUser $user, string $gatewayName): State {
69
		return $this->stateStorage->get($user, $gatewayName);
70
	}
71
72
	/**
73
	 * @throws IdentifierMissingException
74
	 */
75
	public function getChallengePhoneNumber(IUser $user, string $gatewayName): string {
76
		$state = $this->stateStorage->get($user, $gatewayName);
77
		$identifier = $state->getIdentifier();
78
		if (is_null($identifier)) {
79
			throw new IdentifierMissingException("verified identifier for $gatewayName is missing");
80
		}
81
82
		return $identifier;
83
	}
84
85
	/**
86
	 * Send out confirmation message and save current identifier in user settings
87
	 */
88
	public function startSetup(IUser $user, string $gatewayName, string $identifier): State {
89
		$verificationNumber = $this->random->generate(6, ISecureRandom::CHAR_DIGITS);
90
		$gateway = $this->gatewayFactory->getGateway($gatewayName);
91
		try {
92
			$gateway->send($user, $identifier, "$verificationNumber is your Nextcloud verification code.");
93
		} catch (SmsTransmissionException $ex) {
94
			throw new VerificationTransmissionException('could not send verification code', $ex->getCode(), $ex);
95
		}
96
97
		return $this->stateStorage->persist(
98
			State::verifying($user, $gatewayName, $identifier, $verificationNumber)
99
		);
100
	}
101
102
	public function finishSetup(IUser $user, string $gatewayName, string $token): State {
103
		$state = $this->stateStorage->get($user, $gatewayName);
104
		if (is_null($state->getVerificationCode())) {
105
			throw new Exception('no verification code set');
106
		}
107
108
		if ($state->getVerificationCode() !== $token) {
109
			throw new VerificationException('verification token mismatch');
110
		}
111
112
		$provider = $this->providerFactory->getProvider($gatewayName);
113
		$this->providerRegistry->enableProviderFor($provider, $user);
114
115
		return $this->stateStorage->persist(
116
			$state->verify()
117
		);
118
	}
119
120
	public function disable(IUser $user, string $gatewayName): State {
121
		$provider = $this->providerFactory->getProvider($gatewayName);
122
		$this->providerRegistry->enableProviderFor($provider, $user);
123
		$this->providerRegistry->disableProviderFor($provider, $user);
124
125
126
		return $this->stateStorage->persist(
127
			State::disabled($user, $gatewayName)
128
		);
129
	}
130
}
131