PluginProbe
404 Solution / trunk
404 Solution vtrunk
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / policies / AdminStatusFallbackResolver.php

AdminStatusFallbackResolver.php in 404 Solution trunk, at includes/policies/AdminStatusFallbackResolver.php

89 lines 3.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) {
4 exit;
5 }
6
7 /**
8 * Decides whether a request is from a plugin admin AFTER the primary check has
9 * already failed or thrown.
10 *
11 * This is a distinct job from asking the question in the first place. The
12 * primary answer comes from the admin access policy; this owns what to do when
13 * that answer is missing, which is a ladder of progressively weaker sources
14 * (re-ask the policy, then the current WP user, then network super-admin) with
15 * a fail-closed default at the bottom. AJAX handlers only need the verdict.
16 *
17 * It lives here rather than beside those handlers because it is policy, not
18 * response-building, and because two different endpoint groups want different
19 * rungs of the ladder: most stop after re-asking the policy, while the
20 * pagination endpoint also consults the WP user.
21 *
22 * @see ABJ_404_Solution_AjaxAdminEndpointSupport
23 */
24 class ABJ_404_Solution_AdminStatusFallbackResolver {
25
26 /**
27 * @param bool $isPluginAdmin Current best-known admin status (e.g. from before the throw).
28 * @param bool $includeWpUserFallback If true, also fall back to wp_get_current_user() and
29 * is_super_admin() (used only by getPaginationLinks; other
30 * handlers stop at the policy re-check).
31 * @return bool
32 */
33 public static function resolve(bool $isPluginAdmin, bool $includeWpUserFallback = false): bool {
34 if ($isPluginAdmin) {
35 return true;
36 }
37 $isPluginAdmin = self::askPolicyAgain($isPluginAdmin);
38 if (!$includeWpUserFallback || $isPluginAdmin) {
39 return $isPluginAdmin;
40 }
41 return self::askWordPress();
42 }
43
44 /**
45 * Re-ask the admin access policy, failing closed if it cannot answer.
46 *
47 * @param bool $isPluginAdmin
48 * @return bool
49 */
50 private static function askPolicyAgain(bool $isPluginAdmin): bool {
51 $adminAccessPolicy = abj_service('admin_access_policy');
52 if (!is_object($adminAccessPolicy) || !method_exists($adminAccessPolicy, 'isPluginAdmin')) {
53 return $isPluginAdmin;
54 }
55 try {
56 return (bool)$adminAccessPolicy->isPluginAdmin();
57 } catch (Throwable $e) {
58 // Failing closed to non-admin is deliberate. Losing the reason is
59 // not: this runs only after something upstream already threw, so
60 // swallowing it turns an admin-access outage into "the page shows
61 // less" with nothing linking the two.
62 $logger = abj_service('logging');
63 if (is_object($logger) && method_exists($logger, 'debugMessage')) {
64 $logger->debugMessage(
65 'Admin-status re-check threw; failing closed to non-admin. '
66 . get_class($e) . ' (code ' . (string)$e->getCode() . '): ' . $e->getMessage(),
67 $e
68 );
69 }
70 return false;
71 }
72 }
73
74 /**
75 * The weakest rungs: the current WordPress user, then network super-admin.
76 *
77 * @return bool
78 */
79 private static function askWordPress(): bool {
80 if (function_exists('wp_get_current_user')) {
81 $user = ABJ_404_Solution_UserRef::fromWpUser(wp_get_current_user());
82 if ($user !== null && $user->isAdministrator()) {
83 return true;
84 }
85 }
86 return function_exists('is_super_admin') && is_super_admin();
87 }
88 }
89