react-native-bspatch 4.1.0 → 5.0.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 (81) hide show
  1. package/README.md +83 -27
  2. package/android/build.gradle +25 -0
  3. package/android/src/main/AndroidManifest.xml +2 -0
  4. package/android/src/main/java/vn/reactnativebspatch/BsPatchModule.kt +86 -6
  5. package/android/src/main/res/values/bspatch_public_key.xml +5 -0
  6. package/cpp/bsdiff/bspatch_wrapper.c +34 -0
  7. package/cpp/bsdiff/bspatch_wrapper.h +2 -0
  8. package/cpp/bspatch_jni.cpp +18 -0
  9. package/ios/RNBsPatch.mm +142 -1
  10. package/lib/commonjs/NativeBsPatch.js.map +1 -1
  11. package/lib/commonjs/index.js +9 -2
  12. package/lib/commonjs/index.js.map +1 -1
  13. package/lib/commonjs/ota/OtaProvider.js +116 -20
  14. package/lib/commonjs/ota/OtaProvider.js.map +1 -1
  15. package/lib/commonjs/ota/eligibility.js +40 -0
  16. package/lib/commonjs/ota/eligibility.js.map +1 -0
  17. package/lib/commonjs/ota/entrySignature.js +23 -0
  18. package/lib/commonjs/ota/entrySignature.js.map +1 -0
  19. package/lib/commonjs/ota/installId.js +27 -0
  20. package/lib/commonjs/ota/installId.js.map +1 -0
  21. package/lib/commonjs/ota/otaCore.js +96 -21
  22. package/lib/commonjs/ota/otaCore.js.map +1 -1
  23. package/lib/commonjs/ota/storage/{GitHubRawStorage.js → R2Storage.js} +20 -15
  24. package/lib/commonjs/ota/storage/R2Storage.js.map +1 -0
  25. package/lib/commonjs/ota/types.js.map +1 -1
  26. package/lib/module/NativeBsPatch.js.map +1 -1
  27. package/lib/module/index.js +2 -1
  28. package/lib/module/index.js.map +1 -1
  29. package/lib/module/ota/OtaProvider.js +116 -20
  30. package/lib/module/ota/OtaProvider.js.map +1 -1
  31. package/lib/module/ota/eligibility.js +34 -0
  32. package/lib/module/ota/eligibility.js.map +1 -0
  33. package/lib/module/ota/entrySignature.js +17 -0
  34. package/lib/module/ota/entrySignature.js.map +1 -0
  35. package/lib/module/ota/installId.js +22 -0
  36. package/lib/module/ota/installId.js.map +1 -0
  37. package/lib/module/ota/otaCore.js +96 -21
  38. package/lib/module/ota/otaCore.js.map +1 -1
  39. package/lib/module/ota/storage/{GitHubRawStorage.js → R2Storage.js} +18 -14
  40. package/lib/module/ota/storage/R2Storage.js.map +1 -0
  41. package/lib/module/ota/types.js.map +1 -1
  42. package/lib/typescript/NativeBsPatch.d.ts +28 -2
  43. package/lib/typescript/NativeBsPatch.d.ts.map +1 -1
  44. package/lib/typescript/index.d.ts +3 -1
  45. package/lib/typescript/index.d.ts.map +1 -1
  46. package/lib/typescript/ota/OtaProvider.d.ts.map +1 -1
  47. package/lib/typescript/ota/eligibility.d.ts +19 -0
  48. package/lib/typescript/ota/eligibility.d.ts.map +1 -0
  49. package/lib/typescript/ota/entrySignature.d.ts +9 -0
  50. package/lib/typescript/ota/entrySignature.d.ts.map +1 -0
  51. package/lib/typescript/ota/installId.d.ts +3 -0
  52. package/lib/typescript/ota/installId.d.ts.map +1 -0
  53. package/lib/typescript/ota/otaCore.d.ts.map +1 -1
  54. package/lib/typescript/ota/storage/{GitHubRawStorage.d.ts → R2Storage.d.ts} +4 -3
  55. package/lib/typescript/ota/storage/R2Storage.d.ts.map +1 -0
  56. package/lib/typescript/ota/types.d.ts +52 -5
  57. package/lib/typescript/ota/types.d.ts.map +1 -1
  58. package/package.json +3 -2
  59. package/react-native-bspatch.podspec +3 -1
  60. package/src/NativeBsPatch.ts +34 -2
  61. package/src/index.ts +5 -1
  62. package/src/ota/OtaProvider.tsx +115 -24
  63. package/src/ota/eligibility.ts +48 -0
  64. package/src/ota/entrySignature.ts +31 -0
  65. package/src/ota/installId.ts +18 -0
  66. package/src/ota/otaCore.ts +102 -21
  67. package/src/ota/storage/{GitHubRawStorage.ts → R2Storage.ts} +17 -13
  68. package/src/ota/types.ts +49 -5
  69. package/tools/build_ota.sh +343 -116
  70. package/tools/doctor.js +130 -0
  71. package/tools/ensure_signing_key.js +216 -0
  72. package/tools/fingerprint.js +111 -0
  73. package/tools/ios_fingerprint.sh +9 -0
  74. package/tools/ota_admin.js +131 -0
  75. package/tools/setup_project.js +41 -15
  76. package/tools/update_registry.js +111 -11
  77. package/tools/upload_ota.sh +85 -184
  78. package/tools/verify_publish.js +81 -0
  79. package/lib/commonjs/ota/storage/GitHubRawStorage.js.map +0 -1
  80. package/lib/module/ota/storage/GitHubRawStorage.js.map +0 -1
  81. package/lib/typescript/ota/storage/GitHubRawStorage.d.ts.map +0 -1
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * verify_publish.js — after upload, read the release back the way the app will: through
4
+ * OTA_BASE_URL. Catches an app pointed at another bucket, a CDN serving a stale registry,
5
+ * a missing file, or an entry that doesn't verify against the signing key.
6
+ *
7
+ * Usage: node verify_publish.js <projectRoot> <baseUrl> <baseFolder> <appVersion> <flavor> <platform> <version>
8
+ * stdout: one status line. stderr: the first line is the error; exit 1.
9
+ */
10
+
11
+ const crypto = require('crypto');
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+
15
+ const [root, baseUrl, folder, appVersion, flavor, platform, versionStr] = process.argv.slice(2);
16
+ const version = Number(versionStr);
17
+ const base = `${baseUrl.replace(/\/$/, '')}/${folder}`;
18
+
19
+ const fail = (message, detail = '') => {
20
+ console.error(message + (detail ? `\n${detail}` : ''));
21
+ process.exit(1);
22
+ };
23
+
24
+ /** Must stay equal to update_registry.js / src/ota/entrySignature.ts */
25
+ const entryPayload = e =>
26
+ [
27
+ 'bspatch-entry-v2', e.appVersion, e.flavor ?? '', e.platform ?? '', e.fromVersion, e.toVersion,
28
+ e.bundleHash ?? '', e.assetManifestHash ?? '', e.minAppVersion ?? '', e.runtimeFingerprint ?? '',
29
+ e.hermesBytecodeVersion ?? '',
30
+ ].join('\n');
31
+
32
+ const get = async (url, method = 'GET') => {
33
+ const res = await fetch(url, { method, headers: { 'Cache-Control': 'no-cache' }, signal: AbortSignal.timeout(20000) });
34
+ if (!res.ok) throw new Error(`HTTP ${res.status} for ${url}`);
35
+ return res;
36
+ };
37
+
38
+ (async () => {
39
+ let registry;
40
+ try {
41
+ registry = await (await get(`${base}/ota_registry.json?cb=${Date.now()}`)).json();
42
+ } catch (e) {
43
+ fail(`OTA_BASE_URL doesn't serve the registry: ${e.message}`);
44
+ }
45
+ const group = registry?.apps?.[appVersion]?.flavors?.[flavor];
46
+ const entries = (group?.patches || []).filter(e => e.platform === platform && e.toVersion === version);
47
+ if (!entries.length) {
48
+ fail(
49
+ `${new URL(baseUrl).host} doesn't serve ${platform} v${version}: the app reads another bucket or a stale cache`,
50
+ ` It serves latest v${group?.latestOtaVersion ?? '?'} for ${appVersion}/${flavor}. Check OTA_BASE_URL in .env.${flavor} ` +
51
+ 'against the bucket this upload went to (R2 → bucket → Settings → Custom Domains / Public URL).',
52
+ );
53
+ }
54
+
55
+ const keyPem = process.env.OTA_PRIVATE_KEY ||
56
+ (fs.existsSync(path.join(root, 'ota_private_key.pem')) && fs.readFileSync(path.join(root, 'ota_private_key.pem'), 'utf8'));
57
+ if (keyPem) {
58
+ const publicKey = crypto.createPublicKey(keyPem);
59
+ for (const e of entries) {
60
+ const ok = e.entrySignature &&
61
+ crypto.createVerify('SHA256').update(entryPayload(e)).verify(publicKey, e.entrySignature, 'base64');
62
+ if (!ok) fail(`The served entry ${e.id} doesn't verify against the signing key`);
63
+ }
64
+ }
65
+
66
+ // Every file a client of this version may fetch
67
+ const files = new Set();
68
+ for (const e of entries) {
69
+ files.add(e.fullBundleUrl);
70
+ if (e.filename) files.add(e.filename);
71
+ if (e.assetManifestUrl) files.add(e.assetManifestUrl);
72
+ }
73
+ for (const file of files) {
74
+ try {
75
+ await get(`${base}/${appVersion}/${flavor}/${file}`, 'HEAD');
76
+ } catch (e) {
77
+ fail(`Uploaded but not served: ${file}`, ` ${e.message}`);
78
+ }
79
+ }
80
+ console.log(`live at ${new URL(baseUrl).host}`);
81
+ })().catch(e => fail(`Verify failed: ${e.message}`));
@@ -1 +0,0 @@
1
- {"version":3,"names":["NO_CACHE_HEADERS","fetchJson","url","timeoutMs","controller","AbortController","timer","setTimeout","abort","res","fetch","headers","signal","ok","Error","status","json","clearTimeout","exports","bustCache","Date","now","normalizeChannel","channel","lower","toLowerCase","GitHubRawStorageProvider","fetchManifest","config","customServer","baseUrl","baseFolder","channelName","normalizedBaseUrl","endsWith","slice","registryUrl","registry","appVersion","appGroup","apps","flavorGroup","flavors","patches","error","message","getUpdateFileUrl","filename","getAssetUrl","hash","ext"],"sourceRoot":"../../../../src","sources":["ota/storage/GitHubRawStorage.ts"],"mappings":"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","ignoreList":[]}
@@ -1 +0,0 @@
1
- {"version":3,"names":["NO_CACHE_HEADERS","fetchJson","url","timeoutMs","controller","AbortController","timer","setTimeout","abort","res","fetch","headers","signal","ok","Error","status","json","clearTimeout","bustCache","Date","now","normalizeChannel","channel","lower","toLowerCase","GitHubRawStorageProvider","fetchManifest","config","customServer","baseUrl","baseFolder","channelName","normalizedBaseUrl","endsWith","slice","registryUrl","registry","appVersion","appGroup","apps","flavorGroup","flavors","patches","error","message","getUpdateFileUrl","filename","getAssetUrl","hash","ext"],"sourceRoot":"../../../../src","sources":["ota/storage/GitHubRawStorage.ts"],"mappings":"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","ignoreList":[]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"GitHubRawStorage.d.ts","sourceRoot":"","sources":["../../../../src/ota/storage/GitHubRawStorage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAmBxE,uFAAuF;AACvF,eAAO,MAAM,SAAS,GAAU,KAAK,MAAM,EAAE,WAAW,MAAM,KAAG,OAAO,CAAC,GAAG,CAY3E,CAAC;AAaF,qBAAa,wBAAyB,YAAW,kBAAkB;IACzD,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAiCrD,gBAAgB,CAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,GAClB,OAAO,CAAC,MAAM,CAAC;IAeZ,WAAW,CACb,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,SAAS,GAClB,OAAO,CAAC,MAAM,CAAC;CAWrB"}