| | |
| | | } |
| | | |
| | | if (!wp_verify_nonce($nonce, $action)) { |
| | | error_log('[PermissionHandler] Validating nonce....'); |
| | | error_log('Nonce: '.print_r($nonce, true)); |
| | | error_log('Action: '.print_r($action, true)); |
| | | return new WP_Error( |
| | | 'invalid_nonce', |
| | | 'Invalid or expired security token', |
| | |
| | | */ |
| | | public static function verifyActionNonce(WP_REST_Request $request, string $actionPrefix, string $header = 'X-Action-Nonce'): bool|WP_Error |
| | | { |
| | | $userId = $request->get_param('user') ?: get_current_user_id(); |
| | | $userId = absint($request->get_param('user')); |
| | | if ($userId === 0) { |
| | | return false; |
| | | } |
| | | |
| | | $action = $actionPrefix . $userId; |
| | | |
| | | return self::verifyNonce($request, $action, $header); |
| | | } |
| | | |
| | | /** |
| | | * Combined permission check: user match + rate limit |
| | | */ |
| | | public static function userMatchWithRateLimit(WP_REST_Request $request): bool|WP_Error |
| | | { |
| | | static $rateLimiter = null; |
| | | |
| | | if ($rateLimiter === null) { |
| | | $rateLimiter = new RateLimiter(); |
| | | } |
| | | |
| | | // Check rate limit first |
| | | if (!$rateLimiter->checkLimit($request)) { |
| | | return new WP_Error( |
| | | 'rate_limit', |
| | | 'Too many requests. Please wait before trying again.', |
| | | ['status' => 429] |
| | | ); |
| | | } |
| | | |
| | | return self::userMatch($request); |
| | | } |
| | | |
| | | /** |
| | | * Create a custom permission callback combining multiple checks |
| | | * |
| | | * Usage: |
| | |
| | | $check === 'admin' => self::isAdmin($request), |
| | | $check === 'verified' => self::isVerified($request), |
| | | $check === 'user' => self::userMatch($request), |
| | | $check === 'nonce' => self::verifyNonce($request), |
| | | is_array($check) && isset($check['role']) => self::hasRole($request, $check['role']), |
| | | is_array($check) && isset($check['roles']) => self::hasAnyRole($request, $check['roles']), |
| | | is_array($check) && isset($check['capability']) => self::hasCapability($request, $check['capability']), |
| | | is_array($check) && isset($check['actionNonce']) => self::verifyActionNonce($request, $check['actionNonce']), |
| | | is_callable($check) => $check($request), |
| | | default => true, |
| | | }; |
| | |
| | | $check === 'admin' => self::isAdmin($request), |
| | | $check === 'verified' => self::isVerified($request), |
| | | $check === 'user' => self::userMatch($request), |
| | | $check === 'nonce' => self::verifyNonce($request), |
| | | is_array($check) && isset($check['role']) => self::hasRole($request, $check['role']), |
| | | is_array($check) && isset($check['roles']) => self::hasAnyRole($request, $check['roles']), |
| | | is_array($check) && isset($check['capability']) => self::hasCapability($request, $check['capability']), |
| | | is_array($check) && isset($check['actionNonce']) => self::verifyActionNonce($request, $check['actionNonce']), |
| | | is_callable($check) => $check($request), |
| | | default => false, |
| | | }; |
| | | |
| | | // If it's a successful check (true), pass |
| | | if ($result === true) { |
| | | return true; |
| | | } |
| | | |
| | | // Track last error for reporting |
| | | if (is_wp_error($result)) { |
| | | $lastError = $result; |
| | | } |