Updated to new HTTP router.

This commit is contained in:
flash 2024-03-28 23:28:19 +00:00
parent ef5535cb39
commit 8880303543
8 changed files with 72 additions and 65 deletions

32
composer.lock generated
View file

@ -67,7 +67,7 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://patchii.net/flash/index.git", "url": "https://patchii.net/flash/index.git",
"reference": "73051dc71ee2d0045e5dbe5d846bb665a8b1c39c" "reference": "9d5b050b8928435416a7efbebe2a19ae8e626224"
}, },
"require": { "require": {
"ext-mbstring": "*", "ext-mbstring": "*",
@ -105,7 +105,7 @@
], ],
"description": "Composer package for the common library for my projects.", "description": "Composer package for the common library for my projects.",
"homepage": "https://railgun.sh/index", "homepage": "https://railgun.sh/index",
"time": "2024-02-06T23:52:46+00:00" "time": "2024-03-28T23:27:04+00:00"
}, },
{ {
"name": "flashwave/sasae", "name": "flashwave/sasae",
@ -305,16 +305,16 @@
}, },
{ {
"name": "jean85/pretty-package-versions", "name": "jean85/pretty-package-versions",
"version": "2.0.5", "version": "2.0.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Jean85/pretty-package-versions.git", "url": "https://github.com/Jean85/pretty-package-versions.git",
"reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af" "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af", "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/f9fdd29ad8e6d024f52678b570e5593759b550b4",
"reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af", "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -322,9 +322,9 @@
"php": "^7.1|^8.0" "php": "^7.1|^8.0"
}, },
"require-dev": { "require-dev": {
"friendsofphp/php-cs-fixer": "^2.17", "friendsofphp/php-cs-fixer": "^3.2",
"jean85/composer-provided-replaced-stub-package": "^1.0", "jean85/composer-provided-replaced-stub-package": "^1.0",
"phpstan/phpstan": "^0.12.66", "phpstan/phpstan": "^1.4",
"phpunit/phpunit": "^7.5|^8.5|^9.4", "phpunit/phpunit": "^7.5|^8.5|^9.4",
"vimeo/psalm": "^4.3" "vimeo/psalm": "^4.3"
}, },
@ -358,9 +358,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/Jean85/pretty-package-versions/issues", "issues": "https://github.com/Jean85/pretty-package-versions/issues",
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5" "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.6"
}, },
"time": "2021-10-08T21:21:46+00:00" "time": "2024-03-08T09:58:59+00:00"
}, },
{ {
"name": "psr/http-factory", "name": "psr/http-factory",
@ -802,16 +802,16 @@
}, },
{ {
"name": "sentry/sentry", "name": "sentry/sentry",
"version": "4.6.0", "version": "4.6.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/getsentry/sentry-php.git", "url": "https://github.com/getsentry/sentry-php.git",
"reference": "30d98a460ab10f7b7032d76c62da5b1ce6c0765d" "reference": "5a94184175e5830b589bf923da8c9c3af2c0f409"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/30d98a460ab10f7b7032d76c62da5b1ce6c0765d", "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/5a94184175e5830b589bf923da8c9c3af2c0f409",
"reference": "30d98a460ab10f7b7032d76c62da5b1ce6c0765d", "reference": "5a94184175e5830b589bf923da8c9c3af2c0f409",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -875,7 +875,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/getsentry/sentry-php/issues", "issues": "https://github.com/getsentry/sentry-php/issues",
"source": "https://github.com/getsentry/sentry-php/tree/4.6.0" "source": "https://github.com/getsentry/sentry-php/tree/4.6.1"
}, },
"funding": [ "funding": [
{ {
@ -887,7 +887,7 @@
"type": "custom" "type": "custom"
} }
], ],
"time": "2024-02-13T11:32:56+00:00" "time": "2024-03-08T08:18:09+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",

View file

@ -1,7 +1,7 @@
<?php <?php
namespace Mince; namespace Mince;
use Index\Http\HttpFx; use Index\Http\Routing\HttpRouter;
use Index\Security\CSRFP; use Index\Security\CSRFP;
use Sasae\SasaeEnvironment; use Sasae\SasaeEnvironment;
@ -36,19 +36,8 @@ $authorisations->prune();
$verifications = new Verifications($db); $verifications = new Verifications($db);
$verifications->prune(); $verifications->prune();
$router = new HttpFx; $router = new HttpRouter(errorHandler: new RouterErrorHandler($templating));
$router->use('/', function($response, $request) { $router->use('/', function($response, $request) { $response->setPoweredBy('Mince'); });
$response->setPoweredBy('Mince');
});
$router->setDefaultErrorHandler(function($response, $request, $code, $text) use ($templating) {
$response->setContent($templating->render('http-error', [
'error' => [
'code' => sprintf('%03d', $code),
'text' => $text,
],
]));
});
$router->register(new RpcRoutes($users, $accountLinks, $authorisations, $verifications, $cfg->getString('rpc:secret'), $cfg->getString('urls:clients'))); $router->register(new RpcRoutes($users, $accountLinks, $authorisations, $verifications, $cfg->getString('rpc:secret'), $cfg->getString('urls:clients')));
$router->register(new HomeRoutes($templating, new Servers($db), $authInfo, $cfg->getString('site:login'))); $router->register(new HomeRoutes($templating, new Servers($db), $authInfo, $cfg->getString('site:login')));

View file

@ -3,7 +3,7 @@ namespace Mince;
use InvalidArgumentException; use InvalidArgumentException;
use RuntimeException; use RuntimeException;
use Index\Routing\{Route,RouteHandler}; use Index\Http\Routing\{RouteHandler,HttpGet,HttpMiddleware,HttpPost};
use Index\Security\CSRFP; use Index\Security\CSRFP;
use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Uuid;
use Sasae\SasaeEnvironment; use Sasae\SasaeEnvironment;
@ -18,7 +18,7 @@ class ClientsRoutes extends RouteHandler {
private object $authInfo private object $authInfo
) {} ) {}
#[Route('/clients')] #[HttpMiddleware('/clients')]
public function verifyRequest($response, $request) { public function verifyRequest($response, $request) {
if(!$this->authInfo->success) if(!$this->authInfo->success)
return 403; return 403;
@ -41,7 +41,7 @@ class ClientsRoutes extends RouteHandler {
], ],
]; ];
#[Route('GET', '/clients')] #[HttpGet('/clients')]
public function getClients($response, $request) { public function getClients($response, $request) {
$template = $this->templating->load('clients/index'); $template = $this->templating->load('clients/index');
@ -73,7 +73,7 @@ class ClientsRoutes extends RouteHandler {
return $template; return $template;
} }
#[Route('POST', '/clients/link')] #[HttpPost('/clients/link')]
public function postLink($response, $request) { public function postLink($response, $request) {
if($this->accountLinks->checkHasLink($this->authInfo->user_id)) { if($this->accountLinks->checkHasLink($this->authInfo->user_id)) {
$response->redirect('/clients?error=link:already'); $response->redirect('/clients?error=link:already');
@ -103,13 +103,13 @@ class ClientsRoutes extends RouteHandler {
$response->redirect('/clients'); $response->redirect('/clients');
} }
#[Route('POST', '/clients/unlink')] #[HttpPost('/clients/unlink')]
public function postUnlink($response) { public function postUnlink($response) {
$this->accountLinks->deleteLink(userInfo: $this->authInfo->user_id); $this->accountLinks->deleteLink(userInfo: $this->authInfo->user_id);
$response->redirect('/clients'); $response->redirect('/clients');
} }
#[Route('POST', '/clients/authorise')] #[HttpPost('/clients/authorise')]
public function postAuthorise($response, $request) { public function postAuthorise($response, $request) {
$body = $request->getContent(); $body = $request->getContent();
$authId = (string)$body->getParam('auth'); $authId = (string)$body->getParam('auth');
@ -138,7 +138,7 @@ class ClientsRoutes extends RouteHandler {
$response->redirect('/clients'); $response->redirect('/clients');
} }
#[Route('POST', '/clients/deauthorise')] #[HttpPost('/clients/deauthorise')]
public function postDeauthorise($response, $request) { public function postDeauthorise($response, $request) {
$body = $request->getContent(); $body = $request->getContent();
$authId = (string)$body->getParam('auth'); $authId = (string)$body->getParam('auth');

View file

@ -1,7 +1,7 @@
<?php <?php
namespace Mince; namespace Mince;
use Index\Routing\{Route,RouteHandler}; use Index\Http\Routing\{HttpGet,RouteHandler};
use Sasae\SasaeEnvironment; use Sasae\SasaeEnvironment;
class HomeRoutes extends RouteHandler { class HomeRoutes extends RouteHandler {
@ -12,29 +12,29 @@ class HomeRoutes extends RouteHandler {
private string $loginUrl private string $loginUrl
) {} ) {}
#[Route('GET', '/')] #[HttpGet('/')]
public function getIndex($response, $request) { public function getIndex($response, $request) {
return $this->templating->render('index', [ return $this->templating->render('index', [
'servers' => iterator_to_array($this->servers->getServers(deleted: false)), 'servers' => iterator_to_array($this->servers->getServers(deleted: false)),
]); ]);
} }
#[Route('GET', '/login')] #[HttpGet('/login')]
public function getLogin($response) { public function getLogin($response) {
$response->redirect($this->userInfo->success ? '/' : $this->loginUrl); $response->redirect($this->userInfo->success ? '/' : $this->loginUrl);
} }
#[Route('GET', '/downloads')] #[HttpGet('/downloads')]
public function getDownloads() { public function getDownloads() {
return $this->templating->render('downloads'); return $this->templating->render('downloads');
} }
#[Route('GET', '/guide')] #[HttpGet('/guide')]
public function getGuide() { public function getGuide() {
return $this->templating->render('guide'); return $this->templating->render('guide');
} }
#[Route('GET', '/index.php')] #[HttpGet('/index.php')]
public function getRedirect($response) { public function getRedirect($response) {
$response->redirect('/', true); $response->redirect('/', true);
} }

View file

@ -3,7 +3,7 @@ namespace Mince;
use stdClass; use stdClass;
use Index\Http\{HttpResponseBuilder,HttpRequest}; use Index\Http\{HttpResponseBuilder,HttpRequest};
use Index\Routing\IRouter; use Index\Http\Routing\IRouter;
use Ramsey\Uuid\{Uuid,UuidInterface}; use Ramsey\Uuid\{Uuid,UuidInterface};
final class MojangInterop { final class MojangInterop {

View file

@ -0,0 +1,22 @@
<?php
namespace Mince;
use Index\Http\{HttpResponseBuilder,HttpRequest};
use Index\Http\ErrorHandling\IErrorHandler;
use Sasae\SasaeEnvironment;
class RouterErrorHandler implements IErrorHandler {
public function __construct(
private SasaeEnvironment $templating
) {}
public function handle(HttpResponseBuilder $response, HttpRequest $request, int $code, string $message): void {
$response->setTypeHTML();
$response->setContent($this->templating->render('http-error', [
'error' => [
'code' => sprintf('%03d', $code),
'text' => $message,
],
]));
}
}

View file

@ -5,7 +5,7 @@ use stdClass;
use InvalidArgumentException; use InvalidArgumentException;
use RuntimeException; use RuntimeException;
use Stringable; use Stringable;
use Index\Routing\{Route,RouteHandler}; use Index\Http\Routing\{HttpMiddleware,HttpPost,RouteHandler};
use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Uuid;
class RpcRoutes extends RouteHandler { class RpcRoutes extends RouteHandler {
@ -41,7 +41,7 @@ class RpcRoutes extends RouteHandler {
return self::createPayload('error', $attrs); return self::createPayload('error', $attrs);
} }
#[Route('/rpc')] #[HttpMiddleware('/rpc')]
public function verifyRequest($response, $request) { public function verifyRequest($response, $request) {
$userTime = (int)$request->getHeaderLine('X-Mince-Time'); $userTime = (int)$request->getHeaderLine('X-Mince-Time');
$userHash = base64_decode((string)$request->getHeaderLine('X-Mince-Hash')); $userHash = base64_decode((string)$request->getHeaderLine('X-Mince-Hash'));
@ -68,7 +68,7 @@ class RpcRoutes extends RouteHandler {
return self::createErrorPayload('verification', 'Request verification failed.'); return self::createErrorPayload('verification', 'Request verification failed.');
} }
#[Route('POST', '/rpc/auth')] #[HttpPost('/rpc/auth')]
public function postAuth($response, $request) { public function postAuth($response, $request) {
$body = $request->getContent(); $body = $request->getContent();

View file

@ -7,7 +7,7 @@ use ImagickPixel;
use InvalidArgumentException; use InvalidArgumentException;
use RuntimeException; use RuntimeException;
use Index\XString; use Index\XString;
use Index\Routing\{Route,RouteHandler}; use Index\Http\Routing\{RouteHandler,HttpGet,HttpMiddleware,HttpPost};
use Index\Security\CSRFP; use Index\Security\CSRFP;
use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Uuid;
use Sasae\SasaeEnvironment; use Sasae\SasaeEnvironment;
@ -52,7 +52,7 @@ class SkinsRoutes extends RouteHandler {
unlink($path); unlink($path);
} }
#[Route('/skins')] #[HttpMiddleware('/skins')]
public function verifyRequest($response, $request) { public function verifyRequest($response, $request) {
if(!$this->authInfo->success) if(!$this->authInfo->success)
return 403; return 403;
@ -86,7 +86,7 @@ class SkinsRoutes extends RouteHandler {
], ],
]; ];
#[Route('GET', '/skins')] #[HttpGet('/skins')]
public function getSkins($response, $request) { public function getSkins($response, $request) {
$skinInfo = $this->skins->getSkin($this->linkInfo); $skinInfo = $this->skins->getSkin($this->linkInfo);
$skinPath = $skinInfo === null ? null : $this->getRemotePath($skinInfo->getHash(), false); $skinPath = $skinInfo === null ? null : $this->getRemotePath($skinInfo->getHash(), false);
@ -119,7 +119,7 @@ class SkinsRoutes extends RouteHandler {
return $template; return $template;
} }
#[Route('POST', '/skins/upload-skin')] #[HttpPost('/skins/upload-skin')]
public function postUploadSkin($response, $request) { public function postUploadSkin($response, $request) {
$body = $request->getContent(); $body = $request->getContent();
if(!$body->hasUploadedFile('texture')) if(!$body->hasUploadedFile('texture'))
@ -182,7 +182,7 @@ class SkinsRoutes extends RouteHandler {
$response->redirect('/skins'); $response->redirect('/skins');
} }
#[Route('POST', '/skins/delete-skin')] #[HttpPost('/skins/delete-skin')]
public function postDeleteSkin($response) { public function postDeleteSkin($response) {
$skinInfo = $this->skins->getSkin($this->linkInfo); $skinInfo = $this->skins->getSkin($this->linkInfo);
if($skinInfo !== null) { if($skinInfo !== null) {
@ -193,7 +193,7 @@ class SkinsRoutes extends RouteHandler {
$response->redirect('/skins'); $response->redirect('/skins');
} }
#[Route('POST', '/skins/upload-cape')] #[HttpPost('/skins/upload-cape')]
public function postUploadCape($response, $request) { public function postUploadCape($response, $request) {
$body = $request->getContent(); $body = $request->getContent();
if(!$body->hasUploadedFile('texture')) if(!$body->hasUploadedFile('texture'))
@ -245,7 +245,7 @@ class SkinsRoutes extends RouteHandler {
$response->redirect('/skins'); $response->redirect('/skins');
} }
#[Route('POST', '/skins/delete-cape')] #[HttpPost('/skins/delete-cape')]
public function postDeleteCape($response) { public function postDeleteCape($response) {
$capeInfo = $this->capes->getCape($this->linkInfo); $capeInfo = $this->capes->getCape($this->linkInfo);
if($capeInfo !== null) { if($capeInfo !== null) {
@ -256,7 +256,7 @@ class SkinsRoutes extends RouteHandler {
$response->redirect('/skins'); $response->redirect('/skins');
} }
#[Route('POST', '/skins/import')] #[HttpPost('/skins/import')]
public function postImport($response, $request) { public function postImport($response, $request) {
$body = $request->getContent(); $body = $request->getContent();
$userAgent = $request->getHeaderLine('User-Agent'); $userAgent = $request->getHeaderLine('User-Agent');
@ -326,7 +326,7 @@ class SkinsRoutes extends RouteHandler {
$response->redirect('/skins'); $response->redirect('/skins');
} }
#[Route('GET', '/session/minecraft/profile/:id')] #[HttpGet('/session/minecraft/profile/([a-fA-F0-9\-]+)')]
public function getSessionMinecraftProfile($response, $request, string $id) { public function getSessionMinecraftProfile($response, $request, string $id) {
try { try {
$uuid = Uuid::fromString($id); $uuid = Uuid::fromString($id);
@ -386,7 +386,7 @@ class SkinsRoutes extends RouteHandler {
]; ];
} }
#[Route('GET', '/users/profiles/minecraft/:name')] #[HttpGet('/users/profiles/minecraft/([A-Za-z0-9_]+)')]
public function getUsersMinecraftProfile($response, $request, string $name) { public function getUsersMinecraftProfile($response, $request, string $name) {
try { try {
$linkInfo = $this->accountLinks->getLink(name: $name); $linkInfo = $this->accountLinks->getLink(name: $name);
@ -405,15 +405,11 @@ class SkinsRoutes extends RouteHandler {
} }
// quirky path and two of them to achieve equal string length with http://s3.amazonaws.com/MinecraftSkins/ for flashii.net and edgii.net // quirky path and two of them to achieve equal string length with http://s3.amazonaws.com/MinecraftSkins/ for flashii.net and edgii.net
#[Route('GET', '/s3MinecraftSkins/:filename')] #[HttpGet('/s3MinecraftSkins/([A-Za-z0-9_]+).png')]
#[Route('GET', '/s3s3MinecraftSkins/:filename')] #[HttpGet('/s3s3MinecraftSkins/([A-Za-z0-9_]+).png')]
public function getS3MinecraftSkin($response, $request, string $name) { public function getS3MinecraftSkin($response, $request, string $name) {
$path = pathinfo($name);
if(empty($path) || empty($path['filename']) || empty($path['extension']) || $path['extension'] !== 'png')
return 404;
try { try {
$linkInfo = $this->accountLinks->getLink(name: $path['filename']); $linkInfo = $this->accountLinks->getLink(name: $name);
} catch(RuntimeException $ex) { } catch(RuntimeException $ex) {
return 404; return 404;
} }
@ -424,6 +420,6 @@ class SkinsRoutes extends RouteHandler {
$response->accelRedirect($this->getRemotePath($skinInfo->getHash(), false)); $response->accelRedirect($this->getRemotePath($skinInfo->getHash(), false));
$response->setContentType('image/png'); $response->setContentType('image/png');
$response->setFileName("{$path['filename']}.{$path['extension']}", false); $response->setFileName("{$name}.png", false);
} }
} }