@scalebun/react-native 1.10.6 → 1.10.7

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 (53) hide show
  1. package/android/src/main/java/com/scalebun/rn/ota/ScaleBunOtaModule.kt +75 -0
  2. package/android/src/oldarch/java/com/scalebun/rn/ota/ScaleBunOtaSpec.kt +12 -0
  3. package/dist/scalebun.full.js +432 -51
  4. package/dist/scalebun.slim.js +432 -51
  5. package/ios/Ota/ScaleBunOtaBridge.mm +6 -0
  6. package/ios/Ota/ScaleBunOtaModule.swift +67 -0
  7. package/lib/commonjs/core/config/schema.js +34 -1
  8. package/lib/commonjs/core/constants/version.js +1 -1
  9. package/lib/commonjs/features/journey/ScaleBunDebugRoot.js +24 -0
  10. package/lib/commonjs/features/journey/uiState.js +87 -0
  11. package/lib/commonjs/features/ota/crypto/builtinVerifier.js +248 -0
  12. package/lib/commonjs/features/ota/crypto/loadEd25519.js +40 -0
  13. package/lib/commonjs/features/ota/crypto/loadSha512.js +40 -0
  14. package/lib/commonjs/features/ota/crypto/nativeVerifier.js +121 -0
  15. package/lib/commonjs/features/ota/signature.js +87 -27
  16. package/lib/commonjs/metro/serializerCompose.js +32 -0
  17. package/lib/commonjs/public/ScaleBunFacade.js +74 -11
  18. package/lib/module/core/config/schema.js +34 -1
  19. package/lib/module/core/constants/version.js +1 -1
  20. package/lib/module/features/journey/ScaleBunDebugRoot.js +24 -0
  21. package/lib/module/features/journey/uiState.js +79 -0
  22. package/lib/module/features/ota/crypto/builtinVerifier.js +240 -0
  23. package/lib/module/features/ota/crypto/loadEd25519.js +34 -0
  24. package/lib/module/features/ota/crypto/loadSha512.js +34 -0
  25. package/lib/module/features/ota/crypto/nativeVerifier.js +113 -0
  26. package/lib/module/features/ota/signature.js +87 -27
  27. package/lib/module/metro/serializerCompose.js +32 -0
  28. package/lib/module/public/ScaleBunFacade.js +74 -11
  29. package/lib/typescript/core/config/schema.d.ts +2 -0
  30. package/lib/typescript/core/constants/version.d.ts +1 -1
  31. package/lib/typescript/features/journey/uiState.d.ts +53 -0
  32. package/lib/typescript/features/ota/OtaTypes.d.ts +50 -0
  33. package/lib/typescript/features/ota/crypto/builtinVerifier.d.ts +53 -0
  34. package/lib/typescript/features/ota/crypto/loadEd25519.d.ts +30 -0
  35. package/lib/typescript/features/ota/crypto/loadSha512.d.ts +15 -0
  36. package/lib/typescript/features/ota/crypto/nativeVerifier.d.ts +35 -0
  37. package/lib/typescript/features/ota/signature.d.ts +22 -7
  38. package/lib/typescript/public/ScaleBunFacade.d.ts +35 -6
  39. package/lib/typescript/specs/NativeScaleBunOta.d.ts +23 -0
  40. package/package.json +18 -3
  41. package/src/core/config/schema.ts +30 -3
  42. package/src/core/constants/version.ts +1 -1
  43. package/src/features/journey/ScaleBunDebugRoot.tsx +22 -0
  44. package/src/features/journey/uiState.ts +84 -0
  45. package/src/features/ota/OtaTypes.ts +51 -0
  46. package/src/features/ota/crypto/builtinVerifier.ts +257 -0
  47. package/src/features/ota/crypto/loadEd25519.ts +41 -0
  48. package/src/features/ota/crypto/loadSha512.ts +35 -0
  49. package/src/features/ota/crypto/nativeVerifier.ts +117 -0
  50. package/src/features/ota/signature.ts +108 -25
  51. package/src/metro/serializerCompose.ts +38 -2
  52. package/src/public/ScaleBunFacade.ts +87 -13
  53. package/src/specs/NativeScaleBunOta.ts +24 -0
@@ -283,6 +283,81 @@ class ScaleBunOtaModule(reactContext: ReactApplicationContext) :
283
283
  }
284
284
  }
285
285
 
286
+ /**
287
+ * Verify a detached ed25519 signature with PLATFORM crypto.
288
+ *
289
+ * Why native: the JS verifier lives inside the very bundle it protects, so
290
+ * one malicious bundle can neuter it for every update after. Platform
291
+ * crypto sits outside the bundle's reach. It also drops the runtime need
292
+ * for the optional @noble peers on Android 13+.
293
+ *
294
+ * Contract (mirrors the JS spec doc):
295
+ * - inputs are lowercase hex, pre-validated by the JS caller
296
+ * - the message is the RAW 32 BYTES of the bundle SHA-256 — the CLI
297
+ * signs the digest bytes, not their hex text
298
+ * - resolves 'valid' / 'invalid' / 'unavailable'; never rejects for a
299
+ * wrong signature, and any unexpected throw resolves 'unavailable' so
300
+ * machinery failure is distinguishable from a forged bundle
301
+ *
302
+ * Availability: `Signature.getInstance("Ed25519")` ships in Android's
303
+ * conscrypt from API 33. Below that the JCA lookup throws
304
+ * NoSuchAlgorithmException — reported as 'unavailable', and JS falls back
305
+ * to its own verifier. Checked by attempting the lookup rather than by
306
+ * SDK_INT, because the algorithm's presence is the fact that matters.
307
+ */
308
+ @ReactMethod
309
+ override fun verifyEd25519(
310
+ messageHex: String,
311
+ signatureHex: String,
312
+ publicKeyHex: String,
313
+ promise: Promise,
314
+ ) {
315
+ try {
316
+ val message = hexToBytes(messageHex)
317
+ val signature = hexToBytes(signatureHex)
318
+ val rawKey = hexToBytes(publicKeyHex)
319
+ if (message == null || signature == null || rawKey == null || rawKey.size != 32) {
320
+ // Malformed input from our own caller is not a forgery verdict.
321
+ promise.resolve("unavailable")
322
+ return
323
+ }
324
+
325
+ // JCA takes X.509 SubjectPublicKeyInfo, not raw key bytes: the
326
+ // 12-byte ed25519 SPKI prefix (OID 1.3.101.112) + the raw 32.
327
+ val spkiPrefix = byteArrayOf(
328
+ 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00,
329
+ )
330
+ val verifier = try {
331
+ java.security.Signature.getInstance("Ed25519")
332
+ } catch (_: java.security.NoSuchAlgorithmException) {
333
+ promise.resolve("unavailable") // API < 33
334
+ return
335
+ }
336
+ val key = java.security.KeyFactory.getInstance("Ed25519")
337
+ .generatePublic(java.security.spec.X509EncodedKeySpec(spkiPrefix + rawKey))
338
+
339
+ verifier.initVerify(key)
340
+ verifier.update(message)
341
+ promise.resolve(if (verifier.verify(signature)) "valid" else "invalid")
342
+ } catch (_: Throwable) {
343
+ // Fail toward "cannot check", never toward "checked out fine".
344
+ promise.resolve("unavailable")
345
+ }
346
+ }
347
+
348
+ /** Hex → bytes; null for odd length or a non-hex character. */
349
+ private fun hexToBytes(hex: String): ByteArray? {
350
+ if (hex.isEmpty() || hex.length % 2 != 0) return null
351
+ val out = ByteArray(hex.length / 2)
352
+ for (i in out.indices) {
353
+ val hi = Character.digit(hex[i * 2], 16)
354
+ val lo = Character.digit(hex[i * 2 + 1], 16)
355
+ if (hi < 0 || lo < 0) return null
356
+ out[i] = ((hi shl 4) or lo).toByte()
357
+ }
358
+ return out
359
+ }
360
+
286
361
  private fun sha256Hex(bytes: ByteArray): String {
287
362
  val digest = java.security.MessageDigest.getInstance("SHA-256")
288
363
  val hash = digest.digest(bytes)
@@ -28,4 +28,16 @@ abstract class ScaleBunOtaSpec(reactContext: ReactApplicationContext) :
28
28
  abstract fun markHealthy()
29
29
  abstract fun revertToPrevious(promise: Promise)
30
30
  abstract fun restartApp()
31
+
32
+ // Hand-maintained: this file does NOT regenerate from the JS spec. A method
33
+ // added to NativeScaleBunOta.ts that is missing here compiles green on New
34
+ // Arch and breaks EVERY old-arch consumer's build (the ScaleBunCrashModule
35
+ // incident). Non-null Strings to match the codegen base's signature, so the
36
+ // one concrete override compiles against either architecture.
37
+ abstract fun verifyEd25519(
38
+ messageHex: String,
39
+ signatureHex: String,
40
+ publicKeyHex: String,
41
+ promise: Promise,
42
+ )
31
43
  }