From 0b7031959b8b9b614085eb23f3a544435db0a6e6 Mon Sep 17 00:00:00 2001 From: flashwave <me@flash.moe> Date: Tue, 25 Mar 2025 14:27:50 +0000 Subject: [PATCH] Removed RPCii dependency. --- VERSION | 2 +- composer.json | 1 - composer.lock | 43 +------ docs/source.md | 2 - src/Auth/AuthRpcHandler.php | 64 ---------- src/Emoticons/EmotesRpcHandler.php | 41 ------ src/Info/InfoRoutes.php | 3 - src/MisuzuContext.php | 15 --- src/OAuth2/OAuth2RpcHandler.php | 196 ----------------------------- src/Users/UsersRpcHandler.php | 120 ------------------ 10 files changed, 2 insertions(+), 485 deletions(-) delete mode 100644 src/Auth/AuthRpcHandler.php delete mode 100644 src/Emoticons/EmotesRpcHandler.php delete mode 100644 src/OAuth2/OAuth2RpcHandler.php delete mode 100644 src/Users/UsersRpcHandler.php diff --git a/VERSION b/VERSION index e0354d6b..7c3db70d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -20250325.2 +20250325.3 diff --git a/composer.json b/composer.json index b8128202..5f575a6a 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,6 @@ "php": ">=8.4", "ext-mbstring": "*", "flashwave/index": "^0.2503", - "flashii/rpcii": "~5.0", "erusev/parsedown": "~1.7", "chillerlan/php-qrcode": "~5.0", "symfony/mailer": "~7.2", diff --git a/composer.lock b/composer.lock index c805baa5..1c46a961 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "baa15cf491eb4500360fa9c20fd42a4d", + "content-hash": "cd96df7b2981a653c33b100a8b3837cd", "packages": [ { "name": "carbonphp/carbon-doctrine-types", @@ -499,47 +499,6 @@ ], "time": "2025-03-15T12:00:00+00:00" }, - { - "name": "flashii/rpcii", - "version": "v5.0.1", - "source": { - "type": "git", - "url": "https://patchii.net/flashii/rpcii-php.git", - "reference": "28c25e0a342173524f8894d03158663842e03252" - }, - "require": { - "ext-msgpack": ">=2.2", - "flashwave/index": "^0.2503", - "guzzlehttp/guzzle": "~7.0", - "php": ">=8.4", - "psr/http-client": "^1.0" - }, - "require-dev": { - "phpstan/phpstan": "^2.1", - "phpunit/phpunit": "^12.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "RPCii\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "bsd-3-clause-clear" - ], - "authors": [ - { - "name": "flashwave", - "email": "packagist@flash.moe", - "homepage": "https://flash.moe", - "role": "mom" - } - ], - "description": "HTTP RPC client/server library.", - "homepage": "https://railgun.sh/rpcii", - "time": "2025-03-21T19:38:29+00:00" - }, { "name": "flashwave/index", "version": "v0.2503.251417", diff --git a/docs/source.md b/docs/source.md index 34fdd477..953f690c 100644 --- a/docs/source.md +++ b/docs/source.md @@ -12,7 +12,6 @@ Below are a number of links to source code repositories related to Flashii.net a - [Uiharu](https://patchii.net/flashii/uiharu): Service for looking up URL metadata. - [Seria](https://patchii.net/flashii/seria): Software used by the downloads tracker. - [Mince](https://patchii.net/flashii/mince): Source code for the Minecraft servers subwebsite. - - [Aleister](https://patchii.net/flashii/aleister): Public API gateway. ## Tools & Software - [SoFii](https://patchii.net/flashii/sofii): Launcher for Soldier of Fortune 2 @@ -21,7 +20,6 @@ Below are a number of links to source code repositories related to Flashii.net a ## First-Party Libraries - [Index](https://patchii.net/flash/index): Base library used in almost any component of the website that uses PHP. - - [RPCii](https://patchii.net/flashii/rpcii): Internal RPC extension, mainly used to supply data to the API gateway. ## Historical - [AJAX Chat (fork)](https://patchii.net/flashii/ajax-chat): Old chat software (2013-2015). Still kept on life support for the nostalgia. diff --git a/src/Auth/AuthRpcHandler.php b/src/Auth/AuthRpcHandler.php deleted file mode 100644 index 5500c803..00000000 --- a/src/Auth/AuthRpcHandler.php +++ /dev/null @@ -1,64 +0,0 @@ -<?php -namespace Misuzu\Auth; - -use RuntimeException; -use Misuzu\Users\{UsersContext,UserInfo}; -use RPCii\Server\{RpcHandler,RpcHandlerCommon,RpcAction}; -use Index\Config\Config; - -final class AuthRpcHandler implements RpcHandler { - use RpcHandlerCommon; - - public function __construct( - private Config $impersonateConfig, - private UsersContext $usersCtx, - private AuthContext $authCtx - ) {} - - private function canImpersonateUserId(UserInfo $impersonator, string $targetId): bool { - if($impersonator->super) - return true; - - $whitelist = $this->impersonateConfig->getArray(sprintf('allow.u%s', $impersonator->id)); - return in_array($targetId, $whitelist, true); - } - - /** @return array{method: string, error: string}|array{method: string, type: string, user: string, expires: int} */ - #[RpcAction('misuzu:auth:attemptMisuzuAuth')] - public function procAttemptMisuzuAuth(string $remoteAddr, string $token): array { - $tokenInfo = $this->authCtx->createAuthTokenPacker()->unpack($token); - if(!$tokenInfo->isEmpty) - $token = $tokenInfo->sessionToken; - - try { - $sessionInfo = $this->authCtx->sessions->getSession(sessionToken: $token); - } catch(RuntimeException $ex) { - return ['method' => 'misuzu', 'error' => 'token']; - } - - if($sessionInfo->expired) { - $this->authCtx->sessions->deleteSessions(sessionInfos: $sessionInfo); - return ['method' => 'misuzu', 'error' => 'expired']; - } - - $this->authCtx->sessions->recordSessionActivity(sessionInfo: $sessionInfo, remoteAddr: $remoteAddr); - - $userInfo = $this->usersCtx->users->getUser($sessionInfo->userId, 'id'); - if($tokenInfo->hasImpersonatedUserId && $this->canImpersonateUserId($userInfo, $tokenInfo->impersonatedUserId)) { - $userInfoReal = $userInfo; - - try { - $userInfo = $this->usersCtx->users->getUser($tokenInfo->impersonatedUserId, 'id'); - } catch(RuntimeException $ex) { - $userInfo = $userInfoReal; - } - } - - return [ - 'method' => 'misuzu', - 'type' => 'user', - 'user' => $userInfo->id, - 'expires' => $sessionInfo->expiresTime, - ]; - } -} diff --git a/src/Emoticons/EmotesRpcHandler.php b/src/Emoticons/EmotesRpcHandler.php deleted file mode 100644 index be304e17..00000000 --- a/src/Emoticons/EmotesRpcHandler.php +++ /dev/null @@ -1,41 +0,0 @@ -<?php -namespace Misuzu\Emoticons; - -use Index\XArray; -use RPCii\Server\{RpcHandler,RpcHandlerCommon,RpcQuery}; - -final class EmotesRpcHandler implements RpcHandler { - use RpcHandlerCommon; - - public function __construct( - private EmotesData $emotes - ) {} - - /** @return array<array{url: string, strings: string[], id?: string, order?: int, min_rank?: int}> */ - #[RpcQuery('misuzu:emotes:all')] - public function queryAll(bool $includeId = false, bool $includeOrder = false): array { - return XArray::select( - $this->emotes->getEmotes(orderBy: 'order'), - function($emote) use ($includeId, $includeOrder) { - $info = [ - 'url' => $emote->url, - 'strings' => XArray::select( - $this->emotes->getEmoteStrings($emote), - fn($string) => $string->string - ), - ]; - - if($includeId) - $info['id'] = $emote->id; - if($includeOrder) - $info['order'] = $emote->order; - - $rank = $emote->minRank; - if($rank !== 0) - $info['min_rank'] = $rank; - - return $info; - } - ); - } -} diff --git a/src/Info/InfoRoutes.php b/src/Info/InfoRoutes.php index 002f68fe..2493d726 100644 --- a/src/Info/InfoRoutes.php +++ b/src/Info/InfoRoutes.php @@ -8,7 +8,6 @@ use Index\Http\Routing\Routes\{ExactRoute,PatternRoute}; use Index\Urls\{UrlFormat,UrlSource,UrlSourceCommon}; use Misuzu\{Misuzu,Template}; use Misuzu\Parsers\{Parsers,TextFormat}; -use RPCii\RPCii; class InfoRoutes implements RouteHandler, UrlSource { use RouteHandlerCommon, UrlSourceCommon; @@ -16,12 +15,10 @@ class InfoRoutes implements RouteHandler, UrlSource { private const PROJECT_PATHS = [ 'misuzu' => Misuzu::PATH_ROOT, 'index' => Index::PATH_ROOT, - 'rpcii' => RPCii::PATH_ROOT, ]; private const PROJECT_SUFFIXES = [ 'misuzu' => 'Misuzu » %s', 'index' => 'Index » %s', - 'rpcii' => 'RPCii » %s', ]; #[ExactRoute('GET', '/info')] diff --git a/src/MisuzuContext.php b/src/MisuzuContext.php index ed374e37..d47672a4 100644 --- a/src/MisuzuContext.php +++ b/src/MisuzuContext.php @@ -11,8 +11,6 @@ use Index\Templating\TplEnvironment; use Index\Urls\UrlRegistry; use Misuzu\Routing\RoutingContext; use Misuzu\Users\UserInfo; -use RPCii\HmacVerificationProvider; -use RPCii\Server\{HttpRpcServer,RpcServer}; class MisuzuContext { public private(set) Dependencies $deps; @@ -158,11 +156,6 @@ class MisuzuContext { public function registerMainRoutes( RoutingContext $routingCtx ): void { - $rpcServer = new HttpRpcServer; - $routingCtx->register($rpcServer->createRouteHandler( - new HmacVerificationProvider(fn() => $this->config->getString('aleister.secret')) - )); - $this->deps->register($wf = new WebFinger\WebFingerRegistry); $wf->register($this->deps->constructLazy( Users\UsersWebFingerResolver::class, @@ -190,7 +183,6 @@ class MisuzuContext { $routingCtx->register($this->deps->constructLazy(OAuth2\OAuth2ApiRoutes::class)); $routingCtx->register($this->deps->constructLazy(OAuth2\OAuth2WebRoutes::class)); - $rpcServer->register($this->deps->constructLazy(OAuth2\OAuth2RpcHandler::class)); $routingCtx->register($this->deps->constructLazy(WebFinger\WebFingerRoutes::class)); $routingCtx->register($this->deps->constructLazy(Forum\ForumCategoriesRoutes::class)); @@ -210,13 +202,6 @@ class MisuzuContext { )); $routingCtx->register($this->deps->constructLazy(LegacyRoutes::class)); - - $rpcServer->register($this->deps->constructLazy( - Auth\AuthRpcHandler::class, - impersonateConfig: $this->config->scopeTo('impersonate') - )); - $rpcServer->register($this->deps->constructLazy(Emoticons\EmotesRpcHandler::class)); - $rpcServer->register($this->deps->constructLazy(Users\UsersRpcHandler::class)); } public function registerRedirectorRoutes(RoutingContext $routingCtx): void { diff --git a/src/OAuth2/OAuth2RpcHandler.php b/src/OAuth2/OAuth2RpcHandler.php deleted file mode 100644 index de32466c..00000000 --- a/src/OAuth2/OAuth2RpcHandler.php +++ /dev/null @@ -1,196 +0,0 @@ -<?php -namespace Misuzu\OAuth2; - -use RuntimeException; -use RPCii\Server\{RpcHandler,RpcHandlerCommon,RpcAction}; - -final class OAuth2RpcHandler implements RpcHandler { - use RpcHandlerCommon; - - public function __construct( - private OAuth2Context $oauth2Ctx - ) {} - - /** - * @return array{ - * method: 'basic', - * error?: 'app'|'secret', - * type?: 'confapp'|'pubapp', - * app?: string, - * scope?: string[] - * } - */ - #[RpcAction('hanyuu:oauth2:attemptAppAuth')] - public function procAttemptAppAuth(string $remoteAddr, string $clientId, string $clientSecret = ''): array { - try { - $appInfo = $this->oauth2Ctx->appsCtx->apps->getAppInfo(clientId: $clientId, deleted: false); - } catch(RuntimeException $ex) { - return ['method' => 'basic', 'error' => 'app']; - } - - $authed = false; - if($clientSecret !== '') { - // TODO: rate limiting - - if(!$appInfo->verifyClientSecret($clientSecret)) - return ['method' => 'basic', 'error' => 'secret']; - - $authed = true; - } - - return [ - 'method' => 'basic', - 'type' => $authed ? 'confapp' : 'pubapp', - 'app' => $appInfo->id, - 'scope' => ['oauth2'], - ]; - } - - /** - * @return array{ - * method: 'bearer', - * error?: 'token'|'expired', - * type?: 'app'|'user', - * app?: string, - * user?: string, - * scope?: string[], - * expires?: int, - * } - */ - #[RpcAction('hanyuu:oauth2:attemptBearerAuth')] - public function procAttemptBearerAuth(string $remoteAddr, string $token): array { - try { - $tokenInfo = $this->oauth2Ctx->tokens->getAccessInfo($token, OAuth2AccessInfoGetField::Token); - } catch(RuntimeException $ex) { - return ['method' => 'bearer', 'error' => 'token']; - } - - if($tokenInfo->expired) - return ['method' => 'bearer', 'error' => 'expired']; - - return [ - 'method' => 'bearer', - 'type' => empty($tokenInfo->userId) ? 'app' : 'user', - 'app' => $tokenInfo->appId, - 'user' => $tokenInfo->userId ?? '0', - 'scope' => $tokenInfo->scopes, - 'expires' => $tokenInfo->expiresTime, - ]; - } - - /** - * @return array{ - * device_code: string, - * user_code: string, - * verification_uri: string, - * verification_uri_complete: string, - * expires_in?: int, - * interval?: int - * }|array{ error: string, error_description: string } - */ - #[RpcAction('hanyuu:oauth2:createAuthoriseRequest')] - public function procCreateAuthoriseRequest(string $appId, ?string $scope = null): array { - try { - $appInfo = $this->oauth2Ctx->appsCtx->apps->getAppInfo(appId: $appId, deleted: false); - } catch(RuntimeException $ex) { - return [ - 'error' => 'invalid_client', - 'error_description' => 'No application has been registered with this client ID.', - ]; - } - - return $this->oauth2Ctx->createDeviceAuthorisationRequest($appInfo, $scope); - } - - /** - * @return array{ - * access_token: string, - * token_type: 'Bearer', - * expires_in?: int, - * scope?: string, - * refresh_token?: string, - * }|array{ error: string, error_description: string } - */ - #[RpcAction('hanyuu:oauth2:createBearerToken:authorisationCode')] - public function procCreateBearerTokenAuthzCode(string $appId, bool $isAuthed, string $code, string $codeVerifier): array { - try { - $appInfo = $this->oauth2Ctx->appsCtx->apps->getAppInfo(appId: $appId, deleted: false); - } catch(RuntimeException $ex) { - return [ - 'error' => 'invalid_client', - 'error_description' => 'No application has been registered with this client ID.', - ]; - } - - return $this->oauth2Ctx->redeemAuthorisationCode($appInfo, $isAuthed, $code, $codeVerifier); - } - - /** - * @return array{ - * access_token: string, - * token_type: 'Bearer', - * expires_in?: int, - * scope?: string, - * refresh_token?: string, - * }|array{ error: string, error_description: string } - */ - #[RpcAction('hanyuu:oauth2:createBearerToken:refreshToken')] - public function procCreateBearerTokenRefreshToken(string $appId, bool $isAuthed, string $refreshToken, ?string $scope = null): array { - try { - $appInfo = $this->oauth2Ctx->appsCtx->apps->getAppInfo(appId: $appId, deleted: false); - } catch(RuntimeException $ex) { - return [ - 'error' => 'invalid_client', - 'error_description' => 'No application has been registered with this client ID.', - ]; - } - - return $this->oauth2Ctx->redeemRefreshToken($appInfo, $isAuthed, $refreshToken, $scope); - } - - /** - * @return array{ - * access_token: string, - * token_type: 'Bearer', - * expires_in?: int, - * scope?: string, - * refresh_token?: string, - * }|array{ error: string, error_description: string } - */ - #[RpcAction('hanyuu:oauth2:createBearerToken:clientCredentials')] - public function procCreateBearerTokenClientCreds(string $appId, bool $isAuthed, ?string $scope = null): array { - try { - $appInfo = $this->oauth2Ctx->appsCtx->apps->getAppInfo(appId: $appId, deleted: false); - } catch(RuntimeException $ex) { - return [ - 'error' => 'invalid_client', - 'error_description' => 'No application has been registered with this client ID.', - ]; - } - - return $this->oauth2Ctx->redeemClientCredentials($appInfo, $isAuthed, $scope); - } - - /** - * @return array{ - * access_token: string, - * token_type: 'Bearer', - * expires_in?: int, - * scope?: string, - * refresh_token?: string, - * }|array{ error: string, error_description: string } - */ - #[RpcAction('hanyuu:oauth2:createBearerToken:deviceCode')] - public function procCreateBearerTokenDeviceCode(string $appId, bool $isAuthed, string $deviceCode): array { - try { - $appInfo = $this->oauth2Ctx->appsCtx->apps->getAppInfo(appId: $appId, deleted: false); - } catch(RuntimeException $ex) { - return [ - 'error' => 'invalid_client', - 'error_description' => 'No application has been registered with this client ID.', - ]; - } - - return $this->oauth2Ctx->redeemDeviceCode($appInfo, $isAuthed, $deviceCode); - } -} diff --git a/src/Users/UsersRpcHandler.php b/src/Users/UsersRpcHandler.php deleted file mode 100644 index e6e3ad8f..00000000 --- a/src/Users/UsersRpcHandler.php +++ /dev/null @@ -1,120 +0,0 @@ -<?php -namespace Misuzu\Users; - -use RuntimeException; -use Misuzu\SiteInfo; -use Misuzu\Users\Assets\UserAvatarAsset; -use RPCii\Server\{RpcHandler,RpcHandlerCommon,RpcQuery}; -use Index\XArray; -use Index\Colour\{Colour,ColourRgb}; -use Index\Urls\UrlRegistry; - -final class UsersRpcHandler implements RpcHandler { - use RpcHandlerCommon; - - public function __construct( - private SiteInfo $siteInfo, - private UrlRegistry $urls, - private UsersContext $usersCtx - ) {} - - /** - * @return array{error: string}|array{ - * id: string, - * name: string, - * email?: string, - * colour_raw: int, - * colour_css: string, - * rank: int, - * country_code: string, - * roles?: string[], - * is_super?: bool, - * title?: string, - * created_at: string, - * last_active_at?: string, - * profile_url: string, - * avatar_url: string, - * avatar_urls?: array{res: int, url: string}[], - * is_deleted?: bool - * } - */ - #[RpcQuery('misuzu:users:getUser')] - public function queryGetUser(string $userId, bool $includeEMailAddress = false): array { - try { - $userInfo = $this->usersCtx->getUserInfo($userId, UsersData::GET_USER_ID); - } catch(RuntimeException) { - return ['error' => 'notfound']; - } - - // TODO: there should be some kinda privacy controls for users - - - $colour = $this->usersCtx->getUserColour($userInfo); - if($colour->inherits) { - $colourRaw = null; - $colourCSS = (string)$colour; - } else { - $colourRaw = Colour::toRawRgb($colour); - $colourCSS = (string)ColourRgb::convert($colour); - } - - $baseUrl = $this->siteInfo->url; - - $output = []; - - $output['id'] = $userInfo->id; - $output['name'] = $userInfo->name; - if($includeEMailAddress) - $output['email'] = $userInfo->emailAddress; - - $output['colour_raw'] = $colourRaw; - $output['colour_css'] = $colourCSS; - $output['country_code'] = $userInfo->countryCode; - - if($this->usersCtx->hasActiveBan($userInfo)) { - $output['rank'] = 0; - $output['roles'] = ['x-banned']; - } else { - $roles = XArray::select( - $this->usersCtx->roles->getRoles(userInfo: $userInfo, hasString: true, orderByRank: true), - fn($roleInfo) => $roleInfo->string, - ); - - $output['rank'] = $this->usersCtx->getUserRank($userInfo); - if(!empty($roles)) - $output['roles'] = $roles; - if($userInfo->super) - $output['is_super'] = true; - } - - if(!empty($userInfo->title)) - $output['title'] = $userInfo->title; - - $output['created_at'] = $userInfo->createdAt->toIso8601ZuluString(); - if($userInfo->lastActiveTime !== null) - $output['last_active_at'] = $userInfo->lastActiveAt->toIso8601ZuluString(); - - $output['profile_url'] = $baseUrl . $this->urls->format('user-profile', ['user' => $userInfo->id]); - $output['avatar_url'] = $baseUrl . $this->urls->format('user-avatar', ['user' => $userInfo->id]); - - /* Remove the following later */ - $avatars = []; - $formatAvatarUrl = fn($res = 0) => ( - $baseUrl . $this->urls->format('user-avatar', ['user' => $userInfo->id, 'res' => $res]) - ); - - $avatars[] = ['res' => 0, 'url' => $formatAvatarUrl()]; - foreach(UserAvatarAsset::DIMENSIONS as $res) - $avatars[] = ['res' => $res, 'url' => $formatAvatarUrl($res)]; - - $avatars = array_reverse($avatars); - - $output['avatar_urls'] = $avatars; - /* / */ - - if($userInfo->deleted) - $output['is_deleted'] = true; - - return $output; - } -}