rawurlencode( home_url() ), 'name' => rawurlencode( wp_strip_all_tags( get_bloginfo( 'name' ) ) ), 'return' => rawurlencode( self::return_url() ), 'state' => rawurlencode( $state ), 'pk' => rawurlencode( $public ), ), rtrim( ASKMYPAGES_APP_URL, '/' ) . '/connect' ); } /** * Finishes connecting when the portal sends the owner back with a code. * * @param string $code Single-use code. * @param string $state State echoed back by the portal. * @return true|WP_Error */ public static function complete( $code, $state ) { $expected = get_transient( self::STATE_TRANSIENT ); if ( ! is_string( $expected ) || ! hash_equals( $expected, (string) $state ) ) { return new WP_Error( 'askmypages_state', __( 'This connection was not started from this site, or it took too long. Click Connect again.', 'askmypages' ) ); } delete_transient( self::STATE_TRANSIENT ); $creds = Api::exchange( $code ); if ( is_wp_error( $creds ) ) { return $creds; } if ( empty( $creds['keyId'] ) || empty( $creds['siteId'] ) || empty( $creds['searchKey'] ) ) { return new WP_Error( 'askmypages_bad_response', __( 'The service sent an incomplete answer. Click Connect again.', 'askmypages' ) ); } Keys::activate_pending( $creds ); delete_option( self::OPT_REVOKED ); Sync::start(); return true; } /** * The service said this site's key was revoked elsewhere (the owner * disconnected it in the account portal, an administrator disabled it, or * a paid account took the site over): forget the dead keys so search and * chat stop and the page offers Connect, and remember why. */ public static function revoked_elsewhere() { Sync::stop(); Keys::forget(); delete_transient( 'askmypages_status' ); delete_option( Chat::OPTION ); delete_transient( Chat::TRANSIENT ); update_option( self::OPT_REVOKED, time(), false ); } /** * Cancels a pending connection when the portal reports it was declined. * Only the returned one-time state may cancel it, so a crafted link cannot * end someone else's connection attempt. * * @param string $state State echoed back by the portal. * @return bool Whether it matched and the pending connection was cleared. */ public static function cancel( $state ) { $expected = get_transient( self::STATE_TRANSIENT ); if ( ! is_string( $expected ) || '' === (string) $state || ! hash_equals( $expected, (string) $state ) ) { return false; } delete_transient( self::STATE_TRANSIENT ); return true; } /** * Disconnects: tells the service, then forgets the keys locally even if the * service could not be reached. * * @return true|WP_Error */ public static function disconnect() { delete_option( self::OPT_REVOKED ); $result = Keys::is_connected() ? Api::signed( 'POST', '/v1/plugin/disconnect' ) : true; Sync::stop(); Keys::forget(); delete_transient( 'askmypages_status' ); delete_option( Chat::OPTION ); delete_transient( Chat::TRANSIENT ); return is_wp_error( $result ) ? $result : true; } }