Updated to use asymmetric access and property hooks.

This commit is contained in:
flash 2024-12-01 02:50:21 +00:00
parent 2829419111
commit aac8911b4b
12 changed files with 156 additions and 240 deletions

View file

@ -5,6 +5,7 @@
}
},
"require": {
"php": ">=8.4",
"flashwave/index": "^0.2410",
"flashii/rpcii": "^2.0",
"sentry/sdk": "^4.0"

107
composer.lock generated
View file

@ -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": "591ddfd1386e0218b3ee6aa17e883587",
"content-hash": "8cc0e0402ab4ec0726e19e63558e6299",
"packages": [
{
"name": "flashii/rpcii",
@ -47,11 +47,11 @@
},
{
"name": "flashwave/index",
"version": "v0.2410.191603",
"version": "v0.2410.211811",
"source": {
"type": "git",
"url": "https://patchii.net/flash/index.git",
"reference": "17cdb4d1c239241200d7e30968122a8cd8b26509"
"reference": "40cbd35ba3855056987d2f7647f669e66f938979"
},
"require": {
"ext-mbstring": "*",
@ -98,7 +98,7 @@
],
"description": "Composer package for the common library for my projects.",
"homepage": "https://railgun.sh/index",
"time": "2024-10-19T16:04:17+00:00"
"time": "2024-10-21T18:15:09+00:00"
},
{
"name": "guzzlehttp/psr7",
@ -218,28 +218,28 @@
},
{
"name": "jean85/pretty-package-versions",
"version": "2.0.6",
"version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/Jean85/pretty-package-versions.git",
"reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4"
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/f9fdd29ad8e6d024f52678b570e5593759b550b4",
"reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.0.0",
"php": "^7.1|^8.0"
"composer-runtime-api": "^2.1.0",
"php": "^7.4|^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.2",
"jean85/composer-provided-replaced-stub-package": "^1.0",
"phpstan/phpstan": "^1.4",
"phpunit/phpunit": "^7.5|^8.5|^9.4",
"vimeo/psalm": "^4.3"
"phpunit/phpunit": "^7.5|^8.5|^9.6",
"vimeo/psalm": "^4.3 || ^5.0"
},
"type": "library",
"extra": {
@ -271,9 +271,9 @@
],
"support": {
"issues": "https://github.com/Jean85/pretty-package-versions/issues",
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.6"
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0"
},
"time": "2024-03-08T09:58:59+00:00"
"time": "2024-11-18T16:19:46+00:00"
},
{
"name": "psr/http-factory",
@ -623,16 +623,16 @@
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.5.0",
"version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1"
"reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
"reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
"reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
"shasum": ""
},
"require": {
@ -670,7 +670,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0"
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
},
"funding": [
{
@ -686,20 +686,20 @@
"type": "tidelift"
}
],
"time": "2024-04-18T09:32:20+00:00"
"time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/mime",
"version": "v7.1.6",
"version": "v7.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
"reference": "caa1e521edb2650b8470918dfe51708c237f0598"
"reference": "cc84a4b81f62158c3846ac7ff10f696aae2b524d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/caa1e521edb2650b8470918dfe51708c237f0598",
"reference": "caa1e521edb2650b8470918dfe51708c237f0598",
"url": "https://api.github.com/repos/symfony/mime/zipball/cc84a4b81f62158c3846ac7ff10f696aae2b524d",
"reference": "cc84a4b81f62158c3846ac7ff10f696aae2b524d",
"shasum": ""
},
"require": {
@ -754,7 +754,7 @@
"mime-type"
],
"support": {
"source": "https://github.com/symfony/mime/tree/v7.1.6"
"source": "https://github.com/symfony/mime/tree/v7.2.0"
},
"funding": [
{
@ -770,20 +770,20 @@
"type": "tidelift"
}
],
"time": "2024-10-25T15:11:02+00:00"
"time": "2024-11-23T09:19:39+00:00"
},
{
"name": "symfony/options-resolver",
"version": "v7.1.6",
"version": "v7.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "85e95eeede2d41cd146146e98c9c81d9214cae85"
"reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/85e95eeede2d41cd146146e98c9c81d9214cae85",
"reference": "85e95eeede2d41cd146146e98c9c81d9214cae85",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50",
"reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50",
"shasum": ""
},
"require": {
@ -821,7 +821,7 @@
"options"
],
"support": {
"source": "https://github.com/symfony/options-resolver/tree/v7.1.6"
"source": "https://github.com/symfony/options-resolver/tree/v7.2.0"
},
"funding": [
{
@ -837,7 +837,7 @@
"type": "tidelift"
}
],
"time": "2024-09-25T14:20:29+00:00"
"time": "2024-11-20T11:17:29+00:00"
},
{
"name": "symfony/polyfill-ctype",
@ -1240,16 +1240,16 @@
},
{
"name": "twig/html-extra",
"version": "v3.13.0",
"version": "v3.16.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/html-extra.git",
"reference": "8229e750091171c1f11801a525927811c7ac5a7e"
"reference": "2086023d3ffc4bae2b1115f715d17f97fd013665"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/html-extra/zipball/8229e750091171c1f11801a525927811c7ac5a7e",
"reference": "8229e750091171c1f11801a525927811c7ac5a7e",
"url": "https://api.github.com/repos/twigphp/html-extra/zipball/2086023d3ffc4bae2b1115f715d17f97fd013665",
"reference": "2086023d3ffc4bae2b1115f715d17f97fd013665",
"shasum": ""
},
"require": {
@ -1292,7 +1292,7 @@
"twig"
],
"support": {
"source": "https://github.com/twigphp/html-extra/tree/v3.13.0"
"source": "https://github.com/twigphp/html-extra/tree/v3.16.0"
},
"funding": [
{
@ -1304,20 +1304,20 @@
"type": "tidelift"
}
],
"time": "2024-09-03T13:08:40+00:00"
"time": "2024-09-30T06:41:48+00:00"
},
{
"name": "twig/twig",
"version": "v3.14.2",
"version": "v3.16.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a"
"reference": "475ad2dc97d65d8631393e721e7e44fb544f0561"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a",
"reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/475ad2dc97d65d8631393e721e7e44fb544f0561",
"reference": "475ad2dc97d65d8631393e721e7e44fb544f0561",
"shasum": ""
},
"require": {
@ -1328,6 +1328,7 @@
"symfony/polyfill-php81": "^1.29"
},
"require-dev": {
"phpstan/phpstan": "^2.0",
"psr/container": "^1.0|^2.0",
"symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
},
@ -1371,7 +1372,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.14.2"
"source": "https://github.com/twigphp/Twig/tree/v3.16.0"
},
"funding": [
{
@ -1383,22 +1384,22 @@
"type": "tidelift"
}
],
"time": "2024-11-07T12:36:22+00:00"
"time": "2024-11-29T08:27:05+00:00"
}
],
"packages-dev": [
{
"name": "phpstan/phpstan",
"version": "2.0.1",
"version": "2.0.3",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "ab4e9b4415a5fc9e4d27f7fe16c8bc9d067dcd6d"
"reference": "46b4d3529b12178112d9008337beda0cc2a1a6b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/ab4e9b4415a5fc9e4d27f7fe16c8bc9d067dcd6d",
"reference": "ab4e9b4415a5fc9e4d27f7fe16c8bc9d067dcd6d",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/46b4d3529b12178112d9008337beda0cc2a1a6b4",
"reference": "46b4d3529b12178112d9008337beda0cc2a1a6b4",
"shasum": ""
},
"require": {
@ -1443,15 +1444,17 @@
"type": "github"
}
],
"time": "2024-11-11T15:43:04+00:00"
"time": "2024-11-28T22:19:37+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"platform": {
"php": ">=8.4"
},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View file

@ -18,4 +18,4 @@ set_exception_handler(function(\Throwable $ex) {
exit;
});
$ctx->getRouter()->dispatch();
$ctx->router->dispatch();

View file

@ -5,109 +5,85 @@ use RuntimeException;
use RPCii\Client\RpcClient;
class AuthzContext {
private bool $authed = false;
private string $error = '';
private string $method = '';
private string $type = '';
private string $userId = '';
private string $appId = '';
private ?array $scope = null;
private ?int $expires = null;
public private(set) bool $authed = false;
public private(set) string $error = '';
public private(set) string $method = '';
public private(set) string $type = '';
public private(set) string $userId = '';
public private(set) string $appId = '';
private ?array $scopeRaw = null;
private ?int $expiresAtRaw = null;
public function __construct(
private RpcClient $rpcClient
) {}
public function hasAuthed(): bool {
return $this->authed;
public bool $hasError {
get => $this->error !== '';
}
public function hasError(): bool {
return $this->error !== '';
public bool $isBasicAuth {
get => strcasecmp('basic', $this->method) === 0;
}
public function getError(): string {
return $this->error;
public bool $isBearerAuth {
get => strcasecmp('bearer', $this->method) === 0;
}
public function getMethod(): string {
return $this->method;
public bool $isMisuzuAuth {
get => strcasecmp('misuzu', $this->method) === 0;
}
public function isBasicAuth(): bool {
return strcasecmp('basic', $this->method) === 0;
public bool $isRealUser {
get => strcasecmp('user', $this->type) === 0;
}
public function isBearerAuth(): bool {
return strcasecmp('bearer', $this->method) === 0;
public bool $isAppUser {
get => strcasecmp('app', $this->type) === 0;
}
public function isMisuzuAuth(): bool {
return strcasecmp('misuzu', $this->method) === 0;
public bool $isUser {
get => $this->isRealUser
|| $this->isAppUser;
}
public function getType(): string {
return $this->type;
public bool $isPublicApp {
get => strcasecmp('pubapp', $this->type) === 0;
}
public function isRealUser(): bool {
return strcasecmp('user', $this->type) === 0;
public bool $isConfidentialApp {
get => strcasecmp('confapp', $this->type) === 0;
}
public function isAppUser(): bool {
return strcasecmp('app', $this->type) === 0;
public bool $isApp {
get => $this->isPublicApp
|| $this->isConfidentialApp;
}
public function isUser(): bool {
return $this->isRealUser()
|| $this->isAppUser();
public bool $hasWildcardScope {
get => $this->scopeRaw === null;
}
public function isPublicApp(): bool {
return strcasecmp('pubapp', $this->type) === 0;
public string $scopeString {
get => $this->scopeRaw === null ? '' : implode(' ', $this->scopeRaw);
}
public function isConfidentialApp(): bool {
return strcasecmp('confapp', $this->type) === 0;
}
public function isApp(): bool {
return $this->isPublicApp()
|| $this->isConfidentialApp();
}
public function getAppId(): string {
return $this->appId;
}
public function getUserId(): string {
return $this->userId;
}
public function hasWildcardScope(): bool {
return $this->scope === null;
}
public function getScopeString(): string {
return $this->scope === null ? '' : implode(' ', $this->scope);
}
public function getScopeArray(): array {
return $this->scope ?? [];
public array $scope {
get => $this->scopeRaw ?? [];
}
public function hasScope(string $scope): bool {
return $this->scope === null
|| in_array($scope, $this->scope);
return $this->scopeRaw === null
|| in_array($scope, $this->scopeRaw);
}
public function getExpiresAt(): int {
return $this->expires ?? PHP_INT_MAX;
public int $expiresAt {
get => $this->expiresAtRaw ?? PHP_INT_MAX;
}
public function hasExpired(): bool {
return $this->expires !== null
&& $this->expires <= time();
public bool $expired {
get => $this->expiresAtRaw !== null
&& $this->expiresAtRaw <= time();
}
private function handleRpcResponse(mixed $info): void {
@ -132,23 +108,10 @@ class AuthzContext {
$this->appId = $info['app'];
if(array_key_exists('scope', $info) && is_array($info['scope']))
$this->scope = $info['scope'];
$this->scopeRaw = $info['scope'];
if(array_key_exists('expires', $info) && is_int($info['expires']))
$this->expires = $info['expires'];
}
public function dump(): array {
return [
'authed' => $this->authed,
'error' => $this->error,
'method' => $this->method,
'type' => $this->type,
'user' => $this->userId,
'app' => $this->appId,
'scope' => $this->scope,
'expires' => $this->expires,
];
$this->expiresAtRaw = $info['expires'];
}
private function attemptBasicAppAuthInternal(string $remoteAddr, string $clientId, string $clientSecret = ''): void {

View file

@ -3,7 +3,7 @@ namespace Syokuhou\OAuth2;
use RuntimeException;
use Syokuhou\SyokuhouContext;
use Syokuhou\RpcModels\Hanyuu\{OAuth2AuthInfo,OAuth2RfcModel};
use Syokuhou\RpcModels\Hanyuu\OAuth2RfcModel;
use Index\Config\Config;
use Index\Http\Routing\{HandlerAttribute,HttpGet,HttpOptions,HttpPost,Router,RouteHandler,RouteHandlerTrait};
@ -21,7 +21,7 @@ class OAuth2Routes implements RouteHandler {
) {}
public function registerRoutes(Router $router): void {
$router->use('/', $this->ctx->getAuthzContext()->basicAppAuthMiddleware(...));
$router->use('/', $this->ctx->authz->basicAppAuthMiddleware(...));
HandlerAttribute::register($router, $this);
}
@ -62,8 +62,7 @@ class OAuth2Routes implements RouteHandler {
public function postRequestAuthorise($response, $request) {
$response->setHeader('Cache-Control', 'no-store');
$authz = $this->ctx->getAuthzContext();
if($authz->getError() === 'secret')
if($this->ctx->authz->error === 'secret')
return self::filter($response, [
'error' => 'invalid_client',
'error_description' => 'Provided client secret is not correct for this application.',
@ -75,16 +74,16 @@ class OAuth2Routes implements RouteHandler {
'error_description' => 'Your request must use content type application/x-www-form-urlencoded.',
]);
$rpc = $this->ctx->getRpcClient();
$rpc = $this->ctx->rpc;
$content = $request->getContent();
if(!$authz->hasAuthed())
$authz->attemptBasicAppAuth(
if(!$this->ctx->authz->authed)
$this->ctx->authz->attemptBasicAppAuth(
(string)filter_input(INPUT_SERVER, 'REMOTE_ADDR'),
(string)$content->getParam('client_id')
);
if(!$authz->isApp())
if(!$this->ctx->authz->isApp)
return self::filter($response, [
'error' => 'invalid_client',
'error_description' => 'App authentication failed.',
@ -92,20 +91,20 @@ class OAuth2Routes implements RouteHandler {
try {
$reqInfo = new OAuth2RfcModel($rpc->action('hanyuu:oauth2:createAuthoriseRequest', [
'appId' => $authz->getAppId(),
'appId' => $this->ctx->authz->appId,
'scope' => (string)$content->getParam('scope'),
]));
} catch(RuntimeException $ex) {
$reqInfo = null;
}
if($reqInfo === null || ($reqInfo->hasError() && !in_array($reqInfo->getError(), self::REQ_AUTH_ERRORS)))
if($reqInfo === null || ($reqInfo->hasError && !in_array($reqInfo->error, self::REQ_AUTH_ERRORS)))
return self::filter($response, [
'error' => 'server_error',
'error_description' => 'Authorisation server gave unexpected response.',
]);
return self::filter($response, $reqInfo->getRaw());
return self::filter($response, $reqInfo->raw);
}
#[HttpOptions('/token')]
@ -142,27 +141,26 @@ class OAuth2Routes implements RouteHandler {
'error_description' => 'Your request must use content type application/x-www-form-urlencoded.',
]);
$rpc = $this->ctx->getRpcClient();
$rpc = $this->ctx->rpc;
$content = $request->getContent();
$authz = $this->ctx->getAuthzContext();
$authzHeader = true;
if(!$authz->hasAuthed()) {
if(!$this->ctx->authz->authed) {
$authzHeader = false;
$authz->attemptBasicAppAuth(
$this->ctx->authz->attemptBasicAppAuth(
(string)filter_input(INPUT_SERVER, 'REMOTE_ADDR'),
(string)$content->getParam('client_id'),
(string)$content->getParam('client_secret')
);
}
if(!$authz->isApp())
if(!$this->ctx->authz->isApp)
return self::filter($response, [
'error' => 'invalid_client',
'error_description' => 'App authentication failed.',
]);
if($authz->getError() === 'secret')
if($this->ctx->authz->error === 'secret')
return self::filter($response, [
'error' => 'invalid_client',
'error_description' => 'Provided client secret is not correct for this application.'
@ -170,7 +168,10 @@ class OAuth2Routes implements RouteHandler {
try {
$name = '';
$args = ['appId' => $authz->getAppId(), 'isAuthed' => $authz->isConfidentialApp()];
$args = [
'appId' => $this->ctx->authz->appId,
'isAuthed' => $this->ctx->authz->isConfidentialApp
];
switch($content->getParam('grant_type')) {
case 'authorization_code':

View file

@ -1,38 +0,0 @@
<?php
namespace Syokuhou\RpcModels\Hanyuu;
use Syokuhou\RpcModels\RpcModel;
class OAuth2AuthInfo extends RpcModel {
public function getMethod(): string {
return $this->getString('method');
}
public function isAuthed(): bool {
return $this->getBoolean('authed');
}
public function getAppId(): string {
return $this->getString('app_id');
}
public function hasUserId(): bool {
return $this->hasValue('user_id');
}
public function isAppUser(): bool {
return $this->getMethod() === 'basic' || $this->getUserId() === '0';
}
public function getUserId(): string {
return $this->getString('user_id');
}
public function getScope(): string {
return $this->getString('scope');
}
public function getExpiresIn(): int {
return $this->getInteger('expires_in');
}
}

View file

@ -4,19 +4,19 @@ namespace Syokuhou\RpcModels\Hanyuu;
use Syokuhou\RpcModels\RpcModel;
class OAuth2RfcModel extends RpcModel {
public function hasErrorDescription(): bool {
return $this->hasValue('error_description');
public bool $hasErrorDescription {
get => $this->hasValue('error_description');
}
public function getErrorDescription(): string {
return $this->getString('error_description');
public string $errorDescription {
get => $this->getString('error_description');
}
public function hasErrorUri(): bool {
return $this->hasValue('error_uri');
public bool $hasErrorUri {
get => $this->hasValue('error_uri');
}
public function getErrorUri(): string {
return $this->getString('error_uri');
public string $errorUri {
get => $this->getString('error_uri');
}
}

View file

@ -8,16 +8,16 @@ abstract class RpcModel {
$this->info = $info;
}
public function hasError(): bool {
return $this->hasValue('error');
public bool $hasError {
get => $this->hasValue('error');
}
public function getError(): string {
return $this->getString('error');
public string $error {
get => $this->getString('error');
}
public function getRaw(): array {
return $this->info;
public array $raw {
get => $this->info;
}
protected function hasValue(string $name): bool {

View file

@ -2,21 +2,20 @@
namespace Syokuhou;
use RuntimeException;
use Syokuhou\RpcModels\Hanyuu\OAuth2AuthInfo;
use Index\Config\Config;
use Index\Http\Routing\{HttpRouter,Router};
class SyokuhouContext {
private RpcClientWrapper $rpcWrapper;
private HttpRouter $router;
private AuthzContext $authz;
public private(set) RpcClientWrapper $rpc;
public private(set) AuthzContext $authz;
public private(set) HttpRouter $router;
public function __construct(Config $config) {
$this->rpcWrapper = new RpcClientWrapper;
$this->rpcWrapper->createHmacConfig($config, 'hanyuu');
$this->rpcWrapper->createHmacConfig($config, 'misuzu');
$this->rpc = new RpcClientWrapper;
$this->rpc->createHmacConfig($config, 'hanyuu');
$this->rpc->createHmacConfig($config, 'misuzu');
$this->authz = new AuthzContext($this->rpcWrapper);
$this->authz = new AuthzContext($this->rpc);
$this->router = new HttpRouter(
errorHandler: 'plain',
@ -30,18 +29,6 @@ class SyokuhouContext {
$this->router->scopeTo('/v1')->register(new V1\V1Routes(new V1\V1Context($this)));
}
public function getRpcClient(): RpcClientWrapper {
return $this->rpcWrapper;
}
public function getRouter(): Router {
return $this->router;
}
public function getAuthzContext(): AuthzContext {
return $this->authz;
}
public function handleAcceptHeader($response, $request) {
$accept = HttpAcceptHeader::parse($request->getHeaderLine('Accept'));
$contentHandler = new SyokuhouContentHandler($accept);

View file

@ -9,11 +9,11 @@ class V1Context {
private SyokuhouContext $ctx
) {}
public function getRpcClient(): RpcClient {
return $this->ctx->getRpcClient();
public RpcClient $rpc {
get => $this->ctx->rpc;
}
public function getAuthzContext(): AuthzContext {
return $this->ctx->getAuthzContext();
public AuthzContext $authz {
get => $this->ctx->authz;
}
}

View file

@ -9,17 +9,16 @@ class V1Routes implements RouteHandler {
) {}
public function registerRoutes(Router $router): void {
$authz = $this->ctx->getAuthzContext();
$router->use('/', $authz->bearerTokenAuthMiddleware(...));
$router->use('/', $authz->misuzuTokenAuthMiddleware(...));
$router->use('/', $this->ctx->authz->bearerTokenAuthMiddleware(...));
$router->use('/', $this->ctx->authz->misuzuTokenAuthMiddleware(...));
$router->get('/', fn() => ['status' => 'operational']);
$router->scopeTo('/emotes')->register(
new V1EmotesRoutes($this->ctx->getRpcClient()->scopeTo('misuzu:emotes:'))
new V1EmotesRoutes($this->ctx->rpc->scopeTo('misuzu:emotes:'))
);
$usersRoutes = new V1UsersRoutes($this->ctx, $this->ctx->getRpcClient()->scopeTo('misuzu:users:'));
$usersRoutes = new V1UsersRoutes($this->ctx, $this->ctx->rpc->scopeTo('misuzu:users:'));
$router->options('/me', $usersRoutes->getMe(...));
$router->get('/me', $usersRoutes->getMe(...));
$router->scopeTo('/users')->register($usersRoutes);

View file

@ -17,19 +17,19 @@ class V1UsersRoutes implements RouteHandler {
$response->setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
$response->setHeader('Cache-Control', 'no-store');
$authz = $this->ctx->getAuthzContext();
if(!$authz->hasScope('identify') && !$authz->hasScope('beans'))
if(!$this->ctx->authz->hasScope('identify')
&& !$this->ctx->authz->hasScope('beans'))
return 403;
if($authz->isAppUser()) {
if($this->ctx->authz->isAppUser) {
// TODO: what should app users even look like?
return 501;
}
if($authz->isRealUser()) {
if($this->ctx->authz->isRealUser) {
$userInfo = $this->rpc->query('getUser', [
'userId' => $authz->getUserId(),
'includeEMailAddress' => $authz->hasScope('identify:email'),
'userId' => $this->ctx->authz->userId,
'includeEMailAddress' => $this->ctx->authz->hasScope('identify:email'),
]);
if(!is_array($userInfo))
return 500;