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

VerifyHandler::verify()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 3
dl 0
loc 7
rs 10
c 0
b 0
f 0
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
Bug introduced by
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 = [
0 ignored issues
show
introduced by
The private property $dependencies is not used, and could be removed.
Loading history...
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(),
0 ignored issues
show
Bug introduced by
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

70
            'codeLength' => $method->getMethod()->/** @scrutinizer ignore-call */ getCodeLength(),
Loading history...
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