action = $action; $this->isAuthRequired = $isAuthRequired; } public function isAuthRequired(): bool { return $this->isAuthRequired; } /** * @param mixed[] $params * @param ?Account $account * @return HttpResponse */ public function run(array $params, ?Account $account): HttpResponse { $params = array_values($params); if ($this->isAuthRequired) { if ($account == null) { throw new Exception("action requires authorization."); } $params[] = $account; } return call_user_func_array($this->action, $params); } /** * @param callable(mixed[]): HttpResponse $action * @return Action an action that does not require to have an authorization. */ public static function noAuth(callable $action): Action { return new Action($action, false); } /** * @param callable(mixed[]): HttpResponse $action * @return Action an action that does require to have an authorization. */ public static function auth(callable $action): Action { return new Action($action, true); } } /** * @param mixed[] $match * @return HttpResponse * @throws Exception */ function handleMatch(array $match): HttpResponse { if (!$match) { return new JsonHttpResponse([ValidationFail::notFound("not found")]); } $action = $match['target']; if (!$action instanceof Action) { throw new Exception("routed action is not an Action object."); } $auth = null; if ($action->isAuthRequired()) { $auth = tryGetAuthAccount(); if ($auth == null) { return new JsonHttpResponse([ValidationFail::unauthorized("Missing or invalid 'Authorization' header")]); } } return $action->run($match['params'], $auth); } function tryGetAuthAccount(): ?Account { $headers = getallheaders(); // If no authorization header is set, try fallback to php session. if (!isset($headers['Authorization'])) { $session = PhpSessionHandle::init(); return $session->getAccount(); } $token = $headers['Authorization']; $gateway = new AccountGateway(new Connexion(get_database())); return $gateway->getAccountFromToken($token); } $router = new AltoRouter(); $router->setBasePath(get_public_path() . "/api"); $router->map("POST", "/tactic/[i:id]/edit/name", Action::auth(fn(int $id, Account $acc) => getTacticController()->updateName($id, $acc))); $router->map("GET", "/tactic/[i:id]", Action::auth(fn(int $id, Account $acc) => getTacticController()->getTacticInfo($id, $acc))); $router->map("POST", "/tactic/new", Action::auth(fn(Account $acc) => getTacticController()->newTactic($acc))); $router->map("POST", "/auth", Action::noAuth(fn() => getAuthController()->authorize())); $match = $router->match(); $response = handleMatch($match); http_response_code($response->getCode()); if ($response instanceof JsonHttpResponse) { header('Content-type: application/json'); echo $response->getJson(); } elseif ($response instanceof ViewHttpResponse) { throw new Exception("API returned a view http response."); }