Completed
Push — master ( 151189...cefe09 )
by Vitor
27s queued 22s
created

AProvider::getSessionKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 2
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
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
			$this->gateway->send(
89
				$identifier,
90
				$this->l10n->t('%s is your Nextcloud authentication code', [
91
					$secret
92
				]),
93
				['code' => $secret],
94
			);
95
		} catch (MessageTransmissionException) {
96
			return $this->templateManager->getTemplate('twofactor_gateway', 'error');
97
		}
98
99
		$tmpl = $this->templateManager->getTemplate('twofactor_gateway', 'challenge');
100
		$tmpl->assign('phone', PhoneNumberMask::maskNumber($identifier));
101
		return $tmpl;
102
	}
103
104
	#[\Override]
105
	public function verifyChallenge(IUser $user, string $challenge): bool {
106
		$valid = $this->session->exists($this->getSessionKey())
107
			&& $this->session->get($this->getSessionKey()) === $challenge;
108
109
		if ($valid) {
110
			$this->session->remove($this->getSessionKey());
111
		}
112
113
		return $valid;
114
	}
115
116 2
	#[\Override]
117
	public function isTwoFactorAuthEnabledForUser(IUser $user): bool {
118 2
		return $this->stateStorage->get($user, $this->getGatewayName())->getState() === StateStorage::STATE_ENABLED;
119
	}
120
121
	#[\Override]
122
	public function getPersonalSettings(IUser $user): IPersonalProviderSettings {
123
		$this->initialState->provideInitialState('settings-' . $this->gateway->getProviderId(), $this->gateway->getSettings());
124
		return new PersonalSettings(
125
			$this->getGatewayName(),
126
			$this->gateway->isComplete(),
127
		);
128
	}
129
130
	#[\Override]
131
	public function getLightIcon(): String {
132
		return Server::get(IURLGenerator::class)->imagePath(Application::APP_ID, 'app.svg');
133
	}
134
135
	#[\Override]
136
	public function getDarkIcon(): String {
137
		return Server::get(IURLGenerator::class)->imagePath(Application::APP_ID, 'app-dark.svg');
138
	}
139
140
	#[\Override]
141
	public function disableFor(IUser $user) {
142
		$state = $this->stateStorage->get($user, $this->getGatewayName());
143
		if ($state->getState() === StateStorage::STATE_ENABLED) {
144
			$this->stateStorage->persist($state->disabled($user, $this->getGatewayName()));
145
		}
146
	}
147
}
148