electron-webauthn 1.1.0 → 1.1.1

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/README.md CHANGED
@@ -21,6 +21,7 @@ This package provides JavaScript bindings to Apple's AuthenticationServices fram
21
21
  - Credential creation (registration) with attestation
22
22
  - Credential authentication (assertions) with existing credentials
23
23
  - Seamless integration with Electron's native window system
24
+ - Passkey listing via `listPasskeys` (macOS 13.3+)
24
25
  - PRF (Pseudo-Random Function) extension support
25
26
  - Large Blob extension support for reading/writing credential-specific data
26
27
  - User verification preference configuration (preferred, required, discouraged)
@@ -83,7 +84,7 @@ This library implements the W3C WebAuthn standard using Apple's native Authentic
83
84
 
84
85
  ## Error Handling
85
86
 
86
- Both `createCredential` and `getCredential` functions return a result object with a `success` field. Always check this field:
87
+ `createCredential`, `getCredential`, and `listPasskeys` all return a result object with a `success` field. Always check this field:
87
88
 
88
89
  ```typescript
89
90
  const result = await createCredential(publicKeyOptions, additionalOptions);
@@ -118,6 +119,19 @@ if (!result.success) {
118
119
  console.log("Credential ID:", result.data.credentialId);
119
120
  ```
120
121
 
122
+ `listPasskeys` returns an `Error` object (not a string code) when unsuccessful:
123
+
124
+ ```typescript
125
+ const result = await listPasskeys("example.com");
126
+
127
+ if (!result.success) {
128
+ console.error("Failed to list passkeys:", result.error.message);
129
+ return;
130
+ }
131
+
132
+ console.log(`Found ${result.credentials.length} passkeys`);
133
+ ```
134
+
121
135
  ### Common Error Scenarios
122
136
 
123
137
  #### For Both Registration and Authentication
@@ -141,6 +155,7 @@ console.log("Credential ID:", result.data.credentialId);
141
155
 
142
156
  - ✅ WebAuthn credential creation (registration/attestation)
143
157
  - ✅ WebAuthn assertions (authentication with existing credentials)
158
+ - ✅ Passkey listing with `listPasskeys` (macOS 13.3+, requires `com.apple.developer.web-browser.public-key-credential` entitlement)
144
159
  - ✅ Cross-platform authenticators (external security keys like YubiKey)
145
160
  - ✅ Platform authenticators (Touch ID, Face ID)
146
161
  - ✅ Discoverable credentials (resident keys)
@@ -3,7 +3,13 @@ import { bufferFromNSDataDirect } from "objcjs-types/nsdata";
3
3
  import { NSStringFromString } from "objcjs-types/helpers";
4
4
  import { ASAuthorizationWebBrowserPublicKeyCredentialManager, ASAuthorizationWebBrowserPublicKeyCredentialManagerAuthorizationState, } from "objcjs-types/AuthenticationServices";
5
5
  import { isAtLeast, version, formatVersion, getOSVersion, } from "objcjs-types/osversion";
6
- import { makePromise, enumFromValue } from "../helpers/objc.js";
6
+ import { enumFromValue, makePromise1Result } from "objcjs-types/helpers";
7
+ const LOGGING_ENABLED = false;
8
+ function log(...args) {
9
+ if (!LOGGING_ENABLED)
10
+ return;
11
+ console.log(...args);
12
+ }
7
13
  export async function listPasskeys(relyingPartyId) {
8
14
  try {
9
15
  const minVersion = version(13, 3);
@@ -13,26 +19,26 @@ export async function listPasskeys(relyingPartyId) {
13
19
  }
14
20
  const manager = ASAuthorizationWebBrowserPublicKeyCredentialManager.alloc().init();
15
21
  const authState = manager.authorizationStateForPlatformCredentials();
16
- console.log(`[listPasskeys] Authorization state: ${authState}`);
22
+ log(`[listPasskeys] Authorization state: ${authState}`);
17
23
  if (authState ===
18
24
  ASAuthorizationWebBrowserPublicKeyCredentialManagerAuthorizationState.NotDetermined) {
19
- console.log("[listPasskeys] Authorization not determined, requesting...");
20
- const newStateValue = await makePromise(manager.requestAuthorizationForPublicKeyCredentials$);
25
+ log("[listPasskeys] Authorization not determined, requesting...");
26
+ const newStateValue = await makePromise1Result(manager.requestAuthorizationForPublicKeyCredentials$.bind(manager));
21
27
  const newState = enumFromValue(ASAuthorizationWebBrowserPublicKeyCredentialManagerAuthorizationState, newStateValue);
22
- console.log(`[listPasskeys] Authorization request completed, new state: ${newState}`);
28
+ log(`[listPasskeys] Authorization request completed, new state: ${newState}`);
23
29
  }
24
30
  else if (authState ===
25
31
  ASAuthorizationWebBrowserPublicKeyCredentialManagerAuthorizationState.Denied) {
26
32
  throw new Error("Authorization DENIED - user must grant permission in System Settings > Privacy & Security");
27
33
  }
28
34
  else {
29
- console.log("[listPasskeys] Authorization already granted");
35
+ log("[listPasskeys] Authorization already granted");
30
36
  }
31
37
  const rpIdString = NSStringFromString(relyingPartyId);
32
- console.log(`[listPasskeys] Calling platformCredentialsForRelyingParty: ${relyingPartyId}`);
33
- const credentialsArray = await makePromise(rpIdString, manager.platformCredentialsForRelyingParty$completionHandler$);
38
+ log(`[listPasskeys] Calling platformCredentialsForRelyingParty: ${relyingPartyId}`);
39
+ const credentialsArray = await makePromise1Result(manager.platformCredentialsForRelyingParty$completionHandler$.bind(manager), rpIdString);
34
40
  const count = credentialsArray.count();
35
- console.log(`[listPasskeys] platformCredentials returned ${count} entries`);
41
+ log(`[listPasskeys] platformCredentials returned ${count} entries`);
36
42
  const credentials = [];
37
43
  for (let i = 0; i < count; i++) {
38
44
  const cred = credentialsArray.objectAtIndex$(i);
@@ -41,7 +47,7 @@ export async function listPasskeys(relyingPartyId) {
41
47
  const userHandleData = cred.userHandle();
42
48
  const credentialId = bufferToBase64Url(bufferFromNSDataDirect(credentialIdData));
43
49
  const userHandle = bufferToBase64Url(bufferFromNSDataDirect(userHandleData));
44
- console.log(`[listPasskeys] Found credential: name=${userName}, id=${credentialId.substring(0, 20)}...`);
50
+ log(`[listPasskeys] Found credential: name=${userName}, id=${credentialId.substring(0, 20)}...`);
45
51
  credentials.push({
46
52
  id: credentialId,
47
53
  rpId: relyingPartyId,
@@ -49,14 +55,14 @@ export async function listPasskeys(relyingPartyId) {
49
55
  userHandle,
50
56
  });
51
57
  }
52
- console.log(`[listPasskeys] Returning ${credentials.length} results`);
58
+ log(`[listPasskeys] Returning ${credentials.length} results`);
53
59
  return {
54
60
  success: true,
55
61
  credentials,
56
62
  };
57
63
  }
58
64
  catch (error) {
59
- console.error("[listPasskeys] Error:", error);
65
+ console.error("[listPasskeys] ", error);
60
66
  return {
61
67
  success: false,
62
68
  error: error instanceof Error ? error : new Error(String(error)),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "electron-webauthn",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "repository": "https://github.com/iamEvanYT/electron-webauthn.git",
5
5
  "homepage": "https://github.com/iamEvanYT/electron-webauthn#readme",
6
6
  "description": "Add support for WebAuthn for Electron.",
@@ -30,8 +30,8 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@oslojs/webauthn": "^1.0.0",
33
- "objc-js": "^1.3.0",
34
- "objcjs-types": "^0.5.0"
33
+ "objc-js": "^1.3.1",
34
+ "objcjs-types": "^0.5.1"
35
35
  },
36
36
  "trustedDependencies": [
37
37
  "objc-js"
@@ -1,5 +0,0 @@
1
- export declare function enumFromValue<T extends Record<string, number>>(enumObj: T, value: number): keyof T | undefined;
2
- export declare function makePromise<T, Args extends unknown[]>(...argsAndFunc: [
3
- ...args: Args,
4
- func: (...args: [...Args, callback: (result: T) => void]) => void
5
- ]): Promise<T>;
@@ -1,10 +0,0 @@
1
- export function enumFromValue(enumObj, value) {
2
- return Object.keys(enumObj).find((key) => enumObj[key] === value);
3
- }
4
- export function makePromise(...argsAndFunc) {
5
- const func = argsAndFunc[argsAndFunc.length - 1];
6
- const args = argsAndFunc.slice(0, -1);
7
- return new Promise((resolve) => {
8
- func(...args, resolve);
9
- });
10
- }