web/flows: fix error when attempting to enroll new webauthn device

closes #1936

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-12-15 00:24:38 +01:00
parent 72db17f23b
commit 6e83467481
3 changed files with 13 additions and 8 deletions

View File

@ -96,7 +96,6 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
user_verification=str(stage.user_verification), user_verification=str(stage.user_verification),
), ),
) )
registration_options.user.id = user.uid
self.request.session["challenge"] = registration_options.challenge self.request.session["challenge"] = registration_options.challenge
return AuthenticatorWebAuthnChallenge( return AuthenticatorWebAuthnChallenge(

View File

@ -51,6 +51,7 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
// byte arrays as expected by the spec. // byte arrays as expected by the spec.
const publicKeyCredentialCreateOptions = transformCredentialCreateOptions( const publicKeyCredentialCreateOptions = transformCredentialCreateOptions(
this.challenge?.registration as PublicKeyCredentialCreationOptions, this.challenge?.registration as PublicKeyCredentialCreationOptions,
this.challenge?.registration.user.id,
); );
// request the authenticator(s) to create a new credential keypair. // request the authenticator(s) to create a new credential keypair.

View File

@ -8,15 +8,26 @@ export function b64RawEnc(buf: Uint8Array): string {
return base64js.fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_"); return base64js.fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_");
} }
export function u8arr(input: string): Uint8Array {
return Uint8Array.from(atob(input.replace(/_/g, "/").replace(/-/g, "+")), (c) =>
c.charCodeAt(0),
);
}
/** /**
* Transforms items in the credentialCreateOptions generated on the server * Transforms items in the credentialCreateOptions generated on the server
* into byte arrays expected by the navigator.credentials.create() call * into byte arrays expected by the navigator.credentials.create() call
*/ */
export function transformCredentialCreateOptions( export function transformCredentialCreateOptions(
credentialCreateOptions: PublicKeyCredentialCreationOptions, credentialCreateOptions: PublicKeyCredentialCreationOptions,
userId: string,
): PublicKeyCredentialCreationOptions { ): PublicKeyCredentialCreationOptions {
const user = credentialCreateOptions.user; const user = credentialCreateOptions.user;
user.id = u8arr(b64enc(credentialCreateOptions.user.id as Uint8Array)); // Because json can't contain raw bytes, the server base64-encodes the User ID
// So to get the base64 encoded byte array, we first need to convert it to a regular
// string, then a byte array, re-encode it and wrap that in an array.
const stringId = decodeURIComponent(escape(window.atob(userId)));
user.id = u8arr(b64enc(u8arr(stringId)));
const challenge = u8arr(credentialCreateOptions.challenge.toString()); const challenge = u8arr(credentialCreateOptions.challenge.toString());
const transformedCredentialCreateOptions = Object.assign({}, credentialCreateOptions, { const transformedCredentialCreateOptions = Object.assign({}, credentialCreateOptions, {
@ -63,12 +74,6 @@ export function transformNewAssertionForServer(newAssertion: PublicKeyCredential
}; };
} }
function u8arr(input: string): Uint8Array {
return Uint8Array.from(atob(input.replace(/_/g, "/").replace(/-/g, "+")), (c) =>
c.charCodeAt(0),
);
}
export function transformCredentialRequestOptions( export function transformCredentialRequestOptions(
credentialRequestOptions: PublicKeyCredentialRequestOptions, credentialRequestOptions: PublicKeyCredentialRequestOptions,
): PublicKeyCredentialRequestOptions { ): PublicKeyCredentialRequestOptions {