Passed
Pull Request — master (#675)
by Vitor
06:55 queued 01:42
created

SetupService::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 0
dl 0
loc 8
ccs 1
cts 1
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 6
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * SPDX-FileCopyrightText: 2024 Christoph Wurst <[email protected]>
7
 * SPDX-License-Identifier: AGPL-3.0-or-later
8
 */
9
10
namespace OCA\TwoFactorGateway\Service;
11
12
use Exception;
13
use OCA\TwoFactorGateway\Exception\IdentifierMissingException;
14
use OCA\TwoFactorGateway\Exception\InvalidProviderException;
15
use OCA\TwoFactorGateway\Exception\MessageTransmissionException;
16
use OCA\TwoFactorGateway\Exception\VerificationException;
17
use OCA\TwoFactorGateway\Provider\Factory as ProviderFactory;
18
use OCA\TwoFactorGateway\Provider\Gateway\Factory as GatewayFactory;
19
use OCA\TwoFactorGateway\Provider\State;
20
use OCP\Authentication\TwoFactorAuth\IRegistry;
21
use OCP\IL10N;
22
use OCP\IUser;
23
use OCP\Security\ISecureRandom;
24
25
class SetupService {
26 5
	public function __construct(
27
		private StateStorage $stateStorage,
28
		private GatewayFactory $gatewayFactory,
29
		private ProviderFactory $providerFactory,
30
		private ISecureRandom $random,
31
		private IRegistry $providerRegistry,
32
		private IL10N $l10n,
33
	) {
34 5
	}
35
36
	public function getState(IUser $user, string $gatewayName): State {
37
		return $this->stateStorage->get($user, $gatewayName);
38
	}
39
40
	/**
41
	 * @throws IdentifierMissingException
42
	 */
43
	public function getChallengePhoneNumber(IUser $user, string $gatewayName): string {
44
		$state = $this->stateStorage->get($user, $gatewayName);
45
		$identifier = $state->getIdentifier();
46
		if (is_null($identifier)) {
47
			throw new IdentifierMissingException("verified identifier for $gatewayName is missing");
48
		}
49
50
		return $identifier;
51
	}
52
53
	/**
54
	 * Send out confirmation message and save current identifier in user settings
55
	 *
56
	 * @throws VerificationException
57
	 */
58 2
	public function startSetup(IUser $user, string $gatewayName, string $identifier): State {
59 2
		$verificationNumber = $this->random->generate(6, ISecureRandom::CHAR_DIGITS);
60 2
		$gateway = $this->gatewayFactory->get($gatewayName);
61
		try {
62 2
			$message = $gateway->getSettings()['allow_markdown'] ?? false
63
				? $this->l10n->t('`%s` is your verification code.', [$verificationNumber])
64 2
				: $this->l10n->t('%s is your verification code.', [$verificationNumber]);
65 2
			$gateway->send(
66 2
				$identifier,
67 2
				$message,
68 2
				['code' => $verificationNumber],
69 2
			);
70 1
		} catch (MessageTransmissionException $ex) {
71
			throw new VerificationException($ex->getMessage(), $ex->getCode(), $ex);
72
		}
73
74 1
		return $this->stateStorage->persist(
75 1
			State::verifying($user, $gatewayName, $identifier, $verificationNumber)
76 1
		);
77
	}
78
79 3
	public function finishSetup(IUser $user, string $gatewayName, string $token): State {
80 3
		$state = $this->stateStorage->get($user, $gatewayName);
81 3
		if (is_null($state->getVerificationCode())) {
82 1
			throw new VerificationException($this->l10n->t('no verification code set'));
83
		}
84
85 2
		if ($state->getVerificationCode() !== $token) {
86 1
			throw new VerificationException($this->l10n->t('verification token mismatch'));
87
		}
88
89
		try {
90 1
			$provider = $this->providerFactory->get($gatewayName);
91
		} catch (InvalidProviderException) {
92
			throw new VerificationException('Invalid provider');
93
		}
94 1
		$this->providerRegistry->enableProviderFor($provider, $user);
95
96
		try {
97 1
			return $this->stateStorage->persist(
98 1
				$state->verify()
99 1
			);
100
		} catch (Exception $e) {
101
			throw new VerificationException($e->getMessage());
102
		}
103
	}
104
105
	public function disable(IUser $user, string $gatewayName): State {
106
		try {
107
			$provider = $this->providerFactory->get($gatewayName);
108
		} catch (InvalidProviderException) {
109
			throw new VerificationException('Invalid provider');
110
		}
111
		$this->providerRegistry->enableProviderFor($provider, $user);
112
		$this->providerRegistry->disableProviderFor($provider, $user);
113
114
		try {
115
			return $this->stateStorage->persist(
116
				State::disabled($user, $gatewayName)
117
			);
118
		} catch (Exception $e) {
119
			throw new VerificationException($e->getMessage());
120
		}
121
	}
122
}
123