-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathTotpDisenroll.php
More file actions
133 lines (123 loc) · 3.61 KB
/
Copy pathTotpDisenroll.php
File metadata and controls
133 lines (123 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
<?php
declare(strict_types=1);
namespace FediE2EE\PKDServer\RequestHandlers\Api;
use DateMalformedStringException;
use DateTime;
use FediE2EE\PKD\Crypto\Exceptions\{
CryptoException,
JsonException,
NotImplementedException
};
use FediE2EE\PKDServer\{
Exceptions\CacheException,
Exceptions\DependencyException,
Exceptions\ProtocolException,
Exceptions\TableException,
Interfaces\LimitingHandlerInterface,
Meta\Route,
Traits\ReqTrait,
Traits\TOTPTrait
};
use FediE2EE\PKDServer\Tables\TOTP as TOTPTable;
use JsonException as BaseJsonException;
use Override;
use ParagonIE\CipherSweet\Exception\{
ArrayKeyException,
BlindIndexNotFoundException,
CipherSweetException,
CryptoOperationException,
InvalidCiphertextException
};
use Psr\Http\Message\{
ResponseInterface,
ServerRequestInterface
};
use Psr\Http\Server\RequestHandlerInterface;
use SodiumException;
use Throwable;
use TypeError;
use function is_null;
class TotpDisenroll implements RequestHandlerInterface, LimitingHandlerInterface
{
use ReqTrait;
use TOTPTrait;
protected TOTPTable $totpTable;
/**
* @throws DependencyException
* @throws TableException
* @throws CacheException
*/
public function __construct()
{
$totpTable = $this->table('TOTP');
if (!($totpTable instanceof TOTPTable)) {
throw new TypeError('Could not load TOTP table at runtime');
}
$this->totpTable = $totpTable;
}
/**
* @throws ArrayKeyException
* @throws BaseJsonException
* @throws BlindIndexNotFoundException
* @throws CacheException
* @throws CipherSweetException
* @throws CryptoException
* @throws CryptoOperationException
* @throws DateMalformedStringException
* @throws DependencyException
* @throws InvalidCiphertextException
* @throws JsonException
* @throws NotImplementedException
* @throws SodiumException
* @throws TableException
*/
#[Route("/api/totp/disenroll")]
#[Override]
public function handle(ServerRequestInterface $request): ResponseInterface
{
try {
$parsed = $this->parseTotpBody(
$request->getBody()->getContents(),
'disenrollment',
['actor-id', 'key-id', 'otp'],
);
} catch (Throwable) {
return $this->error('Missing required fields', 400);
}
$body = $parsed['body'];
$sub = $parsed['sub'];
try {
$domain = $this->validateTotpRequest(
$body,
$sub['actor-id'],
$sub['key-id'],
'fedi-e2ee:v1/api/totp/disenroll',
'TOTP-Disenroll',
);
} catch (ProtocolException $ex) {
return $this->error($ex->getMessage(), 400);
}
$totp = $this->totpTable->getTotpByDomain($domain);
if (!$totp) {
return $this->error('TOTP not enabled', 409);
}
$ts = $this->verifyTOTP($totp['secret'], $sub['otp']);
if (is_null($ts)) {
return $this->error('Invalid TOTP code', 403);
}
if ($ts <= $totp['last_time_step']) {
return $this->error('TOTP code already used', 403);
}
$this->totpTable->deleteSecret($domain);
return $this->json([
'!pkd-context' => 'fedi-e2ee:v1/api/totp/disenroll',
'success' => true,
'time' => (string) (new DateTime())->getTimestamp(),
]);
}
#[Override]
public function getEnabledRateLimits(): array
{
return ['ip', 'domain'];
}
}