appwrite/src/Appwrite/Auth/Key.php

201 lines
5.4 KiB
PHP
Raw Normal View History

<?php
namespace Appwrite\Auth;
use Ahc\Jwt\JWT;
use Ahc\Jwt\JWTException;
use Appwrite\Extend\Exception;
use Utopia\Config\Config;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\System\System;
class Key
{
public function __construct(
protected string $projectId,
protected string $type,
protected string $role,
protected array $scopes,
protected string $name,
2025-02-12 08:22:08 +00:00
protected bool $expired = false,
protected array $disabledMetrics = [],
protected bool $hostnameOverride = false,
2025-02-21 19:50:43 +00:00
protected bool $bannerDisabled = false,
protected bool $projectCheckDisabled = false,
protected bool $previewAuthDisabled = false,
2025-03-26 11:59:05 +00:00
protected bool $deploymentStatusIgnored = false,
2025-02-11 04:53:40 +00:00
) {
}
public function getProjectId(): string
{
return $this->projectId;
}
public function getType(): string
{
return $this->type;
}
public function getRole(): string
{
return $this->role;
}
public function getScopes(): array
{
return $this->scopes;
}
public function getName(): string
{
return $this->name;
}
2025-02-12 08:22:08 +00:00
public function isExpired(): bool
{
return $this->expired;
}
public function getDisabledMetrics(): array
{
return $this->disabledMetrics;
}
public function getHostnameOverride(): bool
{
return $this->hostnameOverride;
}
2025-02-21 19:50:43 +00:00
public function isBannerDisabled(): bool
{
return $this->bannerDisabled;
}
public function isPreviewAuthDisabled(): bool
{
return $this->previewAuthDisabled;
}
2025-03-26 11:59:05 +00:00
public function isDeploymentStatusIgnored(): bool
{
return $this->deploymentStatusIgnored;
}
2025-02-21 19:50:43 +00:00
public function isProjectCheckDisabled(): bool
{
return $this->projectCheckDisabled;
}
2025-02-11 09:02:20 +00:00
/**
* Decode the given secret key into a Key object, containing the project ID, type, role, scopes, and name.
* Can be a stored API key or a dynamic key (JWT).
*
* @param Document $project
* @param string $key
* @return Key
* @throws Exception
*/
public static function decode(
Document $project,
string $key
2025-02-11 04:53:40 +00:00
): Key {
if (\str_contains($key, '_')) {
[$type, $secret] = \explode('_', $key, 2);
} else {
$type = API_KEY_STANDARD;
$secret = $key;
}
2025-03-17 20:44:31 +00:00
$role = USER_ROLE_APPS;
$roles = Config::getParam('roles', []);
2025-03-17 20:44:31 +00:00
$scopes = $roles[USER_ROLE_APPS]['scopes'] ?? [];
2025-02-12 08:22:08 +00:00
$expired = false;
$guestKey = new Key(
$project->getId(),
$type,
2025-03-17 20:44:31 +00:00
USER_ROLE_GUESTS,
$roles[USER_ROLE_GUESTS]['scopes'] ?? [],
'UNKNOWN'
);
switch ($type) {
case API_KEY_DYNAMIC:
$jwtObj = new JWT(
key: System::getEnv('_APP_OPENSSL_KEY_V1'),
algo: 'HS256',
maxAge: 86400,
leeway: 0
);
try {
$payload = $jwtObj->decode($secret);
} catch (JWTException) {
2025-02-12 08:22:08 +00:00
$expired = true;
}
$name = $payload['name'] ?? 'Dynamic Key';
$projectId = $payload['projectId'] ?? '';
$disabledMetrics = $payload['disabledMetrics'] ?? [];
$hostnameOverride = $payload['hostnameOverride'] ?? false;
2025-02-21 19:50:43 +00:00
$bannerDisabled = $payload['bannerDisabled'] ?? false;
$projectCheckDisabled = $payload['projectCheckDisabled'] ?? false;
$previewAuthDisabled = $payload['previewAuthDisabled'] ?? false;
2025-03-26 11:59:05 +00:00
$deploymentStatusIgnored = $payload['deploymentStatusIgnored'] ?? false;
$scopes = \array_merge($payload['scopes'] ?? [], $scopes);
2025-02-21 19:50:43 +00:00
if (!$projectCheckDisabled && $projectId !== $project->getId()) {
return $guestKey;
}
return new Key(
$projectId,
$type,
$role,
$scopes,
$name,
2025-02-12 08:22:08 +00:00
$expired,
$disabledMetrics,
2025-02-21 19:50:43 +00:00
$hostnameOverride,
$bannerDisabled,
$projectCheckDisabled,
2025-03-26 11:59:05 +00:00
$previewAuthDisabled,
$deploymentStatusIgnored
);
case API_KEY_STANDARD:
$key = $project->find(
key: 'secret',
find: $key,
subject: 'keys'
);
if (!$key) {
return $guestKey;
}
$expire = $key->getAttribute('expire');
if (!empty($expire) && $expire < DateTime::formatTz(DateTime::now())) {
2025-02-12 08:22:08 +00:00
$expired = true;
}
$name = $key->getAttribute('name', 'UNKNOWN');
$scopes = \array_merge($key->getAttribute('scopes', []), $scopes);
return new Key(
$project->getId(),
$type,
$role,
$scopes,
2025-02-12 08:22:08 +00:00
$name,
$expired
);
default:
return $guestKey;
}
}
2025-02-11 04:53:40 +00:00
}