Added ability to scope RoutingContext.

This commit is contained in:
flash 2025-01-29 00:25:53 +00:00
parent 06d0413976
commit 33344541d6
10 changed files with 235 additions and 165 deletions

View file

@ -22,26 +22,26 @@ error_reporting(MSZ_DEBUG ? -1 : 0);
mb_internal_encoding('UTF-8'); mb_internal_encoding('UTF-8');
date_default_timezone_set('GMT'); date_default_timezone_set('GMT');
$cfg = FsConfig::fromFile(MSZ_CONFIG . '/config.cfg'); $env = FsConfig::fromFile(MSZ_CONFIG . '/config.cfg');
if($cfg->hasValues('sentry:dsn')) if($env->hasValues('sentry:dsn'))
(function($cfg) { (function($env) {
\Sentry\init([ \Sentry\init([
'dsn' => $cfg->getString('dsn'), 'dsn' => $env->getString('dsn'),
'traces_sample_rate' => $cfg->getFloat('tracesRate', 0.2), 'traces_sample_rate' => $env->getFloat('tracesRate', 0.2),
'profiles_sample_rate' => $cfg->getFloat('profilesRate', 0.2), 'profiles_sample_rate' => $env->getFloat('profilesRate', 0.2),
]); ]);
set_exception_handler(function(\Throwable $ex) { set_exception_handler(function(\Throwable $ex) {
\Sentry\captureException($ex); \Sentry\captureException($ex);
}); });
})($cfg->scopeTo('sentry')); })($env->scopeTo('sentry'));
$db = DbBackends::create($cfg->getString('database:dsn', 'null:')); $db = DbBackends::create($env->getString('database:dsn', 'null:'));
$db->execute('SET SESSION time_zone = \'+00:00\', sql_mode = \'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION\';'); $db->execute('SET SESSION time_zone = \'+00:00\', sql_mode = \'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION\';');
$cfg = new DbConfig($db, 'msz_config'); $cfg = new DbConfig($db, 'msz_config');
Mailer::init($cfg->scopeTo('mail')); Mailer::init($cfg->scopeTo('mail'));
$msz = new MisuzuContext($db, $cfg); $msz = new MisuzuContext($db, $cfg, $env);

View file

@ -126,25 +126,27 @@ CSRF::init(
); );
// order for these two currently matters i think: it shouldn't. // order for these two currently matters i think: it shouldn't.
$router = $msz->createRouting(); $router = $msz->createRouting($request);
$msz->startTemplating(); $msz->startTemplating();
$mszRequestPath = substr($request->getPath(), 1); if(in_array('main', $env->getArray(sprintf('domain:%s', $request->getHeaderLine('Host'))))) {
$mszLegacyPathPrefix = MSZ_PUBLIC . '-legacy/'; $mszRequestPath = substr($request->getPath(), 1);
$mszLegacyPath = $mszLegacyPathPrefix . $mszRequestPath; $mszLegacyPathPrefix = MSZ_PUBLIC . '-legacy/';
$mszLegacyPath = $mszLegacyPathPrefix . $mszRequestPath;
if(str_starts_with($mszLegacyPath, $mszLegacyPathPrefix)) { if(str_starts_with($mszLegacyPath, $mszLegacyPathPrefix)) {
$mszLegacyPathReal = realpath($mszLegacyPath); $mszLegacyPathReal = realpath($mszLegacyPath);
if($mszLegacyPath === $mszLegacyPathReal || $mszLegacyPath === $mszLegacyPathReal . '/') { if($mszLegacyPath === $mszLegacyPathReal || $mszLegacyPath === $mszLegacyPathReal . '/') {
if(str_starts_with($mszRequestPath, '/manage') && !$msz->hasManageAccess()) if(str_starts_with($mszRequestPath, '/manage') && !$msz->hasManageAccess())
Template::throwError(403); Template::throwError(403);
if(is_dir($mszLegacyPath)) if(is_dir($mszLegacyPath))
$mszLegacyPath .= '/index.php'; $mszLegacyPath .= '/index.php';
if(is_file($mszLegacyPath)) { if(is_file($mszLegacyPath)) {
require_once $mszLegacyPath; require_once $mszLegacyPath;
return; return;
}
} }
} }
} }

View file

@ -13,12 +13,14 @@ use Misuzu\Messages\MessagesContext;
use Misuzu\News\News; use Misuzu\News\News;
use Misuzu\Perms\Permissions; use Misuzu\Perms\Permissions;
use Misuzu\Profile\ProfileFields; use Misuzu\Profile\ProfileFields;
use Misuzu\Routing\{BackedRoutingContext,RoutingContext};
use Misuzu\Users\{UsersContext,UserInfo}; use Misuzu\Users\{UsersContext,UserInfo};
use RPCii\HmacVerificationProvider; use RPCii\HmacVerificationProvider;
use RPCii\Server\HttpRpcServer; use RPCii\Server\HttpRpcServer;
use Index\Config\Config; use Index\Config\Config;
use Index\Db\DbConnection; use Index\Db\DbConnection;
use Index\Db\Migration\{DbMigrationManager,DbMigrationRepo,FsDbMigrationRepo}; use Index\Db\Migration\{DbMigrationManager,DbMigrationRepo,FsDbMigrationRepo};
use Index\Http\HttpRequest;
use Index\Templating\TplEnvironment; use Index\Templating\TplEnvironment;
use Index\Urls\UrlRegistry; use Index\Urls\UrlRegistry;
@ -55,7 +57,8 @@ class MisuzuContext {
public function __construct( public function __construct(
public private(set) DbConnection $dbConn, public private(set) DbConnection $dbConn,
public private(set) Config $config public private(set) Config $config,
public private(set) Config $env
) { ) {
$this->perms = new Permissions($dbConn); $this->perms = new Permissions($dbConn);
$this->authInfo = new AuthInfo($this->perms); $this->authInfo = new AuthInfo($this->perms);
@ -144,132 +147,144 @@ class MisuzuContext {
Template::init($this->templating); Template::init($this->templating);
} }
public function createRouting(): RoutingContext { public function createRouting(HttpRequest $request): RoutingContext {
$routingCtx = new RoutingContext; $prefix = sprintf('domain:%s', $request->getHeaderLine('Host'));
$hostInfo = $this->env->scopeTo($prefix);
$purposes = $this->env->getArray($prefix);
$routingCtx = new BackedRoutingContext;
$this->urls = $routingCtx->urls; $this->urls = $routingCtx->urls;
$routingCtx->register(new \Misuzu\Home\HomeRoutes( if(in_array('main', $purposes)) {
$this->config, $scopedInfo = $hostInfo->scopeTo('main');
$this->dbConn, $scopedCtx = $routingCtx->scopeTo(
$this->siteInfo, $scopedInfo->getString('name'),
$this->authInfo, $scopedInfo->getString('path')
$this->changelog, );
$this->comments,
$this->counters,
$this->news,
$this->usersCtx
));
$routingCtx->register(new \Misuzu\Users\Assets\AssetsRoutes( $scopedCtx->register(new \Misuzu\Home\HomeRoutes(
$this->authInfo, $this->config,
$this->urls, $this->dbConn,
$this->usersCtx $this->siteInfo,
)); $this->authInfo,
$this->changelog,
$this->comments,
$this->counters,
$this->news,
$this->usersCtx
));
$routingCtx->register(new \Misuzu\Info\InfoRoutes); $scopedCtx->register(new \Misuzu\Users\Assets\AssetsRoutes(
$this->authInfo,
$this->urls,
$this->usersCtx
));
$routingCtx->register(new \Misuzu\News\NewsRoutes( $scopedCtx->register(new \Misuzu\Info\InfoRoutes);
$this->siteInfo,
$this->authInfo,
$this->urls,
$this->news,
$this->usersCtx,
$this->comments
));
$routingCtx->register(new \Misuzu\Messages\MessagesRoutes( $scopedCtx->register(new \Misuzu\News\NewsRoutes(
$this->config->scopeTo('messages'), $this->siteInfo,
$this->urls, $this->authInfo,
$this->authInfo, $this->urls,
$this->messagesCtx, $this->news,
$this->usersCtx, $this->usersCtx,
$this->perms $this->comments
)); ));
$routingCtx->register(new \Misuzu\Forum\ForumCategoriesRoutes( $scopedCtx->register(new \Misuzu\Messages\MessagesRoutes(
$this->forumCtx, $this->config->scopeTo('messages'),
$this->usersCtx, $this->urls,
$this->authInfo, $this->authInfo,
)); $this->messagesCtx,
$routingCtx->register(new \Misuzu\Forum\ForumTopicsRoutes( $this->usersCtx,
$this->urls, $this->perms
$this->forumCtx, ));
$this->usersCtx,
$this->auditLog,
$this->authInfo,
));
$routingCtx->register(new \Misuzu\Forum\ForumPostsRoutes(
$this->urls,
$this->forumCtx,
$this->usersCtx,
$this->auditLog,
$this->authInfo,
));
$routingCtx->register(new \Misuzu\Changelog\ChangelogRoutes( $scopedCtx->register(new \Misuzu\Forum\ForumCategoriesRoutes(
$this->siteInfo, $this->forumCtx,
$this->urls, $this->usersCtx,
$this->changelog, $this->authInfo,
$this->usersCtx, ));
$this->authInfo, $scopedCtx->register(new \Misuzu\Forum\ForumTopicsRoutes(
$this->comments $this->urls,
)); $this->forumCtx,
$this->usersCtx,
$this->auditLog,
$this->authInfo,
));
$scopedCtx->register(new \Misuzu\Forum\ForumPostsRoutes(
$this->urls,
$this->forumCtx,
$this->usersCtx,
$this->auditLog,
$this->authInfo,
));
$routingCtx->register(new \Misuzu\SharpChat\SharpChatRoutes( $scopedCtx->register(new \Misuzu\Changelog\ChangelogRoutes(
$this->config->scopeTo('sockChat'), $this->siteInfo,
$this->config->scopeTo('impersonate'), $this->urls,
$this->urls, $this->changelog,
$this->usersCtx, $this->usersCtx,
$this->authCtx, $this->authInfo,
$this->emotes, $this->comments
$this->perms, ));
$this->authInfo,
$this->counters
));
$routingCtx->register(new \Misuzu\Satori\SatoriRoutes( $scopedCtx->register(new \Misuzu\SharpChat\SharpChatRoutes(
$this->config->scopeTo('satori'), $this->config->scopeTo('sockChat'),
$this->usersCtx, $this->config->scopeTo('impersonate'),
$this->forumCtx, $this->urls,
$this->profileFields $this->usersCtx,
)); $this->authCtx,
$this->emotes,
$this->perms,
$this->authInfo,
$this->counters
));
$routingCtx->register(new LegacyRoutes($this->urls)); $scopedCtx->register(new \Misuzu\Satori\SatoriRoutes(
$this->config->scopeTo('satori'),
$this->usersCtx,
$this->forumCtx,
$this->profileFields
));
$rpcServer = new HttpRpcServer; $routingCtx->register(new LegacyRoutes($this->urls));
$routingCtx->router->register($rpcServer->createRouteHandler(
new HmacVerificationProvider(fn() => $this->config->getString('aleister.secret'))
));
$rpcServer->register(new Auth\AuthRpcHandler( $rpcServer = new HttpRpcServer;
$this->config->scopeTo('impersonate'), $scopedCtx->register($rpcServer->createRouteHandler(
$this->usersCtx, new HmacVerificationProvider(fn() => $this->config->getString('aleister.secret'))
$this->authCtx ));
));
$rpcServer->register(new Emoticons\EmotesRpcHandler( $rpcServer->register(new Auth\AuthRpcHandler(
$this->emotes $this->config->scopeTo('impersonate'),
)); $this->usersCtx,
$this->authCtx
));
$rpcServer->register(new Users\UsersRpcHandler( $rpcServer->register(new Emoticons\EmotesRpcHandler(
$this->siteInfo, $this->emotes
$this->urls, ));
$this->usersCtx
));
// This RPC server will eventually despawn when Hanyuu fully owns auth $rpcServer->register(new Users\UsersRpcHandler(
$hanyuuRpcServer = new HttpRpcServer; $this->siteInfo,
$routingCtx->router->scopeTo('/_hanyuu')->register($hanyuuRpcServer->createRouteHandler( $this->urls,
new HmacVerificationProvider(fn() => $this->config->getString('hanyuu.secret')) $this->usersCtx
)); ));
$hanyuuRpcServer->register(new Hanyuu\HanyuuRpcHandler( // This RPC server will eventually despawn when Hanyuu fully owns auth
fn() => $this->config->getString('hanyuu.endpoint'), $hanyuuRpcServer = new HttpRpcServer;
$this->config->scopeTo('impersonate'), $scopedCtx->scopeTo('', '/_hanyuu')->register($hanyuuRpcServer->createRouteHandler(
$this->urls, new HmacVerificationProvider(fn() => $this->config->getString('hanyuu.secret'))
$this->usersCtx, ));
$this->authCtx
)); $hanyuuRpcServer->register(new Hanyuu\HanyuuRpcHandler(
fn() => $this->config->getString('hanyuu.endpoint'),
$this->config->scopeTo('impersonate'),
$this->urls,
$this->usersCtx,
$this->authCtx
));
}
return $routingCtx; return $routingCtx;
} }

View file

@ -0,0 +1,39 @@
<?php
namespace Misuzu\Routing;
use Index\Http\HttpRequest;
use Index\Http\Routing\{HttpRouter,Router,RouteHandler};
use Index\Urls\{ArrayUrlRegistry,UrlRegistry,UrlSource};
class BackedRoutingContext implements RoutingContext {
public private(set) Router $router;
public private(set) UrlRegistry $urls;
public function __construct(
?Router $router = null,
?UrlRegistry $urls = null
) {
$this->urls = $urls ?? new ArrayUrlRegistry;
$this->router = $router ?? new HttpRouter(errorHandler: new RoutingErrorHandler);
$this->router->use('/', fn($resp) => $resp->setPoweredBy('Misuzu'));
}
public function register(RouteHandler|UrlSource $handler): void {
if($handler instanceof RouteHandler)
$this->router->register($handler);
if($handler instanceof UrlSource)
$this->urls->register($handler);
}
public function scopeTo(string $namePrefix, string $pathPrefix): RoutingContext {
return new ScopedRoutingContext(
$this->router->scopeTo($pathPrefix),
$this->urls->scopeTo($namePrefix, $pathPrefix)
);
}
/** @param mixed[] $args */
public function dispatch(?HttpRequest $request = null, array $args = []): void {
$this->router->dispatch($request, $args);
}
}

View file

@ -0,0 +1,12 @@
<?php
namespace Misuzu\Routing;
use Index\Http\HttpRequest;
use Index\Http\Routing\RouteHandler;
use Index\Urls\UrlSource;
interface RoutingContext {
public function register(RouteHandler|UrlSource $handler): void;
public function scopeTo(string $namePrefix, string $pathPrefix): RoutingContext;
public function dispatch(?HttpRequest $request = null, array $args = []): void;
}

View file

@ -1,7 +1,8 @@
<?php <?php
namespace Misuzu; namespace Misuzu\Routing;
use Index\Http\{HtmlHttpErrorHandler,HttpResponseBuilder,HttpRequest}; use Index\Http\{HtmlHttpErrorHandler,HttpResponseBuilder,HttpRequest};
use Misuzu\Template;
class RoutingErrorHandler extends HtmlHttpErrorHandler { class RoutingErrorHandler extends HtmlHttpErrorHandler {
public function handle(HttpResponseBuilder $response, HttpRequest $request, int $code, string $message): void { public function handle(HttpResponseBuilder $response, HttpRequest $request, int $code, string $message): void {

View file

@ -0,0 +1,32 @@
<?php
namespace Misuzu\Routing;
use Index\Http\HttpRequest;
use Index\Http\Routing\{RouteHandler,Router};
use Index\Urls\{UrlRegistry,UrlSource};
class ScopedRoutingContext implements RoutingContext {
public function __construct(
private Router $router,
private UrlRegistry $urls
) {}
public function register(RouteHandler|UrlSource $handler): void {
if($handler instanceof RouteHandler)
$this->router->register($handler);
if($handler instanceof UrlSource)
$this->urls->register($handler);
}
public function scopeTo(string $namePrefix, string $pathPrefix): RoutingContext {
return new ScopedRoutingContext(
$this->router->scopeTo($pathPrefix),
$this->urls->scopeTo($namePrefix, $pathPrefix)
);
}
/** @param mixed[] $args */
public function dispatch(?HttpRequest $request = null, array $args = []): void {
$this->router->dispatch($request, $args);
}
}

View file

@ -1,29 +0,0 @@
<?php
namespace Misuzu;
use Index\Http\HttpRequest;
use Index\Http\Routing\{HttpRouter,Router,RouteHandler};
use Index\Urls\{ArrayUrlRegistry,UrlFormat,UrlRegistry,UrlSource};
class RoutingContext {
public private(set) UrlRegistry $urls;
public private(set) HttpRouter $router;
public function __construct() {
$this->urls = new ArrayUrlRegistry;
$this->router = new HttpRouter(errorHandler: new RoutingErrorHandler);
$this->router->use('/', fn($resp) => $resp->setPoweredBy('Misuzu'));
}
public function register(RouteHandler|UrlSource $handler): void {
if($handler instanceof RouteHandler)
$this->router->register($handler);
if($handler instanceof UrlSource)
$this->urls->register($handler);
}
/** @param mixed[] $args */
public function dispatch(?HttpRequest $request = null, array $args = []): void {
$this->router->dispatch($request, $args);
}
}

View file

@ -7,7 +7,6 @@ use Index\Config\Config;
use Index\Http\{HttpRequest,HttpResponseBuilder}; use Index\Http\{HttpRequest,HttpResponseBuilder};
use Index\Http\Routing\{HttpGet,HttpMiddleware,RouteHandler,RouteHandlerTrait}; use Index\Http\Routing\{HttpGet,HttpMiddleware,RouteHandler,RouteHandlerTrait};
use Misuzu\Pagination; use Misuzu\Pagination;
use Misuzu\RoutingContext;
use Misuzu\Forum\ForumContext; use Misuzu\Forum\ForumContext;
use Misuzu\Profile\ProfileFields; use Misuzu\Profile\ProfileFields;
use Misuzu\Users\UsersContext; use Misuzu\Users\UsersContext;

View file

@ -2,7 +2,6 @@
namespace Misuzu\SharpChat; namespace Misuzu\SharpChat;
use RuntimeException; use RuntimeException;
use Misuzu\RoutingContext;
use Misuzu\Auth\{AuthContext,AuthInfo,Sessions}; use Misuzu\Auth\{AuthContext,AuthInfo,Sessions};
use Misuzu\Counters\Counters; use Misuzu\Counters\Counters;
use Misuzu\Emoticons\Emotes; use Misuzu\Emoticons\Emotes;