diff options
author | Matthew Miller <matthew@millerti.me> | 2020-05-26 22:38:27 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-26 22:38:27 -0700 |
commit | 5a1acc9128be6dbce3d8d718defe93fb14a88e36 (patch) | |
tree | 7eea60332475794ba7fa02ea24374fc98b59baf4 /packages/server/src | |
parent | 2374c09f8444b8a80ce8429f2654ce1b3b92c346 (diff) | |
parent | 1c956b9c39f5c175d3841b1fafaeeb495d1eea6b (diff) |
Merge pull request #16 from MasterKale/feature/support-more-credential-options
feature/support-more-credential-options
Diffstat (limited to 'packages/server/src')
4 files changed, 152 insertions, 127 deletions
diff --git a/packages/server/src/assertion/generateAssertionOptions.test.ts b/packages/server/src/assertion/generateAssertionOptions.test.ts index 257657b..aa345af 100644 --- a/packages/server/src/assertion/generateAssertionOptions.test.ts +++ b/packages/server/src/assertion/generateAssertionOptions.test.ts @@ -3,40 +3,41 @@ import generateAssertionOptions from './generateAssertionOptions'; test('should generate credential request options suitable for sending via JSON', () => { const challenge = 'totallyrandomvalue'; - const options = generateAssertionOptions( + const options = generateAssertionOptions({ challenge, - 1, - [ + timeout: 1, + allowedBase64CredentialIDs: [ Buffer.from('1234', 'ascii').toString('base64'), Buffer.from('5678', 'ascii').toString('base64'), ], - ); + }); expect(options).toEqual({ - publicKey: { - challenge, - allowCredentials: [ - { - id: 'MTIzNA==', - type: 'public-key', - transports: ['usb', 'ble', 'nfc', 'internal'], - }, - { - id: 'NTY3OA==', - type: 'public-key', - transports: ['usb', 'ble', 'nfc', 'internal'], - }, - ], - timeout: 1, - }, + challenge, + allowCredentials: [ + { + id: 'MTIzNA==', + type: 'public-key', + transports: ['usb', 'ble', 'nfc', 'internal'], + }, + { + id: 'NTY3OA==', + type: 'public-key', + transports: ['usb', 'ble', 'nfc', 'internal'], + }, + ], + timeout: 1, }); }); test('defaults to 60 seconds if no timeout is specified', () => { - const options = generateAssertionOptions('totallyrandomvalue', undefined, [ - Buffer.from('1234', 'ascii').toString('base64'), - Buffer.from('5678', 'ascii').toString('base64'), - ]); + const options = generateAssertionOptions({ + challenge: 'totallyrandomvalue', + allowedBase64CredentialIDs: [ + Buffer.from('1234', 'ascii').toString('base64'), + Buffer.from('5678', 'ascii').toString('base64'), + ], + }); - expect(options.publicKey.timeout).toEqual(60000); + expect(options.timeout).toEqual(60000); }); diff --git a/packages/server/src/assertion/generateAssertionOptions.ts b/packages/server/src/assertion/generateAssertionOptions.ts index b30344d..b31a34f 100644 --- a/packages/server/src/assertion/generateAssertionOptions.ts +++ b/packages/server/src/assertion/generateAssertionOptions.ts @@ -2,6 +2,13 @@ import type { PublicKeyCredentialRequestOptionsJSON, } from '@simplewebauthn/typescript-types'; +type Options = { + challenge: string, + allowedBase64CredentialIDs: string[], + suggestedTransports?: AuthenticatorTransport[], + timeout?: number, +}; + /** * Prepare a value to pass into navigator.credentials.get(...) for authenticator "login" * @@ -12,20 +19,22 @@ import type { * @param suggestedTransports Suggested types of authenticators for assertion */ export default function generateAssertionOptions( - challenge: string, - timeout = 60000, - allowedBase64CredentialIDs: string[], - suggestedTransports: AuthenticatorTransport[] = ['usb', 'ble', 'nfc', 'internal'], + options: Options, ): PublicKeyCredentialRequestOptionsJSON { + const { + challenge, + allowedBase64CredentialIDs, + suggestedTransports = ['usb', 'ble', 'nfc', 'internal'], + timeout = 60000, + } = options; + return { - publicKey: { - challenge, - allowCredentials: allowedBase64CredentialIDs.map(id => ({ - id, - type: 'public-key', - transports: suggestedTransports, - })), - timeout, - }, + challenge, + allowCredentials: allowedBase64CredentialIDs.map(id => ({ + id, + type: 'public-key', + transports: suggestedTransports, + })), + timeout, }; } diff --git a/packages/server/src/attestation/generateAttestationOptions.test.ts b/packages/server/src/attestation/generateAttestationOptions.test.ts index 3885dfc..73218bf 100644 --- a/packages/server/src/attestation/generateAttestationOptions.test.ts +++ b/packages/server/src/attestation/generateAttestationOptions.test.ts @@ -5,58 +5,54 @@ test('should generate credential request options suitable for sending via JSON', const rpID = 'not.real'; const challenge = 'totallyrandomvalue'; const userID = '1234'; - const username = 'usernameHere'; + const userName = 'usernameHere'; const timeout = 1; const attestationType = 'indirect'; - const options = generateAttestationOptions( + const options = generateAttestationOptions({ serviceName, rpID, challenge, userID, - username, + userName, timeout, attestationType, - ); + }); expect(options).toEqual({ - publicKey: { - challenge, - rp: { - name: serviceName, - id: rpID, - }, - user: { - id: userID, - name: username, - displayName: username, - }, - pubKeyCredParams: [ - { - alg: -7, - type: 'public-key', - }, - ], - timeout, - attestation: attestationType, - excludeCredentials: [], + challenge, + rp: { + name: serviceName, + id: rpID, + }, + user: { + id: userID, + name: userName, + displayName: userName, }, + pubKeyCredParams: [ + { + alg: -7, + type: 'public-key', + }, + ], + timeout, + attestation: attestationType, + excludeCredentials: [], }); }); test('should map excluded credential IDs if specified', () => { - const options = generateAttestationOptions( - 'SimpleWebAuthn', - 'not.real', - 'totallyrandomvalue', - '1234', - 'usernameHere', - undefined, - undefined, - ['someIDhere'], - ); + const options = generateAttestationOptions({ + serviceName: 'SimpleWebAuthn', + rpID: 'not.real', + challenge: 'totallyrandomvalue', + userID: '1234', + userName: 'usernameHere', + excludedBase64CredentialIDs: ['someIDhere'], + }); - expect(options.publicKey.excludeCredentials).toEqual([{ + expect(options.excludeCredentials).toEqual([{ id: 'someIDhere', type: 'public-key', transports: ['usb', 'ble', 'nfc', 'internal'], @@ -64,25 +60,25 @@ test('should map excluded credential IDs if specified', () => { }); test('defaults to 60 seconds if no timeout is specified', () => { - const options = generateAttestationOptions( - 'SimpleWebAuthn', - 'not.real', - 'totallyrandomvalue', - '1234', - 'usernameHere', - ); + const options = generateAttestationOptions({ + serviceName: 'SimpleWebAuthn', + rpID: 'not.real', + challenge: 'totallyrandomvalue', + userID: '1234', + userName: 'usernameHere', + }); - expect(options.publicKey.timeout).toEqual(60000); + expect(options.timeout).toEqual(60000); }); test('defaults to direct attestation if no attestation type is specified', () => { - const options = generateAttestationOptions( - 'SimpleWebAuthn', - 'not.real', - 'totallyrandomvalue', - '1234', - 'usernameHere', - ); + const options = generateAttestationOptions({ + serviceName: 'SimpleWebAuthn', + rpID: 'not.real', + challenge: 'totallyrandomvalue', + userID: '1234', + userName: 'usernameHere', + }); - expect(options.publicKey.attestation).toEqual('direct'); + expect(options.attestation).toEqual('none'); }); diff --git a/packages/server/src/attestation/generateAttestationOptions.ts b/packages/server/src/attestation/generateAttestationOptions.ts index 27931fa..e2a9926 100644 --- a/packages/server/src/attestation/generateAttestationOptions.ts +++ b/packages/server/src/attestation/generateAttestationOptions.ts @@ -1,57 +1,76 @@ -import { PublicKeyCredentialCreationOptionsJSON } from '@simplewebauthn/typescript-types'; +import { + PublicKeyCredentialCreationOptionsJSON, +} from '@simplewebauthn/typescript-types'; + +type Options = { + serviceName: string, + rpID: string, + challenge: string, + userID: string, + userName: string, + userDisplayName?: string, + timeout?: number, + attestationType?: AttestationConveyancePreference, + excludedBase64CredentialIDs?: string[], + suggestedTransports?: AuthenticatorTransport[], +}; /** * Prepare a value to pass into navigator.credentials.create(...) for authenticator "registration" * + * **Options:** + * * @param serviceName Friendly user-visible website name * @param rpID Valid domain name (after `https://`) * @param challenge Random string the authenticator needs to sign and pass back * @param userID User's website-specific unique ID - * @param username User's website-specific username + * @param userName User's website-specific username (email, etc...) + * @param userDisplayName User's actual name * @param timeout How long (in ms) the user can take to complete attestation - * @param attestationType Request a full ("direct") or anonymized ("indirect") attestation statement + * @param attestationType Specific attestation statement * @param excludedBase64CredentialIDs Array of base64-encoded authenticator IDs registered by the * user so the user can't register the same credential multiple times * @param suggestedTransports Suggested types of authenticators for attestation */ export default function generateAttestationOptions( - serviceName: string, - rpID: string, - challenge: string, - userID: string, - username: string, - timeout = 60000, - attestationType: 'direct' | 'indirect' = 'direct', - excludedBase64CredentialIDs: string[] = [], - suggestedTransports: AuthenticatorTransport[] = ['usb', 'ble', 'nfc', 'internal'], + options: Options, ): PublicKeyCredentialCreationOptionsJSON { + const { + serviceName, + rpID, + challenge, + userID, + userName, + userDisplayName = userName, + timeout = 60000, + attestationType = 'none', + excludedBase64CredentialIDs = [], + suggestedTransports = ['usb', 'ble', 'nfc', 'internal'], + } = options; + return { - publicKey: { - // Cryptographically random bytes to prevent replay attacks - challenge, - // The organization registering and authenticating the user - rp: { - name: serviceName, - id: rpID, - }, - user: { - id: userID, - name: username, - displayName: username, - }, - pubKeyCredParams: [ - { - alg: -7, - type: 'public-key', - }, - ], - timeout, - attestation: attestationType, - excludeCredentials: excludedBase64CredentialIDs.map((id) => ({ - id, - type: 'public-key', - transports: suggestedTransports, - })), + challenge, + rp: { + name: serviceName, + id: rpID, + }, + user: { + id: userID, + name: userName, + displayName: userDisplayName, }, + pubKeyCredParams: [ + { + alg: -7, + type: 'public-key', + }, + ], + timeout, + attestation: attestationType, + excludeCredentials: excludedBase64CredentialIDs.map((id) => ({ + id, + type: 'public-key', + transports: suggestedTransports, + })), }; } |