@onekeyfe/react-native-bundle-crypto 3.0.39

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 (96) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +36 -0
  3. package/ReactNativeBundleCrypto.podspec +35 -0
  4. package/android/CMakeLists.txt +24 -0
  5. package/android/build.gradle +136 -0
  6. package/android/gradle.properties +4 -0
  7. package/android/src/main/AndroidManifest.xml +1 -0
  8. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  9. package/android/src/main/java/com/margelo/nitro/reactnativebundlecrypto/BundleCryptoCore.kt +526 -0
  10. package/android/src/main/java/com/margelo/nitro/reactnativebundlecrypto/ReactNativeBundleCrypto.kt +110 -0
  11. package/android/src/main/java/com/margelo/nitro/reactnativebundlecrypto/ReactNativeBundleCryptoPackage.kt +24 -0
  12. package/ios/BundleCryptoCore.swift +529 -0
  13. package/ios/Frameworks/Gopenpgp.xcframework/Info.plist +52 -0
  14. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Gopenpgp +0 -0
  15. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Armor.objc.h +96 -0
  16. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Constants.objc.h +197 -0
  17. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Crypto.objc.h +1963 -0
  18. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Gopenpgp.h +23 -0
  19. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Mime.objc.h +59 -0
  20. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Mobile.objc.h +252 -0
  21. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Profile.objc.h +107 -0
  22. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/Universe.objc.h +29 -0
  23. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Headers/ref.h +35 -0
  24. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Info.plist +20 -0
  25. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64/Gopenpgp.framework/Modules/module.modulemap +13 -0
  26. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Gopenpgp +0 -0
  27. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Armor.objc.h +96 -0
  28. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Constants.objc.h +197 -0
  29. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Crypto.objc.h +1963 -0
  30. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Gopenpgp.h +23 -0
  31. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Mime.objc.h +59 -0
  32. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Mobile.objc.h +252 -0
  33. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Profile.objc.h +107 -0
  34. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/Universe.objc.h +29 -0
  35. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Headers/ref.h +35 -0
  36. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Info.plist +20 -0
  37. package/ios/Frameworks/Gopenpgp.xcframework/ios-arm64_x86_64-simulator/Gopenpgp.framework/Modules/module.modulemap +13 -0
  38. package/ios/ReactNativeBundleCrypto.swift +104 -0
  39. package/lib/module/ReactNativeBundleCrypto.nitro.js +4 -0
  40. package/lib/module/ReactNativeBundleCrypto.nitro.js.map +1 -0
  41. package/lib/module/index.js +6 -0
  42. package/lib/module/index.js.map +1 -0
  43. package/lib/module/package.json +1 -0
  44. package/lib/typescript/package.json +1 -0
  45. package/lib/typescript/src/ReactNativeBundleCrypto.nitro.d.ts +35 -0
  46. package/lib/typescript/src/ReactNativeBundleCrypto.nitro.d.ts.map +1 -0
  47. package/lib/typescript/src/index.d.ts +4 -0
  48. package/lib/typescript/src/index.d.ts.map +1 -0
  49. package/nitro.json +17 -0
  50. package/nitrogen/generated/android/c++/JDirHashEntry.hpp +61 -0
  51. package/nitrogen/generated/android/c++/JHybridReactNativeBundleCryptoSpec.cpp +240 -0
  52. package/nitrogen/generated/android/c++/JHybridReactNativeBundleCryptoSpec.hpp +74 -0
  53. package/nitrogen/generated/android/c++/JSha256Result.hpp +62 -0
  54. package/nitrogen/generated/android/c++/JVerifyDetachedAscResult.hpp +66 -0
  55. package/nitrogen/generated/android/c++/JVerifyGpgCleartextResult.hpp +66 -0
  56. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativebundlecrypto/DirHashEntry.kt +41 -0
  57. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativebundlecrypto/HybridReactNativeBundleCryptoSpec.kt +94 -0
  58. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativebundlecrypto/Sha256Result.kt +41 -0
  59. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativebundlecrypto/VerifyDetachedAscResult.kt +44 -0
  60. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativebundlecrypto/VerifyGpgCleartextResult.kt +44 -0
  61. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativebundlecrypto/reactnativebundlecryptoOnLoad.kt +35 -0
  62. package/nitrogen/generated/android/reactnativebundlecrypto+autolinking.cmake +81 -0
  63. package/nitrogen/generated/android/reactnativebundlecrypto+autolinking.gradle +27 -0
  64. package/nitrogen/generated/android/reactnativebundlecryptoOnLoad.cpp +44 -0
  65. package/nitrogen/generated/android/reactnativebundlecryptoOnLoad.hpp +25 -0
  66. package/nitrogen/generated/ios/ReactNativeBundleCrypto+autolinking.rb +60 -0
  67. package/nitrogen/generated/ios/ReactNativeBundleCrypto-Swift-Cxx-Bridge.cpp +97 -0
  68. package/nitrogen/generated/ios/ReactNativeBundleCrypto-Swift-Cxx-Bridge.hpp +429 -0
  69. package/nitrogen/generated/ios/ReactNativeBundleCrypto-Swift-Cxx-Umbrella.hpp +59 -0
  70. package/nitrogen/generated/ios/ReactNativeBundleCryptoAutolinking.mm +33 -0
  71. package/nitrogen/generated/ios/ReactNativeBundleCryptoAutolinking.swift +25 -0
  72. package/nitrogen/generated/ios/c++/HybridReactNativeBundleCryptoSpecSwift.cpp +11 -0
  73. package/nitrogen/generated/ios/c++/HybridReactNativeBundleCryptoSpecSwift.hpp +162 -0
  74. package/nitrogen/generated/ios/swift/DirHashEntry.swift +47 -0
  75. package/nitrogen/generated/ios/swift/Func_void.swift +47 -0
  76. package/nitrogen/generated/ios/swift/Func_void_Sha256Result.swift +47 -0
  77. package/nitrogen/generated/ios/swift/Func_void_VerifyDetachedAscResult.swift +47 -0
  78. package/nitrogen/generated/ios/swift/Func_void_VerifyGpgCleartextResult.swift +47 -0
  79. package/nitrogen/generated/ios/swift/Func_void_bool.swift +47 -0
  80. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +47 -0
  81. package/nitrogen/generated/ios/swift/Func_void_std__vector_DirHashEntry_.swift +47 -0
  82. package/nitrogen/generated/ios/swift/Func_void_std__vector_std__string_.swift +47 -0
  83. package/nitrogen/generated/ios/swift/HybridReactNativeBundleCryptoSpec.swift +65 -0
  84. package/nitrogen/generated/ios/swift/HybridReactNativeBundleCryptoSpec_cxx.swift +314 -0
  85. package/nitrogen/generated/ios/swift/Sha256Result.swift +85 -0
  86. package/nitrogen/generated/ios/swift/VerifyDetachedAscResult.swift +96 -0
  87. package/nitrogen/generated/ios/swift/VerifyGpgCleartextResult.swift +96 -0
  88. package/nitrogen/generated/shared/c++/DirHashEntry.hpp +79 -0
  89. package/nitrogen/generated/shared/c++/HybridReactNativeBundleCryptoSpec.cpp +30 -0
  90. package/nitrogen/generated/shared/c++/HybridReactNativeBundleCryptoSpec.hpp +84 -0
  91. package/nitrogen/generated/shared/c++/Sha256Result.hpp +80 -0
  92. package/nitrogen/generated/shared/c++/VerifyDetachedAscResult.hpp +84 -0
  93. package/nitrogen/generated/shared/c++/VerifyGpgCleartextResult.hpp +84 -0
  94. package/package.json +169 -0
  95. package/src/ReactNativeBundleCrypto.nitro.ts +56 -0
  96. package/src/index.tsx +8 -0
@@ -0,0 +1,529 @@
1
+ import Foundation
2
+ import CommonCrypto
3
+ import Gopenpgp
4
+ import ReactNativeNativeLogger
5
+
6
+ // ============================================================================
7
+ // BundleCryptoCore (iOS)
8
+ //
9
+ // P3a refactor: the real GPG/sha256/path-safety/secure-file logic lives here as
10
+ // plain, synchronous, throwing static functions returning plain Swift types
11
+ // (tuples / [DirHashEntry-like] / Bool / throws). This is the single source of
12
+ // truth for the security logic — the Nitro HybridObject (ReactNativeBundleCrypto)
13
+ // is a thin shell that calls these functions and assembles the generated Nitro
14
+ // Result structs.
15
+ //
16
+ // This split lets other native code (e.g. the bundle-update downloader) call the
17
+ // security core directly and synchronously, without going through a Nitro Promise.
18
+ //
19
+ // Behavior is IDENTICAL to the previous in-method implementation:
20
+ // - Verification failures always return invalid + reason — never a false pass.
21
+ // - sha256 failureReason taxonomy preserved verbatim
22
+ // (FILE_NOT_FOUND / FILE_DISAPPEARED / IO_<code>).
23
+ //
24
+ // Single source of truth for the OneKey GPG public key lives here (below).
25
+ // This module does NOT expose the public key to JS.
26
+ //
27
+ // Cleartext form (verifyGpgCleartext) <- ReactNativeBundleUpdate.swift
28
+ // verifyGPGAndExtractSha256 (CryptoPGP
29
+ // verifyCleartext, body JSON -> sha256)
30
+ // Detached form (verifyDetachedAsc) <- aligned to Android
31
+ // ReactNativeAppUpdate.kt
32
+ // verifyAscContentAndExtractSha256
33
+ // (cleartext-signed SHA256SUMS, first
34
+ // hex token). The on-disk SHA256SUMS.asc
35
+ // is a PGP CLEARTEXT SIGNED MESSAGE, so
36
+ // Gopenpgp verifyCleartext is reused;
37
+ // only the body parsing differs.
38
+ // ============================================================================
39
+
40
+ // OneKey GPG public key for signature verification.
41
+ // SINGLE AUTHORITATIVE COPY for the bundle-crypto module.
42
+ private let GPG_PUBLIC_KEY = """
43
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
44
+
45
+ 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
105
+ =HlTQ
106
+ -----END PGP PUBLIC KEY BLOCK-----
107
+ """
108
+
109
+ /// Plain, synchronous, throwing security core for the bundle-crypto module.
110
+ /// The Nitro HybridObject delegates to these functions.
111
+ public enum BundleCryptoCore {
112
+
113
+ // Plain value type mirroring the (relativePath, sha256) pair the Nitro layer
114
+ // exposes as `DirHashEntry`. Kept separate so the core has zero Nitro deps.
115
+ // `public` (incl. an explicit public init) so other modules — e.g.
116
+ // react-native-bundle-update — can construct entries to pass into
117
+ // verifyDirAgainstHashes across the module boundary.
118
+ public struct DirHash {
119
+ public let relativePath: String
120
+ public let sha256: String
121
+
122
+ public init(relativePath: String, sha256: String) {
123
+ self.relativePath = relativePath
124
+ self.sha256 = sha256
125
+ }
126
+ }
127
+
128
+ // MARK: - GPG cleartext (bundle form): body JSON -> sha256
129
+ // Ported verbatim from ReactNativeBundleUpdate.verifyGPGAndExtractSha256.
130
+
131
+ public static func verifyGpgCleartext(_ signedMessage: String) -> (valid: Bool, sha256: String?, reason: String?) {
132
+ // Check if this looks like a PGP signed message
133
+ guard signedMessage.contains("-----BEGIN PGP SIGNED MESSAGE-----") else {
134
+ return (false, nil, "NOT_PGP_SIGNED_MESSAGE")
135
+ }
136
+
137
+ // 1. Load public key
138
+ guard let pubKey = CryptoKey(fromArmored: GPG_PUBLIC_KEY) else {
139
+ OneKeyLog.error("BundleCrypto", "Failed to parse GPG public key")
140
+ return (false, nil, "PUBKEY_PARSE_FAILED")
141
+ }
142
+
143
+ // 2. Get PGP handle
144
+ guard let pgp = CryptoPGP() else {
145
+ OneKeyLog.error("BundleCrypto", "Failed to create PGPHandle")
146
+ return (false, nil, "PGP_HANDLE_FAILED")
147
+ }
148
+
149
+ // 3. Build verify handle: pgp.verify().verificationKey(pubKey).new()
150
+ guard let verifyBuilder = pgp.verify() else {
151
+ OneKeyLog.error("BundleCrypto", "Failed to get verify builder")
152
+ return (false, nil, "VERIFY_BUILDER_FAILED")
153
+ }
154
+ guard let builderWithKey = verifyBuilder.verificationKey(pubKey) else {
155
+ OneKeyLog.error("BundleCrypto", "Failed to set verification key")
156
+ return (false, nil, "VERIFY_KEY_FAILED")
157
+ }
158
+
159
+ let verifyHandle: any CryptoPGPVerifyProtocol
160
+ do {
161
+ verifyHandle = try builderWithKey.new()
162
+ } catch {
163
+ OneKeyLog.error("BundleCrypto", "Failed to create verify handle: \(error.localizedDescription)")
164
+ return (false, nil, "VERIFY_HANDLE_FAILED")
165
+ }
166
+
167
+ // 4. Verify cleartext
168
+ guard let signatureData = signedMessage.data(using: .utf8) else {
169
+ return (false, nil, "ENCODING_FAILED")
170
+ }
171
+
172
+ let cleartextResult: CryptoVerifyCleartextResult
173
+ do {
174
+ cleartextResult = try verifyHandle.verifyCleartext(signatureData)
175
+ } catch {
176
+ OneKeyLog.error("BundleCrypto", "GPG verification error: \(error.localizedDescription)")
177
+ return (false, nil, "VERIFY_ERROR")
178
+ }
179
+
180
+ // 5. Check signature error
181
+ do {
182
+ try cleartextResult.signatureError()
183
+ } catch {
184
+ OneKeyLog.error("BundleCrypto", "GPG signature invalid: \(error.localizedDescription)")
185
+ return (false, nil, "SIGNATURE_INVALID")
186
+ }
187
+
188
+ // 6. Get cleartext
189
+ guard let cleartextData = cleartextResult.cleartext() else {
190
+ OneKeyLog.error("BundleCrypto", "Failed to extract cleartext from GPG result")
191
+ return (false, nil, "CLEARTEXT_EXTRACT_FAILED")
192
+ }
193
+
194
+ guard let text = String(data: cleartextData, encoding: .utf8) else {
195
+ return (false, nil, "CLEARTEXT_DECODE_FAILED")
196
+ }
197
+
198
+ // 7. Parse JSON and extract sha256
199
+ guard let jsonData = text.data(using: .utf8),
200
+ let json = try? JSONSerialization.jsonObject(with: jsonData) as? [String: Any],
201
+ let sha256 = json["sha256"] as? String else {
202
+ OneKeyLog.error("BundleCrypto", "Failed to parse cleartext JSON")
203
+ return (false, nil, "JSON_PARSE_FAILED")
204
+ }
205
+
206
+ OneKeyLog.info("BundleCrypto", "GPG cleartext verification succeeded")
207
+ return (true, sha256, nil)
208
+ }
209
+
210
+ // MARK: - Detached ASC (APK form): cleartext-signed SHA256SUMS -> first hex token
211
+ // The SHA256SUMS.asc on disk is a PGP CLEARTEXT SIGNED MESSAGE, so the same
212
+ // Gopenpgp verifyCleartext path is reused; only the body parsing differs
213
+ // (no JSON — the verified body's first whitespace token must be a 64-char
214
+ // lowercase hex sha256).
215
+
216
+ public static func verifyDetachedAsc(_ ascContent: String) -> (valid: Bool, sha256: String?, reason: String?) {
217
+ guard ascContent.contains("-----BEGIN PGP SIGNED MESSAGE-----") else {
218
+ return (false, nil, "NOT_PGP_SIGNED_MESSAGE")
219
+ }
220
+
221
+ guard let pubKey = CryptoKey(fromArmored: GPG_PUBLIC_KEY) else {
222
+ OneKeyLog.error("BundleCrypto", "Failed to parse GPG public key")
223
+ return (false, nil, "PUBKEY_PARSE_FAILED")
224
+ }
225
+ guard let pgp = CryptoPGP() else {
226
+ return (false, nil, "PGP_HANDLE_FAILED")
227
+ }
228
+ guard let verifyBuilder = pgp.verify() else {
229
+ return (false, nil, "VERIFY_BUILDER_FAILED")
230
+ }
231
+ guard let builderWithKey = verifyBuilder.verificationKey(pubKey) else {
232
+ return (false, nil, "VERIFY_KEY_FAILED")
233
+ }
234
+ let verifyHandle: any CryptoPGPVerifyProtocol
235
+ do {
236
+ verifyHandle = try builderWithKey.new()
237
+ } catch {
238
+ return (false, nil, "VERIFY_HANDLE_FAILED")
239
+ }
240
+
241
+ guard let signatureData = ascContent.data(using: .utf8) else {
242
+ return (false, nil, "ENCODING_FAILED")
243
+ }
244
+
245
+ let cleartextResult: CryptoVerifyCleartextResult
246
+ do {
247
+ cleartextResult = try verifyHandle.verifyCleartext(signatureData)
248
+ } catch {
249
+ OneKeyLog.error("BundleCrypto", "ASC verification error: \(error.localizedDescription)")
250
+ return (false, nil, "VERIFY_ERROR")
251
+ }
252
+
253
+ do {
254
+ try cleartextResult.signatureError()
255
+ } catch {
256
+ OneKeyLog.error("BundleCrypto", "ASC signature invalid: \(error.localizedDescription)")
257
+ return (false, nil, "SIGNATURE_INVALID")
258
+ }
259
+
260
+ guard let cleartextData = cleartextResult.cleartext(),
261
+ let text = String(data: cleartextData, encoding: .utf8) else {
262
+ return (false, nil, "CLEARTEXT_EXTRACT_FAILED")
263
+ }
264
+
265
+ // Mirror Android: first whitespace token of the verified SHA256SUMS body,
266
+ // lowercased, must be exactly 64 hex chars.
267
+ let sha256 = text
268
+ .trimmingCharacters(in: .whitespacesAndNewlines)
269
+ .split(whereSeparator: { $0 == " " || $0 == "\t" || $0 == "\n" || $0 == "\r" })
270
+ .first
271
+ .map { String($0).lowercased() } ?? ""
272
+ let isHex = sha256.count == 64 && sha256.unicodeScalars.allSatisfy {
273
+ ($0 >= "0" && $0 <= "9") || ($0 >= "a" && $0 <= "f")
274
+ }
275
+ guard isHex else {
276
+ OneKeyLog.error("BundleCrypto", "ASC body sha256 token invalid")
277
+ return (false, nil, "SHA256_TOKEN_INVALID")
278
+ }
279
+
280
+ OneKeyLog.info("BundleCrypto", "ASC detached verification succeeded")
281
+ return (true, sha256, nil)
282
+ }
283
+
284
+ // MARK: - sha256 (CommonCrypto streaming) — ported from calculateSHA256
285
+ // + lastSHA256FailureReason. failureReason taxonomy preserved verbatim
286
+ // (FILE_NOT_FOUND / FILE_DISAPPEARED / IO_<code>).
287
+
288
+ public static func sha256OfFile(_ filePath: String) -> (sha256: String?, failureReason: String?) {
289
+ let fm = FileManager.default
290
+ if !fm.fileExists(atPath: filePath) {
291
+ OneKeyLog.error("BundleCrypto", "sha256OfFile: file not found: \(filePath)")
292
+ return (nil, "FILE_NOT_FOUND")
293
+ }
294
+ guard let fileHandle = FileHandle(forReadingAtPath: filePath) else {
295
+ OneKeyLog.error("BundleCrypto", "sha256OfFile: open failed (file disappeared between stat and open): \(filePath)")
296
+ return (nil, "FILE_DISAPPEARED")
297
+ }
298
+ defer { fileHandle.closeFile() }
299
+
300
+ var context = CC_SHA256_CTX()
301
+ CC_SHA256_Init(&context)
302
+ var threwError: Error?
303
+ // safeRead routes reads through FileHandle.read(upToCount:) on iOS 13.4+,
304
+ // surfacing disk failures as throwing NSError. On pre-13.4 OS versions the
305
+ // fallback raises NSFileHandleOperationException (uncatchable in Swift) —
306
+ // accepted on the floor since 13.4+ is the long-standing deployment target.
307
+ while autoreleasepool(invoking: {
308
+ do {
309
+ let data = try Self.safeRead(fileHandle: fileHandle, length: 8192)
310
+ if data.count > 0 {
311
+ data.withUnsafeBytes { CC_SHA256_Update(&context, $0.baseAddress, CC_LONG(data.count)) }
312
+ return true
313
+ }
314
+ return false
315
+ } catch {
316
+ threwError = error
317
+ return false
318
+ }
319
+ }) {}
320
+ if let err = threwError {
321
+ let nsErr = err as NSError
322
+ // Keep failure tag low-cardinality (`IO_<code>`); full detail logged locally.
323
+ OneKeyLog.error("BundleCrypto", "sha256OfFile: read failed: \(nsErr.domain) \(nsErr.code) \(nsErr.localizedDescription)")
324
+ return (nil, "IO_\(nsErr.code)")
325
+ }
326
+ var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
327
+ CC_SHA256_Final(&hash, &context)
328
+ let hex = hash.map { String(format: "%02x", $0) }.joined()
329
+ return (hex, nil)
330
+ }
331
+
332
+ /// Throwing wrapper around FileHandle.read(upToCount:) so disk I/O failures
333
+ /// become catchable Swift errors rather than NSFileHandleOperationException.
334
+ private static func safeRead(fileHandle: FileHandle, length: Int) throws -> Data {
335
+ if #available(iOS 13.4, macOS 10.15.4, *) {
336
+ return try fileHandle.read(upToCount: length) ?? Data()
337
+ } else {
338
+ return fileHandle.readData(ofLength: length)
339
+ }
340
+ }
341
+
342
+ // MARK: - Constant-time hex compare — ported from String.secureCompare.
343
+
344
+ public static func secureEqualHex(_ a: String, _ b: String) -> Bool {
345
+ return secureCompare(a, b)
346
+ }
347
+
348
+ private static func secureCompare(_ a: String, _ b: String) -> Bool {
349
+ let lhs = Array(a.utf8)
350
+ let rhs = Array(b.utf8)
351
+ guard lhs.count == rhs.count else { return false }
352
+ var result: UInt8 = 0
353
+ for i in 0..<lhs.count {
354
+ result |= lhs[i] ^ rhs[i]
355
+ }
356
+ return result == 0
357
+ }
358
+
359
+ /// Synchronous sha256 used internally by dir hashing — returns nil on any
360
+ /// failure (used where only the hex/nil distinction matters).
361
+ private static func calculateSHA256Sync(_ filePath: String) -> String? {
362
+ let fm = FileManager.default
363
+ guard fm.fileExists(atPath: filePath),
364
+ let fileHandle = FileHandle(forReadingAtPath: filePath) else { return nil }
365
+ defer { fileHandle.closeFile() }
366
+ var context = CC_SHA256_CTX()
367
+ CC_SHA256_Init(&context)
368
+ var threwError: Error?
369
+ while autoreleasepool(invoking: {
370
+ do {
371
+ let data = try Self.safeRead(fileHandle: fileHandle, length: 8192)
372
+ if data.count > 0 {
373
+ data.withUnsafeBytes { CC_SHA256_Update(&context, $0.baseAddress, CC_LONG(data.count)) }
374
+ return true
375
+ }
376
+ return false
377
+ } catch {
378
+ threwError = error
379
+ return false
380
+ }
381
+ }) {}
382
+ if threwError != nil { return nil }
383
+ var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
384
+ CC_SHA256_Final(&hash, &context)
385
+ return hash.map { String(format: "%02x", $0) }.joined()
386
+ }
387
+
388
+ // MARK: - Per-entry directory hash verification — ported from
389
+ // validateAllFilesInDir. Caller passes the expected relativePath -> sha256
390
+ // entries (the JS layer derives these from verified metadata). Verifies every
391
+ // on-disk file matches AND every expected entry exists (completeness).
392
+
393
+ public static func verifyDirAgainstHashes(dirPath: String, entries: [DirHash]) -> Bool {
394
+ let fm = FileManager.default
395
+ var isDir: ObjCBool = false
396
+ guard fm.fileExists(atPath: dirPath, isDirectory: &isDir), isDir.boolValue else {
397
+ OneKeyLog.error("BundleCrypto", "[bundle-verify] dir not found: \(dirPath)")
398
+ return false
399
+ }
400
+ // Normalize the directory prefix so relative paths match.
401
+ let normalizedDir = (dirPath as NSString).hasSuffix("/") ? dirPath : dirPath + "/"
402
+
403
+ var expected: [String: String] = [:]
404
+ for entry in entries { expected[entry.relativePath] = entry.sha256 }
405
+
406
+ guard let enumerator = fm.enumerator(atPath: dirPath) else { return false }
407
+ while let file = enumerator.nextObject() as? String {
408
+ if file.contains("metadata.json") || file.contains(".DS_Store") { continue }
409
+ let fullPath = (dirPath as NSString).appendingPathComponent(file)
410
+ var entryIsDir: ObjCBool = false
411
+ if fm.fileExists(atPath: fullPath, isDirectory: &entryIsDir), entryIsDir.boolValue { continue }
412
+
413
+ let relativePath = fullPath.replacingOccurrences(of: normalizedDir, with: "")
414
+ guard let expectedSHA256 = expected[relativePath] else {
415
+ OneKeyLog.error("BundleCrypto", "[bundle-verify] File on disk not found in metadata: \(relativePath)")
416
+ return false
417
+ }
418
+ guard let actualSHA256 = Self.calculateSHA256Sync(fullPath) else {
419
+ OneKeyLog.error("BundleCrypto", "[bundle-verify] Failed to calculate SHA256 for file: \(relativePath)")
420
+ return false
421
+ }
422
+ if !Self.secureCompare(expectedSHA256, actualSHA256) {
423
+ OneKeyLog.error("BundleCrypto", "[bundle-verify] SHA256 mismatch for \(relativePath)")
424
+ return false
425
+ }
426
+ }
427
+
428
+ // Verify completeness: every expected entry must exist on disk.
429
+ for (relativePath, _) in expected {
430
+ let expectedFilePath = normalizedDir + relativePath
431
+ if !fm.fileExists(atPath: expectedFilePath) {
432
+ OneKeyLog.error("BundleCrypto", "[bundle-verify] File listed in metadata but missing on disk: \(relativePath)")
433
+ return false
434
+ }
435
+ }
436
+ return true
437
+ }
438
+
439
+ // MARK: - Hash a whole dir into relativePath -> sha256 entries (new helper,
440
+ // same enumeration/skip rules as verifyDirAgainstHashes). Throws HASH_FAILED
441
+ // if any file cannot be hashed.
442
+
443
+ public static func hashDir(_ dirPath: String) throws -> [DirHash] {
444
+ let fm = FileManager.default
445
+ let normalizedDir = (dirPath as NSString).hasSuffix("/") ? dirPath : dirPath + "/"
446
+ var results: [DirHash] = []
447
+ guard let enumerator = fm.enumerator(atPath: dirPath) else { return [] }
448
+ while let file = enumerator.nextObject() as? String {
449
+ if file.contains("metadata.json") || file.contains(".DS_Store") { continue }
450
+ let fullPath = (dirPath as NSString).appendingPathComponent(file)
451
+ var entryIsDir: ObjCBool = false
452
+ if fm.fileExists(atPath: fullPath, isDirectory: &entryIsDir), entryIsDir.boolValue { continue }
453
+ guard let sha256 = Self.calculateSHA256Sync(fullPath) else {
454
+ OneKeyLog.error("BundleCrypto", "hashDir: failed to hash \(file)")
455
+ throw NSError(domain: "BundleCrypto", code: -1, userInfo: [NSLocalizedDescriptionKey: "HASH_FAILED"])
456
+ }
457
+ let relativePath = fullPath.replacingOccurrences(of: normalizedDir, with: "")
458
+ results.append(DirHash(relativePath: relativePath, sha256: sha256))
459
+ }
460
+ return results
461
+ }
462
+
463
+ // MARK: - Symlink / path-traversal guard — ported from
464
+ // validateExtractedPathSafety.
465
+
466
+ public static func validateExtractedPathSafety(_ destination: String) -> Bool {
467
+ let fm = FileManager.default
468
+ let resolvedDestination = (destination as NSString).resolvingSymlinksInPath
469
+
470
+ guard let enumerator = fm.enumerator(atPath: destination) else { return true }
471
+ while let file = enumerator.nextObject() as? String {
472
+ let fullPath = (destination as NSString).appendingPathComponent(file)
473
+ if let attrs = enumerator.fileAttributes,
474
+ attrs[.type] as? FileAttributeType == .typeSymbolicLink {
475
+ OneKeyLog.error("BundleCrypto", "Symlink detected in extracted bundle: \(file)")
476
+ return false
477
+ }
478
+ let resolvedPath = (fullPath as NSString).resolvingSymlinksInPath
479
+ if !resolvedPath.hasPrefix(resolvedDestination) {
480
+ OneKeyLog.error("BundleCrypto", "Path traversal detected in extracted bundle: \(file)")
481
+ return false
482
+ }
483
+ }
484
+ return true
485
+ }
486
+
487
+ // MARK: - Safe file verbs — atomic write / safe rename / version-dir listing.
488
+ // Consolidates the FileManager write/move/enumerate patterns scattered through
489
+ // ReactNativeBundleUpdate (writeSignatureFile atomic write, downloadBundle
490
+ // remove-then-move, listLocalBundles contentsOfDirectory) into explicit APIs.
491
+
492
+ public static func atomicWriteFile(filePath: String, contentUtf8: String) throws {
493
+ let dir = (filePath as NSString).deletingLastPathComponent
494
+ let fm = FileManager.default
495
+ if !fm.fileExists(atPath: dir) {
496
+ try fm.createDirectory(atPath: dir, withIntermediateDirectories: true)
497
+ }
498
+ // Foundation's atomically:true writes to a temp file then renames into place.
499
+ try contentUtf8.write(toFile: filePath, atomically: true, encoding: .utf8)
500
+ }
501
+
502
+ public static func safeRename(fromPath: String, toPath: String) throws {
503
+ let fm = FileManager.default
504
+ let destDir = (toPath as NSString).deletingLastPathComponent
505
+ if !fm.fileExists(atPath: destDir) {
506
+ try fm.createDirectory(atPath: destDir, withIntermediateDirectories: true)
507
+ }
508
+ // Same pattern as downloadBundle: remove existing target, then move.
509
+ if fm.fileExists(atPath: toPath) {
510
+ try fm.removeItem(atPath: toPath)
511
+ }
512
+ try fm.moveItem(at: URL(fileURLWithPath: fromPath), to: URL(fileURLWithPath: toPath))
513
+ }
514
+
515
+ public static func listVersionDirs(_ parentDir: String) -> [String] {
516
+ let fm = FileManager.default
517
+ guard let contents = try? fm.contentsOfDirectory(atPath: parentDir) else {
518
+ return []
519
+ }
520
+ var results: [String] = []
521
+ for name in contents {
522
+ let fullPath = (parentDir as NSString).appendingPathComponent(name)
523
+ var isDir: ObjCBool = false
524
+ guard fm.fileExists(atPath: fullPath, isDirectory: &isDir), isDir.boolValue else { continue }
525
+ results.append(name)
526
+ }
527
+ return results
528
+ }
529
+ }
@@ -0,0 +1,52 @@
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>Gopenpgp.framework/Gopenpgp</string>
10
+ <key>LibraryIdentifier</key>
11
+ <string>ios-arm64_x86_64-simulator</string>
12
+ <key>LibraryPath</key>
13
+ <string>Gopenpgp.framework</string>
14
+ <key>SupportedArchitectures</key>
15
+ <array>
16
+ <string>arm64</string>
17
+ <string>x86_64</string>
18
+ </array>
19
+ <key>SupportedPlatform</key>
20
+ <string>ios</string>
21
+ <key>SupportedPlatformVariant</key>
22
+ <string>simulator</string>
23
+ <key>MinimumOSVersion</key>
24
+ <string>15.5</string>
25
+ </dict>
26
+ <dict>
27
+ <key>BinaryPath</key>
28
+ <string>Gopenpgp.framework/Gopenpgp</string>
29
+ <key>LibraryIdentifier</key>
30
+ <string>ios-arm64</string>
31
+ <key>LibraryPath</key>
32
+ <string>Gopenpgp.framework</string>
33
+ <key>SupportedArchitectures</key>
34
+ <array>
35
+ <string>arm64</string>
36
+ </array>
37
+ <key>SupportedPlatform</key>
38
+ <string>ios</string>
39
+ <key>MinimumOSVersion</key>
40
+ <string>15.5</string>
41
+ </dict>
42
+ </array>
43
+ <key>CFBundlePackageType</key>
44
+ <string>XFWK</string>
45
+ <key>RCTNewArchEnabled</key>
46
+ <true/>
47
+ <key>XCFrameworkFormatVersion</key>
48
+ <string>1.0</string>
49
+ <key>MinimumOSVersion</key>
50
+ <string>15.5</string>
51
+ </dict>
52
+ </plist>
@@ -0,0 +1,96 @@
1
+ // Objective-C API for talking to github.com/ProtonMail/gopenpgp/v3/armor Go package.
2
+ // gobind -lang=objc github.com/ProtonMail/gopenpgp/v3/armor
3
+ //
4
+ // File is generated by gobind. Do not edit.
5
+
6
+ #ifndef __Armor_H__
7
+ #define __Armor_H__
8
+
9
+ @import Foundation;
10
+ #include "ref.h"
11
+ #include "Universe.objc.h"
12
+
13
+ #include "Constants.objc.h"
14
+
15
+ /**
16
+ * ArmorKey armors input as a public key.
17
+ */
18
+ FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorKey(NSData* _Nullable input, NSError* _Nullable* _Nullable error);
19
+
20
+ FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorPGPMessage(NSData* _Nullable signature, NSError* _Nullable* _Nullable error);
21
+
22
+ FOUNDATION_EXPORT NSData* _Nullable ArmorArmorPGPMessageBytes(NSData* _Nullable signature, NSError* _Nullable* _Nullable error);
23
+
24
+ FOUNDATION_EXPORT NSData* _Nullable ArmorArmorPGPMessageBytesChecksum(NSData* _Nullable signature, BOOL checksum, NSError* _Nullable* _Nullable error);
25
+
26
+ FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorPGPMessageChecksum(NSData* _Nullable signature, BOOL checksum, NSError* _Nullable* _Nullable error);
27
+
28
+ FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorPGPSignature(NSData* _Nullable signature, NSError* _Nullable* _Nullable error);
29
+
30
+ FOUNDATION_EXPORT NSData* _Nullable ArmorArmorPGPSignatureBinary(NSData* _Nullable signature, NSError* _Nullable* _Nullable error);
31
+
32
+ // skipped function ArmorReader with unsupported parameter or return types
33
+
34
+
35
+ /**
36
+ * ArmorWithType armors input with the given armorType.
37
+ */
38
+ FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorWithType(NSData* _Nullable input, NSString* _Nullable armorType, NSError* _Nullable* _Nullable error);
39
+
40
+ /**
41
+ * ArmorWithTypeAndCustomHeaders armors input with the given armorType and
42
+ headers.
43
+ */
44
+ FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorWithTypeAndCustomHeaders(NSData* _Nullable input, NSString* _Nullable armorType, NSString* _Nullable version, NSString* _Nullable comment, NSError* _Nullable* _Nullable error);
45
+
46
+ /**
47
+ * ArmorWithTypeAndCustomHeadersBytes armors input with the given armorType and
48
+ headers.
49
+ */
50
+ FOUNDATION_EXPORT NSData* _Nullable ArmorArmorWithTypeAndCustomHeadersBytes(NSData* _Nullable input, NSString* _Nullable armorType, NSString* _Nullable version, NSString* _Nullable comment, NSError* _Nullable* _Nullable error);
51
+
52
+ /**
53
+ * ArmorWithTypeAndCustomHeadersChecksum armors input with the given armorType and
54
+ headers and checksum option.
55
+ */
56
+ FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorWithTypeAndCustomHeadersChecksum(NSData* _Nullable input, NSString* _Nullable armorType, NSString* _Nullable version, NSString* _Nullable comment, BOOL checksum, NSError* _Nullable* _Nullable error);
57
+
58
+ /**
59
+ * ArmorWithTypeBytes armors input with the given armorType.
60
+ */
61
+ FOUNDATION_EXPORT NSData* _Nullable ArmorArmorWithTypeBytes(NSData* _Nullable input, NSString* _Nullable armorType, NSError* _Nullable* _Nullable error);
62
+
63
+ /**
64
+ * ArmorWithTypeBytesChecksum armors input with the given armorType and checksum option.
65
+ */
66
+ FOUNDATION_EXPORT NSData* _Nullable ArmorArmorWithTypeBytesChecksum(NSData* _Nullable input, NSString* _Nullable armorType, BOOL checksum, NSError* _Nullable* _Nullable error);
67
+
68
+ /**
69
+ * ArmorWithTypeChecksum armors input with the given armorType.
70
+ The checksum option determines if an armor checksum is written at the end.
71
+ */
72
+ FOUNDATION_EXPORT NSString* _Nonnull ArmorArmorWithTypeChecksum(NSData* _Nullable input, NSString* _Nullable armorType, BOOL checksum, NSError* _Nullable* _Nullable error);
73
+
74
+ // skipped function ArmorWriterWithType with unsupported parameter or return types
75
+
76
+
77
+ // skipped function ArmorWriterWithTypeAndCustomHeaders with unsupported parameter or return types
78
+
79
+
80
+ // skipped function ArmorWriterWithTypeChecksum with unsupported parameter or return types
81
+
82
+
83
+ // skipped function IsPGPArmored with unsupported parameter or return types
84
+
85
+
86
+ /**
87
+ * Unarmor unarmors an armored input into a byte array.
88
+ */
89
+ FOUNDATION_EXPORT NSData* _Nullable ArmorUnarmor(NSString* _Nullable input, NSError* _Nullable* _Nullable error);
90
+
91
+ /**
92
+ * UnarmorBytes unarmors an armored input into a byte array.
93
+ */
94
+ FOUNDATION_EXPORT NSData* _Nullable ArmorUnarmorBytes(NSData* _Nullable input, NSError* _Nullable* _Nullable error);
95
+
96
+ #endif