Replaced internal Flashii ID routes with RPC library.
This commit is contained in:
parent
cc9fccdf18
commit
0bf7ca0d52
4 changed files with 78 additions and 81 deletions
|
@ -8,7 +8,8 @@
|
|||
"symfony/mailer": "^6.0",
|
||||
"matomo/device-detector": "^6.1",
|
||||
"sentry/sdk": "^4.0",
|
||||
"nesbot/carbon": "^3.7"
|
||||
"nesbot/carbon": "^3.7",
|
||||
"flashwave/aiwass": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
|
|
41
composer.lock
generated
41
composer.lock
generated
|
@ -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": "cec099ea3b4fce65aa1b1ff6b0b40f24",
|
||||
"content-hash": "c8edfa21e13dedc126a6351b7d367559",
|
||||
"packages": [
|
||||
{
|
||||
"name": "carbonphp/carbon-doctrine-types",
|
||||
|
@ -416,6 +416,45 @@
|
|||
},
|
||||
"time": "2019-12-30T22:54:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "flashwave/aiwass",
|
||||
"version": "v1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://patchii.net/flashii/aiwass.git",
|
||||
"reference": "de27da54b603f0fdc06dab89341908e73ea7a880"
|
||||
},
|
||||
"require": {
|
||||
"ext-msgpack": ">=2.2",
|
||||
"flashwave/index": "^0.2408.40014",
|
||||
"php": ">=8.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.11",
|
||||
"phpunit/phpunit": "^11.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Aiwass\\": "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": "Shared HTTP RPC client/server library.",
|
||||
"homepage": "https://railgun.sh/aiwass",
|
||||
"time": "2024-08-16T15:59:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "flashwave/index",
|
||||
"version": "v0.2408.40014",
|
||||
|
|
|
@ -1,42 +1,30 @@
|
|||
<?php
|
||||
namespace Misuzu\Hanyuu;
|
||||
|
||||
use stdClass;
|
||||
use RuntimeException;
|
||||
use Index\UriBase64;
|
||||
use Index\Colour\Colour;
|
||||
use Index\Http\Routing\{HttpGet,HttpMiddleware,HttpPost,RouteHandler};
|
||||
use Syokuhou\IConfig;
|
||||
use Misuzu\CSRF;
|
||||
use Misuzu\Auth\{AuthContext,AuthInfo,Sessions};
|
||||
use Misuzu\Auth\AuthContext;
|
||||
use Misuzu\URLs\URLRegistry;
|
||||
use Misuzu\Users\{UsersContext,UserInfo};
|
||||
use Aiwass\Server\{RpcActionHandler,RpcProcedure};
|
||||
use Index\Colour\Colour;
|
||||
use Syokuhou\IConfig;
|
||||
|
||||
final class HanyuuRoutes extends RouteHandler {
|
||||
final class HanyuuRpcActions extends RpcActionHandler {
|
||||
public function __construct(
|
||||
private IConfig $config,
|
||||
private IConfig $impersonateConfig, // this sucks lol
|
||||
private $getBaseUrl,
|
||||
private IConfig $impersonateConfig,
|
||||
private URLRegistry $urls,
|
||||
private UsersContext $usersCtx,
|
||||
private AuthContext $authCtx
|
||||
) {}
|
||||
|
||||
private function getEndpoint(): string {
|
||||
return $this->config->getString('endpoint');
|
||||
}
|
||||
|
||||
private function getSecret(): string {
|
||||
return $this->config->getString('secret');
|
||||
}
|
||||
|
||||
private static function createPayload(string $name, array $attrs = []): object {
|
||||
$payload = new stdClass;
|
||||
$payload->name = $name;
|
||||
$payload->attrs = [];
|
||||
private static function createPayload(string $name, array $attrs = []): array {
|
||||
$payload = ['name' => $name, 'attrs' => []];
|
||||
foreach($attrs as $name => $value) {
|
||||
if($value === null)
|
||||
continue;
|
||||
$payload->attrs[(string)$name] = $value;
|
||||
$payload['attrs'][(string)$name] = $value;
|
||||
}
|
||||
|
||||
return $payload;
|
||||
|
@ -50,42 +38,6 @@ final class HanyuuRoutes extends RouteHandler {
|
|||
return self::createPayload('error', $attrs);
|
||||
}
|
||||
|
||||
#[HttpMiddleware('/_hanyuu/(.*)')]
|
||||
public function verifyRequest($response, $request, string $action) {
|
||||
$userTime = (int)$request->getHeaderLine('X-Hanyuu-Timestamp');
|
||||
$userHash = UriBase64::decode((string)$request->getHeaderLine('X-Hanyuu-Signature'));
|
||||
|
||||
$currentTime = time();
|
||||
if(empty($userHash) || $userTime < $currentTime - 60 || $userTime > $currentTime + 60)
|
||||
return self::createErrorPayload('verification', 'Request verification failed.');
|
||||
|
||||
$url = sprintf('%s/_hanyuu/%s', $this->getEndpoint(), $action);
|
||||
$params = $request->getParamString();
|
||||
if($params !== '')
|
||||
$url .= sprintf('?%s', $params);
|
||||
|
||||
if($request->getMethod() === 'POST') {
|
||||
if(!$request->isFormContent())
|
||||
return self::createErrorPayload('request', 'Request body is not in expect format.');
|
||||
|
||||
$body = $request->getContent()->getParamString();
|
||||
} elseif($request->getMethod() !== 'GET') {
|
||||
return self::createErrorPayload('request', 'Only GET and POST methods are allowed.');
|
||||
} else {
|
||||
$body = '';
|
||||
}
|
||||
|
||||
$verifyHash = hash_hmac(
|
||||
'sha256',
|
||||
sprintf('[%s|%s|%s]', $userTime, $url, $body),
|
||||
$this->getSecret(),
|
||||
true
|
||||
);
|
||||
|
||||
if(!hash_equals($verifyHash, $userHash))
|
||||
return self::createErrorPayload('verification', 'Request verification failed.');
|
||||
}
|
||||
|
||||
private function canImpersonateUserId(UserInfo $impersonator, string $targetId): bool {
|
||||
if($impersonator->isSuperUser())
|
||||
return true;
|
||||
|
@ -97,18 +49,15 @@ final class HanyuuRoutes extends RouteHandler {
|
|||
);
|
||||
}
|
||||
|
||||
#[HttpPost('/_hanyuu/auth-check')]
|
||||
public function postCheckAuth($response, $request) {
|
||||
$content = $request->getContent();
|
||||
$method = (string)$content->getParam('method');
|
||||
#[RpcProcedure('mszhau:authCheck')]
|
||||
public function procAuthCheck(string $method, string $remoteAddr, string $token, string $avatars = '') {
|
||||
if($method !== 'Misuzu')
|
||||
return self::createErrorPayload('auth:check:method', 'Requested auth method is not supported.');
|
||||
|
||||
$remoteAddr = (string)$content->getParam('remote_addr');
|
||||
if(filter_var($remoteAddr, FILTER_VALIDATE_IP) === false)
|
||||
return self::createErrorPayload('auth:check:remote_addr', 'Provided remote address is not in a valid format.');
|
||||
|
||||
$avatarResolutions = trim((string)$content->getParam('avatars'));
|
||||
$avatarResolutions = trim($avatars);
|
||||
if($avatarResolutions === '') {
|
||||
$avatarResolutions = [];
|
||||
} else {
|
||||
|
@ -121,11 +70,12 @@ final class HanyuuRoutes extends RouteHandler {
|
|||
$avatarResolutions = array_unique($avatarResolutions);
|
||||
}
|
||||
|
||||
$loginUrl = $this->getEndpoint() . $this->urls->format('auth-login');
|
||||
$registerUrl = $this->getEndpoint() . $this->urls->format('auth-register');
|
||||
$baseUrl = ($this->getBaseUrl)();
|
||||
$loginUrl = $baseUrl . $this->urls->format('auth-login');
|
||||
$registerUrl = $baseUrl . $this->urls->format('auth-register');
|
||||
|
||||
$tokenPacker = $this->authCtx->createAuthTokenPacker();
|
||||
$tokenInfo = $tokenPacker->unpack(trim((string)$content->getParam('token')));
|
||||
$tokenInfo = $tokenPacker->unpack(trim($token));
|
||||
if($tokenInfo->isEmpty())
|
||||
return self::createPayload('auth:check:fail', ['reason' => 'empty', 'login_url' => $loginUrl, 'register_url' => $registerUrl]);
|
||||
|
||||
|
@ -173,9 +123,9 @@ final class HanyuuRoutes extends RouteHandler {
|
|||
'remaining_str' => $banInfo->getRemainingString(),
|
||||
];
|
||||
|
||||
$gatherRequestedAvatars = function($userInfo) use ($avatarResolutions) {
|
||||
$gatherRequestedAvatars = function($userInfo) use ($avatarResolutions, $baseUrl) {
|
||||
$formatAvatarUrl = fn($res = 0) => (
|
||||
$this->getEndpoint() . $this->urls->format('user-avatar', ['user' => $userInfo->getId(), 'res' => $res])
|
||||
$baseUrl . $this->urls->format('user-avatar', ['user' => $userInfo->getId(), 'res' => $res])
|
||||
);
|
||||
|
||||
$avatars = ['original' => $formatAvatarUrl()];
|
||||
|
@ -195,7 +145,7 @@ final class HanyuuRoutes extends RouteHandler {
|
|||
'country_code' => $userInfo->getCountryCode(),
|
||||
'is_deleted' => $userInfo->isDeleted(),
|
||||
'has_totp' => $userInfo->hasTOTPKey(),
|
||||
'profile_url' => $this->getEndpoint() . $this->urls->format('user-profile', ['user' => $userInfo->getId()]),
|
||||
'profile_url' => $baseUrl . $this->urls->format('user-profile', ['user' => $userInfo->getId()]),
|
||||
'avatars' => $gatherRequestedAvatars($userInfo),
|
||||
];
|
||||
|
||||
|
@ -204,7 +154,7 @@ final class HanyuuRoutes extends RouteHandler {
|
|||
$response['guise'] = $extractUserInfo($userInfoReal);
|
||||
|
||||
$csrfp = CSRF::create($sessionInfo->getToken());
|
||||
$response['guise']['revert_url'] = $this->getEndpoint() . $this->urls->format('auth-revert', ['csrf' => $csrfp->createToken()]);
|
||||
$response['guise']['revert_url'] = $baseUrl . $this->urls->format('auth-revert', ['csrf' => $csrfp->createToken()]);
|
||||
}
|
||||
|
||||
return self::createPayload('auth:check:success', $response);
|
|
@ -1,10 +1,6 @@
|
|||
<?php
|
||||
namespace Misuzu;
|
||||
|
||||
use Index\Data\IDbConnection;
|
||||
use Index\Data\Migration\{IDbMigrationRepo,DbMigrationManager,FsDbMigrationRepo};
|
||||
use Sasae\SasaeEnvironment;
|
||||
use Syokuhou\IConfig;
|
||||
use Misuzu\Template;
|
||||
use Misuzu\Auth\{AuthContext,AuthInfo};
|
||||
use Misuzu\AuditLog\AuditLog;
|
||||
|
@ -19,6 +15,12 @@ use Misuzu\Perms\Permissions;
|
|||
use Misuzu\Profile\ProfileFields;
|
||||
use Misuzu\URLs\URLRegistry;
|
||||
use Misuzu\Users\{UsersContext,UserInfo};
|
||||
use Aiwass\HmacVerificationProvider;
|
||||
use Aiwass\Server\RpcServer;
|
||||
use Index\Data\IDbConnection;
|
||||
use Index\Data\Migration\{IDbMigrationRepo,DbMigrationManager,FsDbMigrationRepo};
|
||||
use Sasae\SasaeEnvironment;
|
||||
use Syokuhou\IConfig;
|
||||
|
||||
// this class should function as the root for everything going forward
|
||||
// no more magical static classes that are just kind of assumed to exist
|
||||
|
@ -277,16 +279,21 @@ class MisuzuContext {
|
|||
$this->profileFields
|
||||
));
|
||||
|
||||
$routingCtx->register(new \Misuzu\Hanyuu\HanyuuRoutes(
|
||||
$this->config->scopeTo('hanyuu'),
|
||||
$routingCtx->register(new LegacyRoutes($this->urls));
|
||||
|
||||
$rpcServer = new RpcServer;
|
||||
$routingCtx->getRouter()->scopeTo('/_hanyuu')->register($rpcServer->createRouteHandler(
|
||||
new HmacVerificationProvider(fn() => $this->config->getString('hanyuu.secret'))
|
||||
));
|
||||
|
||||
$rpcServer->register(new Hanyuu\HanyuuRpcActions(
|
||||
fn() => $this->config->getString('hanyuu.endpoint'),
|
||||
$this->config->scopeTo('impersonate'),
|
||||
$this->urls,
|
||||
$this->usersCtx,
|
||||
$this->authCtx
|
||||
));
|
||||
|
||||
$routingCtx->register(new LegacyRoutes($this->urls));
|
||||
|
||||
return $routingCtx;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue