This commit is contained in:
Girish Ramakrishnan
2026-02-17 19:30:33 +01:00
parent 3ef990b0bf
commit 319360f8d0
5 changed files with 68 additions and 101 deletions
+27 -35
View File
@@ -14,7 +14,7 @@ import webauthnHelper from './webauthn-helper.js';
/* global after:false */
describe('Passkeys', function () {
const { domainSetup, cleanup, admin, user, auditSource, dashboardFqdn } = common;
const { domainSetup, cleanup, admin, auditSource, dashboardFqdn } = common;
const origin = `https://${dashboardFqdn}`;
async function cleanupUsers() {
@@ -36,7 +36,7 @@ describe('Passkeys', function () {
before(createOwner);
it('list returns empty', async function () {
const result = await passkeys.list(admin.id);
const result = await passkeys.listByUserId(admin.id);
expect(result).to.be.an(Array);
expect(result.length).to.be(0);
});
@@ -48,7 +48,7 @@ describe('Passkeys', function () {
});
it('list returns one passkey', async function () {
const result = await passkeys.list(admin.id);
const result = await passkeys.listByUserId(admin.id);
expect(result.length).to.be(1);
expect(result[0].userId).to.be(admin.id);
expect(result[0].credentialId).to.be('credId123');
@@ -59,7 +59,7 @@ describe('Passkeys', function () {
});
it('can get by id', async function () {
const list = await passkeys.list(admin.id);
const list = await passkeys.listByUserId(admin.id);
const result = await passkeys.get(list[0].id);
expect(result).to.not.be(null);
expect(result.credentialId).to.be('credId123');
@@ -87,23 +87,15 @@ describe('Passkeys', function () {
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);
});
it('can update counter', async function () {
const list = await passkeys.list(admin.id);
await passkeys.updateCounter(list[0].id, 42);
const updated = await passkeys.get(list[0].id);
expect(updated.counter).to.be(42);
expect(updated.lastUsedTime).to.not.be(null);
});
it('can delete a passkey', async function () {
const list = await passkeys.list(admin.id);
await passkeys.del(list[0].id, admin.id);
const afterDel = await passkeys.list(admin.id);
const list = await passkeys.listByUserId(admin.id);
await passkeys.del(list[0].id);
const afterDel = await passkeys.listByUserId(admin.id);
expect(afterDel.length).to.be(0);
});
it('delete throws for unknown passkey', async function () {
const [error] = await safe(passkeys.del('pk-nonexistent', admin.id));
const [error] = await safe(passkeys.del('pk-nonexistent'));
expect(error).to.not.be(null);
expect(error.reason).to.be(BoxError.NOT_FOUND);
});
@@ -111,7 +103,7 @@ describe('Passkeys', function () {
it('delAll clears all passkeys', async function () {
await passkeys.add(admin.id, 'cred1', 'pk1', 0, [], 'Key1');
await passkeys.delAll();
const result = await passkeys.list(admin.id);
const result = await passkeys.listByUserId(admin.id);
expect(result.length).to.be(0);
});
@@ -127,7 +119,7 @@ describe('Passkeys', function () {
expect(filtered.counter).to.be(undefined);
expect(filtered.userId).to.be(undefined);
await passkeys.del(id, admin.id);
await passkeys.del(id);
});
});
@@ -138,7 +130,7 @@ describe('Passkeys', function () {
it('can generate registration options', async function () {
const adminUser = await users.get(admin.id);
const options = await passkeys.generateRegistrationOptions(adminUser);
const options = await passkeys.getRegistrationOptions(adminUser);
expect(options).to.be.an(Object);
expect(options.challenge).to.be.a('string');
expect(options.rp).to.be.an(Object);
@@ -151,7 +143,7 @@ describe('Passkeys', function () {
authenticator = webauthnHelper.createVirtualAuthenticator();
const adminUser = await users.get(admin.id);
const options = await passkeys.generateRegistrationOptions(adminUser);
const options = await passkeys.getRegistrationOptions(adminUser);
const response = await webauthnHelper.createRegistrationResponse(authenticator, options, origin);
const result = await passkeys.verifyRegistration(adminUser, response, 'My Test Key');
@@ -159,14 +151,14 @@ describe('Passkeys', function () {
expect(result.id).to.be.a('string');
expect(result.id).to.match(/^pk-/);
const list = await passkeys.list(admin.id);
const list = await passkeys.listByUserId(admin.id);
expect(list.length).to.be(1);
expect(list[0].name).to.be('My Test Key');
});
it('rejects duplicate registration', async function () {
const adminUser = await users.get(admin.id);
const [error] = await safe(passkeys.generateRegistrationOptions(adminUser));
const [error] = await safe(passkeys.getRegistrationOptions(adminUser));
expect(error).to.not.be(null);
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);
});
@@ -180,7 +172,7 @@ describe('Passkeys', function () {
authenticator = webauthnHelper.createVirtualAuthenticator();
// generate options to get a challenge, but use a different challenge in the response
const options = await passkeys.generateRegistrationOptions(adminUser);
const options = await passkeys.getRegistrationOptions(adminUser);
options.challenge = 'tampered-challenge-value';
const response = await webauthnHelper.createRegistrationResponse(authenticator, options, origin);
@@ -198,7 +190,7 @@ describe('Passkeys', function () {
await users.enableTwoFactorAuthentication(adminUser, totpToken, auditSource);
adminUser.twoFactorAuthenticationEnabled = true;
const [error] = await safe(passkeys.generateRegistrationOptions(adminUser));
const [error] = await safe(passkeys.getRegistrationOptions(adminUser));
expect(error).to.not.be(null);
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);
@@ -217,14 +209,14 @@ describe('Passkeys', function () {
authenticator = webauthnHelper.createVirtualAuthenticator();
const adminUser = await users.get(admin.id);
const options = await passkeys.generateRegistrationOptions(adminUser);
const options = await passkeys.getRegistrationOptions(adminUser);
const response = await webauthnHelper.createRegistrationResponse(authenticator, options, origin);
await passkeys.verifyRegistration(adminUser, response, 'Auth Test Key');
});
it('can generate authentication options', async function () {
const adminUser = await users.get(admin.id);
const options = await passkeys.generateAuthenticationOptions(adminUser);
const options = await passkeys.getAuthenticationOptions(adminUser);
expect(options).to.be.an(Object);
expect(options.challenge).to.be.a('string');
expect(options.allowCredentials).to.be.an(Array);
@@ -233,7 +225,7 @@ describe('Passkeys', function () {
it('can authenticate with virtual authenticator', async function () {
const adminUser = await users.get(admin.id);
const options = await passkeys.generateAuthenticationOptions(adminUser);
const options = await passkeys.getAuthenticationOptions(adminUser);
const response = await webauthnHelper.createAuthenticationResponse(authenticator, options, origin);
const result = await passkeys.verifyAuthentication(adminUser, response);
@@ -243,26 +235,26 @@ describe('Passkeys', function () {
});
it('counter was updated after authentication', async function () {
const list = await passkeys.list(admin.id);
const list = await passkeys.listByUserId(admin.id);
expect(list[0].counter).to.be(1);
expect(list[0].lastUsedTime).to.not.be(null);
});
it('can authenticate again (counter increments)', async function () {
const adminUser = await users.get(admin.id);
const options = await passkeys.generateAuthenticationOptions(adminUser);
const options = await passkeys.getAuthenticationOptions(adminUser);
const response = await webauthnHelper.createAuthenticationResponse(authenticator, options, origin);
const result = await passkeys.verifyAuthentication(adminUser, response);
expect(result.verified).to.be(true);
const list = await passkeys.list(admin.id);
const list = await passkeys.listByUserId(admin.id);
expect(list[0].counter).to.be(2);
});
it('rejects authentication with wrong credential', async function () {
const adminUser = await users.get(admin.id);
const options = await passkeys.generateAuthenticationOptions(adminUser);
const options = await passkeys.getAuthenticationOptions(adminUser);
// create a different authenticator and try to auth with it
const fakeAuth = webauthnHelper.createVirtualAuthenticator();
@@ -275,7 +267,7 @@ describe('Passkeys', function () {
it('rejects authentication with tampered challenge', async function () {
const adminUser = await users.get(admin.id);
const options = await passkeys.generateAuthenticationOptions(adminUser);
const options = await passkeys.getAuthenticationOptions(adminUser);
options.challenge = 'tampered-challenge';
const response = await webauthnHelper.createAuthenticationResponse(authenticator, options, origin);
@@ -287,7 +279,7 @@ describe('Passkeys', function () {
await passkeys.delAll();
const adminUser = await users.get(admin.id);
const [error] = await safe(passkeys.generateAuthenticationOptions(adminUser));
const [error] = await safe(passkeys.getAuthenticationOptions(adminUser));
expect(error).to.not.be(null);
expect(error.reason).to.be(BoxError.NOT_FOUND);
});
@@ -300,7 +292,7 @@ describe('Passkeys', function () {
// register a passkey
const authenticator = webauthnHelper.createVirtualAuthenticator();
const adminUser = await users.get(admin.id);
const options = await passkeys.generateRegistrationOptions(adminUser);
const options = await passkeys.getRegistrationOptions(adminUser);
const response = await webauthnHelper.createRegistrationResponse(authenticator, options, origin);
await passkeys.verifyRegistration(adminUser, response, 'Exclusion Test');
@@ -326,7 +318,7 @@ describe('Passkeys', function () {
await users.enableTwoFactorAuthentication(adminUser, totpToken, auditSource);
adminUser.twoFactorAuthenticationEnabled = true;
const [error] = await safe(passkeys.generateRegistrationOptions(adminUser));
const [error] = await safe(passkeys.getRegistrationOptions(adminUser));
expect(error).to.not.be(null);
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);