\WP_REST_Server::CREATABLE, 'callback' => array( $this, 'start' ), 'permission_callback' => array( $this, 'can_manage' ), 'args' => array( 'features' => self::arg( array( 'type' => 'array', 'items' => array( 'type' => 'string', 'enum' => array( 'analytics', 'searchconsole' ), ), 'maxItems' => 2, 'uniqueItems' => true, 'default' => array( 'analytics' ), ) ), ), ) ); register_rest_route( self::REST_NAMESPACE, '/auth/disconnect', array( 'methods' => \WP_REST_Server::CREATABLE, 'callback' => array( $this, 'disconnect' ), 'permission_callback' => array( $this, 'can_manage' ), 'args' => array(), ) ); register_rest_route( self::REST_NAMESPACE, '/auth/byo', array( 'methods' => \WP_REST_Server::CREATABLE, 'callback' => array( $this, 'byo' ), 'permission_callback' => array( $this, 'can_manage' ), 'args' => array( 'client_id' => self::arg( array( 'type' => 'string', 'maxLength' => 256, 'required' => true, ) ), 'client_secret' => self::arg( array( 'type' => 'string', 'maxLength' => 256, 'required' => true, ) ), ), ) ); register_rest_route( self::REST_NAMESPACE, '/auth/accept-url', array( 'methods' => \WP_REST_Server::CREATABLE, 'callback' => array( $this, 'accept_url' ), 'permission_callback' => array( $this, 'can_manage' ), 'args' => array(), ) ); } /** * POST /auth/start → {url}, or tagsmith_https_required (400) when * wp-admin is plain http on a non-local host. * * @param \WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public function start( \WP_REST_Request $request ) { $features = (array) $request->get_param( 'features' ); try { $url = $this->plugin->oauth()->start_url( get_current_user_id(), $features ); } catch ( ApiError $e ) { return $e->to_wp_error(); } return new \WP_REST_Response( array( 'url' => $url ) ); } /** * POST /auth/disconnect → {ok:true}. Also invalidates cached reports. * * On a site whose address changed since it connected, the token is only * forgotten here and not revoked at Google (the site may be a copy that * shares the live site's token), so the answer adds revoke_skipped:true * and a message saying where the access is removed. */ public function disconnect(): \WP_REST_Response { $revoke_skipped = $this->plugin->oauth()->disconnect(); $this->plugin->reports()->clear_cache(); if ( $revoke_skipped ) { return new \WP_REST_Response( array( 'ok' => true, 'revoke_skipped' => true, 'message' => __( "This site is disconnected, but Tagsmith did not revoke its access at Google: the site's address has changed, so another copy of this site may still use it. To remove the access, go to myaccount.google.com/permissions.", 'tagsmith' ), ) ); } return new \WP_REST_Response( array( 'ok' => true ) ); } /** * POST /auth/byo: both empty clears the credentials; otherwise both are * required and the client id must be a Google OAuth client id. Returns * the connection summary (never the secret). * * @param \WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public function byo( \WP_REST_Request $request ) { $client_id = trim( (string) $request->get_param( 'client_id' ) ); $client_secret = trim( (string) $request->get_param( 'client_secret' ) ); $connection = $this->plugin->connection(); if ( '' === $client_id && '' === $client_secret ) { if ( 'byo' === $connection->mode() ) { // The BYO connection cannot refresh without its client, so // removing the client also disconnects (best-effort revoke). $this->plugin->oauth()->disconnect(); $this->plugin->reports()->clear_cache(); } $connection->set_byo_credentials( null, null ); return new \WP_REST_Response( $connection->summary() ); } if ( 1 !== preg_match( '/' . self::CLIENT_ID_PATTERN . '/', $client_id ) ) { return new \WP_Error( 'tagsmith_invalid_client_id', __( 'Enter the full client ID of your Google OAuth client, as shown in Google Cloud under APIs and Services, Credentials.', 'tagsmith' ), array( 'status' => 400 ) ); } if ( '' === $client_secret || 1 !== preg_match( '/^[\x21-\x7E]+$/', $client_secret ) ) { return new \WP_Error( 'tagsmith_invalid_client_secret', __( 'Enter the client secret for this Google OAuth client.', 'tagsmith' ), array( 'status' => 400 ) ); } $connection->set_byo_credentials( $client_id, $client_secret ); return new \WP_REST_Response( $connection->summary() ); } /** * POST /auth/accept-url: keeps the connection after a site address change. */ public function accept_url(): \WP_REST_Response { $connection = $this->plugin->connection(); $connection->accept_home_url(); return new \WP_REST_Response( $connection->summary() ); } }