Updated to use asymmetric access and property hooks.
This commit is contained in:
parent
2829419111
commit
aac8911b4b
12 changed files with 156 additions and 240 deletions
|
@ -5,6 +5,7 @@
|
|||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.4",
|
||||
"flashwave/index": "^0.2410",
|
||||
"flashii/rpcii": "^2.0",
|
||||
"sentry/sdk": "^4.0"
|
||||
|
|
107
composer.lock
generated
107
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": "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"
|
||||
}
|
||||
|
|
|
@ -18,4 +18,4 @@ set_exception_handler(function(\Throwable $ex) {
|
|||
exit;
|
||||
});
|
||||
|
||||
$ctx->getRouter()->dispatch();
|
||||
$ctx->router->dispatch();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue