|
@@ -4,19 +4,33 @@ declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace App\App;
|
|
namespace App\App;
|
|
|
|
|
|
|
|
|
|
+use App\Application\Admin\ConsumersController;
|
|
|
use App\Application\Admin\MeController;
|
|
use App\Application\Admin\MeController;
|
|
|
|
|
+use App\Application\Admin\ReportersController;
|
|
|
|
|
+use App\Application\Admin\TokensController;
|
|
|
use App\Application\Auth\AuthController;
|
|
use App\Application\Auth\AuthController;
|
|
|
|
|
+use App\Application\Public\ReportController;
|
|
|
use App\Domain\Auth\Role;
|
|
use App\Domain\Auth\Role;
|
|
|
use App\Domain\Auth\TokenHasher;
|
|
use App\Domain\Auth\TokenHasher;
|
|
|
use App\Domain\Auth\TokenIssuer;
|
|
use App\Domain\Auth\TokenIssuer;
|
|
|
|
|
+use App\Domain\Reputation\PairScorer;
|
|
|
|
|
+use App\Domain\Time\Clock;
|
|
|
|
|
+use App\Domain\Time\SystemClock;
|
|
|
use App\Infrastructure\Auth\RoleMappingRepository;
|
|
use App\Infrastructure\Auth\RoleMappingRepository;
|
|
|
use App\Infrastructure\Auth\ServiceTokenBootstrap;
|
|
use App\Infrastructure\Auth\ServiceTokenBootstrap;
|
|
|
use App\Infrastructure\Auth\TokenRepository;
|
|
use App\Infrastructure\Auth\TokenRepository;
|
|
|
use App\Infrastructure\Auth\UserRepository;
|
|
use App\Infrastructure\Auth\UserRepository;
|
|
|
|
|
+use App\Infrastructure\Category\CategoryRepository;
|
|
|
|
|
+use App\Infrastructure\Consumer\ConsumerRepository;
|
|
|
use App\Infrastructure\Db\ConnectionFactory;
|
|
use App\Infrastructure\Db\ConnectionFactory;
|
|
|
use App\Infrastructure\Http\JsonErrorHandler;
|
|
use App\Infrastructure\Http\JsonErrorHandler;
|
|
|
use App\Infrastructure\Http\Middleware\ImpersonationMiddleware;
|
|
use App\Infrastructure\Http\Middleware\ImpersonationMiddleware;
|
|
|
|
|
+use App\Infrastructure\Http\Middleware\RateLimitMiddleware;
|
|
|
use App\Infrastructure\Http\Middleware\TokenAuthenticationMiddleware;
|
|
use App\Infrastructure\Http\Middleware\TokenAuthenticationMiddleware;
|
|
|
|
|
+use App\Infrastructure\Http\RateLimiter;
|
|
|
|
|
+use App\Infrastructure\Reporter\ReporterRepository;
|
|
|
|
|
+use App\Infrastructure\Reputation\IpScoreRepository;
|
|
|
|
|
+use App\Infrastructure\Reputation\ReportRepository;
|
|
|
|
|
|
|
|
use function DI\autowire;
|
|
use function DI\autowire;
|
|
|
|
|
|
|
@@ -36,10 +50,10 @@ use Slim\Psr7\Factory\ResponseFactory;
|
|
|
/**
|
|
/**
|
|
|
* Builds the api's DI container.
|
|
* Builds the api's DI container.
|
|
|
*
|
|
*
|
|
|
- * Adds in M03: token domain helpers, repositories, middlewares, the JSON
|
|
|
|
|
- * error handler, and the controllers. Wiring is autowire-friendly except
|
|
|
|
|
- * where we need to inject a primitive (the OIDC default Role) or pull a
|
|
|
|
|
- * value out of `settings`.
|
|
|
|
|
|
|
+ * M04 additions: ReporterRepository / ConsumerRepository / CategoryRepository /
|
|
|
|
|
+ * ReportRepository / IpScoreRepository, the PairScorer + Clock pair, and the
|
|
|
|
|
+ * RateLimiter singleton plus its middleware. The rate-limit settings flow
|
|
|
|
|
+ * through `settings` so tests can override capacity/refill cleanly.
|
|
|
*/
|
|
*/
|
|
|
final class Container
|
|
final class Container
|
|
|
{
|
|
{
|
|
@@ -59,6 +73,8 @@ final class Container
|
|
|
'settings.app_env' => $settings['app_env'] ?? 'production',
|
|
'settings.app_env' => $settings['app_env'] ?? 'production',
|
|
|
'settings.log_level' => $settings['log_level'] ?? \Monolog\Level::Info,
|
|
'settings.log_level' => $settings['log_level'] ?? \Monolog\Level::Info,
|
|
|
'settings.oidc_default_role' => $settings['oidc_default_role'] ?? Role::Viewer,
|
|
'settings.oidc_default_role' => $settings['oidc_default_role'] ?? Role::Viewer,
|
|
|
|
|
+ 'settings.score_hard_cutoff_days' => (int) ($settings['score_hard_cutoff_days'] ?? 365),
|
|
|
|
|
+ 'settings.rate_limit_per_second' => (int) ($settings['rate_limit_per_second'] ?? 60),
|
|
|
ConnectionFactory::class => factory(static function (ContainerInterface $c): ConnectionFactory {
|
|
ConnectionFactory::class => factory(static function (ContainerInterface $c): ConnectionFactory {
|
|
|
/** @var array{driver: string, sqlite_path: string, mysql_host: string, mysql_port: int, mysql_database: string, mysql_username: string, mysql_password: string} $db */
|
|
/** @var array{driver: string, sqlite_path: string, mysql_host: string, mysql_port: int, mysql_database: string, mysql_username: string, mysql_password: string} $db */
|
|
|
$db = $c->get('settings.db');
|
|
$db = $c->get('settings.db');
|
|
@@ -82,14 +98,42 @@ final class Container
|
|
|
return $logger;
|
|
return $logger;
|
|
|
}),
|
|
}),
|
|
|
ResponseFactoryInterface::class => autowire(ResponseFactory::class),
|
|
ResponseFactoryInterface::class => autowire(ResponseFactory::class),
|
|
|
|
|
+ Clock::class => autowire(SystemClock::class),
|
|
|
TokenHasher::class => autowire(),
|
|
TokenHasher::class => autowire(),
|
|
|
TokenIssuer::class => autowire(),
|
|
TokenIssuer::class => autowire(),
|
|
|
TokenRepository::class => autowire(),
|
|
TokenRepository::class => autowire(),
|
|
|
RoleMappingRepository::class => autowire(),
|
|
RoleMappingRepository::class => autowire(),
|
|
|
UserRepository::class => autowire(),
|
|
UserRepository::class => autowire(),
|
|
|
|
|
+ ReporterRepository::class => autowire(),
|
|
|
|
|
+ ConsumerRepository::class => autowire(),
|
|
|
|
|
+ CategoryRepository::class => autowire(),
|
|
|
|
|
+ ReportRepository::class => autowire(),
|
|
|
|
|
+ IpScoreRepository::class => autowire(),
|
|
|
ServiceTokenBootstrap::class => autowire(),
|
|
ServiceTokenBootstrap::class => autowire(),
|
|
|
TokenAuthenticationMiddleware::class => autowire(),
|
|
TokenAuthenticationMiddleware::class => autowire(),
|
|
|
ImpersonationMiddleware::class => autowire(),
|
|
ImpersonationMiddleware::class => autowire(),
|
|
|
|
|
+ PairScorer::class => factory(static function (ContainerInterface $c): PairScorer {
|
|
|
|
|
+ /** @var ReportRepository $reports */
|
|
|
|
|
+ $reports = $c->get(ReportRepository::class);
|
|
|
|
|
+ /** @var CategoryRepository $categories */
|
|
|
|
|
+ $categories = $c->get(CategoryRepository::class);
|
|
|
|
|
+ /** @var Clock $clock */
|
|
|
|
|
+ $clock = $c->get(Clock::class);
|
|
|
|
|
+ /** @var int $cutoff */
|
|
|
|
|
+ $cutoff = $c->get('settings.score_hard_cutoff_days');
|
|
|
|
|
+
|
|
|
|
|
+ return new PairScorer($reports, $categories, $clock, $cutoff);
|
|
|
|
|
+ }),
|
|
|
|
|
+ RateLimiter::class => factory(static function (ContainerInterface $c): RateLimiter {
|
|
|
|
|
+ /** @var Clock $clock */
|
|
|
|
|
+ $clock = $c->get(Clock::class);
|
|
|
|
|
+ /** @var int $perSecond */
|
|
|
|
|
+ $perSecond = $c->get('settings.rate_limit_per_second');
|
|
|
|
|
+ $perSecond = max(1, $perSecond);
|
|
|
|
|
+
|
|
|
|
|
+ return new RateLimiter($clock, (float) $perSecond, (float) ($perSecond * 2));
|
|
|
|
|
+ }),
|
|
|
|
|
+ RateLimitMiddleware::class => autowire(),
|
|
|
JsonErrorHandler::class => factory(static function (ContainerInterface $c): JsonErrorHandler {
|
|
JsonErrorHandler::class => factory(static function (ContainerInterface $c): JsonErrorHandler {
|
|
|
/** @var ResponseFactoryInterface $factory */
|
|
/** @var ResponseFactoryInterface $factory */
|
|
|
$factory = $c->get(ResponseFactoryInterface::class);
|
|
$factory = $c->get(ResponseFactoryInterface::class);
|
|
@@ -111,6 +155,10 @@ final class Container
|
|
|
return new AuthController($users, $role ?? Role::Viewer);
|
|
return new AuthController($users, $role ?? Role::Viewer);
|
|
|
}),
|
|
}),
|
|
|
MeController::class => autowire(),
|
|
MeController::class => autowire(),
|
|
|
|
|
+ ReportersController::class => autowire(),
|
|
|
|
|
+ ConsumersController::class => autowire(),
|
|
|
|
|
+ TokensController::class => autowire(),
|
|
|
|
|
+ ReportController::class => autowire(),
|
|
|
]);
|
|
]);
|
|
|
|
|
|
|
|
return $builder->build();
|
|
return $builder->build();
|