wpdb = $wpdb; $this->settings = $settings; } /** * Handle scent authentication requests (OAuth2 endpoints) */ public function handle_scent_request(): void { $endpoint = get_query_var('oauth_endpoint'); switch ($endpoint) { case 'authorize': $this->handle_territory_authorization(); break; case 'token': $this->handle_scent_token_exchange(); break; case 'introspect': $this->handle_scent_analysis(); break; case 'revoke': $this->handle_scent_revocation(); break; default: $this->send_error_response(404, 'unknown_territory', 'Unknown territory endpoint'); } } /** * Handle territory authorization (OAuth2 authorize endpoint) */ private function handle_territory_authorization(): void { // Validate query parameters $response_type = sanitize_text_field($_GET['response_type'] ?? ''); $client_id = sanitize_text_field($_GET['client_id'] ?? ''); $redirect_uri = esc_url_raw($_GET['redirect_uri'] ?? ''); $scope = sanitize_text_field($_GET['scope'] ?? ''); $state = sanitize_text_field($_GET['state'] ?? ''); // Validate required parameters for territory access if (empty($response_type) || empty($client_id)) { $this->send_error_response(400, 'invalid_request', 'Missing required territory parameters'); return; } // Only support authorization code (territory code) flow if ($response_type !== 'code') { $this->send_error_response(400, 'unsupported_response_type', 'Only territory code flow is supported'); return; } // Validate client scent credentials $client = $this->recognize_client_scent($client_id); if (!$client) { $this->send_error_response(400, 'invalid_client', 'Unknown client scent'); return; } // Validate redirect URI for safe territory return if (!empty($redirect_uri) && !$this->validate_territory_return_uri($client, $redirect_uri)) { $this->send_error_response(400, 'invalid_request', 'Invalid territory return URI'); return; } // Check if user is authenticated (has proper scent) if (!is_user_logged_in()) { // Redirect to WordPress login with return URL $login_url = wp_login_url(add_query_arg($_GET, admin_url('admin.php'))); wp_redirect($login_url); exit; } // Handle POST request (user authorization decision) if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (isset($_POST['authorize']) && wp_verify_nonce($_POST['_wpnonce'], 'tigerstyle_scent_authorize')) { $this->grant_territory_access($client_id, $redirect_uri, $scope, $state); } elseif (isset($_POST['deny'])) { $this->deny_territory_access($redirect_uri, $state); } return; } // Show territory authorization form $this->show_territory_authorization_form([ 'client' => $client, 'scope' => $scope, 'state' => $state, 'redirect_uri' => $redirect_uri, 'client_id' => $client_id ]); } /** * Handle scent token exchange (OAuth2 token endpoint) */ private function handle_scent_token_exchange(): void { // Only accept POST requests for scent token exchange if ($_SERVER['REQUEST_METHOD'] !== 'POST') { $this->send_error_response(405, 'method_not_allowed', 'Scent exchange requires POST'); return; } $grant_type = sanitize_text_field($_POST['grant_type'] ?? ''); switch ($grant_type) { case 'authorization_code': $this->handle_territory_code_grant(); break; case 'refresh_token': $this->handle_scent_refresh_grant(); break; case 'client_credentials': $this->handle_client_scent_credentials_grant(); break; default: $this->send_error_response(400, 'unsupported_grant_type', 'Unsupported scent grant type'); } } /** * Handle territory code grant (authorization code flow) */ private function handle_territory_code_grant(): void { // Extract scent parameters $code = sanitize_text_field($_POST['code'] ?? ''); $client_id = sanitize_text_field($_POST['client_id'] ?? ''); $redirect_uri = esc_url_raw($_POST['redirect_uri'] ?? ''); $code_verifier = sanitize_text_field($_POST['code_verifier'] ?? ''); // Get client scent credentials from Authorization header or POST $client_credentials = $this->extract_client_scent_credentials(); if ($client_credentials) { $client_id = $client_credentials['client_id']; $client_secret = $client_credentials['client_secret']; } else { $client_secret = sanitize_text_field($_POST['client_secret'] ?? ''); } // Validate required scent parameters if (empty($code) || empty($client_id)) { $this->send_error_response(400, 'invalid_request', 'Missing required scent parameters'); return; } // Get and validate territory code $territory_code = $this->get_territory_code($code); if (!$territory_code) { $this->send_error_response(400, 'invalid_grant', 'Invalid territory code'); return; } // Check if territory code has expired if (strtotime($territory_code['expires']) < time()) { $this->delete_territory_code($code); $this->send_error_response(400, 'invalid_grant', 'Territory code expired'); return; } // Validate client scent match if ($territory_code['client_id'] !== $client_id) { $this->send_error_response(400, 'invalid_client', 'Client scent mismatch'); return; } // Get client details for scent recognition $client = $this->recognize_client_scent($client_id); if (!$client) { $this->send_error_response(400, 'invalid_client', 'Invalid client scent'); return; } // Validate client secret for confidential clients (strong scent verification) if (!$client['is_public']) { if (empty($client_secret) || !hash_equals($client['client_secret'], $client_secret)) { $this->send_error_response(401, 'invalid_client', 'Invalid scent credentials'); return; } } // Validate territory return URI if (!empty($redirect_uri) && $territory_code['redirect_uri'] !== $redirect_uri) { $this->send_error_response(400, 'invalid_grant', 'Territory return URI mismatch'); return; } // Generate scent tokens $scent_token = $this->generate_scent_token($client_id, $territory_code['user_id'], $territory_code['scope']); $refresh_scent = $this->generate_refresh_scent($client_id, $territory_code['user_id'], $territory_code['scope']); // Delete territory code (one-time use like a scent trail) $this->delete_territory_code($code); // Send scent token response $this->send_scent_token_response($scent_token, $refresh_scent, $territory_code['scope']); } /** * Handle scent analysis (OAuth2 introspect endpoint) */ private function handle_scent_analysis(): void { $token = sanitize_text_field($_POST['token'] ?? ''); if (empty($token)) { $this->send_error_response(400, 'invalid_request', 'Missing scent token for analysis'); return; } $scent_data = $this->analyze_scent_token($token); header('Content-Type: application/json'); echo json_encode($scent_data); exit; } /** * Recognize client by their unique scent (get client data) */ private function recognize_client_scent(string $client_id): ?array { // Query WordPress posts to find OAuth2 client by scent signature $posts = get_posts([ 'post_type' => 'oauth2_client', 'meta_key' => 'client_id', 'meta_value' => $client_id, 'posts_per_page' => 1, 'post_status' => 'publish' ]); if (empty($posts)) { return null; } $post = $posts[0]; $client_scent_data = [ 'client_id' => get_post_meta($post->ID, 'client_id', true), 'client_secret' => get_post_meta($post->ID, 'client_secret', true), 'redirect_uris' => get_post_meta($post->ID, 'redirect_uris', true), 'grant_types' => get_post_meta($post->ID, 'grant_types', true), 'scope' => get_post_meta($post->ID, 'scope', true), 'is_public' => (bool)get_post_meta($post->ID, 'is_public', true), 'name' => $post->post_title, 'client_name' => $post->post_title // Add client_name for scent recognition display ]; return $client_scent_data; } /** * Validate territory return URI for safe scent trail */ private function validate_territory_return_uri(array $client, string $redirect_uri): bool { $redirect_uris = $client['redirect_uris'] ?? ''; if (empty($redirect_uris)) { return false; } $allowed_uris = explode(',', $redirect_uris); return in_array($redirect_uri, array_map('trim', $allowed_uris)); } /** * Generate unique scent token (access token) */ private function generate_scent_token(string $client_id, int $user_id, string $scope): string { $scent_token = bin2hex(random_bytes(32)); $expires = date('Y-m-d H:i:s', time() + 3600); // 1 hour scent trail // Store scent token in territory database $this->wpdb->insert( $this->wpdb->prefix . 'oauth_access_tokens', [ 'access_token' => $scent_token, 'client_id' => $client_id, 'user_id' => $user_id, 'expires' => $expires, 'scope' => $scope ] ); return $scent_token; } /** * Generate refresh scent for long-term authentication */ private function generate_refresh_scent(string $client_id, int $user_id, string $scope): string { $refresh_scent = bin2hex(random_bytes(32)); $expires = date('Y-m-d H:i:s', time() + (30 * 24 * 3600)); // 30 day scent memory // Store refresh scent in territory database $this->wpdb->insert( $this->wpdb->prefix . 'oauth_refresh_tokens', [ 'refresh_token' => $refresh_scent, 'client_id' => $client_id, 'user_id' => $user_id, 'expires' => $expires, 'scope' => $scope ] ); return $refresh_scent; } /** * Analyze scent token validity and return data */ public function analyze_scent_token(string $token): ?array { $result = $this->wpdb->get_row( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->prefix}oauth_access_tokens WHERE access_token = %s", $token ), ARRAY_A ); if (!$result) { return ['active' => false]; } // Check if scent has expired if (strtotime($result['expires']) < time()) { // Clean up expired scent $this->wpdb->delete( $this->wpdb->prefix . 'oauth_access_tokens', ['access_token' => $token] ); return ['active' => false]; } return [ 'active' => true, 'client_id' => $result['client_id'], 'user_id' => (int)$result['user_id'], 'scope' => $result['scope'], 'exp' => strtotime($result['expires']) ]; } /** * Show territory authorization form with cat-themed UI */ private function show_territory_authorization_form(array $params): void { // Set content type header('Content-Type: text/html; charset=utf-8'); // TigerStyle Scent authorization form with cat theming ?>
The application "" wants to recognize your scent.