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.
package/README.md CHANGED
@@ -1,266 +1,15 @@
1
- # electron-webauthn
1
+ # electron-webauthn-test
2
2
 
3
- A high-performance, cross-platform WebAuthn/Passkey implementation for Electron applications, built with Rust and native platform APIs.
4
-
5
- ## Overview
6
-
7
- This library provides seamless WebAuthn (Web Authentication) and Passkey support for Electron applications across multiple platforms. It leverages native platform authenticators including Touch ID, Face ID, Windows Hello, and security keys to deliver a secure and user-friendly authentication experience.
8
-
9
- ### Key Features
10
-
11
- - **Native Platform Integration**: Uses platform-specific APIs for optimal performance and security
12
- - **Cross-Platform Support**: Works on macOS, Windows, and Linux
13
- - **WebAuthn Level 2 Compliance**: Full support for the latest WebAuthn specifications
14
- - **Biometric Authentication**: Touch ID, Face ID, Windows Hello, and Apple Watch support
15
- - **Secure Enclave Integration**: Hardware-backed key storage on supported platforms
16
- - **TypeScript Support**: Complete type definitions included
17
-
18
- ## Requirements
19
-
20
- ### macOS
21
-
22
- - **macOS 13+ (Ventura or later)** - Required for ASAuthorization framework
23
- - Touch ID, Face ID, or Apple Watch for biometric authentication
24
- - Valid code signing certificate for production use
25
-
26
- ### Windows
27
-
28
- - **Windows 10 version 1903+ or Windows 11**
29
- - Windows Hello capable device (fingerprint, face recognition, or PIN)
30
-
31
- ### Linux
32
-
33
- - Modern Linux distribution with WebAuthn support
34
- - Compatible authenticator device
35
-
36
- ## Installation
3
+ To install dependencies:
37
4
 
38
5
  ```bash
39
- npm install electron-webauthn
40
- # or
41
- yarn add electron-webauthn
6
+ bun install
42
7
  ```
43
8
 
44
- ## Usage
45
-
46
- ### Basic Registration (Creating a Credential)
47
-
48
- ```typescript
49
- import { createCredential } from "electron-webauthn";
50
-
51
- const options = {
52
- rp: {
53
- id: "example.com",
54
- name: "Example Corp",
55
- },
56
- user: {
57
- id: new Uint8Array([1, 2, 3, 4]),
58
- name: "user@example.com",
59
- displayName: "John Doe",
60
- },
61
- challenge: new Uint8Array(32), // Generate random 32 bytes
62
- pubKeyCredParams: [
63
- { type: "public-key", alg: -7 }, // ES256
64
- { type: "public-key", alg: -257 }, // RS256
65
- ],
66
- authenticatorSelection: {
67
- authenticatorAttachment: "platform",
68
- userVerification: "required",
69
- },
70
- };
71
-
72
- try {
73
- const credential = await createCredential(options);
74
- console.log("Registration successful:", credential);
75
- } catch (error) {
76
- console.error("Registration failed:", error);
77
- }
78
- ```
79
-
80
- ### Basic Authentication (Getting a Credential)
81
-
82
- ```typescript
83
- import { getCredential } from "electron-webauthn";
84
-
85
- const options = {
86
- rpId: "example.com",
87
- challenge: new Uint8Array(32), // Generate random 32 bytes
88
- allowCredentials: [
89
- {
90
- type: "public-key",
91
- id: credentialId, // From previous registration
92
- },
93
- ],
94
- userVerification: "required",
95
- };
96
-
97
- try {
98
- const assertion = await getCredential(options);
99
- console.log("Authentication successful:", assertion);
100
- } catch (error) {
101
- console.error("Authentication failed:", error);
102
- }
103
- ```
104
-
105
- ## Platform Support
106
-
107
- | Platform | Architecture | Status | Notes |
108
- | -------- | ------------- | ------ | ------------------------------ |
109
- | macOS | arm64 | ✅ | Native ASAuthorization support |
110
- | macOS | x64 | ✅ | Native ASAuthorization support |
111
- | macOS | universal | ✅ | Universal binary |
112
- | Windows | x64 | ✅ | Windows Hello integration |
113
- | Windows | arm64 | ✅ | Windows Hello integration |
114
- | Windows | ia32 | ✅ | Windows Hello integration |
115
- | Linux | x64 (GNU) | ✅ | Generic WebAuthn support |
116
- | Linux | x64 (musl) | ✅ | Alpine Linux compatible |
117
- | Linux | arm64 (GNU) | ✅ | ARM64 Linux support |
118
- | Linux | arm64 (musl) | ✅ | ARM64 Alpine support |
119
- | Linux | riscv64 (GNU) | ✅ | RISC-V architecture |
120
-
121
- ## macOS Entitlements
122
-
123
- For macOS applications, you need to include the following entitlements in your `entitlements.plist` file:
124
-
125
- ```xml
126
- <?xml version="1.0" encoding="UTF-8"?>
127
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
128
- <plist version="1.0">
129
- <dict>
130
- <!-- Required for WebAuthn/Passkey support -->
131
- <key>com.apple.developer.authentication-services.autofill-credential-provider</key>
132
- <true/>
133
-
134
- <!-- Required for platform authenticator access -->
135
- <key>com.apple.developer.web-browser</key>
136
- <true/>
137
-
138
- <!-- Required for Touch ID/Face ID/Apple Watch access -->
139
- <key>com.apple.security.device.biometry</key>
140
- <true/>
141
-
142
- <!-- Required for keychain access -->
143
- <key>keychain-access-groups</key>
144
- <array>
145
- <string>$(AppIdentifierPrefix)com.yourcompany.yourapp</string>
146
- </array>
147
-
148
- <!-- Optional: For network requests to verify credentials -->
149
- <key>com.apple.security.network.client</key>
150
- <true/>
151
- </dict>
152
- </plist>
153
- ```
154
-
155
- ### Electron Builder Configuration
156
-
157
- If using `electron-builder`, add the entitlements to your `package.json`:
158
-
159
- ```json
160
- {
161
- "build": {
162
- "mac": {
163
- "entitlements": "build/entitlements.mac.plist",
164
- "entitlementsInherit": "build/entitlements.mac.plist",
165
- "hardenedRuntime": true
166
- }
167
- }
168
- }
169
- ```
170
-
171
- ## Development
172
-
173
- ### Prerequisites
174
-
175
- - Node.js 16+
176
- - Rust 1.70+
177
- - Platform-specific build tools:
178
- - **macOS**: Xcode Command Line Tools
179
- - **Windows**: Visual Studio Build Tools
180
- - **Linux**: build-essential
181
-
182
- ### Building from Source
9
+ To run:
183
10
 
184
11
  ```bash
185
- # Clone the repository
186
- git clone https://github.com/your-org/electron-webauthn.git
187
- cd electron-webauthn
188
-
189
- # Install dependencies
190
- npm install
191
-
192
- # Build the native module
193
- npm run build
194
-
195
- # Run tests
196
- npm test
197
- ```
198
-
199
- ### Architecture
200
-
201
- This library uses:
202
-
203
- - **Rust** for high-performance native implementations
204
- - **NAPI-RS** for seamless Node.js bindings
205
- - **Platform-specific APIs**:
206
- - macOS: ASAuthorization framework
207
- - Windows: Windows Hello APIs
208
- - Linux: Generic WebAuthn implementation
209
-
210
- ## Error Handling
211
-
212
- The library provides detailed error messages for common scenarios:
213
-
214
- ```typescript
215
- try {
216
- const credential = await createCredential(options);
217
- } catch (error) {
218
- switch (error.code) {
219
- case "NotSupportedError":
220
- console.log("WebAuthn not supported on this platform");
221
- break;
222
- case "SecurityError":
223
- console.log("Security requirements not met");
224
- break;
225
- case "NotAllowedError":
226
- console.log("User cancelled or timeout occurred");
227
- break;
228
- default:
229
- console.log("Unexpected error:", error.message);
230
- }
231
- }
12
+ bun run index.ts
232
13
  ```
233
14
 
234
- ## Security Considerations
235
-
236
- - Always validate challenges on your server
237
- - Use HTTPS in production environments
238
- - Implement proper CORS policies
239
- - Store credentials securely on your backend
240
- - Regularly update the library for security patches
241
-
242
- ## Contributing
243
-
244
- We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
245
-
246
- ### Development Setup
247
-
248
- 1. Fork the repository
249
- 2. Create a feature branch
250
- 3. Make your changes
251
- 4. Add tests for new functionality
252
- 5. Submit a pull request
253
-
254
- ## License
255
-
256
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
257
-
258
- ## Support
259
-
260
- - **Issues**: [GitHub Issues](https://github.com/your-org/electron-webauthn/issues)
261
- - **Documentation**: [API Documentation](https://docs.your-org.com/electron-webauthn)
262
- - **Community**: [Discussions](https://github.com/your-org/electron-webauthn/discussions)
263
-
264
- ## Changelog
265
-
266
- See [CHANGELOG.md](CHANGELOG.md) for a detailed history of changes.
15
+ This project was created using `bun init` in bun v1.3.5. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
@@ -0,0 +1,23 @@
1
+ import { NSData } from "./objc/foundation/nsdata.js";
2
+ import { NSString } from "./objc/foundation/nsstring.js";
3
+ import { NSArray } from "./objc/foundation/nsarray.js";
4
+ const myString = NSString.stringWithUTF8String$("Hello from Objective-C!");
5
+ console.log("Created NSString:", myString);
6
+ const buf = Buffer.from("Hello from Objective-C!");
7
+ const myData = NSData.dataWithBytes$length$(buf, buf.length);
8
+ console.log("Created NSData:", myData);
9
+ // Test NSArray
10
+ const str1 = NSString.stringWithUTF8String$("First");
11
+ const str2 = NSString.stringWithUTF8String$("Second");
12
+ const str3 = NSString.stringWithUTF8String$("Third");
13
+ // Create array with one object, then add more
14
+ let myArray = NSArray.arrayWithObject$(str1);
15
+ myArray = myArray.arrayByAddingObject$(str2);
16
+ myArray = myArray.arrayByAddingObject$(str3);
17
+ console.log("Created NSArray with count:", myArray.count());
18
+ // Access elements
19
+ for (let i = 0; i < myArray.count(); i++) {
20
+ const obj = myArray.objectAtIndex$(i);
21
+ const nsString = obj;
22
+ console.log(`Array[${i}]:`, nsString.UTF8String());
23
+ }
package/dist/helper.js ADDED
@@ -0,0 +1,23 @@
1
+ import { NobjcLibrary, NobjcObject } from "@iamevan/nobjc";
2
+ // Load the Foundation framework
3
+ export const foundation = new NobjcLibrary("/System/Library/Frameworks/Foundation.framework/Foundation");
4
+ // Load the AuthenticationServices framework
5
+ export const authServices = new NobjcLibrary("/System/Library/Frameworks/AuthenticationServices.framework/AuthenticationServices");
6
+ // NSString helpers
7
+ const NSString = foundation["NSString"];
8
+ const _stringWithUTF8String = NSString["stringWithUTF8String:"];
9
+ export function createNSString(str) {
10
+ return _stringWithUTF8String(str);
11
+ }
12
+ // NSData helpers
13
+ const NSData = foundation["NSData"];
14
+ const _dataWithBytesLength = NSData["dataWithBytes:length:"];
15
+ export function createNSData(buffer) {
16
+ return _dataWithBytesLength(buffer, buffer.length);
17
+ }
18
+ // NSArray helpers
19
+ const NSArray = foundation["NSArray"];
20
+ const _arrayWithObject = NSArray["arrayWithObject:"];
21
+ export function createNSArray(obj) {
22
+ return _arrayWithObject(obj);
23
+ }
package/dist/index.js CHANGED
@@ -1,9 +1,49 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.webauthn = void 0;
4
- const index_1 = require("../index");
5
- exports.webauthn = {
6
- create: index_1.create,
7
- get: index_1.get,
8
- };
9
- //# sourceMappingURL=index.js.map
1
+ import { fromPointer, getPointer } from "objc-js";
2
+ import { createAuthorizationControllerDelegate } from "./objc/authentication-services/as-authorization-controller-delegate.js";
3
+ import { createAuthorizationController } from "./objc/authentication-services/as-authorization-controller.js";
4
+ import { createPresentationContextProvider } from "./objc/authentication-services/as-authorization-controller-presentation-context-providing.js";
5
+ import { createPlatformPublicKeyCredentialProvider } from "./objc/authentication-services/as-authorization-platform-public-key-credential-provider.js";
6
+ import { NSArray } from "./objc/foundation/nsarray.js";
7
+ import { NSDataFromBuffer } from "./objc/foundation/nsdata.js";
8
+ import { NSStringFromString } from "./objc/foundation/nsstring.js";
9
+ // const window = createEmptyWindow();
10
+ // const nsView = getNativeWindowHandle(window);
11
+ // const nsViewPointer = getPointer(nsView);
12
+ function getCredential(rpid, challenge, nativeWindowHandle) {
13
+ const NS_rpID = NSStringFromString(rpid);
14
+ // let challenge: Data // Obtain this from the server.
15
+ const NS_challenge = NSDataFromBuffer(challenge);
16
+ // let platformProvider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: "example.com")
17
+ const platformProvider = createPlatformPublicKeyCredentialProvider(NS_rpID);
18
+ // let platformKeyRequest = platformProvider.createCredentialAssertionRequest(challenge: challenge)
19
+ const platformKeyRequest = platformProvider.createCredentialAssertionRequestWithChallenge$(NS_challenge);
20
+ // let authController = ASAuthorizationController(authorizationRequests: [platformKeyRequest])
21
+ const requestsArray = NSArray.arrayWithObject$(platformKeyRequest);
22
+ const authController = createAuthorizationController(requestsArray);
23
+ // authController.delegate = self
24
+ const delegate = createAuthorizationControllerDelegate({
25
+ didCompleteWithAuthorization: (controller, authorization) => {
26
+ console.log("Authorization succeeded:", authorization);
27
+ },
28
+ didCompleteWithError: (controller, error) => {
29
+ // Parse the NSError into a readable format
30
+ const parsedError = error;
31
+ console.error("Authorization failed:", parsedError.localizedDescription().UTF8String());
32
+ },
33
+ });
34
+ authController.setDelegate$(delegate);
35
+ // authController.presentationContextProvider = self
36
+ const presentationContextProvider = createPresentationContextProvider({
37
+ presentationAnchorForAuthorizationController: (controller) => {
38
+ // Return the NSWindow to present the authorization UI in
39
+ const nsView = fromPointer(nativeWindowHandle);
40
+ const nsWindow = nsView.window();
41
+ return nsWindow;
42
+ },
43
+ });
44
+ authController.setPresentationContextProvider$(presentationContextProvider);
45
+ // authController.performRequests()
46
+ authController.performRequests();
47
+ return authController;
48
+ }
49
+ export { getCredential };
@@ -0,0 +1,28 @@
1
+ import { NobjcLibrary, NobjcObject } from "@iamevan/nobjc";
2
+ import { allocInit, NobjcInstanceWrapper } from "./helpers.js";
3
+ // Load the AuthenticationServices framework
4
+ export const authServices = new NobjcLibrary("/System/Library/Frameworks/AuthenticationServices.framework/AuthenticationServices");
5
+ // Wrapper for ASAuthorizationPlatformPublicKeyCredentialProvider
6
+ const _ASAuthorizationPlatformPublicKeyCredentialProvider = authServices["ASAuthorizationPlatformPublicKeyCredentialProvider"];
7
+ export class ASAuthorizationPlatformPublicKeyCredentialProvider extends NobjcInstanceWrapper {
8
+ constructor(relyingPartyIdentifier) {
9
+ const instance = allocInit(_ASAuthorizationPlatformPublicKeyCredentialProvider, "initWithRelyingPartyIdentifier:", relyingPartyIdentifier);
10
+ super(instance);
11
+ }
12
+ createCredentialAssertionRequest(challenge) {
13
+ const method = this.instance["createCredentialAssertionRequestWithChallenge:"];
14
+ return method(challenge);
15
+ }
16
+ }
17
+ // Wrapper for ASAuthorizationController
18
+ const _ASAuthorizationController = authServices["ASAuthorizationController"];
19
+ export class ASAuthorizationController extends NobjcInstanceWrapper {
20
+ constructor(authorizationRequests) {
21
+ const instance = allocInit(_ASAuthorizationController, "initWithAuthorizationRequests:", authorizationRequests);
22
+ super(instance);
23
+ }
24
+ performRequests() {
25
+ const method = this.instance["performRequests"];
26
+ method();
27
+ }
28
+ }
@@ -0,0 +1,40 @@
1
+ import { NobjcObject, NobjcProtocol } from "objc-js";
2
+ /**
3
+ * Create an ASAuthorizationControllerDelegate instance
4
+ *
5
+ * This creates an Objective-C object that implements the ASAuthorizationControllerDelegate
6
+ * protocol using the objc-js protocol implementation API.
7
+ *
8
+ * @param callbacks Object containing callback functions for delegate methods
9
+ * @returns A NobjcObject that can be set as the delegate of an ASAuthorizationController
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const delegate = createAuthorizationControllerDelegate({
14
+ * didCompleteWithAuthorization: (controller, authorization) => {
15
+ * console.log("Authorization succeeded!");
16
+ * const credential = authorization.credential();
17
+ * // Process the credential
18
+ * },
19
+ * didCompleteWithError: (controller, error) => {
20
+ * console.error("Authorization failed:", error.localizedDescription());
21
+ * }
22
+ * });
23
+ *
24
+ * authController.setDelegate$(delegate);
25
+ * authController.performRequests();
26
+ * ```
27
+ */
28
+ export function createAuthorizationControllerDelegate(callbacks) {
29
+ const methodImplementations = {};
30
+ // Map the callbacks to Objective-C method names using $ notation
31
+ if (callbacks.didCompleteWithAuthorization) {
32
+ methodImplementations["authorizationController$didCompleteWithAuthorization$"] = callbacks.didCompleteWithAuthorization;
33
+ }
34
+ if (callbacks.didCompleteWithError) {
35
+ methodImplementations["authorizationController$didCompleteWithError$"] =
36
+ callbacks.didCompleteWithError;
37
+ }
38
+ // Create and return the protocol implementation
39
+ return NobjcProtocol.implement("ASAuthorizationControllerDelegate", methodImplementations);
40
+ }
@@ -0,0 +1,31 @@
1
+ import { NobjcObject, NobjcProtocol } from "objc-js";
2
+ /**
3
+ * Create an ASAuthorizationControllerPresentationContextProviding instance
4
+ *
5
+ * This creates an Objective-C object that implements the ASAuthorizationControllerPresentationContextProviding
6
+ * protocol using the objc-js protocol implementation API.
7
+ *
8
+ * @param callbacks Object containing callback functions for protocol methods
9
+ * @returns A NobjcObject that can be set as the presentationContextProvider of an ASAuthorizationController
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const presentationContextProvider = createPresentationContextProvider({
14
+ * presentationAnchorForAuthorizationController: (controller) => {
15
+ * // Return the NSWindow to present the authorization UI in
16
+ * return myNSWindow;
17
+ * }
18
+ * });
19
+ *
20
+ * authController.setPresentationContextProvider$(presentationContextProvider);
21
+ * authController.performRequests();
22
+ * ```
23
+ */
24
+ export function createPresentationContextProvider(callbacks) {
25
+ const methodImplementations = {};
26
+ // Map the callback to Objective-C method name using $ notation
27
+ methodImplementations["presentationAnchorForAuthorizationController$"] =
28
+ callbacks.presentationAnchorForAuthorizationController;
29
+ // Create and return the protocol implementation
30
+ return NobjcProtocol.implement("ASAuthorizationControllerPresentationContextProviding", methodImplementations);
31
+ }
@@ -0,0 +1,12 @@
1
+ import { AuthenticationServices } from "./index.js";
2
+ export const ASAuthorizationController = AuthenticationServices.ASAuthorizationController;
3
+ // Helper Functions
4
+ /**
5
+ * Create an ASAuthorizationController instance
6
+ * @param authorizationRequests An NSArray of authorization requests
7
+ * @returns An initialized controller instance
8
+ */
9
+ export function createAuthorizationController(authorizationRequests) {
10
+ const instance = ASAuthorizationController.alloc();
11
+ return instance.initWithAuthorizationRequests$(authorizationRequests);
12
+ }
@@ -0,0 +1,12 @@
1
+ import { AuthenticationServices } from "./index.js";
2
+ export const ASAuthorizationPlatformPublicKeyCredentialProvider = AuthenticationServices.ASAuthorizationPlatformPublicKeyCredentialProvider;
3
+ // Helper Functions
4
+ /**
5
+ * Create an ASAuthorizationPlatformPublicKeyCredentialProvider instance
6
+ * @param relyingPartyIdentifier The relying party identifier (domain)
7
+ * @returns An initialized provider instance
8
+ */
9
+ export function createPlatformPublicKeyCredentialProvider(relyingPartyIdentifier) {
10
+ const instance = ASAuthorizationPlatformPublicKeyCredentialProvider.alloc();
11
+ return instance.initWithRelyingPartyIdentifier$(relyingPartyIdentifier);
12
+ }
@@ -0,0 +1,3 @@
1
+ import { NobjcLibrary } from "objc-js";
2
+ // Load the framework
3
+ export const AuthenticationServices = new NobjcLibrary("/System/Library/Frameworks/AuthenticationServices.framework/AuthenticationServices");
@@ -0,0 +1,142 @@
1
+ import { NSArray, NSData, NSString } from "./main";
2
+ /**
3
+ * Foundation Framework Helpers
4
+ *
5
+ * This module provides convenient helper functions for working with
6
+ * Foundation framework objects in JavaScript/TypeScript.
7
+ *
8
+ * Key features:
9
+ * - NSString: String conversion helpers
10
+ * - NSData: Data conversion between Objective-C and JavaScript
11
+ * - NSArray: Array creation and manipulation
12
+ */
13
+ /**
14
+ * NSData to Buffer Conversion Methods
15
+ *
16
+ * Two methods are provided for converting NSData to JavaScript Buffers:
17
+ *
18
+ * 1. bufferFromNSData (base64): Uses base64 as an intermediate format.
19
+ * - Most reliable and compatible
20
+ * - Recommended for general use
21
+ * - Slight overhead due to base64 encoding/decoding
22
+ *
23
+ * 2. bufferFromNSDataDirect (direct): Uses getBytes:length: for direct memory copy.
24
+ * - More efficient for large data
25
+ * - Direct memory access
26
+ * - May have compatibility issues with some nobjc versions
27
+ */
28
+ /**
29
+ * Convert NSData to a JavaScript Buffer using base64 encoding
30
+ * This is the most reliable method for data conversion.
31
+ * @param data The NSData object
32
+ * @returns A Buffer containing the data
33
+ */
34
+ export function bufferFromNSData(data) {
35
+ const nsData = data;
36
+ const length = nsData.length();
37
+ if (length === 0) {
38
+ return Buffer.alloc(0);
39
+ }
40
+ // Use base64 encoding as a reliable bridge between NSData and JS Buffer
41
+ const base64String = nsData.base64EncodedStringWithOptions$(0);
42
+ const base64Str = base64String.UTF8String();
43
+ return Buffer.from(base64Str, "base64");
44
+ }
45
+ /**
46
+ * Convert NSData to a JavaScript Buffer using direct memory copy
47
+ * This method uses getBytes:length: for direct memory access.
48
+ * May be more efficient for large data, but requires proper buffer allocation.
49
+ * @param data The NSData object
50
+ * @returns A Buffer containing the data
51
+ */
52
+ export function bufferFromNSDataDirect(data) {
53
+ const nsData = data;
54
+ const length = nsData.length();
55
+ if (length === 0) {
56
+ return Buffer.alloc(0);
57
+ }
58
+ // Allocate a buffer and copy bytes directly
59
+ const buffer = Buffer.alloc(length);
60
+ nsData.getBytes$length$(buffer, length);
61
+ return buffer;
62
+ }
63
+ /**
64
+ * Convert NSData to a JavaScript Uint8Array
65
+ * @param data The NSData object
66
+ * @returns A Uint8Array containing the data
67
+ */
68
+ export function uint8ArrayFromNSData(data) {
69
+ const buffer = bufferFromNSData(data);
70
+ return new Uint8Array(buffer);
71
+ }
72
+ /**
73
+ * Convert NSData to a base64 string
74
+ * @param data The NSData object
75
+ * @returns A base64-encoded string
76
+ */
77
+ export function base64FromNSData(data) {
78
+ const nsData = data;
79
+ const nsString = nsData.base64EncodedStringWithOptions$(0);
80
+ return nsString.UTF8String();
81
+ }
82
+ /**
83
+ * Create NSData from a base64 string
84
+ * @param base64String The base64-encoded string
85
+ * @returns An NSData object
86
+ */
87
+ export function NSDataFromBase64(base64String) {
88
+ const nsString = NSString.stringWithUTF8String$(base64String);
89
+ const nsData = NSData.alloc();
90
+ return nsData.initWithBase64EncodedString$options$(nsString, 0);
91
+ }
92
+ /**
93
+ * Get the length of NSData
94
+ * @param data The NSData object
95
+ * @returns The length in bytes
96
+ */
97
+ export function NSDataLength(data) {
98
+ const nsData = data;
99
+ return nsData.length();
100
+ }
101
+ /**
102
+ * Create a copy of NSData
103
+ * @param data The NSData object
104
+ * @returns A new NSData object with copied data
105
+ */
106
+ export function NSDataCopy(data) {
107
+ return NSData.dataWithData$(data);
108
+ }
109
+ /**
110
+ * Compare two NSData objects for equality
111
+ * @param data1 The first NSData object
112
+ * @param data2 The second NSData object
113
+ * @returns True if the data is equal
114
+ */
115
+ export function NSDataIsEqual(data1, data2) {
116
+ const nsData1 = data1;
117
+ return nsData1.isEqualToData$(data2);
118
+ }
119
+ /**
120
+ * Extract a subrange of NSData
121
+ * Note: This method may not work with all versions of nobjc due to NSRange struct limitations.
122
+ * As an alternative, convert to Buffer, slice, and convert back.
123
+ * @param data The NSData object
124
+ * @param location The starting position
125
+ * @param length The number of bytes to extract
126
+ * @returns A new NSData object containing the subdata
127
+ */
128
+ export function NSDataSubdata(data, location, length) {
129
+ // Workaround: Convert to buffer, slice, and convert back
130
+ // This avoids the NSRange struct issue with nobjc
131
+ const buffer = bufferFromNSData(data);
132
+ const slicedBuffer = buffer.subarray(location, location + length);
133
+ return NSDataFromBuffer(slicedBuffer);
134
+ }
135
+ // NSArray helpers
136
+ export function NSArrayFromObjects(objects) {
137
+ let array = NSArray.array();
138
+ for (const obj of objects) {
139
+ array = array.arrayByAddingObject$(obj);
140
+ }
141
+ return array;
142
+ }
@@ -0,0 +1,3 @@
1
+ import { NobjcLibrary } from "objc-js";
2
+ // Load the framework
3
+ export const Foundation = new NobjcLibrary("/System/Library/Frameworks/Foundation.framework/Foundation");
@@ -0,0 +1,4 @@
1
+ import { NobjcLibrary, NobjcObject } from "@iamevan/nobjc";
2
+ // Load the Foundation framework
3
+ export const Foundation = new NobjcLibrary("/System/Library/Frameworks/Foundation.framework/Foundation");
4
+ export const NSArray = Foundation.NSArray;