Files
loks0n 98f6ca347f chore: prefer ->inject('match') over \$utopia->getResource() in resource resolvers
Replaces \$utopia->match(\$request) calls in the project, team, and auth
resolvers with the per-request RouteMatch injected directly via DI:

- app/init/resources/request.php — project / team resource closures now
  declare 'match' as a dependency and read \$match?->route.
- app/controllers/shared/api/auth.php — auth init hook injects 'match'
  instead of resolving via \$utopia.
- app/controllers/shared/api.php — drop the redundant re-match in the
  storage cache init hook; \$route from the action's \$match inject is
  already in scope.

Only Resolvers::resolve still calls \$utopia->match(...) — that path
genuinely matches a synthesized sub-request URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 16:00:55 +01:00

110 lines
4.4 KiB
PHP

<?php
use Appwrite\Extend\Exception;
use Appwrite\Utopia\Database\Documents\User;
use Appwrite\Utopia\Request;
use MaxMind\Db\Reader;
use Utopia\Config\Config;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\Http\Http;
use Utopia\Http\RouteMatch;
use Utopia\System\System;
Http::init()
->groups(['mfaProtected'])
->inject('session')
->action(function (Document $session) {
$isSessionFresh = false;
$lastUpdate = $session->getAttribute('mfaUpdatedAt');
if (!empty($lastUpdate)) {
$now = DateTime::now();
$maxAllowedDate = DateTime::addSeconds(new \DateTime($lastUpdate), MFA_RECENT_DURATION); // Maximum date until session is considered safe before asking for another challenge
$isSessionFresh = DateTime::formatTz($maxAllowedDate) >= DateTime::formatTz($now);
}
if (!$isSessionFresh) {
throw new Exception(Exception::USER_CHALLENGE_REQUIRED);
}
});
Http::init()
->groups(['auth'])
->inject('request')
->inject('project')
->inject('geodb')
->inject('user')
->inject('authorization')
->inject('match')
->action(function (Request $request, Document $project, Reader $geodb, User $user, Authorization $authorization, ?RouteMatch $match) {
$denylist = System::getEnv('_APP_CONSOLE_COUNTRIES_DENYLIST', '');
if (!empty($denylist && $project->getId() === 'console')) {
$countries = explode(',', $denylist);
$record = $geodb->get($request->getIP()) ?? [];
$country = $record['country']['iso_code'] ?? '';
if (in_array($country, $countries)) {
throw new Exception(Exception::GENERAL_REGION_ACCESS_DENIED);
}
}
$route = $match?->route;
$isPrivilegedUser = $user->isPrivileged($authorization->getRoles());
$isAppUser = $user->isApp($authorization->getRoles());
if ($isAppUser || $isPrivilegedUser) { // Skip limits for app and console devs
return;
}
$auths = $project->getAttribute('auths', []);
switch ($route->getLabel('auth.type', '')) {
case 'email-password':
if (($auths[Config::getParam('auth')['email-password']['key']] ?? true) === false) {
throw new Exception(Exception::USER_AUTH_METHOD_UNSUPPORTED, 'Email / Password authentication is disabled for this project');
}
break;
case 'magic-url':
if (($auths[Config::getParam('auth')['magic-url']['key']] ?? true) === false) {
throw new Exception(Exception::USER_AUTH_METHOD_UNSUPPORTED, 'Magic URL authentication is disabled for this project');
}
break;
case 'anonymous':
if (($auths[Config::getParam('auth')['anonymous']['key']] ?? true) === false) {
throw new Exception(Exception::USER_AUTH_METHOD_UNSUPPORTED, 'Anonymous authentication is disabled for this project');
}
break;
case 'phone':
if (($auths[Config::getParam('auth')['phone']['key']] ?? true) === false) {
throw new Exception(Exception::USER_AUTH_METHOD_UNSUPPORTED, 'Phone authentication is disabled for this project');
}
break;
case 'invites':
if (($auths[Config::getParam('auth')['invites']['key']] ?? true) === false) {
throw new Exception(Exception::USER_AUTH_METHOD_UNSUPPORTED, 'Invites authentication is disabled for this project');
}
break;
case 'jwt':
if (($auths[Config::getParam('auth')['jwt']['key']] ?? true) === false) {
throw new Exception(Exception::USER_AUTH_METHOD_UNSUPPORTED, 'JWT authentication is disabled for this project');
}
break;
case 'email-otp':
if (($auths[Config::getParam('auth')['email-otp']['key']] ?? true) === false) {
throw new Exception(Exception::USER_AUTH_METHOD_UNSUPPORTED, 'Email OTP authentication is disabled for this project');
}
break;
default:
throw new Exception(Exception::USER_AUTH_METHOD_UNSUPPORTED, 'Unsupported authentication route');
}
});