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

MemberExtension::onAfterWrite()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 7
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
        $this->updateMFA = false;
58
        $fields->removeByName(['BackupCodes', 'PrimaryMFA']);
59
        $session = Controller::curr()->getRequest()->getSession();
60
        $rootTabSet = $fields->fieldByName('Root');
61
        $field = LiteralField::create('tokens', $session->get('tokens'));
62
        // We need to push the tab for unit tests
63
        $tab = Tab::create(
64
            'MFA',
65
            _t(self::class . '.MFATAB', 'Multi Factor Authentication')
66
        );
67
        $rootTabSet->push(
68
            $tab
69
        );
70
        $fields->addFieldToTab(
71
            'Root.MFA',
72
            $enabled = CheckboxField::create('MFAEnabled', _t(self::class . '.MFAEnabled', 'MFA Enabled'))
73
        );
74
        $fields->addFieldToTab(
75
            'Root.MFA',
76
            CheckboxField::create('updateMFA', _t(self::class . '.RESETMFA', 'Reset MFA codes'))
77
        );
78
79
        if ($session->get('tokens')) {
80
            $fields->addFieldToTab('Root.MFA', $field);
81
            $session->clear('tokens');
82
        }
83
    }
84
85
    /**
86
     * Force enable MFA on the member if needed
87
     */
88
    public function onBeforeWrite()
89
    {
90
        if (!$this->owner->MFAEnabled && SiteConfig::current_site_config()->ForceMFA) {
91
            $this->owner->MFAEnabled = true;
92
            $this->owner->updateMFA = true;
93
        }
94
    }
95
96
    /**
97
     *
98
     * @throws \Psr\Container\NotFoundExceptionInterface
99
     */
100
    public function onAfterWrite()
101
    {
102
        parent::onAfterWrite();
103
        if ($this->owner->updateMFA) {
104
            $provider = Injector::inst()->get(BootstrapMFAProvider::class);
105
            $provider->setMember($this->owner);
106
            $provider->updateTokens();
107
        }
108
    }
109
110
    public function getBackupcodes()
111
    {
112
        return $this->owner->BackupCodes();
113
    }
114
115
    public function isInGracePeriod()
116
    {
117
        /** @var Member|MemberExtension $member */
118
        $member = $this->owner;
119
120
        // If MFA is enabled on the member, we're always using it
121
        if ($member->MFAEnabled) {
122
            return false;
123
        }
124
125
        /** @var SiteConfig|SiteConfigExtension $config */
126
        $config = SiteConfig::current_site_config();
127
        // If MFA is not enforced, we're in an endless grace period
128
        if ($config->ForceMFA === null) {
129
            return true;
130
        }
131
132
        $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...
133
        $graceStartDay = new DateTime($graceStartDay);
134
135
        $gracePeriod = Config::inst()->get(BootstrapMFAAuthenticator::class, 'grace_period');
136
137
        $nowDate = new DateTime(date('Y-m-d'));
138
139
        $diff = $nowDate->diff($graceStartDay)->format('%a');
140
141
        return !($diff >= $gracePeriod);
142
    }
143
}
144