Authentication
1 week ago
Consent
1 week ago
Endpoints
1 week ago
Helpers
1 week ago
PKCE
1 week ago
Storage
1 week ago
Bootstrap.php
1 week ago
Constants.php
1 week ago
Module.php
1 week ago
Module.php
125 lines
| 1 | <?php |
| 2 | /** |
| 3 | * OAuth 2.1 + DCR service bootstrap. |
| 4 | * |
| 5 | * Installs the OAuth storage schema once AI access is enabled. The individual |
| 6 | * OAuth services (Endpoints, Authentication, Discovery, etc.) are registered as |
| 7 | * their own components in `inc/config/app.php` and self-register their REST |
| 8 | * routes on `rest_api_init`. |
| 9 | * |
| 10 | * @package PrestoPlayer |
| 11 | * @subpackage Services\OAuth |
| 12 | */ |
| 13 | |
| 14 | namespace PrestoPlayer\Services\OAuth; |
| 15 | |
| 16 | use PrestoPlayer\Contracts\Service; |
| 17 | use PrestoPlayer\Services\Abilities\Module as AbilitiesModule; |
| 18 | use PrestoPlayer\Services\OAuth\Storage\Schema; |
| 19 | |
| 20 | /** |
| 21 | * Service entry point for the OAuth integration. |
| 22 | */ |
| 23 | class Module implements Service { |
| 24 | |
| 25 | /** |
| 26 | * Cron hook that triggers the daily storage cleanup. |
| 27 | * |
| 28 | * @var string |
| 29 | */ |
| 30 | public const GC_HOOK = 'presto_player_oauth_gc'; |
| 31 | |
| 32 | /** |
| 33 | * Hook into WordPress. |
| 34 | * |
| 35 | * @return void |
| 36 | */ |
| 37 | public function register() { |
| 38 | add_action( 'init', array( $this, 'ensureSchema' ), 5 ); |
| 39 | // Create the tables the moment AI access is switched on, so the OAuth |
| 40 | // endpoints have storage immediately without waiting for the next load. |
| 41 | add_action( 'add_option_' . AbilitiesModule::OPTION_KEY, array( $this, 'onOptionAdded' ), 10, 2 ); |
| 42 | add_action( 'update_option_' . AbilitiesModule::OPTION_KEY, array( $this, 'onOptionUpdated' ), 10, 2 ); |
| 43 | |
| 44 | // Daily garbage collection so expired/revoked tokens and codes don't pile up. |
| 45 | // Only the handler is wired every request; the schedule is created/torn down |
| 46 | // on the enable/disable transition (see onOptionAdded / onOptionUpdated). |
| 47 | add_action( self::GC_HOOK, array( Schema::class, 'prune' ) ); |
| 48 | } |
| 49 | |
| 50 | /** |
| 51 | * Schedule the daily garbage collection if it isn't already. |
| 52 | * |
| 53 | * @return void |
| 54 | */ |
| 55 | protected function scheduleGc() { |
| 56 | if ( ! wp_next_scheduled( self::GC_HOOK ) ) { |
| 57 | wp_schedule_event( time(), 'daily', self::GC_HOOK ); |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | /** |
| 62 | * Install the schema on `init`, but only when AI access is enabled — sites |
| 63 | * that never use MCP shouldn't get the OAuth tables as a side effect. |
| 64 | * |
| 65 | * @return void |
| 66 | */ |
| 67 | public function ensureSchema() { |
| 68 | if ( ! $this->isEnabled() ) { |
| 69 | return; |
| 70 | } |
| 71 | Schema::installIfNeeded(); |
| 72 | $this->scheduleGc(); |
| 73 | } |
| 74 | |
| 75 | /** |
| 76 | * Install the schema when the option is first created in the enabled state. |
| 77 | * |
| 78 | * @param string $option Option name. |
| 79 | * @param mixed $value New option value. |
| 80 | * @return void |
| 81 | */ |
| 82 | public function onOptionAdded( $option, $value ) { |
| 83 | if ( ! empty( $value['enabled'] ) ) { |
| 84 | Schema::installIfNeeded(); |
| 85 | $this->scheduleGc(); |
| 86 | } else { |
| 87 | wp_clear_scheduled_hook( self::GC_HOOK ); |
| 88 | // Switching AI access off is the only revocation control the site owner |
| 89 | // has, so it has to mean it — otherwise every previously issued grant |
| 90 | // comes straight back the moment the toggle is switched on again. |
| 91 | Schema::revokeAllGrants(); |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | /** |
| 96 | * Install the schema when the option transitions into the enabled state. |
| 97 | * |
| 98 | * @param mixed $old_value Previous option value. |
| 99 | * @param mixed $value New option value. |
| 100 | * @return void |
| 101 | */ |
| 102 | public function onOptionUpdated( $old_value, $value ) { |
| 103 | if ( ! empty( $value['enabled'] ) ) { |
| 104 | Schema::installIfNeeded(); |
| 105 | $this->scheduleGc(); |
| 106 | } else { |
| 107 | wp_clear_scheduled_hook( self::GC_HOOK ); |
| 108 | // Switching AI access off is the only revocation control the site owner |
| 109 | // has, so it has to mean it — otherwise every previously issued grant |
| 110 | // comes straight back the moment the toggle is switched on again. |
| 111 | Schema::revokeAllGrants(); |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | /** |
| 116 | * Whether AI access is enabled. |
| 117 | * |
| 118 | * @return bool |
| 119 | */ |
| 120 | protected function isEnabled() { |
| 121 | $option = get_option( AbilitiesModule::OPTION_KEY, array() ); |
| 122 | return ! empty( $option['enabled'] ); |
| 123 | } |
| 124 | } |
| 125 |