AProvider::verifyChallenge()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 10
ccs 0
cts 6
cp 0
rs 10
c 0
b 0
f 0
cc 3
nc 4
nop 2
crap 12
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\Provider;
11
12
use OCA\TwoFactorGateway\AppInfo\Application;
13
use OCA\TwoFactorGateway\Exception\MessageTransmissionException;
14
use OCA\TwoFactorGateway\PhoneNumberMask;
15
use OCA\TwoFactorGateway\Provider\Gateway\Factory as GatewayFactory;
16
use OCA\TwoFactorGateway\Provider\Gateway\IGateway;
17
use OCA\TwoFactorGateway\Service\StateStorage;
18
use OCA\TwoFactorGateway\Settings\PersonalSettings;
19
use OCP\AppFramework\Services\IInitialState;
20
use OCP\Authentication\TwoFactorAuth\IDeactivatableByAdmin;
21
use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings;
22
use OCP\Authentication\TwoFactorAuth\IProvider;
23
use OCP\Authentication\TwoFactorAuth\IProvidesIcons;
24
use OCP\Authentication\TwoFactorAuth\IProvidesPersonalSettings;
25
use OCP\IL10N;
26
use OCP\ISession;
27
use OCP\IURLGenerator;
28
use OCP\IUser;
29
use OCP\Security\ISecureRandom;
30
use OCP\Server;
31
use OCP\Template\ITemplate;
32
use OCP\Template\ITemplateManager;
33
34
abstract class AProvider implements IProvider, IProvidesIcons, IDeactivatableByAdmin, IProvidesPersonalSettings {
35
36
	protected string $gatewayName = '';
37
	protected IGateway $gateway;
38
39
	private function getSessionKey(): string {
40
		return 'twofactor_gateway_' . $this->getGatewayName() . '_secret';
41
	}
42
43 8
	public function __construct(
44
		protected GatewayFactory $gatewayFactory,
45
		protected StateStorage $stateStorage,
46
		protected ISession $session,
47
		protected ISecureRandom $secureRandom,
48
		protected IL10N $l10n,
49
		protected ITemplateManager $templateManager,
50
		protected IInitialState $initialState,
51
	) {
52 8
		$this->gateway = $this->gatewayFactory->get($this->getGatewayName());
53
	}
54
55 8
	private function getGatewayName(): string {
56 8
		if ($this->gatewayName) {
57 4
			return $this->gatewayName;
58
		}
59 8
		$fqcn = static::class;
60 8
		$parts = explode('\\', $fqcn);
61 8
		[$name] = array_slice($parts, -2, 1);
62 8
		$this->gatewayName = strtolower($name);
63 8
		return $this->gatewayName;
64
	}
65
66 2
	#[\Override]
67
	public function getId(): string {
68 2
		return 'gateway_' . $this->getGatewayName();
69
	}
70
71
	private function getSecret(): string {
72
		if ($this->session->exists($this->getSessionKey())) {
73
			return $this->session->get($this->getSessionKey());
74
		}
75
76
		$secret = $this->secureRandom->generate(6, ISecureRandom::CHAR_DIGITS);
77
		$this->session->set($this->getSessionKey(), $secret);
78
79
		return $secret;
80
	}
81
82
	#[\Override]
83
	public function getTemplate(IUser $user): ITemplate {
84
		$secret = $this->getSecret();
85
86
		try {
87
			$identifier = $this->stateStorage->get($user, $this->getGatewayName())->getIdentifier() ?? '';
88
89
			$message = $this->gateway->getSettings()->allow_markdown ?? false
0 ignored issues
show
Bug introduced by
The property allow_markdown does not exist on OCA\TwoFactorGateway\Provider\Settings. Did you mean allowMarkdown?
Loading history...
90
				? $this->l10n->t('`%s` is your Nextcloud authentication code', [$secret])
91
				: $this->l10n->t('%s is your Nextcloud authentication code', [$secret]);
92
93
			$this->gateway->send(
94
				$identifier,
95
				$message,
96
				['code' => $secret],
97
			);
98
		} catch (MessageTransmissionException) {
99
			return $this->templateManager->getTemplate('twofactor_gateway', 'error');
100
		}
101
102
		$tmpl = $this->templateManager->getTemplate('twofactor_gateway', 'challenge');
103
		$tmpl->assign('phone', PhoneNumberMask::maskNumber($identifier));
104
		return $tmpl;
105
	}
106
107
	#[\Override]
108
	public function verifyChallenge(IUser $user, string $challenge): bool {
109
		$valid = $this->session->exists($this->getSessionKey())
110
			&& $this->session->get($this->getSessionKey()) === $challenge;
111
112
		if ($valid) {
113
			$this->session->remove($this->getSessionKey());
114
		}
115
116
		return $valid;
117
	}
118
119 2
	#[\Override]
120
	public function isTwoFactorAuthEnabledForUser(IUser $user): bool {
121 2
		return $this->stateStorage->get($user, $this->getGatewayName())->getState() === StateStorage::STATE_ENABLED;
122
	}
123
124
	#[\Override]
125
	public function getPersonalSettings(IUser $user): IPersonalProviderSettings {
126
		$this->initialState->provideInitialState('settings-' . $this->gateway->getProviderId(), $this->gateway->getSettings());
127
		return new PersonalSettings(
128
			$this->getGatewayName(),
129
			$this->gateway->isComplete(),
130
		);
131
	}
132
133
	#[\Override]
134
	public function getLightIcon(): String {
135
		return Server::get(IURLGenerator::class)->imagePath(Application::APP_ID, 'app.svg');
136
	}
137
138
	#[\Override]
139
	public function getDarkIcon(): String {
140
		return Server::get(IURLGenerator::class)->imagePath(Application::APP_ID, 'app-dark.svg');
141
	}
142
143
	#[\Override]
144
	public function disableFor(IUser $user) {
145
		$state = $this->stateStorage->get($user, $this->getGatewayName());
146
		if ($state->getState() === StateStorage::STATE_ENABLED) {
147
			$this->stateStorage->persist($state->disabled($user, $this->getGatewayName()));
148
		}
149
	}
150
}
151