Skip to content

Commit

Permalink
Merge pull request #625 from MasterKale/fix/rename-authenticatordevic…
Browse files Browse the repository at this point in the history
…e-type

fix/rename-authenticatordevice-type
  • Loading branch information
MasterKale authored Oct 11, 2024
2 parents 11c49fe + 0510aa1 commit 0aedc62
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
parseAuthenticatorData,
} from '../helpers/parseAuthenticatorData.ts';
import { toHash } from '../helpers/toHash.ts';
import { AuthenticationResponseJSON, AuthenticatorDevice } from '../deps.ts';
import { AuthenticationResponseJSON, WebAuthnCredential } from '../deps.ts';
import { isoBase64URL, isoUint8Array } from '../helpers/iso/index.ts';
import { assertObjectMatch } from 'https://deno.land/[email protected]/assert/assert_object_match.ts';
import { assertFalse } from 'https://deno.land/[email protected]/assert/assert_false.ts';
Expand All @@ -25,7 +25,7 @@ Deno.test('should verify an assertion response', async () => {
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
requireUserVerification: false,
});

Expand All @@ -38,14 +38,14 @@ Deno.test('should return authenticator info after verification', async () => {
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
requireUserVerification: false,
});

assertEquals(verification.authenticationInfo.newCounter, 144);
assertEquals(
verification.authenticationInfo.credentialID,
authenticator.credentialID,
credential.id,
);
assertEquals(verification.authenticationInfo?.origin, assertionOrigin);
assertEquals(verification.authenticationInfo?.rpID, 'dev.dontneeda.pw');
Expand All @@ -59,7 +59,7 @@ Deno.test('should throw when response challenge is not expected value', async ()
expectedChallenge: 'shouldhavebeenthisvalue',
expectedOrigin: 'https://different.address',
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
}),
Error,
'authentication response challenge',
Expand All @@ -74,7 +74,7 @@ Deno.test('should throw when response origin is not expected value', async () =>
expectedChallenge: assertionChallenge,
expectedOrigin: 'https://different.address',
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
}),
Error,
'authentication response origin',
Expand All @@ -101,7 +101,7 @@ Deno.test('should throw when assertion type is not webauthn.create', async () =>
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
}),
Error,
'authentication response type',
Expand Down Expand Up @@ -132,7 +132,7 @@ Deno.test('should throw error if user was not present', async () => {
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
}),
Error,
'not present',
Expand All @@ -145,7 +145,7 @@ Deno.test('should throw error if previous counter value is not less than in resp
// This'll match the `counter` value in `assertionResponse`, simulating a potential replay attack
const badCounter = 144;
const badDevice = {
...authenticator,
...credential,
counter: badCounter,
};

Expand All @@ -156,7 +156,7 @@ Deno.test('should throw error if previous counter value is not less than in resp
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: badDevice,
credential: badDevice,
requireUserVerification: false,
}),
Error,
Expand Down Expand Up @@ -184,7 +184,7 @@ Deno.test('should throw error if assertion RP ID is unexpected value', async ()
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
}),
Error,
'RP ID',
Expand All @@ -199,7 +199,7 @@ Deno.test('should not compare counters if both are 0', async () => {
expectedChallenge: assertionFirstTimeUsedChallenge,
expectedOrigin: assertionFirstTimeUsedOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticatorFirstTimeUsed,
credential: authenticatorFirstTimeUsed,
requireUserVerification: false,
});

Expand Down Expand Up @@ -233,7 +233,7 @@ Deno.test('should throw an error if user verification is required but user was n
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
requireUserVerification: true,
}),
Error,
Expand Down Expand Up @@ -265,9 +265,9 @@ Deno.test('should verify TPM assertion', { ignore: true }, async () => {
expectedChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: {
credentialPublicKey: isoBase64URL.toBuffer('BAEAAQ'),
credentialID: 'YJ8FMM-AmcUt73XPX341WXWd7ypBMylGjjhu0g3VzME',
credential: {
publicKey: isoBase64URL.toBuffer('BAEAAQ'),
id: 'YJ8FMM-AmcUt73XPX341WXWd7ypBMylGjjhu0g3VzME',
counter: 0,
},
});
Expand All @@ -281,7 +281,7 @@ Deno.test('should support multiple possible origins', async () => {
expectedChallenge: assertionChallenge,
expectedOrigin: ['https://simplewebauthn.dev', assertionOrigin],
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
requireUserVerification: false,
});

Expand All @@ -297,7 +297,7 @@ Deno.test('should throw an error if origin not in list of expected origins', asy
expectedChallenge: assertionChallenge,
expectedOrigin: ['https://simplewebauthn.dev', 'https://fizz.buzz'],
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
}),
Error,
'Unexpected authentication response origin',
Expand All @@ -310,7 +310,7 @@ Deno.test('should support multiple possible RP IDs', async () => {
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: ['dev.dontneeda.pw', 'simplewebauthn.dev'],
authenticator: authenticator,
credential,
requireUserVerification: false,
});

Expand All @@ -326,7 +326,7 @@ Deno.test('should throw an error if RP ID not in list of possible RP IDs', async
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: ['simplewebauthn.dev'],
authenticator: authenticator,
credential,
}),
Error,
'Unexpected RP ID',
Expand All @@ -343,7 +343,7 @@ Deno.test('should throw an error if type not the expected type', async () => {
// assertionResponse contains webauthn.get, this should produce an error
expectedType: 'payment.get',
expectedRPID: 'localhost',
authenticator: authenticator,
credential,
}),
Error,
'Unexpected authentication response type',
Expand All @@ -360,7 +360,7 @@ Deno.test('should throw an error if type not in list of expected types', async (
// assertionResponse contains webauthn.get, this should produce an error
expectedType: ['payment.get', 'something.get'],
expectedRPID: 'localhost',
authenticator: authenticator,
credential,
}),
Error,
'Unexpected authentication response type',
Expand Down Expand Up @@ -397,10 +397,10 @@ Deno.test('should pass verification if custom challenge verifier returns true',
},
expectedOrigin: 'http://localhost:8000',
expectedRPID: 'localhost',
authenticator: {
credentialID:
credential: {
id:
'AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA',
credentialPublicKey: isoBase64URL.toBuffer(
publicKey: isoBase64URL.toBuffer(
'pQECAyYgASFYILTrxTUQv3X4DRM6L_pk65FSMebenhCx3RMsTKoBm-AxIlggEf3qk5552QLNSh1T1oQs7_2C2qysDwN4r4fCp52Hsqs',
),
counter: 0,
Expand All @@ -418,7 +418,7 @@ Deno.test('should fail verification if custom challenge verifier returns false',
expectedChallenge: (challenge) => challenge === 'willNeverMatch',
expectedOrigin: assertionOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
}),
Error,
'Custom challenge verifier returned false',
Expand Down Expand Up @@ -457,10 +457,10 @@ Deno.test('should pass verification if custom challenge verifier returns a Promi
},
expectedOrigin: 'http://localhost:8000',
expectedRPID: 'localhost',
authenticator: {
credentialID:
credential: {
id:
'AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA',
credentialPublicKey: isoBase64URL.toBuffer(
publicKey: isoBase64URL.toBuffer(
'pQECAyYgASFYILTrxTUQv3X4DRM6L_pk65FSMebenhCx3RMsTKoBm-AxIlggEf3qk5552QLNSh1T1oQs7_2C2qysDwN4r4fCp52Hsqs',
),
counter: 0,
Expand All @@ -478,7 +478,7 @@ Deno.test('should fail verification if custom challenge verifier returns a Promi
expectedChallenge: (challenge) => Promise.resolve(challenge === 'willNeverMatch'),
expectedOrigin: assertionOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
}),
Error,
'Custom challenge verifier returned false',
Expand All @@ -493,7 +493,7 @@ Deno.test('should fail verification if custom challenge verifier returns a Promi
expectedChallenge: () => Promise.reject(new Error('rejected')),
expectedOrigin: assertionOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
}),
Error,
'rejected',
Expand All @@ -520,10 +520,10 @@ Deno.test('should return authenticator extension output', async () => {
expectedOrigin: 'android:apk-key-hash:gx7sq_pxhxhrIQdLyfG0pxKwiJ7hOk2DJQ4xvKd438Q',
expectedRPID: 'try-webauthn.appspot.com',
expectedChallenge: 'iZsVCztrDW7D2U_GHCIlYKLwV2bCsBTRqVQUnJXn9Tk',
authenticator: {
credentialID:
credential: {
id:
'AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA',
credentialPublicKey: isoBase64URL.toBuffer(
publicKey: isoBase64URL.toBuffer(
'pQECAyYgASFYILTrxTUQv3X4DRM6L_pk65FSMebenhCx3RMsTKoBm-AxIlggEf3qk5552QLNSh1T1oQs7_2C2qysDwN4r4fCp52Hsqs',
),
counter: 0,
Expand Down Expand Up @@ -554,7 +554,7 @@ Deno.test('should return credential backup info', async () => {
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
requireUserVerification: false,
});

Expand All @@ -571,7 +571,7 @@ Deno.test('should return user verified flag after successful auth', async () =>
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: 'dev.dontneeda.pw',
authenticator: authenticator,
credential,
requireUserVerification: false,
});

Expand Down Expand Up @@ -602,12 +602,11 @@ const assertionChallenge = isoBase64URL.fromUTF8String(
);
const assertionOrigin = 'https://dev.dontneeda.pw';

const authenticator: AuthenticatorDevice = {
credentialPublicKey: isoBase64URL.toBuffer(
const credential: WebAuthnCredential = {
publicKey: isoBase64URL.toBuffer(
'pQECAyYgASFYIIheFp-u6GvFT2LNGovf3ZrT0iFVBsA_76rRysxRG9A1Ilgg8WGeA6hPmnab0HAViUYVRkwTNcN77QBf_RR0dv3lIvQ',
),
credentialID:
'KEbWNCc7NgaYnUyrNeFGX9_3Y-8oJ3KwzjnaiD1d1LVTxR7v3CaKfCz2Vy_g_MHSh7yJ8yL0Pxg6jo_o0hYiew',
id: 'KEbWNCc7NgaYnUyrNeFGX9_3Y-8oJ3KwzjnaiD1d1LVTxR7v3CaKfCz2Vy_g_MHSh7yJ8yL0Pxg6jo_o0hYiew',
counter: 143,
};

Expand All @@ -631,11 +630,10 @@ const assertionFirstTimeUsedChallenge = isoBase64URL.fromUTF8String(
'totallyUniqueValueEveryAssertion',
);
const assertionFirstTimeUsedOrigin = 'https://dev.dontneeda.pw';
const authenticatorFirstTimeUsed: AuthenticatorDevice = {
credentialPublicKey: isoBase64URL.toBuffer(
const authenticatorFirstTimeUsed: WebAuthnCredential = {
publicKey: isoBase64URL.toBuffer(
'pQECAyYgASFYIGmaxR4mBbukc2QhtW2ldhAAd555r-ljlGQN8MbcTnPPIlgg9CyUlE-0AB2fbzZbNgBvJuRa7r6o2jPphOmtyNPR_kY',
),
credentialID:
'wSisR0_4hlzw3Y1tj4uNwwifIhRa-ZxWJwWbnfror0pVK9qPdBPO5pW3gasPqn6wXHb0LNhXB_IrA1nFoSQJ9A',
id: 'wSisR0_4hlzw3Y1tj4uNwwifIhRa-ZxWJwWbnfror0pVK9qPdBPO5pW3gasPqn6wXHb0LNhXB_IrA1nFoSQJ9A',
counter: 0,
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type {
AuthenticationResponseJSON,
AuthenticatorDevice,
Base64URLString,
CredentialDeviceType,
UserVerificationRequirement,
WebAuthnCredential,
} from '../deps.ts';
import { decodeClientDataJSON } from '../helpers/decodeClientDataJSON.ts';
import { toHash } from '../helpers/toHash.ts';
Expand All @@ -19,7 +19,7 @@ export type VerifyAuthenticationResponseOpts = {
expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>);
expectedOrigin: string | string[];
expectedRPID: string | string[];
authenticator: AuthenticatorDevice;
credential: WebAuthnCredential;
expectedType?: string | string[];
requireUserVerification?: boolean;
allowEmbeddedAuthentication?: boolean;
Expand All @@ -37,7 +37,7 @@ export type VerifyAuthenticationResponseOpts = {
* @param expectedChallenge - The base64url-encoded `options.challenge` returned by `generateAuthenticationOptions()`
* @param expectedOrigin - Website URL (or array of URLs) that the registration should have occurred on
* @param expectedRPID - RP ID (or array of IDs) that was specified in the registration options
* @param authenticator - An internal {@link AuthenticatorDevice} matching the credential's ID
* @param credential - An internal {@link WebAuthnCredential} corresponding to `id` in the authentication response
* @param expectedType **(Optional)** - The response type expected ('webauthn.get')
* @param requireUserVerification **(Optional)** - Enforce user verification by the authenticator (via PIN, fingerprint, etc...) Defaults to `true`
* @param allowEmbeddedAuthentication **(Optional)** - Allow credential use from within an iframe embedded on a different origin ("cross-origin"). Defaults to `false`
Expand All @@ -53,7 +53,7 @@ export async function verifyAuthenticationResponse(
expectedOrigin,
expectedRPID,
expectedType,
authenticator,
credential,
requireUserVerification = true,
allowEmbeddedAuthentication = false,
advancedFIDOConfig,
Expand Down Expand Up @@ -233,15 +233,15 @@ export async function verifyAuthenticationResponse(
const signature = isoBase64URL.toBuffer(assertionResponse.signature);

if (
(counter > 0 || authenticator.counter > 0) &&
counter <= authenticator.counter
(counter > 0 || credential.counter > 0) &&
counter <= credential.counter
) {
// Error out when the counter in the DB is greater than or equal to the counter in the
// dataStruct. It's related to how the authenticator maintains the number of times its been
// used for this client. If this happens, then someone's somehow increased the counter
// on the device without going through this site
throw new Error(
`Response counter value ${counter} was lower than expected ${authenticator.counter}`,
`Response counter value ${counter} was lower than expected ${credential.counter}`,
);
}

Expand All @@ -251,11 +251,11 @@ export async function verifyAuthenticationResponse(
verified: await verifySignature({
signature,
data: signatureBase,
credentialPublicKey: authenticator.credentialPublicKey,
credentialPublicKey: credential.publicKey,
}),
authenticationInfo: {
newCounter: counter,
credentialID: authenticator.credentialID,
credentialID: credential.id,
userVerified: flags.uv,
credentialDeviceType,
credentialBackedUp,
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ export type {
AttestationConveyancePreference,
AuthenticationExtensionsClientInputs,
AuthenticationResponseJSON,
AuthenticatorDevice,
AuthenticatorSelectionCriteria,
AuthenticatorTransportFuture,
Base64URLString,
Expand All @@ -15,6 +14,7 @@ export type {
PublicKeyCredentialRequestOptionsJSON,
RegistrationResponseJSON,
UserVerificationRequirement,
WebAuthnCredential,
} from '../../types/src/index.ts';

// tiny_cbor (a.k.a. tiny-cbor in Node land)
Expand Down
Loading

0 comments on commit 0aedc62

Please sign in to comment.