Completed
Push — master ( 81e619...f6cb00 )
by Paolo
28s queued 15s
created

PermsHelper::userIsAllowed()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 8
nc 6
nop 1
dl 0
loc 14
rs 9.6111
c 0
b 0
f 0
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2021 ChannelWeb Srl, Chialab Srl
5
 *
6
 * This file is part of BEdita: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
12
 */
13
namespace App\View\Helper;
14
15
use Cake\Utility\Hash;
16
use Cake\View\Helper;
17
18
/**
19
 * Helper class to handle permissions on modules.
20
 */
21
class PermsHelper extends Helper
22
{
23
    /**
24
     * API methods allowed in current module
25
     *
26
     * @var array
27
     */
28
    protected $current = [];
29
30
    /**
31
     * API methods allowed in all modules
32
     *
33
     * @var array
34
     */
35
    protected $allowed = [];
36
37
    /**
38
     * {@inheritDoc}
39
     *
40
     * Init API and WebAPP base URL
41
     *
42
     * @return  void
43
     */
44
    public function initialize(array $config): void
45
    {
46
        $modules = (array)$this->_View->get('modules');
47
        // using foreach instead of Hash::combine
48
        // to avoid RuntimeError "Hash::combine() needs an equal number of keys + values"
49
        foreach ($modules as $name => $module) {
50
            if (Hash::check($module, 'hints.allow')) {
51
                $this->allowed[$name] = Hash::get($module, 'hints.allow');
52
            }
53
        }
54
        $currentModule = (array)$this->_View->get('currentModule');
55
        $this->current = (array)Hash::get($currentModule, 'hints.allow');
56
    }
57
58
    /**
59
     * Check lock/unlock permission.
60
     *
61
     * @return bool
62
     */
63
    public function canLock(): bool
64
    {
65
        return $this->userIsAdmin();
66
    }
67
68
    /**
69
     * Check create permission.
70
     *
71
     * @param string|null $module Module name
72
     * @return bool
73
     */
74
    public function canCreate(?string $module = null): bool
75
    {
76
        return $this->isAllowed('POST', $module) && $this->userIsAllowed($module);
77
    }
78
79
    /**
80
     * Check delete permission.
81
     *
82
     * @param array $object The object
83
     * @return bool
84
     */
85
    public function canDelete(array $object): bool
86
    {
87
        $locked = (bool)Hash::get($object, 'meta.locked', false);
88
        $module = (string)Hash::get($object, 'type');
89
90
        return !$locked && $this->isAllowed('DELETE', $module) && $this->userIsAllowed($module);
91
    }
92
93
    /**
94
     * Check save permission.
95
     *
96
     * @param string|null $module Module name
97
     * @return bool
98
     */
99
    public function canSave(?string $module = null): bool
100
    {
101
        return $this->isAllowed('PATCH', $module) && $this->userIsAllowed($module);
102
    }
103
104
    /**
105
     * Check read permission.
106
     *
107
     * @param string|null $module Module name
108
     * @return bool
109
     */
110
    public function canRead(?string $module = null): bool
111
    {
112
        return $this->isAllowed('GET', $module);
113
    }
114
115
    /**
116
     * Check if a method is allowed on a module.
117
     *
118
     * @param string $method Method to check
119
     * @param string|null $module Module name, if missing or null current module is used.
120
     * @return bool
121
     */
122
    protected function isAllowed(string $method, ?string $module = null): bool
123
    {
124
        if (empty($module)) {
125
            if (empty($this->current)) {
126
                return true;
127
            }
128
129
            return in_array($method, $this->current);
130
        }
131
132
        $allowed = (array)Hash::get($this->allowed, $module);
133
134
        return in_array($method, $allowed);
135
    }
136
137
    /**
138
     * Access string (can be 'read', 'write', 'hidden') per role and module.
139
     *
140
     * @param array $accessControl The access control array
141
     * @param string $roleName The role name
142
     * @param string $moduleName The module name
143
     * @return string
144
     */
145
    public function access(array $accessControl, string $roleName, string $moduleName): string
146
    {
147
        $roleAccesses = Hash::get($accessControl, $roleName, []);
148
        if (empty($roleAccesses)) {
149
            return 'write';
150
        }
151
        $hiddenModules = Hash::get($roleAccesses, 'hidden', []);
152
        if (in_array($moduleName, $hiddenModules)) {
153
            return 'hidden';
154
        }
155
        $readonlyModules = Hash::get($roleAccesses, 'readonly', []);
156
157
        return in_array($moduleName, $readonlyModules) ? 'read' : 'write';
158
    }
159
160
    /**
161
     * Return true if authenticated user has role admin
162
     *
163
     * @return bool
164
     */
165
    public function userIsAdmin(): bool
166
    {
167
        return in_array('admin', $this->userRoles());
168
    }
169
170
    /**
171
     * Check permissions for user if object is a folder.
172
     *
173
     * @param string|null $module The module, if passed.
174
     * @return bool
175
     */
176
    public function userIsAllowed(?string $module): bool
177
    {
178
        $objectType = !empty($module) ? $module : $this->_View->get('objectType');
179
        if ($objectType !== 'folders' || $this->userIsAdmin()) {
180
            return true;
181
        }
182
183
        $object = $this->_View->get('object');
184
        $permsRoles = (array)Hash::get((array)$object, 'meta.perms.roles');
185
        if (empty($permsRoles)) {
186
            return true;
187
        }
188
189
        return !empty(array_intersect($permsRoles, (array)$this->userRoles()));
190
    }
191
192
    /**
193
     * Return authenticated user roles
194
     *
195
     * @return array
196
     */
197
    public function userRoles(): array
198
    {
199
        /** @var \Authentication\Identity $identity */
200
        $identity = $this->_View->get('user');
201
202
        return (array)$identity->get('roles');
203
    }
204
}
205