Issues (5)

src/VerifyHandler.php (2 issues)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace SilverStripe\TOTP;
6
7
use Exception;
8
use Psr\Log\LoggerInterface;
9
use RuntimeException;
10
use SilverStripe\Control\HTTPRequest;
11
use SilverStripe\Core\Injector\Injectable;
12
use SilverStripe\Core\Injector\Injector;
13
use SilverStripe\MFA\Exception\AuthenticationFailedException;
14
use SilverStripe\MFA\Method\Handler\VerifyHandlerInterface;
15
use SilverStripe\MFA\Model\RegisteredMethod;
16
use SilverStripe\MFA\Service\EncryptionAdapterInterface;
17
use SilverStripe\MFA\State\Result;
18
use SilverStripe\MFA\Store\StoreInterface;
19
20
/**
21
 * Handles verification requests using a time-based one-time password (TOTP) with the silverstripe/mfa module.
22
 */
23
class VerifyHandler implements VerifyHandlerInterface
24
{
25
    use Injectable;
26
    use TOTPAware;
27
28
    /**
29
     * @var string[]
30
     */
31
    private static $dependencies = [
0 ignored issues
show
The private property $dependencies is not used, and could be removed.
Loading history...
32
        'Logger' => '%$' . LoggerInterface::class . '.mfa',
33
    ];
34
35
    /**
36
     * @var LoggerInterface
37
     */
38
    protected $logger;
39
40
    public function start(StoreInterface $store, RegisteredMethod $method): array
41
    {
42
        try {
43
            $data = json_decode((string) $method->Data, true);
44
            if (!$data || !isset($data['secret'])) {
45
                throw new RuntimeException('TOTP secret is not available in the registered method data');
46
            }
47
48
            $key = $this->getEncryptionKey();
49
            if (empty($key)) {
50
                throw new AuthenticationFailedException(
51
                    'Please define a SS_MFA_SECRET_KEY environment variable for encryption'
52
                );
53
            }
54
55
            // Decrypt the TOTP secret from the registered method
56
            $secret = Injector::inst()->get(EncryptionAdapterInterface::class)->decrypt($data['secret'], $key);
57
58
            $store->setState([
59
                'secret' => $secret,
60
            ]);
61
62
            $enabled = true;
63
        } catch (Exception $ex) {
64
            // noop: encryption may not be defined, so method should be disabled rather than application error
65
            $enabled = false;
66
67
            $this->getLogger()->debug($ex->getMessage(), $ex->getTrace());
68
        }
69
70
        return [
71
            'enabled' => $enabled,
72
            'codeLength' => $method->getMethod()->getCodeLength(),
0 ignored issues
show
The method getCodeLength() does not exist on SilverStripe\MFA\Method\MethodInterface. It seems like you code against a sub-type of SilverStripe\MFA\Method\MethodInterface such as SilverStripe\TOTP\Method. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

72
            'codeLength' => $method->getMethod()->/** @scrutinizer ignore-call */ getCodeLength(),
Loading history...
73
        ];
74
    }
75
76
    public function verify(HTTPRequest $request, StoreInterface $store, RegisteredMethod $registeredMethod): Result
77
    {
78
        $data = json_decode($request->getBody(), true);
79
        if (!$this->getTotp($store)->verify($data['code'] ?? '')) {
80
            return Result::create(false, _t(__CLASS__ . '.INVALID_CODE', 'Invalid code'));
81
        }
82
        return Result::create();
83
    }
84
85
    public function getComponent(): string
86
    {
87
        return 'TOTPVerify';
88
    }
89
90
    /**
91
     * @return LoggerInterface
92
     */
93
    public function getLogger(): ?LoggerInterface
94
    {
95
        return $this->logger;
96
    }
97
98
    /**
99
     * @param LoggerInterface $logger
100
     * @return VerifyHandler
101
     */
102
    public function setLogger(LoggerInterface $logger): VerifyHandler
103
    {
104
        $this->logger = $logger;
105
        return $this;
106
    }
107
}
108