1
0
Fork 0
mirror of synced 2024-10-01 01:37:56 +13:00

Fix encoding errors and comment class helper

This commit is contained in:
Bradley Schofield 2024-06-24 15:49:05 +09:00
parent 16e64dba3b
commit 5d10fcbf54
2 changed files with 60 additions and 6 deletions

View file

@ -4279,8 +4279,9 @@ App::post('/v1/account/mfa/authenticators/webauthn')
$authenticators = array_filter($user->getAttribute('authenticators', []), fn ($authenticator) => $authenticator['type'] === Type::WEBAUTHN); $authenticators = array_filter($user->getAttribute('authenticators', []), fn ($authenticator) => $authenticator['type'] === Type::WEBAUTHN);
foreach ($authenticators as $authenticator) { foreach ($authenticators as $authenticator) {
if (empty($authenticator['verified'])) { /** @var Document $authenticator */
$dbForProject->deleteDocument('authenticators', $authenticator['id']); if (empty($authenticator->getAttribute('verified', false))) {
$dbForProject->deleteDocument('authenticators', $authenticator->getId());
} }
} }
@ -4295,7 +4296,7 @@ App::post('/v1/account/mfa/authenticators/webauthn')
'userInternalId' => $user->getInternalId(), 'userInternalId' => $user->getInternalId(),
'type' => Type::WEBAUTHN, 'type' => Type::WEBAUTHN,
'verified' => false, 'verified' => false,
'data' => $challenge->jsonSerialize(), 'data' => json_encode($challenge),
'$permissions' => [ '$permissions' => [
Permission::read(Role::user($user->getId())), Permission::read(Role::user($user->getId())),
Permission::update(Role::user($user->getId())), Permission::update(Role::user($user->getId())),
@ -4360,7 +4361,7 @@ App::put('/v1/account/mfa/authenticators/webauthn')
} }
$authenticator->setAttribute('verified', true); $authenticator->setAttribute('verified', true);
$authenticator->setAttribute('data', $publicKeyCredentials->jsonSerialize()); $authenticator->setAttribute('data', json_encode($publicKeyCredentials));
$dbForProject->updateDocument('authenticators', $authenticator->getId(), $authenticator); $dbForProject->updateDocument('authenticators', $authenticator->getId(), $authenticator);
$factors = $session->getAttribute('factors', []); $factors = $session->getAttribute('factors', []);

View file

@ -43,6 +43,13 @@ class WebAuthn extends Type
$this->authenticatiorAssertionResponseValdiator = AuthenticatorAssertionResponseValidator::create(); $this->authenticatiorAssertionResponseValdiator = AuthenticatorAssertionResponseValidator::create();
} }
/**
* Create a new relying party entity, uses the platform if possible
*
* @param Document $project
* @param Request $request
* @return PublicKeyCredentialRpEntity
*/
public static function createRelyingParty(Document $project, Request $request): PublicKeyCredentialRpEntity public static function createRelyingParty(Document $project, Request $request): PublicKeyCredentialRpEntity
{ {
// Calculate Relying Party ID and Name // Calculate Relying Party ID and Name
@ -113,6 +120,12 @@ class WebAuthn extends Type
); );
} }
/**
* Create a new user entity from an Appwrite user document
*
* @param Document $user
* @return PublicKeyCredentialUserEntity
*/
public static function createUserEntity(Document $user): PublicKeyCredentialUserEntity public static function createUserEntity(Document $user): PublicKeyCredentialUserEntity
{ {
$name = $user->getAttribute('name') ?? $user->getAttribute('email'); $name = $user->getAttribute('name') ?? $user->getAttribute('email');
@ -124,23 +137,39 @@ class WebAuthn extends Type
); );
} }
/**
* Create a new register challenge
*
* @param PublicKeyCredentialRpEntity $rpEntity
* @param PublicKeyCredentialUserEntity $userEntity
* @param int $timeout Timeout in seconds
* @return PublicKeyCredentialCreationOptions
*/
public static function createRegisterChallenge(PublicKeyCredentialRpEntity $rpEntity, PublicKeyCredentialUserEntity $userEntity, int $timeout): PublicKeyCredentialCreationOptions public static function createRegisterChallenge(PublicKeyCredentialRpEntity $rpEntity, PublicKeyCredentialUserEntity $userEntity, int $timeout): PublicKeyCredentialCreationOptions
{ {
return PublicKeyCredentialCreationOptions::create( return PublicKeyCredentialCreationOptions::create(
rp: $rpEntity, rp: $rpEntity,
user: $userEntity, user: $userEntity,
challenge: random_bytes(32), challenge: random_bytes(32),
timeout: $timeout timeout: $timeout * 1000, // Convert seconds to milliseconds
); );
} }
/**
* Create a new login challenge
*
* @param PublicKeyCredentialRpEntity $rpEntity
* @param PublicKeyCredentialSource[] $allowedCredentials
* @param int $timeout Timeout in seconds
* @return PublicKeyCredentialRequestOptions
*/
public static function createLoginChallenge(PublicKeyCredentialRpEntity $rpEntity, array $allowedCredentials, int $timeout): PublicKeyCredentialRequestOptions public static function createLoginChallenge(PublicKeyCredentialRpEntity $rpEntity, array $allowedCredentials, int $timeout): PublicKeyCredentialRequestOptions
{ {
return PublicKeyCredentialRequestOptions::create( return PublicKeyCredentialRequestOptions::create(
rpId: $rpEntity->id, rpId: $rpEntity->id,
userVerification: PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_DEFAULT, userVerification: PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_DEFAULT,
challenge: random_bytes(32), challenge: random_bytes(32),
timeout: $timeout, timeout: $timeout * 1000,
allowCredentials: $allowedCredentials allowCredentials: $allowedCredentials
); );
} }
@ -160,6 +189,10 @@ class WebAuthn extends Type
{ {
$authenticators = self::getAuthenticatorsFromUser($user); $authenticators = self::getAuthenticatorsFromUser($user);
if (empty($authenticators)) {
throw new Exception(Exception::USER_AUTHENTICATOR_NOT_FOUND);
}
$authenticators = array_filter($authenticators, function ($authenticator) { $authenticators = array_filter($authenticators, function ($authenticator) {
/** @var Document $authenticator */ /** @var Document $authenticator */
return $authenticator->getAttribute('verified') === true; return $authenticator->getAttribute('verified') === true;
@ -176,6 +209,12 @@ class WebAuthn extends Type
} }
/** /**
* Verify a register challenge
*
* @param array $challenge The challenge data deserialized from the database
* @param string $challengeResponse The challenge response from the client
*
* @return PublicKeyCredentialSource
* @throws \Throwable * @throws \Throwable
*/ */
public function verifyRegisterChallenge(array $challenge, string $challengeResponse): PublicKeyCredentialSource public function verifyRegisterChallenge(array $challenge, string $challengeResponse): PublicKeyCredentialSource
@ -208,6 +247,13 @@ class WebAuthn extends Type
} }
/** /**
* Verify a login challenge
*
* @param array $challenge The challenge data deserialized from the database
* @param string $challengeResponse The challenge response from the client
* @param string $hostname The hostname of the request
* @param PublicKeyCredentialSource $authenticatorPublicKey The public key of the authenticator
*
* @throws \Throwable * @throws \Throwable
*/ */
public function verifyLoginChallenge(array $challenge, string $challengeResponse, string $hostname, PublicKeyCredentialSource $authenticatorPublicKey): PublicKeyCredentialSource public function verifyLoginChallenge(array $challenge, string $challengeResponse, string $hostname, PublicKeyCredentialSource $authenticatorPublicKey): PublicKeyCredentialSource
@ -235,6 +281,13 @@ class WebAuthn extends Type
); );
} }
/**
* Get all authenticators from a user
*
* @param Document $user
* @return Document[]|null
* @throws Exception
*/
public static function getAuthenticatorsFromUser(Document $user): ?array public static function getAuthenticatorsFromUser(Document $user): ?array
{ {
$authenticators = array_filter($user->getAttribute('authenticators', []), function ($authenticator) { $authenticators = array_filter($user->getAttribute('authenticators', []), function ($authenticator) {