Completed
Push — master ( 9231cc...030c4e )
by Robbie
14s queued 11s
created

src/VerifyHandler.php (1 issue)

Labels
Severity
1
<?php declare(strict_types=1);
2
3
namespace SilverStripe\TOTP;
4
5
use Exception;
6
use Psr\Log\LoggerInterface;
7
use RuntimeException;
8
use SilverStripe\Control\HTTPRequest;
9
use SilverStripe\Core\Injector\Injectable;
10
use SilverStripe\Core\Injector\Injector;
11
use SilverStripe\MFA\Exception\AuthenticationFailedException;
12
use SilverStripe\MFA\Method\Handler\VerifyHandlerInterface;
0 ignored issues
show
The type SilverStripe\MFA\Method\...\VerifyHandlerInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
13
use SilverStripe\MFA\Model\RegisteredMethod;
14
use SilverStripe\MFA\Service\EncryptionAdapterInterface;
15
use SilverStripe\MFA\State\Result;
16
use SilverStripe\MFA\Store\StoreInterface;
17
18
/**
19
 * Handles verification requests using a time-based one-time password (TOTP) with the silverstripe/mfa module.
20
 */
21
class VerifyHandler implements VerifyHandlerInterface
22
{
23
    use Injectable;
24
    use TOTPAware;
25
26
    /**
27
     * @var string[]
28
     */
29
    private static $dependencies = [
30
        'Logger' => '%$' . LoggerInterface::class . '.mfa',
31
    ];
32
33
    /**
34
     * @var LoggerInterface
35
     */
36
    protected $logger;
37
38
    public function start(StoreInterface $store, RegisteredMethod $method): array
39
    {
40
        try {
41
            $data = json_decode((string) $method->Data, true);
42
            if (!$data || !isset($data['secret'])) {
43
                throw new RuntimeException('TOTP secret is not available in the registered method data');
44
            }
45
46
            $key = $this->getEncryptionKey();
47
            if (empty($key)) {
48
                throw new AuthenticationFailedException(
49
                    'Please define a SS_MFA_SECRET_KEY environment variable for encryption'
50
                );
51
            }
52
53
            // Decrypt the TOTP secret from the registered method
54
            $secret = Injector::inst()->get(EncryptionAdapterInterface::class)->decrypt($data['secret'], $key);
55
56
            $store->setState([
57
                'secret' => $secret,
58
            ]);
59
60
            $enabled = true;
61
        } catch (Exception $ex) {
62
            // noop: encryption may not be defined, so method should be disabled rather than application error
63
            $enabled = false;
64
65
            $this->getLogger()->debug($ex->getMessage(), $ex->getTrace());
66
        }
67
68
        return [
69
            'enabled' => $enabled,
70
            'codeLength' => $method->getMethod()->getCodeLength(),
71
        ];
72
    }
73
74
    public function verify(HTTPRequest $request, StoreInterface $store, RegisteredMethod $registeredMethod): Result
75
    {
76
        $data = json_decode($request->getBody(), true);
77
        if (!$this->getTotp($store)->verify($data['code'] ?? '')) {
78
            return Result::create(false, _t(__CLASS__ . '.INVALID_CODE', 'Invalid code'));
79
        }
80
        return Result::create();
81
    }
82
83
    public function getLeadInLabel(): string
84
    {
85
        return _t(__CLASS__ . '.NAME', 'Verify with authenticator app');
86
    }
87
88
    public function getComponent(): string
89
    {
90
        return 'TOTPVerify';
91
    }
92
93
    /**
94
     * @return LoggerInterface
95
     */
96
    public function getLogger(): ?LoggerInterface
97
    {
98
        return $this->logger;
99
    }
100
101
    /**
102
     * @param LoggerInterface $logger
103
     * @return VerifyHandler
104
     */
105
    public function setLogger(LoggerInterface $logger): VerifyHandler
106
    {
107
        $this->logger = $logger;
108
        return $this;
109
    }
110
}
111