electron-webauthn 0.0.5 → 0.0.6

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.
@@ -0,0 +1,15 @@
1
+ import { Foundation } from "./index.js";
2
+ export const NSArray = Foundation.NSArray;
3
+ // Helper Functions
4
+ /**
5
+ * Create an NSArray from an array of objects
6
+ * @param objects The array of objects
7
+ * @returns An NSArray object
8
+ */
9
+ export function NSArrayFromObjects(objects) {
10
+ let array = NSArray.array();
11
+ for (const obj of objects) {
12
+ array = array.arrayByAddingObject$(obj);
13
+ }
14
+ return array;
15
+ }
@@ -0,0 +1,119 @@
1
+ import { Foundation } from "./index.js";
2
+ import { NSString } from "./nsstring.js";
3
+ export const NSData = Foundation.NSData;
4
+ // Helper Functions
5
+ /**
6
+ * Create NSData from a JavaScript Buffer
7
+ * @param buffer The Buffer object
8
+ * @returns An NSData object
9
+ */
10
+ export function NSDataFromBuffer(buffer) {
11
+ return NSData.dataWithBytes$length$(buffer, buffer.length);
12
+ }
13
+ /**
14
+ * Convert NSData to a JavaScript Buffer using base64 encoding
15
+ * This is the most reliable method for data conversion.
16
+ * @param data The NSData object
17
+ * @returns A Buffer containing the data
18
+ */
19
+ export function bufferFromNSData(data) {
20
+ const nsData = data;
21
+ const length = nsData.length();
22
+ if (length === 0) {
23
+ return Buffer.alloc(0);
24
+ }
25
+ // Use base64 encoding as a reliable bridge between NSData and JS Buffer
26
+ const base64String = nsData.base64EncodedStringWithOptions$(0);
27
+ const base64Str = base64String.UTF8String();
28
+ return Buffer.from(base64Str, "base64");
29
+ }
30
+ /**
31
+ * Convert NSData to a JavaScript Buffer using direct memory copy
32
+ * This method uses getBytes:length: for direct memory access.
33
+ * May be more efficient for large data, but requires proper buffer allocation.
34
+ * @param data The NSData object
35
+ * @returns A Buffer containing the data
36
+ */
37
+ export function bufferFromNSDataDirect(data) {
38
+ const nsData = data;
39
+ const length = nsData.length();
40
+ if (length === 0) {
41
+ return Buffer.alloc(0);
42
+ }
43
+ // Allocate a buffer and copy bytes directly
44
+ const buffer = Buffer.alloc(length);
45
+ nsData.getBytes$length$(buffer, length);
46
+ return buffer;
47
+ }
48
+ /**
49
+ * Convert NSData to a JavaScript Uint8Array
50
+ * @param data The NSData object
51
+ * @returns A Uint8Array containing the data
52
+ */
53
+ export function uint8ArrayFromNSData(data) {
54
+ const buffer = bufferFromNSData(data);
55
+ return new Uint8Array(buffer);
56
+ }
57
+ /**
58
+ * Convert NSData to a base64 string
59
+ * @param data The NSData object
60
+ * @returns A base64-encoded string
61
+ */
62
+ export function base64FromNSData(data) {
63
+ const nsData = data;
64
+ const nsString = nsData.base64EncodedStringWithOptions$(0);
65
+ return nsString.UTF8String();
66
+ }
67
+ /**
68
+ * Create NSData from a base64 string
69
+ * @param base64String The base64-encoded string
70
+ * @returns An NSData object
71
+ */
72
+ export function NSDataFromBase64(base64String) {
73
+ const nsString = NSString.stringWithUTF8String$(base64String);
74
+ const nsData = NSData.alloc();
75
+ return nsData.initWithBase64EncodedString$options$(nsString, 0);
76
+ }
77
+ /**
78
+ * Get the length of NSData
79
+ * @param data The NSData object
80
+ * @returns The length in bytes
81
+ */
82
+ export function NSDataLength(data) {
83
+ const nsData = data;
84
+ return nsData.length();
85
+ }
86
+ /**
87
+ * Create a copy of NSData
88
+ * @param data The NSData object
89
+ * @returns A new NSData object with copied data
90
+ */
91
+ export function NSDataCopy(data) {
92
+ return NSData.dataWithData$(data);
93
+ }
94
+ /**
95
+ * Compare two NSData objects for equality
96
+ * @param data1 The first NSData object
97
+ * @param data2 The second NSData object
98
+ * @returns True if the data is equal
99
+ */
100
+ export function NSDataIsEqual(data1, data2) {
101
+ const nsData1 = data1;
102
+ return nsData1.isEqualToData$(data2);
103
+ }
104
+ /**
105
+ * Extract a subrange of NSData
106
+ * Note: This method may not work with all versions of nobjc due to NSRange struct limitations.
107
+ * As an alternative, convert to Buffer, slice, and convert back.
108
+ * @param data The NSData object
109
+ * @param location The starting position
110
+ * @param length The number of bytes to extract
111
+ * @returns A new NSData object containing the subdata
112
+ */
113
+ export function NSDataSubdata(data, location, length) {
114
+ // Workaround: Convert to buffer, slice, and convert back
115
+ // This avoids the NSRange struct issue with nobjc
116
+ const buffer = bufferFromNSData(data);
117
+ const slicedBuffer = buffer.subarray(location, location + length);
118
+ return NSDataFromBuffer(slicedBuffer);
119
+ }
@@ -0,0 +1,70 @@
1
+ import { Foundation } from "./index.js";
2
+ import {} from "./nsstring.js";
3
+ export const NSError = Foundation.NSError;
4
+ /**
5
+ * Parse an NSError object into a JavaScript-friendly format
6
+ * @param error The NSError object
7
+ * @returns An object containing the error details
8
+ */
9
+ export function parseNSError(error) {
10
+ const nsError = error;
11
+ const domain = nsError.domain().UTF8String();
12
+ const code = nsError.code();
13
+ const localizedDescription = nsError.localizedDescription().UTF8String();
14
+ // Optional properties that may be null
15
+ let localizedFailureReason;
16
+ try {
17
+ const reason = nsError.localizedFailureReason();
18
+ if (reason) {
19
+ localizedFailureReason = reason.UTF8String();
20
+ }
21
+ }
22
+ catch (e) {
23
+ // Property may not exist or be null
24
+ }
25
+ let localizedRecoverySuggestion;
26
+ try {
27
+ const suggestion = nsError.localizedRecoverySuggestion();
28
+ if (suggestion) {
29
+ localizedRecoverySuggestion = suggestion.UTF8String();
30
+ }
31
+ }
32
+ catch (e) {
33
+ // Property may not exist or be null
34
+ }
35
+ // userInfo is a dictionary - basic parsing
36
+ let userInfo;
37
+ try {
38
+ const userInfoDict = nsError.userInfo();
39
+ if (userInfoDict) {
40
+ // For now, just get the description
41
+ // Full dictionary parsing would require NSDictionary wrapper
42
+ userInfo = {
43
+ description: userInfoDict.description().UTF8String(),
44
+ };
45
+ }
46
+ }
47
+ catch (e) {
48
+ // userInfo may not be accessible
49
+ }
50
+ return {
51
+ domain,
52
+ code,
53
+ localizedDescription,
54
+ ...(localizedFailureReason && { localizedFailureReason }),
55
+ ...(localizedRecoverySuggestion && { localizedRecoverySuggestion }),
56
+ ...(userInfo && { userInfo }),
57
+ };
58
+ }
59
+ /**
60
+ * Convert an NSError to a JavaScript Error object
61
+ * @param error The NSError object
62
+ * @returns A JavaScript Error with NSError details
63
+ */
64
+ export function nsErrorToJSError(error) {
65
+ const parsed = parseNSError(error);
66
+ const jsError = new Error(parsed.localizedDescription);
67
+ jsError.name = `${parsed.domain} (${parsed.code})`;
68
+ jsError.nsError = parsed;
69
+ return jsError;
70
+ }
@@ -0,0 +1,11 @@
1
+ import { Foundation } from "./index.js";
2
+ export const NSString = Foundation.NSString;
3
+ // Helper Functions
4
+ /**
5
+ * Create NSString from a JavaScript string
6
+ * @param str The string object
7
+ * @returns An NSString object
8
+ */
9
+ export function NSStringFromString(str) {
10
+ return NSString.stringWithUTF8String$(str);
11
+ }
@@ -0,0 +1,2 @@
1
+ import { Foundation } from ".";
2
+ export const NSValue = Foundation.NSValue;
@@ -0,0 +1,2 @@
1
+ import { Foundation } from "./index.js";
2
+ export const NSView = Foundation.NSView;
@@ -0,0 +1,2 @@
1
+ import { Foundation } from "./index.js";
2
+ export const NSWindow = Foundation.NSWindow;
@@ -0,0 +1,28 @@
1
+ import { NobjcLibrary, NobjcObject } from "@iamevan/nobjc";
2
+ import { NobjcObjectWrapper } from "./helpers";
3
+ // Load the Foundation framework
4
+ export const foundation = new NobjcLibrary("/System/Library/Frameworks/Foundation.framework/Foundation");
5
+ // NSString helpers
6
+ const _NSString = foundation["NSString"];
7
+ const _stringWithUTF8String = _NSString["stringWithUTF8String:"];
8
+ export class NSString extends NobjcObjectWrapper {
9
+ constructor(str) {
10
+ super(_stringWithUTF8String(str));
11
+ }
12
+ }
13
+ // NSData helpers
14
+ const _NSData = foundation["NSData"];
15
+ const _dataWithBytesLength = _NSData["dataWithBytes:length:"];
16
+ export class NSData extends NobjcObjectWrapper {
17
+ constructor(buffer) {
18
+ super(_dataWithBytesLength(buffer, buffer.length));
19
+ }
20
+ }
21
+ // NSArray helpers
22
+ const _NSArray = foundation["NSArray"];
23
+ const _arrayWithObject = _NSArray["arrayWithObject:"];
24
+ export class NSArray extends NobjcObjectWrapper {
25
+ constructor(obj) {
26
+ super(_arrayWithObject(obj));
27
+ }
28
+ }
@@ -0,0 +1,31 @@
1
+ export class NobjcInstanceWrapper {
2
+ _instance;
3
+ constructor(instance) {
4
+ this._instance = instance;
5
+ }
6
+ get instance() {
7
+ return this._instance;
8
+ }
9
+ }
10
+ /**
11
+ * Helper to allocate and initialize an Objective-C object with a single argument initializer
12
+ * @param cls The Objective-C class
13
+ * @param initMethod The initializer method name (e.g., "initWithRelyingPartyIdentifier:")
14
+ * @param arg The argument to pass to the initializer
15
+ * @returns The initialized instance
16
+ */
17
+ export function allocInit(cls, initMethod, arg) {
18
+ const instance = cls["alloc"]();
19
+ const initializer = instance[initMethod];
20
+ return initializer(arg);
21
+ }
22
+ /**
23
+ * Helper to allocate and initialize an Objective-C object with no arguments
24
+ * @param cls The Objective-C class
25
+ * @returns The initialized instance
26
+ */
27
+ export function allocInitPlain(cls) {
28
+ const instance = cls["alloc"]();
29
+ const initializer = instance["init"];
30
+ return initializer();
31
+ }
package/dist/window.js ADDED
@@ -0,0 +1,57 @@
1
+ import { NobjcLibrary, NobjcProtocol } from "objc-js";
2
+ import { allocInitPlain } from "./objc/helpers.js";
3
+ import { NSStringFromString } from "./objc/foundation/nsstring.js";
4
+ const AppKit = new NobjcLibrary("/System/Library/Frameworks/AppKit.framework/AppKit");
5
+ const Foundation = new NobjcLibrary("/System/Library/Frameworks/Foundation.framework/Foundation");
6
+ function createEmptyWindow() {
7
+ const NSApp = AppKit.NSApplication.sharedApplication();
8
+ const window = allocInitPlain(AppKit.NSWindow);
9
+ const styleMask = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3); // titled, closable, miniaturizable, resizable
10
+ // Make the app active and show the window.
11
+ window.setStyleMask$(styleMask);
12
+ window.setFrameFromString$(NSStringFromString("{{100, 100}, {800, 600}}"));
13
+ NSApp.setActivationPolicy$(0);
14
+ NSApp.finishLaunching();
15
+ NSApp.activateIgnoringOtherApps$(true);
16
+ window.setIsVisible$(true);
17
+ window.makeKeyWindow();
18
+ window.orderFrontRegardless();
19
+ const delegate = NobjcProtocol.implement("NSWindowDelegate", {
20
+ windowShouldClose$: () => {
21
+ NSApp.terminate$(NSApp);
22
+ return true;
23
+ },
24
+ windowWillClose$: () => {
25
+ NSApp.terminate$(NSApp);
26
+ },
27
+ });
28
+ window.setDelegate$(delegate);
29
+ const shutdown = () => {
30
+ try {
31
+ window.close();
32
+ }
33
+ finally {
34
+ NSApp.stop$(NSApp);
35
+ NSApp.terminate$(NSApp);
36
+ }
37
+ };
38
+ const handleSignal = () => shutdown();
39
+ process.once("exit", shutdown);
40
+ process.once("SIGINT", handleSignal);
41
+ process.once("SIGTERM", handleSignal);
42
+ process.once("SIGQUIT", handleSignal);
43
+ // Pump the AppKit run loop for a short tick to keep JS responsive.
44
+ const runLoop = Foundation.NSRunLoop.currentRunLoop();
45
+ const pump = () => {
46
+ const untilDate = Foundation.NSDate.dateWithTimeIntervalSinceNow$(0.01);
47
+ runLoop.runUntilDate$(untilDate);
48
+ };
49
+ const pumpId = setInterval(pump, 10);
50
+ process.once("exit", () => clearInterval(pumpId));
51
+ return window;
52
+ }
53
+ function getNativeWindowHandle(window) {
54
+ // Electron expects an NSView* on macOS; contentView returns that NSView.
55
+ return window.contentView();
56
+ }
57
+ export { createEmptyWindow, getNativeWindowHandle };
package/package.json CHANGED
@@ -1,53 +1,27 @@
1
1
  {
2
2
  "name": "electron-webauthn",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
+ "repository": "https://github.com/iamEvanYT/electron-webauthn",
5
+ "description": "Add support for WebAuthn for Electron.",
4
6
  "main": "dist/index.js",
5
- "types": "dist/index.d.ts",
6
- "napi": {
7
- "name": "electron-webauthn",
8
- "triples": {
9
- "additional": [
10
- "aarch64-apple-darwin",
11
- "aarch64-pc-windows-msvc"
12
- ]
7
+ "module": "dist/index.js",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "require": "./dist/index.js"
13
12
  }
14
13
  },
15
- "license": "MIT",
16
14
  "files": [
17
- "dist",
18
- "index.d.ts",
19
- "index.js"
15
+ "dist/"
20
16
  ],
17
+ "type": "module",
21
18
  "devDependencies": {
22
- "@napi-rs/cli": "^2.18.4",
23
- "ava": "^6.0.1",
24
- "typescript": "^5.8.3"
19
+ "@types/bun": "latest"
25
20
  },
26
- "ava": {
27
- "timeout": "3m"
21
+ "peerDependencies": {
22
+ "typescript": "^5"
28
23
  },
29
- "engines": {
30
- "node": ">= 10"
31
- },
32
- "scripts": {
33
- "artifacts": "napi artifacts",
34
- "build": "yarn run build:ts && yarn run build:rust",
35
- "build:ts": "tsc",
36
- "build:rust": "napi build --platform --release",
37
- "build:debug": "napi build --platform",
38
- "prepublishOnly": "napi prepublish -t npm",
39
- "test": "ava",
40
- "universal": "napi universal",
41
- "version": "napi version"
42
- },
43
- "packageManager": "yarn@4.9.2",
44
- "repository": "https://github.com/iamEvanYT/electron-webauthn.git",
45
- "description": "Add support for WebAuthn in Electron.",
46
- "optionalDependencies": {
47
- "electron-webauthn-win32-x64-msvc": "0.0.5",
48
- "electron-webauthn-darwin-x64": "0.0.5",
49
- "electron-webauthn-linux-x64-gnu": "0.0.5",
50
- "electron-webauthn-darwin-arm64": "0.0.5",
51
- "electron-webauthn-win32-arm64-msvc": "0.0.5"
24
+ "dependencies": {
25
+ "objc-js": "^0.0.8"
52
26
  }
53
- }
27
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Evan
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/dist/index.d.ts DELETED
@@ -1,6 +0,0 @@
1
- import { create, get } from "../index";
2
- export declare const webauthn: {
3
- create: typeof create;
4
- get: typeof get;
5
- };
6
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../ts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEvC,eAAO,MAAM,QAAQ;;;CAGpB,CAAC"}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../ts/index.ts"],"names":[],"mappings":";;;AAAA,oCAAuC;AAE1B,QAAA,QAAQ,GAAG;IACtB,MAAM,EAAN,cAAM;IACN,GAAG,EAAH,WAAG;CACJ,CAAC"}
package/index.d.ts DELETED
@@ -1,68 +0,0 @@
1
- /* tslint:disable */
2
- /* eslint-disable */
3
-
4
- /* auto-generated by NAPI-RS */
5
-
6
- export interface PublicKeyCredentialRpEntity {
7
- id?: string | undefined
8
- name: string
9
- }
10
- export interface PublicKeyCredentialUserEntity {
11
- id: Buffer
12
- name: string
13
- displayName: string
14
- }
15
- export interface PublicKeyCredentialParameters {
16
- type: string
17
- alg: number
18
- }
19
- export interface AuthenticatorSelectionCriteria {
20
- authenticatorAttachment?: string | undefined
21
- requireResidentKey?: boolean | undefined
22
- residentKey?: string | undefined
23
- userVerification?: string | undefined
24
- }
25
- export interface PublicKeyCredentialDescriptor {
26
- type: string
27
- id: Buffer
28
- transports?: Array<string> | undefined
29
- }
30
- export interface PublicKeyCredentialCreationOptions {
31
- rp: PublicKeyCredentialRpEntity
32
- user: PublicKeyCredentialUserEntity
33
- challenge: Buffer
34
- pubKeyCredParams: Array<PublicKeyCredentialParameters>
35
- timeout?: number | undefined
36
- excludeCredentials?: Array<PublicKeyCredentialDescriptor> | undefined
37
- authenticatorSelection?: AuthenticatorSelectionCriteria | undefined
38
- attestation?: string | undefined
39
- }
40
- export interface PublicKeyCredentialRequestOptions {
41
- challenge: Buffer
42
- timeout?: number | undefined
43
- rpId?: string | undefined
44
- allowCredentials?: Array<PublicKeyCredentialDescriptor> | undefined
45
- userVerification?: string | undefined
46
- }
47
- export interface AuthenticatorAttestationResponse {
48
- clientDataJson: Buffer
49
- attestationObject: Buffer
50
- transports: Array<string>
51
- }
52
- export interface AuthenticatorAssertionResponse {
53
- clientDataJson: Buffer
54
- authenticatorData: Buffer
55
- signature: Buffer
56
- userHandle?: Buffer | undefined
57
- }
58
- export interface PublicKeyCredential {
59
- id: string
60
- rawId: Buffer
61
- response: AuthenticatorAttestationResponse | AuthenticatorAssertionResponse
62
- authenticatorAttachment?: string | undefined
63
- type: string
64
- }
65
- /** Create a new WebAuthn credential */
66
- export declare function create(options: PublicKeyCredentialCreationOptions): PublicKeyCredential
67
- /** Get/authenticate with an existing WebAuthn credential */
68
- export declare function get(options: PublicKeyCredentialRequestOptions): PublicKeyCredential