3
0
mirror of https://github.com/snipe/snipe-it.git synced 2026-08-18 11:15:42 +00:00
Files
snipe-it/app/Http/Middleware/EnforceApiTwoFactorEnrollment.php

59 lines
2.1 KiB
PHP

<?php
namespace App\Http\Middleware;
use App\Helpers\Helper;
use App\Models\Setting;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnforceApiTwoFactorEnrollment
{
public function handle(Request $request, Closure $next)
{
// If auth:api didn't populate a user (bad token, no token), let it
// produce the standard 401 rather than emitting a 403 here.
$user = $request->user();
if ($user === null) {
return $next($request);
}
$settings = Setting::getSettings();
if ($settings === null) {
return $next($request);
}
// Normalize the same way CheckForTwoFactor does: only '1' (optional)
// and '2' (required for all) count as on. Empty, '0', null all mean
// 2FA is disabled and we don't gate the API.
$mode = (string) $settings->two_factor_enabled;
if ($mode !== '1' && $mode !== '2') {
return $next($request);
}
// Optional mode only gates users who opted in; matches the web-side
// semantics so an install can't accidentally break every legacy PAT
// by flipping optional 2FA on.
if ($mode === '1' && (string) $user->two_factor_optin !== '1') {
return $next($request);
}
// Stateless bearer tokens can't prompt for a live TOTP code, so the
// strongest guarantee we can enforce is that the token's owner has
// provisioned and confirmed a TOTP secret. A PAT owned by a not-yet-
// enrolled user gets refused so that setting two_factor_enabled = 2
// actually gates the API surface (previously it only gated the web
// group, leaving already-issued PATs fully live). Web session auth
// still flows through CheckForTwoFactor and remains untouched.
if ((string) $user->two_factor_enrolled !== '1') {
return response()->json(
Helper::formatStandardApiResponse('error', null, trans('auth/message.two_factor.please_enroll')),
Response::HTTP_FORBIDDEN,
);
}
return $next($request);
}
}