PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.14
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.14
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Modules / Acl / Acl.php

Acl.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.14, at app/Modules/Acl/Acl.php

457 lines 13.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Modules\Acl;
4
5 use FluentForm\App\Services\Manager\FormManagerService;
6 use FluentForm\Framework\Helpers\ArrayHelper;
7
8 class Acl
9 {
10 public static $capability = '';
11
12 public static $role = '';
13
14 public static function normalizeFormId($formId)
15 {
16 if (null === $formId || false === $formId || '' === $formId) {
17 return null;
18 }
19
20 if (is_string($formId)) {
21 $formId = trim($formId);
22 }
23
24 if (!is_int($formId) && (!is_string($formId) || !ctype_digit($formId))) {
25 return null;
26 }
27
28 $formId = (int) $formId;
29
30 return $formId > 0 ? $formId : null;
31 }
32
33 public static function verifyFormId(
34 $formId,
35 $message = 'Invalid form id.',
36 $json = true
37 ) {
38 $formId = static::normalizeFormId($formId);
39
40 if ($formId) {
41 return $formId;
42 }
43
44 if ($json) {
45 wp_send_json_error([
46 'message' => $message,
47 ], 422);
48 }
49
50 throw new \InvalidArgumentException(esc_html($message));
51 }
52
53 public static function getPermissionSet()
54 {
55 $data = [
56 'fluentform_dashboard_access',
57 'fluentform_forms_manager',
58 'fluentform_entries_viewer',
59 'fluentform_manage_entries',
60 'fluentform_view_payments',
61 'fluentform_manage_payments',
62 'fluentform_settings_manager',
63 'fluentform_full_access',
64 ];
65
66 $data = apply_filters_deprecated(
67 'fluentform_permission_set',
68 [
69 $data,
70 ],
71 FLUENTFORM_FRAMEWORK_UPGRADE,
72 'fluentform/permission_set',
73 'Use fluentform/permission_set instead of fluentform_permission_set.'
74 );
75
76 return apply_filters('fluentform/permission_set', $data);
77 }
78
79 /**
80 * Fluentform access controll permissions assignment.
81 */
82 public static function setPermissions()
83 {
84 // Fire an event letting others know that fluentform
85 // is going to assign permission set to a role.
86 do_action_deprecated(
87 'before_fluentform_permission_set_assignment',
88 [
89
90 ],
91 FLUENTFORM_FRAMEWORK_UPGRADE,
92 'fluentform/before_permission_set_assignment',
93 'Use fluentform/before_permission_set_assignment instead of before_fluentform_permission_set_assignment.'
94 );
95
96 do_action('fluentform/before_permission_set_assignment');
97
98 // The permissions that fluentform supports altogether.
99 $permissions = self::getPermissionSet();
100
101 // The role that fluentform will use
102 // to attach the permission set.
103 $role = get_role('administrator');
104
105 if ($role) {
106 // Looping through permission set to add to the role.
107 foreach ($permissions as $permission) {
108 $role->add_cap($permission);
109 }
110 }
111
112 // Fire an event letting others know that fluentform is
113 // done with the permission assignment to the role.
114 do_action_deprecated(
115 'after_fluentform_permission_set_assignment',
116 [
117
118 ],
119 FLUENTFORM_FRAMEWORK_UPGRADE,
120 'fluentform/after_permission_set_assignment',
121 'Use fluentform/after_permission_set_assignment instead of after_fluentform_permission_set_assignment.'
122 );
123 do_action('fluentform/after_permission_set_assignment');
124 }
125
126 /**
127 * Verify if current user has a fluentform permission.
128 *
129 * @param $permission
130 * @param null $formId
131 * @param string $message
132 * @param bool $json
133 *
134 * @throws \Exception
135 */
136 public static function verify(
137 $permission,
138 $formId = null,
139 $message = 'You do not have permission to perform this action.',
140 $json = true
141 ) {
142 static::verifyNonce();
143
144 $allowed = static::hasPermission($permission, $formId);
145
146 if (!$allowed) {
147 if ($json) {
148 wp_send_json_error([
149 'message' => $message,
150 ], 422);
151 } else {
152 throw new \Exception(esc_html($message));
153 }
154 }
155 }
156
157 public static function hasPermission($permissions, $formId = false)
158 {
159 if ($formId && !FormManagerService::hasFormPermission($formId)) {
160 return false;
161 }
162
163 // Only explicit full-access users should bypass individual permission checks.
164 if (static::hasExplicitFullAccess()) {
165 return true;
166 }
167
168 // Skip the role fallback for explicit managers, else a limited manager escalates.
169 $grantedRole = self::isExplicitManager() ? false : static::getCurrentUserCapability();
170
171 foreach ((array) $permissions as $permission) {
172 $allowed = current_user_can($permission);
173
174 // A granted role can satisfy scoped permissions, but never full access.
175 if (!$allowed && $grantedRole && 'fluentform_full_access' !== $permission) {
176 $allowed = true;
177 }
178
179 if (!$allowed) {
180 continue;
181 }
182
183 return static::filterPermissionCheck($permission, $allowed, $formId);
184 }
185
186 return false;
187 }
188
189 private static function hasExplicitFullAccess()
190 {
191 return current_user_can('fluentform_full_access') || current_user_can('manage_options');
192 }
193
194 // Is the CURRENT user a Manager added by name (per-user), not just someone riding a delegated role?
195 private static function isExplicitManager()
196 {
197 $userId = get_current_user_id();
198
199 return (bool) ($userId && self::userHasDirectGrant($userId, wp_get_current_user()));
200 }
201
202 // "Direct grant" = permissions attached to the USER themselves (per-user Manager),
203 // as opposed to access inherited from a delegated WordPress role.
204 private static function userHasDirectGrant($userId, $user)
205 {
206 // Flag set when an admin adds the user via Settings -> Managers.
207 if (get_user_meta($userId, '_fluent_forms_has_role', true)) {
208 return true;
209 }
210
211 // Legacy fallback: caps stored on the user itself ($user->caps), not merged in from a role.
212 foreach (static::getPermissionSet() as $permission) {
213 if ($user && !empty($user->caps[$permission])) {
214 return true;
215 }
216 }
217
218 return false;
219 }
220
221 private static function filterPermissionCheck($permission, $allowed, $formId)
222 {
223 $allowed = apply_filters_deprecated(
224 'fluentform_verify_user_permission_' . $permission,
225 [
226 $allowed,
227 $formId,
228 ],
229 FLUENTFORM_FRAMEWORK_UPGRADE,
230 'fluentform/verify_user_permission_' . $permission,
231 'Use fluentform/verify_user_permission_' . $permission . ' instead of fluentform_verify_user_permission_' . $permission
232 );
233
234 return apply_filters('fluentform/verify_user_permission_' . $permission, $allowed, $formId);
235 }
236
237 public static function hasAnyFormPermission($form_id = false)
238 {
239 $allPermissions = static::getPermissionSet();
240
241 foreach ($allPermissions as $permission) {
242 if (static::hasPermission($permission, $form_id)) {
243 return true;
244 }
245 }
246
247 return false;
248 }
249
250 public static function getCurrentUserCapability()
251 {
252 if (static::$capability) {
253 return static::$capability;
254 }
255
256 if (is_user_logged_in()) {
257 static::$capability = static::findUserCapability(wp_get_current_user());
258 } else {
259 static::$capability = false;
260 }
261
262 return apply_filters('fluentform/current_user_capability', static::$capability);
263 }
264
265 public static function findUserCapability($user)
266 {
267 if (!$user) {
268 return false;
269 }
270
271 if (static::isSuperMan($user)) {
272 return 'manage_options';
273 }
274
275 $capabilities = get_option('_fluentform_form_permission');
276
277 if (is_string($capabilities)) {
278 $capabilities = (array) $capabilities;
279 }
280
281 if (!$capabilities) {
282 return false;
283 }
284
285 foreach ($capabilities as $capability) {
286 if ($user->has_cap($capability)) {
287 return $capability;
288 }
289 }
290
291 return false;
292 }
293
294 public static function getCurrentUserRole()
295 {
296 $user = wp_get_current_user();
297
298 return static::$role = $user->roles[0];
299 }
300
301 public static function verifyNonce($key = 'fluent_forms_admin_nonce')
302 {
303 if (!wp_doing_ajax()) {
304 return;
305 }
306
307 $nonce = wpFluentForm('request')->get($key);
308
309 if (!wp_verify_nonce($nonce, $key)) {
310 $message = __('Nonce verification failed, please try again.', 'fluentform');
311 $message = apply_filters('fluentform/nonce_error', $message);
312
313 wp_send_json_error([
314 'message' => $message,
315 ], 422);
316 }
317 }
318
319 public static function getReadablePermissions()
320 {
321 return [
322 'fluentform_dashboard_access' => [
323 'title' => __('View Forms', 'fluentform'),
324 'depends' => [],
325 ],
326 'fluentform_forms_manager' => [
327 'title' => __('Manage Forms', 'fluentform'),
328 'depends' => [
329 'fluentform_dashboard_access',
330 ],
331 ],
332 'fluentform_entries_viewer' => [
333 'title' => __('View Entries', 'fluentform'),
334 'depends' => [
335 'fluentform_dashboard_access',
336 ],
337 ],
338 'fluentform_manage_entries' => [
339 'title' => __('Manage Entries', 'fluentform'),
340 'depends' => [
341 'fluentform_entries_viewer',
342 ],
343 ],
344 'fluentform_view_payments' => [
345 'title' => __('View Payments', 'fluentform'),
346 'depends' => [
347 'fluentform_dashboard_access',
348 'fluentform_entries_viewer',
349 ],
350 ],
351 'fluentform_manage_payments' => [
352 'title' => __('Manage Payments', 'fluentform'),
353 'depends' => [
354 'fluentform_view_payments',
355 ],
356 ],
357 'fluentform_settings_manager' => [
358 'title' => __('Manage Settings', 'fluentform'),
359 'depends' => [],
360 ],
361 'fluentform_full_access' => [
362 'title' => __('Full Access', 'fluentform'),
363 'depends' => [],
364 ],
365 ];
366 }
367
368 public static function getUserPermissions($user = false)
369 {
370 if (is_numeric($user)) {
371 $user = get_user_by('ID', $user);
372 }
373
374 if (!$user) {
375 return [];
376 }
377
378 $permissionSet = static::getPermissionSet();
379 $isSuperMan = static::isSuperMan($user);
380 $capability = static::findUserCapability($user);
381
382 $isManager = self::userHasDirectGrant($user->ID, $user);
383
384 if ($isSuperMan) {
385 return $permissionSet;
386 }
387
388 $userPermissions = array_values(array_intersect(array_keys($user->allcaps), $permissionSet));
389
390 // Delegated-role users still return before the filter (unchanged boundary);
391 // a manager just reports their own scoped caps instead of the full set.
392 if ($capability) {
393 return $isManager ? $userPermissions : $permissionSet;
394 }
395
396 return apply_filters('fluentform/current_user_permissions', $userPermissions);
397 }
398
399 public static function isSuperMan($user = false)
400 {
401 if ($user) {
402 return $user->has_cap('manage_options');
403 } else {
404 return current_user_can('manage_options');
405 }
406 }
407
408 public static function getCurrentUserPermissions()
409 {
410 return static::getUserPermissions(wp_get_current_user());
411 }
412
413 public static function attachPermissions($user, $permissions)
414 {
415 if (is_numeric($user)) {
416 $user = get_user_by('ID', $user);
417 }
418
419 if (!$user) {
420 return false;
421 }
422
423 if (user_can($user, 'manage_options')) {
424 return $user;
425 }
426
427 $allPermissions = static::getPermissionSet();
428
429 foreach ($allPermissions as $permission) {
430 $user->remove_cap($permission);
431 }
432
433 $permissions = array_intersect($allPermissions, $permissions);
434
435 foreach ($permissions as $permission) {
436 $user->add_cap($permission);
437 }
438
439 /**
440 * Fires after per-user FluentForm permissions are attached.
441 *
442 * Role-level changes already announce themselves via
443 * fluentform/after_permission_set_assignment; this is the per-user
444 * equivalent, so caches keyed on a user's effective permissions can be
445 * invalidated when an individual manager is granted or revoked.
446 *
447 * @since 6.2.5
448 *
449 * @param \WP_User $user The user whose permissions changed.
450 * @param array $permissions The permissions now attached.
451 */
452 do_action('fluentform/after_user_permissions_attached', $user, $permissions);
453
454 return $user;
455 }
456 }
457