Skip to content

Commit 396a3ae

Browse files
authored
Add cancel feature to web authenticator (#876)
1 parent 7c039b9 commit 396a3ae

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

packages/webauthn-authenticator/src/web-authenticator.ts

+25
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,15 @@ function generateAssertionObject(
125125

126126
export class Authenticator {
127127
public readonly credentials: Record<string, WebauthnCredential> = {}
128+
private cancelNext = false
129+
130+
private throwNotAllowedError() {
131+
throw {
132+
name: 'NotAllowedError',
133+
message: 'The operation either timed out or was not allowed.',
134+
constructor: { name: 'DOMException' },
135+
}
136+
}
128137

129138
/**
130139
* Creates a new public key credential to be used for WebAuthn attestations and assertions.
@@ -180,6 +189,12 @@ export class Authenticator {
180189
credentialOptions: CredentialCreationOptionsSerialized
181190
): Promise<PublicKeyCredentialAttestationSerialized> {
182191
log('createPublicKeyCredential', credentialOptions)
192+
193+
if (this.cancelNext) {
194+
this.cancelNext = false
195+
this.throwNotAllowedError()
196+
}
197+
183198
const credOptsPubKey = credentialOptions.publicKey
184199
if (
185200
!credOptsPubKey ||
@@ -240,6 +255,12 @@ export class Authenticator {
240255
*/
241256
async getPublicKeyCredential(credentialRequestOptions: CredentialRequestOptionsSerialized) {
242257
log('getPublicKeyCredential', credentialRequestOptions)
258+
259+
if (this.cancelNext) {
260+
this.cancelNext = false
261+
this.throwNotAllowedError()
262+
}
263+
243264
const credReqOptsPubKey = credentialRequestOptions.publicKey
244265
const clientDataJSON = {
245266
type: 'webauthn.get',
@@ -286,4 +307,8 @@ export class Authenticator {
286307

287308
return credentialResponse
288309
}
310+
311+
cancelNextOperation() {
312+
this.cancelNext = true
313+
}
289314
}

packages/webauthn-authenticator/test/index.test.ts

+34
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,23 @@ M2r/eobZPWzLAuuKhc4rKm6jQJtExXSvmg==
106106

107107
verifyAssertion({ cred: cred2, testBytes, keyPair })
108108
})
109+
110+
it('should throw exception after calling cancelNextOperation', async () => {
111+
const { Authenticator } = await import('../src')
112+
113+
const authenticator = new Authenticator()
114+
authenticator.cancelNextOperation()
115+
116+
await expect(
117+
authenticator.createPublicKeyCredential({} as CredentialCreationOptionsSerialized)
118+
).rejects.toThrowError('The operation either timed out or was not allowed.')
119+
120+
authenticator.cancelNextOperation()
121+
122+
await expect(
123+
authenticator.getPublicKeyCredential({} as CredentialRequestOptionsSerialized)
124+
).rejects.toThrowError('The operation either timed out or was not allowed.')
125+
})
109126
})
110127

111128
describe('without mock', () => {
@@ -196,6 +213,23 @@ M2r/eobZPWzLAuuKhc4rKm6jQJtExXSvmg==
196213

197214
verifyAssertion({ cred: cred2, testBytes, keyPair })
198215
})
216+
217+
it('should throw exception after calling cancelNextOperation', async () => {
218+
const { Authenticator } = await import('../src')
219+
220+
const authenticator = new Authenticator()
221+
authenticator.cancelNextOperation()
222+
223+
await expect(
224+
authenticator.createPublicKeyCredential({} as CredentialCreationOptionsSerialized)
225+
).rejects.toThrowError('The operation either timed out or was not allowed.')
226+
227+
authenticator.cancelNextOperation()
228+
229+
await expect(
230+
authenticator.getPublicKeyCredential({} as CredentialRequestOptionsSerialized)
231+
).rejects.toThrowError('The operation either timed out or was not allowed.')
232+
})
199233
})
200234
})
201235
})

0 commit comments

Comments
 (0)