@le-space/orbitdb-identity-provider-webauthn-did 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,58 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.4.2
6
+
7
+ ### Fixed
8
+
9
+ - Restore debug logging in the browser. `weald`, which `@libp2p/logger` uses,
10
+ does `import { ms as humanize } from 'ms'` — a named export that only exists
11
+ in `ms@3`+. All three demos pinned `ms` to `2.1.3`, which is CommonJS with no
12
+ named export, so the import resolved to `undefined` and the first debug call
13
+ threw `TypeError: (0, import_ms2.ms) is not a function`. Enabling `DEBUG` in a
14
+ browser therefore crashed credential creation outright. Dropping the pin lets
15
+ `weald` resolve the version it declares.
16
+
17
+ This is why `webauthn-logging-e2e` had been failing continuously: it is the
18
+ only suite that sets `localStorage.debug`, so it was the only one to reach the
19
+ broken path.
20
+
21
+ - Clear the production dependency advisories. `iso-web > iso-kv > conf > ajv`
22
+ carried four high `fast-uri` advisories and one moderate `ajv` one; the scoped
23
+ overrides `conf>ajv` and `ajv>fast-uri` resolve it. Scoped deliberately: a
24
+ blanket `ajv` override also hits ESLint, which needs ajv 6 and dies on the
25
+ removed `missingRefs` option.
26
+ `pnpm audit --prod` now reports nothing, so the enforced CI gate moves from
27
+ `critical` to `moderate`.
28
+ - Stop writing WebAuthn credentials to the console. `logWebAuthnResponse()` dumped
29
+ the whole credential — `rawId`, `attestationObject`, `clientDataJSON`,
30
+ `signature`, `getPublicKey()` and `getClientExtensionResults()` — on every
31
+ `navigator.credentials.create()` and `.get()`, unconditionally and in
32
+ production code paths. Two things made that more than noise: extension results
33
+ can carry the PRF output, which is what both the keystore encryption and (since
34
+ 0.4.1) the OrbitDB signing key derive from, and `rawId` is a stable per-user,
35
+ per-RP identifier that landed in any console capture or session replay the
36
+ embedding app happened to run. Replaced by a single shared helper that logs
37
+ shape only — byte lengths, presence flags and the names of the extensions that
38
+ returned results — behind the package debug logger, so it is silent unless
39
+ `DEBUG=orbitdb-identity-provider-webauthn-did*` is set. Closes #22.
40
+ - Keep the demos' P2P component out of the server render. Turning on `ssr`
41
+ so prerendering emitted real content also meant `+page.svelte` was evaluated
42
+ in Node, and it imported the libp2p stack at module scope — reaching
43
+ `@libp2p/webrtc` and its native `node-datachannel` binding, which the demos
44
+ do not build. The dev server returned 500 for every request. The component is
45
+ loaded in the browser only now; the shared shell still renders server-side, so
46
+ prerendering keeps producing a real title and description.
47
+
48
+ ### Changed
49
+
50
+ - Route the remaining informational `console.log` output through the debug
51
+ logger. A library should not print unconditionally; `console.error` and
52
+ `console.warn` stay as they are, so genuine failures remain visible. `src/`
53
+ went from 61 `console.*` calls to 16, none of them `console.log`.
54
+ - Deduplicate three byte-identical copies of the WebAuthn debug helper into
55
+ `src/webauthn/debug-log.js`.
56
+
5
57
  ## 0.4.1
6
58
 
7
59
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@le-space/orbitdb-identity-provider-webauthn-did",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "WebAuthn-based DID identity provider for OrbitDB for hardware-secured wallets and biometric Passkey authentication",
5
5
  "main": "src/index.js",
6
6
  "types": "types/index.d.ts",
@@ -143,7 +143,9 @@
143
143
  "iso-base": "npm:@le-space/iso-base",
144
144
  "iso-did": "npm:@le-space/iso-did@2.1.2",
145
145
  "iso-web": "^3.1.2",
146
- "iso-webauthn-varsig": "npm:@le-space/iso-webauthn-varsig@^0.2.0"
146
+ "iso-webauthn-varsig": "npm:@le-space/iso-webauthn-varsig@^0.2.0",
147
+ "conf>ajv": "^8.18.0",
148
+ "ajv>fast-uri": "^3.1.4"
147
149
  },
148
150
  "onlyBuiltDependencies": [
149
151
  "@ipshipyard/node-datachannel",
@@ -77,10 +77,6 @@ export class OrbitDBWebAuthnIdentityProvider {
77
77
  return IDENTITY_TYPES.WEBAUTHN;
78
78
  }
79
79
 
80
- /**
81
- * Resolve the identity DID.
82
- * @returns {Promise<string>} DID string.
83
- */
84
80
  /**
85
81
  * Resolve the identity DID.
86
82
  *
@@ -352,11 +348,11 @@ export class OrbitDBWebAuthnIdentityProvider {
352
348
  */
353
349
  async createEncryptedKeystore() {
354
350
  if (!this.encryptKeystore) {
355
- console.log('ℹ️ Keystore encryption not enabled, skipping');
351
+ identityLog('ℹ️ Keystore encryption not enabled, skipping');
356
352
  return;
357
353
  }
358
354
 
359
- console.log(
355
+ identityLog(
360
356
  '🔐 Creating encrypted keystore with method:',
361
357
  this.keystoreEncryptionMethod
362
358
  );
@@ -448,7 +444,7 @@ export class OrbitDBWebAuthnIdentityProvider {
448
444
  }
449
445
 
450
446
  // Store encrypted keystore
451
- console.log(
447
+ identityLog(
452
448
  '💾 Storing encrypted keystore with credentialId:',
453
449
  this.credential.credentialId?.substring(0, 16) + '...'
454
450
  );
@@ -461,7 +457,7 @@ export class OrbitDBWebAuthnIdentityProvider {
461
457
  publicKey: publicKeyBytes,
462
458
  keyType,
463
459
  };
464
- console.log('✅ Encrypted keystore stored successfully');
460
+ identityLog('✅ Encrypted keystore stored successfully');
465
461
 
466
462
  identityLog('Encrypted keystore created and stored successfully');
467
463
  } catch (error) {
@@ -649,15 +645,15 @@ export class OrbitDBWebAuthnIdentityProvider {
649
645
  // If encryption is enabled, create and unlock encrypted keystore
650
646
  if (encryptKeystore && keystore) {
651
647
  try {
652
- console.log(
648
+ identityLog(
653
649
  '🔐 Creating encrypted keystore with',
654
650
  keystoreEncryptionMethod,
655
651
  '...'
656
652
  );
657
653
  await provider.createEncryptedKeystore();
658
- console.log('🔓 Unlocking encrypted keystore...');
654
+ identityLog('🔓 Unlocking encrypted keystore...');
659
655
  await provider.unlockEncryptedKeystore();
660
- console.log('✅ Encrypted keystore created and unlocked successfully');
656
+ identityLog('✅ Encrypted keystore created and unlocked successfully');
661
657
  identityLog('Encrypted keystore created and unlocked');
662
658
  } catch (error) {
663
659
  // Log error visibly so users know encryption failed
@@ -19,40 +19,11 @@ import {
19
19
  VarsigVerificationError,
20
20
  WebAuthnAuthenticationError,
21
21
  } from '../errors.js';
22
+ import { logWebAuthnResponse } from '../webauthn/debug-log.js';
22
23
 
23
24
  const isTestMode = () =>
24
25
  typeof window !== 'undefined' && window.__PLAYWRIGHT__ === true;
25
26
 
26
- function logWebAuthnResponse(label, credential) {
27
- const response = credential?.response;
28
- const getPublicKeyResult =
29
- typeof response?.getPublicKey === 'function'
30
- ? response.getPublicKey()
31
- : null;
32
-
33
- console.group(`[WebAuthn Debug] ${label}`);
34
- console.log('credential', credential);
35
- console.log('credential.id', credential?.id);
36
- console.log('credential.type', credential?.type);
37
- console.log('credential.rawId', credential?.rawId);
38
- console.log('credential.response', response);
39
- console.log('response.clientDataJSON', response?.clientDataJSON);
40
- console.log('response.attestationObject', response?.attestationObject);
41
- console.log('response.authenticatorData', response?.authenticatorData);
42
- console.log('response.signature', response?.signature);
43
- console.log('response.userHandle', response?.userHandle);
44
- console.log(
45
- 'response.getPublicKey exists',
46
- typeof response?.getPublicKey === 'function'
47
- );
48
- console.log('response.getPublicKey()', getPublicKeyResult);
49
- console.log(
50
- 'client extension results',
51
- credential?.getClientExtensionResults?.() || null
52
- );
53
- console.groupEnd();
54
- }
55
-
56
27
  /**
57
28
  * Run a WebAuthn assertion for a payload.
58
29
  * @param {Object} credential - WebAuthn credential info.
@@ -5,40 +5,11 @@ import { DIDKey } from 'iso-did';
5
5
  import { parseAttestationObject } from 'iso-passkeys';
6
6
  import { toArrayBuffer } from './utils.js';
7
7
  import { buildAuthenticatorSelection } from '../webauthn/config.js';
8
+ import { logWebAuthnResponse } from '../webauthn/debug-log.js';
8
9
 
9
10
  const isTestMode = () =>
10
11
  typeof window !== 'undefined' && window.__PLAYWRIGHT__ === true;
11
12
 
12
- function logWebAuthnResponse(label, credential) {
13
- const response = credential?.response;
14
- const getPublicKeyResult =
15
- typeof response?.getPublicKey === 'function'
16
- ? response.getPublicKey()
17
- : null;
18
-
19
- console.group(`[WebAuthn Debug] ${label}`);
20
- console.log('credential', credential);
21
- console.log('credential.id', credential?.id);
22
- console.log('credential.type', credential?.type);
23
- console.log('credential.rawId', credential?.rawId);
24
- console.log('credential.response', response);
25
- console.log('response.clientDataJSON', response?.clientDataJSON);
26
- console.log('response.attestationObject', response?.attestationObject);
27
- console.log('response.authenticatorData', response?.authenticatorData);
28
- console.log('response.signature', response?.signature);
29
- console.log('response.userHandle', response?.userHandle);
30
- console.log(
31
- 'response.getPublicKey exists',
32
- typeof response?.getPublicKey === 'function'
33
- );
34
- console.log('response.getPublicKey()', getPublicKeyResult);
35
- console.log(
36
- 'client extension results',
37
- credential?.getClientExtensionResults?.() || null
38
- );
39
- console.groupEnd();
40
- }
41
-
42
13
  /**
43
14
  * Extract public key info from a WebAuthn attestation object.
44
15
  * @param {Uint8Array} attestationObject - Raw attestation object bytes.
@@ -7,6 +7,10 @@
7
7
  * without relying on external network calls or IPFS gateway timeouts.
8
8
  */
9
9
 
10
+ import { logger } from '@libp2p/logger';
11
+
12
+ const log = logger('orbitdb-identity-provider-webauthn-did:verification');
13
+
10
14
  /**
11
15
  * Verify database update events using pragmatic approach
12
16
  * @param {Object} database - The OrbitDB database instance
@@ -19,7 +23,7 @@ export async function verifyDatabaseUpdate(
19
23
  identityHash,
20
24
  expectedWebAuthnDID
21
25
  ) {
22
- console.log('🔄 Verifying database update event');
26
+ log('🔄 Verifying database update event');
23
27
 
24
28
  // Simple logic: if an update is happening in our database and our database
25
29
  // identity matches the expected WebAuthn DID, then the update is from us
@@ -72,7 +76,7 @@ export async function verifyIdentityStorage(
72
76
  identity,
73
77
  timeoutMs = 5000
74
78
  ) {
75
- console.log('🔍 Verifying identity storage...');
79
+ log('🔍 Verifying identity storage...');
76
80
 
77
81
  try {
78
82
  // Try to retrieve the identity from the store with a timeout
@@ -131,10 +135,8 @@ export async function verifyDataEntries(
131
135
  const { matchFn, checkLog = true } = options;
132
136
  const verificationResults = new Map();
133
137
 
134
- console.log(
135
- `🔍 Starting verification of ${dataEntries.length} data entries...`
136
- );
137
- console.log(`🎯 Expected WebAuthn DID: ${expectedWebAuthnDID}`);
138
+ log(`🔍 Starting verification of ${dataEntries.length} data entries...`);
139
+ log(`🎯 Expected WebAuthn DID: ${expectedWebAuthnDID}`);
138
140
 
139
141
  try {
140
142
  // Check if our database identity matches the expected WebAuthn DID
@@ -142,7 +144,7 @@ export async function verifyDataEntries(
142
144
  const databaseIdentityMatches =
143
145
  databaseIdentity?.id === expectedWebAuthnDID;
144
146
 
145
- console.log('🔑 Database identity check:', {
147
+ log('🔑 Database identity check:', {
146
148
  databaseDID: databaseIdentity?.id,
147
149
  expectedDID: expectedWebAuthnDID,
148
150
  matches: databaseIdentityMatches,
@@ -150,7 +152,7 @@ export async function verifyDataEntries(
150
152
 
151
153
  for (const entry of dataEntries) {
152
154
  try {
153
- console.log(`📝 Verifying entry: ${entry.id}`);
155
+ log(`📝 Verifying entry: ${entry.id}`);
154
156
 
155
157
  // Method 1: Check if we can access the entry in our database
156
158
  const entryInDb = await database.get(entry.id);
@@ -204,7 +206,7 @@ export async function verifyDataEntries(
204
206
 
205
207
  verificationResults.set(entry.id, result);
206
208
 
207
- console.log(
209
+ log(
208
210
  `${verificationSuccess ? '✅' : '❌'} Entry ${entry.id}: ${verificationSuccess ? 'VERIFIED' : 'FAILED'}`
209
211
  );
210
212
  } catch (error) {
@@ -232,7 +234,7 @@ export async function verifyDataEntries(
232
234
  }
233
235
  }
234
236
 
235
- console.log(
237
+ log(
236
238
  `✅ Verification completed: ${verificationResults.size} entries processed`
237
239
  );
238
240
  return verificationResults;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * @module WebAuthnDebugLog
3
+ * @description
4
+ * Describes a WebAuthn credential or assertion for debugging without putting
5
+ * its contents anywhere.
6
+ *
7
+ * This replaces three copies of a helper that wrote the whole credential to
8
+ * `console` on every `navigator.credentials.create()` and `.get()` —
9
+ * unconditionally, in production code paths. Two reasons that mattered:
10
+ *
11
+ * - `getClientExtensionResults()` was logged verbatim. Since 0.4.1 the PRF
12
+ * extension is requested on every credential, so that object can carry the
13
+ * PRF output, which is the material both the keystore encryption and the
14
+ * OrbitDB signing key are derived from.
15
+ * - `rawId` is a stable per-user, per-RP identifier. Emitting it on every call
16
+ * put it into any console capture, error reporter or session replay the
17
+ * embedding app happens to run.
18
+ *
19
+ * What is logged here is shape, not content: byte lengths, presence flags, and
20
+ * which extensions came back. Enough to tell "the authenticator returned no PRF
21
+ * result" from "the assertion never happened", which is what these logs were
22
+ * ever used for.
23
+ *
24
+ * See issue #22.
25
+ */
26
+ import { logger } from '@libp2p/logger';
27
+
28
+ const log = logger('orbitdb-identity-provider-webauthn-did:webauthn');
29
+
30
+ /**
31
+ * Byte length of an ArrayBuffer or view, or null when absent.
32
+ * @param {ArrayBuffer|ArrayBufferView|null|undefined} value - Buffer-ish value.
33
+ * @returns {number|null} Length in bytes, or null.
34
+ */
35
+ function byteLength(value) {
36
+ if (!value) return null;
37
+ if (typeof value.byteLength === 'number') return value.byteLength;
38
+ if (typeof value.length === 'number') return value.length;
39
+ return null;
40
+ }
41
+
42
+ /**
43
+ * Names of the extensions that returned results, without their values.
44
+ *
45
+ * The names alone are diagnostic — they say whether PRF engaged. The values are
46
+ * key material and never belong in a log.
47
+ *
48
+ * @param {PublicKeyCredential} credential - Credential or assertion.
49
+ * @returns {string[]|null} Extension names, or null if unavailable.
50
+ */
51
+ function extensionNames(credential) {
52
+ try {
53
+ const results = credential?.getClientExtensionResults?.();
54
+ return results ? Object.keys(results) : null;
55
+ } catch {
56
+ return null;
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Describe a WebAuthn response by shape alone.
62
+ *
63
+ * Every value here is a length, a boolean or an extension name. Nothing
64
+ * derived from credential bytes, and no extension values. Exported so the
65
+ * redaction can be asserted in tests rather than assumed.
66
+ *
67
+ * @param {PublicKeyCredential} credential - Credential or assertion.
68
+ * @returns {Object} Redacted description.
69
+ */
70
+ export function describeWebAuthnResponse(credential) {
71
+ const response = credential?.response;
72
+
73
+ return {
74
+ type: credential?.type ?? null,
75
+ rawIdBytes: byteLength(credential?.rawId),
76
+ clientDataJSONBytes: byteLength(response?.clientDataJSON),
77
+ // Registration only.
78
+ attestationObjectBytes: byteLength(response?.attestationObject),
79
+ hasGetPublicKey: typeof response?.getPublicKey === 'function',
80
+ // Assertion only.
81
+ authenticatorDataBytes: byteLength(response?.authenticatorData),
82
+ signatureBytes: byteLength(response?.signature),
83
+ hasUserHandle: Boolean(response?.userHandle),
84
+ extensions: extensionNames(credential),
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Log the shape of a WebAuthn response.
90
+ *
91
+ * Goes through the package debug logger, so it is off unless
92
+ * `DEBUG=orbitdb-identity-provider-webauthn-did*` is set, and it never writes
93
+ * credential contents.
94
+ *
95
+ * @param {string} label - What produced the response.
96
+ * @param {PublicKeyCredential} credential - Credential or assertion.
97
+ */
98
+ export function logWebAuthnResponse(label, credential) {
99
+ if (!log.enabled) return;
100
+ log('%s returned: %o', label, describeWebAuthnResponse(credential));
101
+ }
@@ -27,39 +27,10 @@ import {
27
27
  buildAuthenticatorSelection,
28
28
  buildCredentialRequestOptions,
29
29
  } from './config.js';
30
+ import { logWebAuthnResponse } from './debug-log.js';
30
31
 
31
32
  const webauthnLog = logger('orbitdb-identity-provider-webauthn-did:webauthn');
32
33
 
33
- function logWebAuthnResponse(label, credential) {
34
- const response = credential?.response;
35
- const getPublicKeyResult =
36
- typeof response?.getPublicKey === 'function'
37
- ? response.getPublicKey()
38
- : null;
39
-
40
- console.group(`[WebAuthn Debug] ${label}`);
41
- console.log('credential', credential);
42
- console.log('credential.id', credential?.id);
43
- console.log('credential.type', credential?.type);
44
- console.log('credential.rawId', credential?.rawId);
45
- console.log('credential.response', response);
46
- console.log('response.clientDataJSON', response?.clientDataJSON);
47
- console.log('response.attestationObject', response?.attestationObject);
48
- console.log('response.authenticatorData', response?.authenticatorData);
49
- console.log('response.signature', response?.signature);
50
- console.log('response.userHandle', response?.userHandle);
51
- console.log(
52
- 'response.getPublicKey exists',
53
- typeof response?.getPublicKey === 'function'
54
- );
55
- console.log('response.getPublicKey()', getPublicKeyResult);
56
- console.log(
57
- 'client extension results',
58
- credential?.getClientExtensionResults?.() || null
59
- );
60
- console.groupEnd();
61
- }
62
-
63
34
  /**
64
35
  * WebAuthn DID Provider Core Implementation
65
36
  */