Make response sensitive mode instance-scoped

This commit is contained in:
Chirag Aggarwal
2026-04-06 10:24:32 +05:30
parent cb74a5756a
commit b8eb0810c2
3 changed files with 20 additions and 43 deletions
+4 -4
View File
@@ -3937,7 +3937,7 @@ Http::post('/v1/account/recovery')
->setParam('userId', $profile->getId())
->setParam('tokenId', $recovery->getId())
->setUser($profile)
->setPayload(Response::showSensitive(fn () => $response->output($recovery, Response::MODEL_TOKEN)), sensitive: ['secret']);
->setPayload($response->showSensitive(fn () => $response->output($recovery, Response::MODEL_TOKEN)), sensitive: ['secret']);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -4038,7 +4038,7 @@ Http::put('/v1/account/recovery')
$queueForEvents
->setParam('userId', $profile->getId())
->setParam('tokenId', $recoveryDocument->getId())
->setPayload(Response::showSensitive(fn () => $response->output($recoveryDocument, Response::MODEL_TOKEN)), sensitive: ['secret']);
->setPayload($response->showSensitive(fn () => $response->output($recoveryDocument, Response::MODEL_TOKEN)), sensitive: ['secret']);
$response->dynamic($recoveryDocument, Response::MODEL_TOKEN);
});
@@ -4268,7 +4268,7 @@ Http::post('/v1/account/verifications/email')
$queueForEvents
->setParam('userId', $user->getId())
->setParam('tokenId', $verification->getId())
->setPayload(Response::showSensitive(fn () => $response->output($verification, Response::MODEL_TOKEN)), sensitive: ['secret']);
->setPayload($response->showSensitive(fn () => $response->output($verification, Response::MODEL_TOKEN)), sensitive: ['secret']);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -4360,7 +4360,7 @@ Http::put('/v1/account/verifications/email')
$queueForEvents
->setParam('userId', $userId)
->setParam('tokenId', $verification->getId())
->setPayload(Response::showSensitive(fn () => $response->output($verification, Response::MODEL_TOKEN)), sensitive: ['secret']);
->setPayload($response->showSensitive(fn () => $response->output($verification, Response::MODEL_TOKEN)), sensitive: ['secret']);
$response->dynamic($verification, Response::MODEL_TOKEN);
});
+7 -30
View File
@@ -8,7 +8,6 @@ use Appwrite\Utopia\Response\Filter;
use Appwrite\Utopia\Response\Model;
use Exception;
use JsonException;
use Swoole\Coroutine;
use Swoole\Http\Response as SwooleHTTPResponse;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
@@ -20,8 +19,6 @@ use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
*/
class Response extends SwooleResponse
{
private const SHOW_SENSITIVE_CONTEXT_KEY = '__appwrite_response_show_sensitive';
// General
public const MODEL_NONE = 'none';
public const MODEL_ANY = 'any';
@@ -302,7 +299,7 @@ class Response extends SwooleResponse
/**
* @var bool
*/
protected static bool $showSensitive = false;
protected bool $showSensitive = false;
/**
* @var array<string, Model>
@@ -512,7 +509,7 @@ class Response extends SwooleResponse
$isPrivilegedUser = $user->isPrivileged($roles);
$isAppUser = $user->isApp($roles);
if ((!$isPrivilegedUser && !$isAppUser) && !self::isShowingSensitive()) {
if ((!$isPrivilegedUser && !$isAppUser) && !$this->showSensitive) {
$data->setAttribute($key, '');
}
}
@@ -662,43 +659,23 @@ class Response extends SwooleResponse
}
/**
* Static wrapper to show sensitive data in response
* Wrapper to show sensitive data in response
*
* @param callable(): array $callback The callback to show sensitive information for
* @return array
*/
public static function showSensitive(callable $callback): array
public function showSensitive(callable $callback): array
{
$previous = self::isShowingSensitive();
$previous = $this->showSensitive;
try {
self::setShowSensitive(true);
$this->showSensitive = true;
return $callback();
} finally {
self::setShowSensitive($previous);
$this->showSensitive = $previous;
}
}
private static function isShowingSensitive(): bool
{
if (Coroutine::getCid() !== -1) {
return (bool) (Coroutine::getContext()[self::SHOW_SENSITIVE_CONTEXT_KEY] ?? false);
}
return self::$showSensitive;
}
private static function setShowSensitive(bool $value): void
{
if (Coroutine::getCid() !== -1) {
Coroutine::getContext()[self::SHOW_SENSITIVE_CONTEXT_KEY] = $value;
return;
}
self::$showSensitive = $value;
}
private ?Authorization $authorization = null;
private ?DBUser $user = null;
+9 -9
View File
@@ -5,7 +5,7 @@ namespace Tests\Unit\Utopia;
use Appwrite\Utopia\Response;
use Exception;
use PHPUnit\Framework\TestCase;
use ReflectionMethod;
use ReflectionProperty;
use Swoole\Http\Response as SwooleResponse;
use Tests\Unit\Utopia\Response\Filters\First;
use Tests\Unit\Utopia\Response\Filters\Second;
@@ -180,23 +180,23 @@ class ResponseTest extends TestCase
public function testShowSensitiveRestoresPreviousState(): void
{
$isShowingSensitive = new ReflectionMethod(Response::class, 'isShowingSensitive');
$isShowingSensitive = new ReflectionProperty(Response::class, 'showSensitive');
$this->assertFalse($isShowingSensitive->invoke(null));
$this->assertFalse($isShowingSensitive->getValue($this->response));
$payload = Response::showSensitive(function () use ($isShowingSensitive) {
$payload = $this->response->showSensitive(function () use ($isShowingSensitive) {
return [
'outer' => $isShowingSensitive->invoke(null),
'inner' => Response::showSensitive(fn () => [
'state' => $isShowingSensitive->invoke(null),
'outer' => $isShowingSensitive->getValue($this->response),
'inner' => $this->response->showSensitive(fn () => [
'state' => $isShowingSensitive->getValue($this->response),
]),
'afterInner' => $isShowingSensitive->invoke(null),
'afterInner' => $isShowingSensitive->getValue($this->response),
];
});
$this->assertTrue($payload['outer']);
$this->assertTrue($payload['inner']['state']);
$this->assertTrue($payload['afterInner']);
$this->assertFalse($isShowingSensitive->invoke(null));
$this->assertFalse($isShowingSensitive->getValue($this->response));
}
}