updated plugin ActivityPub version 9.1.0
This commit is contained in:
@ -153,21 +153,13 @@ class Authorization_Controller extends \WP_REST_Controller {
|
||||
// Rate-limit authorization requests to prevent abuse (max 20 per minute per IP).
|
||||
$ip = get_client_ip();
|
||||
if ( '' === $ip ) {
|
||||
return new \WP_Error(
|
||||
'activitypub_rate_limit',
|
||||
\__( 'Too many authorization requests. Please try again later.', 'activitypub' ),
|
||||
array( 'status' => 429 )
|
||||
);
|
||||
return $this->rate_limit_response( \__( 'Too many authorization requests. Please try again later.', 'activitypub' ) );
|
||||
}
|
||||
$transient_key = 'ap_oauth_auth_' . \md5( $ip );
|
||||
$count = (int) \get_transient( $transient_key );
|
||||
|
||||
if ( $count >= 20 ) {
|
||||
return new \WP_Error(
|
||||
'activitypub_rate_limit',
|
||||
\__( 'Too many authorization requests. Please try again later.', 'activitypub' ),
|
||||
array( 'status' => 429 )
|
||||
);
|
||||
return $this->rate_limit_response( \__( 'Too many authorization requests. Please try again later.', 'activitypub' ) );
|
||||
}
|
||||
|
||||
\set_transient( $transient_key, $count + 1, MINUTE_IN_SECONDS );
|
||||
@ -403,4 +395,25 @@ class Authorization_Controller extends \WP_REST_Controller {
|
||||
array( 'Location' => $redirect_url )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a 429 rate-limit response with a Retry-After header.
|
||||
*
|
||||
* @since 9.0.0
|
||||
*
|
||||
* @param string $message Translated human-readable error message.
|
||||
* @return \WP_REST_Response
|
||||
*/
|
||||
private function rate_limit_response( $message ) {
|
||||
return new \WP_REST_Response(
|
||||
array(
|
||||
'code' => 'activitypub_rate_limit',
|
||||
'message' => $message,
|
||||
'data' => array( 'status' => 429 ),
|
||||
),
|
||||
429,
|
||||
// RFC 6585 §4: send Retry-After so clients can back off.
|
||||
array( 'Retry-After' => (string) MINUTE_IN_SECONDS )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,21 +118,13 @@ class Clients_Controller extends \WP_REST_Controller {
|
||||
// Rate-limit registrations to prevent DB spam (max 10 per minute per IP).
|
||||
$ip = get_client_ip();
|
||||
if ( '' === $ip ) {
|
||||
return new \WP_Error(
|
||||
'activitypub_rate_limited',
|
||||
\__( 'Too many client registration requests. Please try again later.', 'activitypub' ),
|
||||
array( 'status' => 429 )
|
||||
);
|
||||
return $this->rate_limit_response( \__( 'Too many client registration requests. Please try again later.', 'activitypub' ) );
|
||||
}
|
||||
$transient_key = 'ap_oauth_reg_' . \md5( $ip );
|
||||
$count = (int) \get_transient( $transient_key );
|
||||
|
||||
if ( $count >= 10 ) {
|
||||
return new \WP_Error(
|
||||
'activitypub_rate_limited',
|
||||
\__( 'Too many client registration requests. Please try again later.', 'activitypub' ),
|
||||
array( 'status' => 429 )
|
||||
);
|
||||
return $this->rate_limit_response( \__( 'Too many client registration requests. Please try again later.', 'activitypub' ) );
|
||||
}
|
||||
|
||||
\set_transient( $transient_key, $count + 1, MINUTE_IN_SECONDS );
|
||||
@ -183,4 +175,25 @@ class Clients_Controller extends \WP_REST_Controller {
|
||||
array( 'Content-Type' => 'application/json' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a 429 rate-limit response with a Retry-After header.
|
||||
*
|
||||
* @since 9.0.0
|
||||
*
|
||||
* @param string $message Translated human-readable error message.
|
||||
* @return \WP_REST_Response
|
||||
*/
|
||||
private function rate_limit_response( $message ) {
|
||||
return new \WP_REST_Response(
|
||||
array(
|
||||
'code' => 'activitypub_rate_limited',
|
||||
'message' => $message,
|
||||
'data' => array( 'status' => 429 ),
|
||||
),
|
||||
429,
|
||||
// RFC 6585 §4: send Retry-After so clients can back off.
|
||||
array( 'Retry-After' => (string) MINUTE_IN_SECONDS )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,11 +313,22 @@ class Token_Controller extends \WP_REST_Controller {
|
||||
// Introspect the token.
|
||||
$response = Token::introspect( $token );
|
||||
|
||||
// Scope introspection to same client: non-admin users can only
|
||||
// introspect tokens belonging to the same client as their own.
|
||||
/*
|
||||
* Scope introspection for non-admins. An OAuth-authenticated caller may only
|
||||
* introspect tokens issued to its own client; a cookie-authenticated caller may
|
||||
* only introspect its own tokens. Without the cookie branch, any logged-in user
|
||||
* could read metadata for any token string, because get_current_token() is null
|
||||
* for cookie sessions and the same-client check was skipped entirely.
|
||||
*/
|
||||
if ( $response['active'] && ! \current_user_can( 'manage_options' ) ) {
|
||||
$current_token = OAuth_Server::get_current_token();
|
||||
if ( $current_token && $current_token->get_client_id() !== $response['client_id'] ) {
|
||||
|
||||
if ( $current_token ) {
|
||||
if ( $current_token->get_client_id() !== $response['client_id'] ) {
|
||||
$response = array( 'active' => false );
|
||||
}
|
||||
} elseif ( \get_current_user_id() !== (int) $response['sub'] ) {
|
||||
// `sub` is stored as a string; cast before comparing with the integer user ID.
|
||||
$response = array( 'active' => false );
|
||||
}
|
||||
}
|
||||
@ -397,18 +408,25 @@ class Token_Controller extends \WP_REST_Controller {
|
||||
* @return \WP_REST_Response
|
||||
*/
|
||||
private function token_error( $error, $error_description, $status = 400 ) {
|
||||
$headers = array(
|
||||
'Content-Type' => 'application/json',
|
||||
// RFC 6749 §5.1 requires the same no-cache headers on error responses as on success responses.
|
||||
'Cache-Control' => 'no-store',
|
||||
'Pragma' => 'no-cache',
|
||||
);
|
||||
|
||||
// RFC 6585 §4: send Retry-After with rate-limit responses so clients can back off.
|
||||
if ( 429 === $status ) {
|
||||
$headers['Retry-After'] = (string) MINUTE_IN_SECONDS;
|
||||
}
|
||||
|
||||
return new \WP_REST_Response(
|
||||
array(
|
||||
'error' => $error,
|
||||
'error_description' => $error_description,
|
||||
),
|
||||
$status,
|
||||
array(
|
||||
'Content-Type' => 'application/json',
|
||||
// RFC 6749 §5.1 requires the same no-cache headers on error responses as on success responses.
|
||||
'Cache-Control' => 'no-store',
|
||||
'Pragma' => 'no-cache',
|
||||
)
|
||||
$headers
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user