Passed
Pull Request — master (#38)
by Simon
01:51
created

MemberExtension::getBackupcodes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Firesphere\BootstrapMFA\Extensions;
4
5
use DateTime;
6
use Firesphere\BootstrapMFA\Authenticators\BootstrapMFAAuthenticator;
7
use Firesphere\BootstrapMFA\Models\BackupCode;
8
use Firesphere\BootstrapMFA\Providers\BootstrapMFAProvider;
9
use SilverStripe\Control\Controller;
10
use SilverStripe\Core\Config\Config;
11
use SilverStripe\Core\Injector\Injector;
12
use SilverStripe\Forms\CheckboxField;
13
use SilverStripe\Forms\FieldList;
14
use SilverStripe\Forms\LiteralField;
15
use SilverStripe\Forms\Tab;
16
use SilverStripe\ORM\DataExtension;
17
use SilverStripe\ORM\DataList;
18
use SilverStripe\Security\Member;
19
use SilverStripe\SiteConfig\SiteConfig;
20
21
/**
22
 * Class MemberExtension
23
 *
24
 * @package Firesphere\BootstrapMFA
25
 * @property Member|MemberExtension $owner
26
 * @property boolean $MFAEnabled
27
 * @property string $PrimaryMFA
28
 * @method DataList|BackupCode[] BackupCodes()
29
 */
30
class MemberExtension extends DataExtension
31
{
32
    /**
33
     * @var array
34
     */
35
    private static $db = [
0 ignored issues
show
introduced by
The private property $db is not used, and could be removed.
Loading history...
36
        'MFAEnabled' => 'Boolean(false)',
37
        'PrimaryMFA' => 'Varchar(255)',
38
    ];
39
40
    /**
41
     * @var array
42
     */
43
    private static $has_many = [
0 ignored issues
show
introduced by
The private property $has_many is not used, and could be removed.
Loading history...
44
        'BackupCodes' => BackupCode::class
45
    ];
46
47
    /**
48
     * @var bool
49
     */
50
    public $updateMFA = false;
51
52
    /**
53
     * @param FieldList $fields
54
     */
55
    public function updateCMSFields(FieldList $fields)
56
    {
57
        // Force the updateMFA value of this field. This resolves that when it's checked and submitted
58
        // The checkbox stays checked.
59
        $this->updateMFA = false;
60
        $fields->removeByName(['BackupCodes', 'PrimaryMFA']);
61
        $session = Controller::curr()->getRequest()->getSession();
62
        $rootTabSet = $fields->fieldByName('Root');
63
        $field = LiteralField::create('tokens', $session->get('tokens'));
64
        // We need to push the tab for unit tests
65
        $tab = Tab::create(
66
            'MFA',
67
            _t(self::class . '.MFATAB', 'Multi Factor Authentication')
68
        );
69
        $rootTabSet->push(
70
            $tab
71
        );
72
        $fields->addFieldToTab(
73
            'Root.MFA',
74
            $enabled = CheckboxField::create('MFAEnabled', _t(self::class . '.MFAEnabled', 'MFA Enabled'))
75
        );
76
        $fields->addFieldToTab(
77
            'Root.MFA',
78
            CheckboxField::create('updateMFA', _t(self::class . '.RESETMFA', 'Reset MFA codes'))
79
        );
80
81
        if ($session->get('tokens')) {
82
            $fields->addFieldToTab('Root.MFA', $field);
83
            $session->clear('tokens');
84
        }
85
    }
86
87
    /**
88
     * Force enable MFA on the member if needed
89
     */
90
    public function onBeforeWrite()
91
    {
92
        if (!$this->owner->MFAEnabled && SiteConfig::current_site_config()->ForceMFA) {
93
            $this->owner->MFAEnabled = true;
94
            $this->owner->updateMFA = true;
95
        }
96
    }
97
98
    /**
99
     *
100
     * @throws \Psr\Container\NotFoundExceptionInterface
101
     */
102
    public function onAfterWrite()
103
    {
104
        parent::onAfterWrite();
105
        if ($this->owner->updateMFA) {
106
            $provider = Injector::inst()->get(BootstrapMFAProvider::class);
107
            $provider->setMember($this->owner);
108
            $provider->updateTokens();
109
        }
110
    }
111
112
    public function isInGracePeriod()
113
    {
114
        /** @var Member|MemberExtension $member */
115
        $member = $this->owner;
116
117
        // If MFA is enabled on the member, we're always using it
118
        if ($member->MFAEnabled) {
119
            return false;
120
        }
121
122
        /** @var SiteConfig|SiteConfigExtension $config */
123
        $config = SiteConfig::current_site_config();
124
        // If MFA is not enforced, we're in an endless grace period
125
        if ($config->ForceMFA === null) {
126
            return true;
127
        }
128
129
        $graceStartDay = ($member->Created > $config->ForceMFA) ? $member->Created : $config->ForceMFA;
0 ignored issues
show
Bug Best Practice introduced by
The property Created does not exist on Firesphere\BootstrapMFA\Extensions\MemberExtension. Did you maybe forget to declare it?
Loading history...
130
        $graceStartDay = new DateTime($graceStartDay);
131
132
        $gracePeriod = Config::inst()->get(BootstrapMFAAuthenticator::class, 'grace_period');
133
134
        $nowDate = new DateTime(date('Y-m-d'));
135
136
        $diff = $nowDate->diff($graceStartDay)->format('%a');
137
138
        return !($diff >= $gracePeriod);
139
    }
140
}
141