@genation/bridge-peer 0.1.0

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.
Files changed (72) hide show
  1. package/GenationBridgePeer.podspec +17 -0
  2. package/LICENSE +190 -0
  3. package/README.md +66 -0
  4. package/package.json +59 -0
  5. package/react-native/android/build.gradle +24 -0
  6. package/react-native/android/src/main/java/com/genation/bridge/GenationBridgePeerModule.kt +182 -0
  7. package/react-native/android/src/main/java/com/genation/bridge/GenationBridgePeerPackage.kt +15 -0
  8. package/react-native/android/src/main/jniLibs/arm64-v8a/libgenation_bridge_crypto_uniffi.so +0 -0
  9. package/react-native/android/src/main/jniLibs/armeabi-v7a/libgenation_bridge_crypto_uniffi.so +0 -0
  10. package/react-native/android/src/main/jniLibs/x86/libgenation_bridge_crypto_uniffi.so +0 -0
  11. package/react-native/android/src/main/jniLibs/x86_64/libgenation_bridge_crypto_uniffi.so +0 -0
  12. package/react-native/generated/kotlin/uniffi/genation_bridge_crypto_uniffi/genation_bridge_crypto_uniffi.kt +2006 -0
  13. package/react-native/generated/swift/GenationBridgeCryptoMobile.swift +1072 -0
  14. package/react-native/generated/swift/GenationBridgeCryptoMobileFFI.h +703 -0
  15. package/react-native/generated/swift/GenationBridgeCryptoMobileFFI.modulemap +7 -0
  16. package/react-native/ios/GenationBridgePeer.m +14 -0
  17. package/react-native/ios/GenationBridgePeer.swift +234 -0
  18. package/react-native/native/GenationBridgeCryptoMobile.xcframework/Info.plist +48 -0
  19. package/react-native/native/GenationBridgeCryptoMobile.xcframework/ios-arm64/Headers/GenationBridgeCryptoMobileFFI.h +703 -0
  20. package/react-native/native/GenationBridgeCryptoMobile.xcframework/ios-arm64/Headers/module.modulemap +7 -0
  21. package/react-native/native/GenationBridgeCryptoMobile.xcframework/ios-arm64/libgenation_bridge_crypto_uniffi.a +0 -0
  22. package/react-native/native/GenationBridgeCryptoMobile.xcframework/ios-arm64_x86_64-simulator/Headers/GenationBridgeCryptoMobileFFI.h +703 -0
  23. package/react-native/native/GenationBridgeCryptoMobile.xcframework/ios-arm64_x86_64-simulator/Headers/module.modulemap +7 -0
  24. package/react-native/native/GenationBridgeCryptoMobile.xcframework/ios-arm64_x86_64-simulator/libgenation_bridge_crypto_uniffi.a +0 -0
  25. package/react-native.config.js +8 -0
  26. package/src/core/codec.d.ts +5 -0
  27. package/src/core/codec.js +46 -0
  28. package/src/core/errors.d.ts +11 -0
  29. package/src/core/errors.js +27 -0
  30. package/src/core/identity.d.ts +16 -0
  31. package/src/core/identity.js +1 -0
  32. package/src/core/lifecycle.d.ts +4 -0
  33. package/src/core/lifecycle.js +1 -0
  34. package/src/core/mod.d.ts +6 -0
  35. package/src/core/mod.js +3 -0
  36. package/src/core/peer.d.ts +67 -0
  37. package/src/core/peer.js +373 -0
  38. package/src/core/runtime.d.ts +78 -0
  39. package/src/core/runtime.js +0 -0
  40. package/src/node/crypto-core/javascript/mod.d.ts +8 -0
  41. package/src/node/crypto-core/javascript/mod.js +24 -0
  42. package/src/node/crypto-core/javascript/provider.d.ts +2 -0
  43. package/src/node/crypto-core/javascript/provider.js +43 -0
  44. package/src/node/crypto-core/pkg/wasm/genation_bridge_crypto_wasm.d.ts +122 -0
  45. package/src/node/crypto-core/pkg/wasm/genation_bridge_crypto_wasm.js +433 -0
  46. package/src/node/crypto-core/pkg/wasm/genation_bridge_crypto_wasm_bg.wasm +0 -0
  47. package/src/node/crypto-core/pkg/wasm/genation_bridge_crypto_wasm_bg.wasm.d.ts +25 -0
  48. package/src/node/encoding.js +1 -0
  49. package/src/node/file-key-store.d.ts +6 -0
  50. package/src/node/file-key-store.js +111 -0
  51. package/src/node/identity-provider.d.ts +8 -0
  52. package/src/node/identity-provider.js +57 -0
  53. package/src/node/identity.js +45 -0
  54. package/src/node/mod.d.ts +16 -0
  55. package/src/node/mod.js +17 -0
  56. package/src/node/relay-runtime.d.ts +11 -0
  57. package/src/node/relay-runtime.js +11 -0
  58. package/src/react-native/identity-provider.d.ts +4 -0
  59. package/src/react-native/identity-provider.js +125 -0
  60. package/src/react-native/lifecycle.d.ts +8 -0
  61. package/src/react-native/lifecycle.js +9 -0
  62. package/src/react-native/mod.d.ts +20 -0
  63. package/src/react-native/mod.js +36 -0
  64. package/src/react-native/native-module.d.ts +17 -0
  65. package/src/react-native/native-module.js +9 -0
  66. package/src/relay/encoding.js +32 -0
  67. package/src/relay/frame-channel.d.ts +1 -0
  68. package/src/relay/frame-channel.js +110 -0
  69. package/src/relay/identity.d.ts +27 -0
  70. package/src/relay/identity.js +0 -0
  71. package/src/relay/runtime.d.ts +8 -0
  72. package/src/relay/runtime.js +900 -0
@@ -0,0 +1,7 @@
1
+ module GenationBridgeCryptoMobileFFI {
2
+ header "GenationBridgeCryptoMobileFFI.h"
3
+ export *
4
+ use "Darwin"
5
+ use "_Builtin_stdbool"
6
+ use "_Builtin_stdint"
7
+ }
@@ -0,0 +1,14 @@
1
+ #import <React/RCTBridgeModule.h>
2
+
3
+ @interface RCT_EXTERN_MODULE(GenationBridgePeer, NSObject)
4
+ RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(loadOrCreateIdentity:(NSString *)projectId peerId:(NSString *)peerId)
5
+ RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(signConnectionProof:(NSString *)handle inputJson:(NSString *)inputJson)
6
+ RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(createInitiator:(NSString *)handle prologue:(NSString *)prologue responderPublicKey:(NSString *)publicKey)
7
+ RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(createResponder:(NSString *)handle prologue:(NSString *)prologue initiatorPublicKey:(NSString *)publicKey)
8
+ RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(beginHandshake:(NSString *)handle)
9
+ RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(finishHandshake:(NSString *)handle message:(NSString *)message)
10
+ RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(acceptHandshake:(NSString *)handle message:(NSString *)message)
11
+ RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(encrypt:(NSString *)handle aad:(NSString *)aad plaintext:(NSString *)plaintext)
12
+ RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(decrypt:(NSString *)handle aad:(NSString *)aad ciphertext:(NSString *)ciphertext)
13
+ RCT_EXTERN_METHOD(closeSession:(NSString *)handle)
14
+ @end
@@ -0,0 +1,234 @@
1
+ import CryptoKit
2
+ import Foundation
3
+ import React
4
+ import Security
5
+
6
+ private struct StoredIdentity: Codable {
7
+ let connectionPrivateKey: Data
8
+ let connectionPublicKey: Data
9
+ let noiseStaticPrivateKey: Data
10
+ let noiseStaticPublicKey: Data
11
+ }
12
+
13
+ private enum NativeSession {
14
+ case initiator(MobileInitiator)
15
+ case responder(MobileResponder)
16
+ }
17
+
18
+ @objc(GenationBridgePeer)
19
+ final class GenationBridgePeer: NSObject {
20
+ private let lock = NSLock()
21
+ private var identities: [String: StoredIdentity] = [:]
22
+ private var sessions: [String: NativeSession] = [:]
23
+ private let service = "com.genation.bridge.peer.identity.v1"
24
+
25
+ @objc static func requiresMainQueueSetup() -> Bool { false }
26
+
27
+ private func base64url(_ data: Data) -> String {
28
+ data.base64EncodedString().replacingOccurrences(of: "+", with: "-")
29
+ .replacingOccurrences(of: "/", with: "_")
30
+ .replacingOccurrences(of: "=", with: "")
31
+ }
32
+
33
+ private func decode64(_ value: String) throws -> Data {
34
+ var encoded = value.replacingOccurrences(of: "-", with: "+")
35
+ .replacingOccurrences(of: "_", with: "/")
36
+ encoded += String(repeating: "=", count: (4 - encoded.count % 4) % 4)
37
+ guard let data = Data(base64Encoded: encoded) else { throw NativeError.invalid }
38
+ return data
39
+ }
40
+
41
+ private func identityKey(_ projectId: String, _ peerId: String) -> String {
42
+ let digest = SHA256.hash(data: Data("\(projectId)\u{0}\(peerId)".utf8))
43
+ return digest.map { String(format: "%02x", $0) }.joined()
44
+ }
45
+
46
+ private func readIdentity(_ key: String) throws -> StoredIdentity? {
47
+ let query: [CFString: Any] = [
48
+ kSecClass: kSecClassGenericPassword,
49
+ kSecAttrService: service,
50
+ kSecAttrAccount: key,
51
+ kSecReturnData: true,
52
+ kSecMatchLimit: kSecMatchLimitOne,
53
+ ]
54
+ var result: CFTypeRef?
55
+ let status = SecItemCopyMatching(query as CFDictionary, &result)
56
+ if status == errSecItemNotFound { return nil }
57
+ guard status == errSecSuccess, let data = result as? Data else {
58
+ throw NativeError.storage
59
+ }
60
+ return try JSONDecoder().decode(StoredIdentity.self, from: data)
61
+ }
62
+
63
+ private func createIdentity(_ key: String) throws -> StoredIdentity {
64
+ let generated = try generateMobileIdentity()
65
+ let identity = StoredIdentity(
66
+ connectionPrivateKey: generated.connectionPrivateKey,
67
+ connectionPublicKey: generated.connectionPublicKey,
68
+ noiseStaticPrivateKey: generated.noiseStaticPrivateKey,
69
+ noiseStaticPublicKey: generated.noiseStaticPublicKey
70
+ )
71
+ let encoded = try JSONEncoder().encode(identity)
72
+ let query: [CFString: Any] = [
73
+ kSecClass: kSecClassGenericPassword,
74
+ kSecAttrService: service,
75
+ kSecAttrAccount: key,
76
+ kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
77
+ kSecValueData: encoded,
78
+ ]
79
+ let status = SecItemAdd(query as CFDictionary, nil)
80
+ if status == errSecDuplicateItem, let existing = try readIdentity(key) { return existing }
81
+ guard status == errSecSuccess else { throw NativeError.storage }
82
+ return identity
83
+ }
84
+
85
+ private func identity(_ handle: String) throws -> StoredIdentity {
86
+ guard let value = identities[handle] else { throw NativeError.invalid }
87
+ return value
88
+ }
89
+
90
+ @objc func loadOrCreateIdentity(
91
+ _ projectId: String,
92
+ peerId: String
93
+ ) -> NSDictionary {
94
+ lock.lock(); defer { lock.unlock() }
95
+ do {
96
+ let handle = "identity:\(identityKey(projectId, peerId))"
97
+ let key = String(handle.dropFirst("identity:".count))
98
+ let value = try readIdentity(key) ?? createIdentity(key)
99
+ identities[handle] = value
100
+ return [
101
+ "identityHandle": handle,
102
+ "connectionPublicKey": base64url(value.connectionPublicKey),
103
+ "noiseStaticPublicKey": base64url(value.noiseStaticPublicKey),
104
+ ]
105
+ } catch { return [:] }
106
+ }
107
+
108
+ @objc func signConnectionProof(_ handle: String, inputJson: String) -> String {
109
+ lock.lock(); defer { lock.unlock() }
110
+ do {
111
+ let value = try identity(handle)
112
+ guard
113
+ let input = try JSONSerialization.jsonObject(with: Data(inputJson.utf8)) as? [String: Any],
114
+ let grant = input["grant"] as? String,
115
+ let expiresAt = input["challengeExpiresAt"] as? Double
116
+ else { throw NativeError.invalid }
117
+ let now = Int(Date().timeIntervalSince1970)
118
+ let payload: [String: Any] = [
119
+ "version": "proof.v1",
120
+ "projectId": input["projectId"]!,
121
+ "peerId": input["peerId"]!,
122
+ "connectionId": input["connectionId"]!,
123
+ "challenge": input["challenge"]!,
124
+ "grantSha256": base64url(Data(SHA256.hash(data: Data(grant.utf8)))),
125
+ "issuedAt": now,
126
+ "expiresAt": min(now + 15, Int(expiresAt / 1000)),
127
+ ]
128
+ let header = base64url(Data("{\"alg\":\"EdDSA\"}".utf8))
129
+ let body = base64url(try JSONSerialization.data(withJSONObject: payload))
130
+ let signingInput = Data("\(header).\(body)".utf8)
131
+ let signature = try signMobileEd25519(
132
+ privateKey: value.connectionPrivateKey,
133
+ message: signingInput
134
+ )
135
+ return "\(header).\(body).\(base64url(signature))"
136
+ } catch { return "" }
137
+ }
138
+
139
+ @objc func createInitiator(
140
+ _ identityHandle: String,
141
+ prologue: String,
142
+ responderPublicKey: String
143
+ ) -> String {
144
+ lock.lock(); defer { lock.unlock() }
145
+ do {
146
+ let value = try identity(identityHandle)
147
+ let handle = "session:\(UUID().uuidString)"
148
+ sessions[handle] = .initiator(try MobileInitiator(
149
+ prologue: decode64(prologue),
150
+ localPrivateKey: value.noiseStaticPrivateKey,
151
+ responderPublicKey: decode64(responderPublicKey)
152
+ ))
153
+ return handle
154
+ } catch { return "" }
155
+ }
156
+
157
+ @objc func createResponder(
158
+ _ identityHandle: String,
159
+ prologue: String,
160
+ initiatorPublicKey: String
161
+ ) -> String {
162
+ lock.lock(); defer { lock.unlock() }
163
+ do {
164
+ let value = try identity(identityHandle)
165
+ let handle = "session:\(UUID().uuidString)"
166
+ sessions[handle] = .responder(try MobileResponder(
167
+ prologue: decode64(prologue),
168
+ localPrivateKey: value.noiseStaticPrivateKey,
169
+ initiatorPublicKey: decode64(initiatorPublicKey)
170
+ ))
171
+ return handle
172
+ } catch { return "" }
173
+ }
174
+
175
+ @objc func beginHandshake(_ handle: String) -> String {
176
+ lock.lock(); defer { lock.unlock() }
177
+ guard case .initiator(let session) = sessions[handle] else { return "" }
178
+ return (try? base64url(session.beginHandshake())) ?? ""
179
+ }
180
+
181
+ @objc func finishHandshake(_ handle: String, message: String) -> Bool {
182
+ lock.lock(); defer { lock.unlock() }
183
+ guard case .initiator(let session) = sessions[handle] else { return false }
184
+ do {
185
+ try session.finishHandshake(message: decode64(message))
186
+ return true
187
+ } catch {
188
+ sessions.removeValue(forKey: handle)
189
+ try? session.closeSession()
190
+ return false
191
+ }
192
+ }
193
+
194
+ @objc func acceptHandshake(_ handle: String, message: String) -> String {
195
+ lock.lock(); defer { lock.unlock() }
196
+ guard case .responder(let session) = sessions[handle] else { return "" }
197
+ return (try? base64url(session.acceptHandshake(message: decode64(message)))) ?? ""
198
+ }
199
+
200
+ @objc func encrypt(_ handle: String, aad: String, plaintext: String) -> String {
201
+ lock.lock(); defer { lock.unlock() }
202
+ do {
203
+ let aadData = try decode64(aad); let plainData = try decode64(plaintext)
204
+ switch sessions[handle] {
205
+ case .initiator(let value): return base64url(try value.encrypt(aad: aadData, plaintext: plainData))
206
+ case .responder(let value): return base64url(try value.encrypt(aad: aadData, plaintext: plainData))
207
+ case .none: return ""
208
+ }
209
+ } catch { return "" }
210
+ }
211
+
212
+ @objc func decrypt(_ handle: String, aad: String, ciphertext: String) -> String {
213
+ lock.lock(); defer { lock.unlock() }
214
+ do {
215
+ let aadData = try decode64(aad); let cipherData = try decode64(ciphertext)
216
+ switch sessions[handle] {
217
+ case .initiator(let value): return base64url(try value.decrypt(aad: aadData, ciphertext: cipherData))
218
+ case .responder(let value): return base64url(try value.decrypt(aad: aadData, ciphertext: cipherData))
219
+ case .none: return ""
220
+ }
221
+ } catch { return "" }
222
+ }
223
+
224
+ @objc func closeSession(_ handle: String) {
225
+ lock.lock(); defer { lock.unlock() }
226
+ switch sessions.removeValue(forKey: handle) {
227
+ case .initiator(let value): try? value.closeSession()
228
+ case .responder(let value): try? value.closeSession()
229
+ case .none: break
230
+ }
231
+ }
232
+ }
233
+
234
+ private enum NativeError: Error { case invalid, storage }
@@ -0,0 +1,48 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>AvailableLibraries</key>
6
+ <array>
7
+ <dict>
8
+ <key>BinaryPath</key>
9
+ <string>libgenation_bridge_crypto_uniffi.a</string>
10
+ <key>HeadersPath</key>
11
+ <string>Headers</string>
12
+ <key>LibraryIdentifier</key>
13
+ <string>ios-arm64_x86_64-simulator</string>
14
+ <key>LibraryPath</key>
15
+ <string>libgenation_bridge_crypto_uniffi.a</string>
16
+ <key>SupportedArchitectures</key>
17
+ <array>
18
+ <string>arm64</string>
19
+ <string>x86_64</string>
20
+ </array>
21
+ <key>SupportedPlatform</key>
22
+ <string>ios</string>
23
+ <key>SupportedPlatformVariant</key>
24
+ <string>simulator</string>
25
+ </dict>
26
+ <dict>
27
+ <key>BinaryPath</key>
28
+ <string>libgenation_bridge_crypto_uniffi.a</string>
29
+ <key>HeadersPath</key>
30
+ <string>Headers</string>
31
+ <key>LibraryIdentifier</key>
32
+ <string>ios-arm64</string>
33
+ <key>LibraryPath</key>
34
+ <string>libgenation_bridge_crypto_uniffi.a</string>
35
+ <key>SupportedArchitectures</key>
36
+ <array>
37
+ <string>arm64</string>
38
+ </array>
39
+ <key>SupportedPlatform</key>
40
+ <string>ios</string>
41
+ </dict>
42
+ </array>
43
+ <key>CFBundlePackageType</key>
44
+ <string>XFWK</string>
45
+ <key>XCFrameworkFormatVersion</key>
46
+ <string>1.0</string>
47
+ </dict>
48
+ </plist>