wiki.techinc.nl/includes/Rest/Handler/Helper/RestAuthorizeTrait.php
Daniel Kinzler 32c12be6fe Re-apply "Rest: replace use of deprecated pingLimiter method"
This introduces RestAuthorizeTrait to ensure proper error reporting
after calls to Authorizer methods to avoid misleading error reports,
see T350117 and T350202.

This reverts commit e047668d9f.
This restores change 701ff30193.

Change-Id: I617cb7ba24a1614c39e2b1072888f0ee7b3127e3
2023-11-22 13:57:06 +11:00

107 lines
2.5 KiB
PHP

<?php
namespace MediaWiki\Rest\Handler\Helper;
use MediaWiki\Page\PageIdentity;
use MediaWiki\Permissions\Authority;
use MediaWiki\Permissions\PermissionStatus;
use MediaWiki\Rest\HttpException;
use MediaWiki\Rest\LocalizedHttpException;
use MessageSpecifier;
use Wikimedia\Message\MessageValue;
trait RestAuthorizeTrait {
/**
* Authorize an action
*
* @see Authroity::authorizeWrite
* @throws HttpException
*/
private function authorizeActionOrThrow(
Authority $authority,
string $action
): void {
$status = PermissionStatus::newEmpty();
if ( !$authority->authorizeAction( $action, $status ) ) {
$this->handleStatus( $status );
}
}
/**
* Authorize a read operation
*
* @see Authroity::authorizeWrite
* @throws HttpException
*/
private function authorizeReadOrThrow(
Authority $authority,
string $action,
PageIdentity $target
): void {
$status = PermissionStatus::newEmpty();
if ( !$authority->authorizeRead( $action, $target, $status ) ) {
$this->handleStatus( $status );
}
}
/**
* Authorize a write operation
*
* @see Authroity::authorizeWrite
* @throws HttpException
*/
private function authorizeWriteOrThrow(
Authority $authority,
string $action,
PageIdentity $target
): void {
$status = PermissionStatus::newEmpty();
if ( !$authority->authorizeWrite( $action, $target, $status ) ) {
$this->handleStatus( $status );
}
}
/**
* Throw an exception if the status contains an error.
*
* @throws HttpException
* @return never
*/
private function handleStatus( PermissionStatus $status ): void {
// The permission name should always be set, but don't explode if it isn't.
$permission = $status->getPermission() ?: '(unknown)';
if ( $status->isRateLimitExceeded() ) {
throw new LocalizedHttpException(
MessageValue::new( 'rest-rate-limit-exceeded', [ $permission ] ),
// See https://www.rfc-editor.org/rfc/rfc6585#section-4
429,
[ 'errors-keys' => $this->getStatusErrorKeys( $status ) ]
);
}
throw new LocalizedHttpException(
MessageValue::new( 'rest-permission-error', [ $permission ] ),
403,
[ 'errors-keys' => $this->getStatusErrorKeys( $status ) ]
);
}
private function getStatusErrorKeys( PermissionStatus $status ) {
$keys = [];
foreach ( $status->getErrors() as [ 'message' => $msg ] ) {
if ( is_string( $msg ) ) {
$keys[] = $msg;
} elseif ( is_array( $msg ) ) {
$keys[] = $msg[0];
} elseif ( $msg instanceof MessageSpecifier ) {
$keys[] = $msg->getKey();
}
}
return array_unique( $keys );
}
}