@bravemobile/react-native-code-push 12.3.2 → 12.4.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 (78) hide show
  1. package/CodePush.podspec +0 -2
  2. package/README.md +4 -2
  3. package/android/app/build.gradle +0 -1
  4. package/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java +0 -35
  5. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushConstants.java +0 -1
  6. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java +1 -1
  7. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java +1 -28
  8. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java +1 -99
  9. package/cli/commands/bundleCommand/bundleCodePush.ts +29 -0
  10. package/cli/commands/bundleCommand/index.ts +3 -0
  11. package/cli/commands/releaseCommand/index.ts +3 -0
  12. package/cli/commands/releaseCommand/release.ts +2 -1
  13. package/cli/dist/commands/bundleCommand/bundleCodePush.js +14 -1
  14. package/cli/dist/commands/bundleCommand/index.js +2 -1
  15. package/cli/dist/commands/releaseCommand/index.js +2 -1
  16. package/cli/dist/commands/releaseCommand/release.js +2 -2
  17. package/cli/dist/utils/hash-utils.js +1 -4
  18. package/cli/utils/hash-utils.ts +1 -4
  19. package/ios/CodePush/CodePush.h +0 -16
  20. package/ios/CodePush/CodePush.m +0 -12
  21. package/ios/CodePush/CodePushConfig.m +0 -10
  22. package/ios/CodePush/CodePushPackage.m +0 -39
  23. package/ios/CodePush/CodePushUpdateUtils.m +1 -91
  24. package/ios/CodePush.xcodeproj/project.pbxproj +0 -324
  25. package/package.json +1 -1
  26. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushInvalidPublicKeyException.java +0 -12
  27. package/ios/CodePush/Base64/Base64/MF_Base64Additions.h +0 -34
  28. package/ios/CodePush/Base64/Base64/MF_Base64Additions.m +0 -252
  29. package/ios/CodePush/Base64/README.md +0 -47
  30. package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithm.h +0 -69
  31. package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmFactory.h +0 -16
  32. package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmFactory.m +0 -51
  33. package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmNone.h +0 -15
  34. package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmNone.m +0 -55
  35. package/ios/CodePush/JWT/Core/Algorithms/ESFamily/JWTAlgorithmESBase.h +0 -24
  36. package/ios/CodePush/JWT/Core/Algorithms/ESFamily/JWTAlgorithmESBase.m +0 -41
  37. package/ios/CodePush/JWT/Core/Algorithms/HSFamily/JWTAlgorithmHSBase.h +0 -28
  38. package/ios/CodePush/JWT/Core/Algorithms/HSFamily/JWTAlgorithmHSBase.m +0 -205
  39. package/ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolder.h +0 -103
  40. package/ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolder.m +0 -322
  41. package/ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolderChain.h +0 -37
  42. package/ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolderChain.m +0 -145
  43. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/JWTAlgorithmRSBase.h +0 -35
  44. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/JWTAlgorithmRSBase.m +0 -551
  45. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/JWTRSAlgorithm.h +0 -23
  46. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKey.h +0 -43
  47. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKey.m +0 -230
  48. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKeyExtractor.h +0 -31
  49. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKeyExtractor.m +0 -113
  50. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.h +0 -38
  51. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m +0 -500
  52. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaim.h +0 -18
  53. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaim.m +0 -214
  54. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSet.h +0 -23
  55. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSet.m +0 -29
  56. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetSerializer.h +0 -19
  57. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetSerializer.m +0 -68
  58. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetVerifier.h +0 -18
  59. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetVerifier.m +0 -72
  60. package/ios/CodePush/JWT/Core/Coding/JWTCoding+ResultTypes.h +0 -67
  61. package/ios/CodePush/JWT/Core/Coding/JWTCoding+ResultTypes.m +0 -111
  62. package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionOne.h +0 -119
  63. package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionOne.m +0 -307
  64. package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionThree.h +0 -94
  65. package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionThree.m +0 -619
  66. package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionTwo.h +0 -164
  67. package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionTwo.m +0 -514
  68. package/ios/CodePush/JWT/Core/Coding/JWTCoding.h +0 -24
  69. package/ios/CodePush/JWT/Core/Coding/JWTCoding.m +0 -11
  70. package/ios/CodePush/JWT/Core/FrameworkSupplement/JWT.h +0 -52
  71. package/ios/CodePush/JWT/Core/FrameworkSupplement/Map.modulemap +0 -5
  72. package/ios/CodePush/JWT/Core/Supplement/JWTBase64Coder.h +0 -28
  73. package/ios/CodePush/JWT/Core/Supplement/JWTBase64Coder.m +0 -70
  74. package/ios/CodePush/JWT/Core/Supplement/JWTDeprecations.h +0 -22
  75. package/ios/CodePush/JWT/Core/Supplement/JWTErrorDescription.h +0 -34
  76. package/ios/CodePush/JWT/Core/Supplement/JWTErrorDescription.m +0 -73
  77. package/ios/CodePush/JWT/LICENSE +0 -19
  78. package/ios/CodePush/JWT/README.md +0 -489
package/CodePush.podspec CHANGED
@@ -22,6 +22,4 @@ Pod::Spec.new do |s|
22
22
  # linked properly at a parent workspace level.
23
23
  s.dependency 'React-Core'
24
24
  s.dependency 'SSZipArchive', '~> 2.5.5'
25
- s.dependency 'JWT', '~> 3.0.0-beta.12'
26
- s.dependency 'Base64', '~> 1.1'
27
25
  end
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ### 🚀 New Architecture support
10
10
 
11
- Supports React Native 0.74 ~ 0.84.
11
+ Supports React Native 0.77 ~ 0.84.
12
12
 
13
13
  > [!NOTE]
14
14
  > If you are using React Native 0.76 or lower, please use version `12.0.2` of this library.
@@ -17,7 +17,7 @@ Supports React Native 0.74 ~ 0.84.
17
17
 
18
18
  ### ✅ Requirements
19
19
 
20
- - **React Native**: 0.74 or higher
20
+ - **React Native**: 0.77 or higher
21
21
  - **iOS**: 15.5 or higher
22
22
  - **Android**: API level 16 or higher
23
23
 
@@ -397,6 +397,8 @@ module.exports = Config;
397
397
 
398
398
  > [!TIP]
399
399
  > You can use `--help` command to see the available commands and options.
400
+ >
401
+ > For detailed documentation, see the [CLI README](cli/README.md) ([한국어](cli/README.ko.md)).
400
402
 
401
403
  (interactive mode not supported yet)
402
404
 
@@ -29,5 +29,4 @@ android {
29
29
 
30
30
  dependencies {
31
31
  implementation "com.facebook.react:react-native:+"
32
- implementation 'com.nimbusds:nimbus-jose-jwt:9.37.3'
33
32
  }
@@ -3,10 +3,8 @@ package com.microsoft.codepush.react;
3
3
  import android.content.Context;
4
4
  import android.content.pm.PackageInfo;
5
5
  import android.content.pm.PackageManager;
6
- import android.content.res.Resources;
7
6
 
8
7
  import com.facebook.react.ReactPackage;
9
- import com.facebook.react.bridge.JavaScriptModule;
10
8
  import com.facebook.react.bridge.NativeModule;
11
9
  import com.facebook.react.bridge.ReactApplicationContext;
12
10
  import com.facebook.react.uimanager.ViewManager;
@@ -40,8 +38,6 @@ public class CodePush implements ReactPackage {
40
38
  private Context mContext;
41
39
  private final boolean mIsDebugMode;
42
40
 
43
- private static String mPublicKey;
44
-
45
41
  private static CodePush mCurrentInstance;
46
42
 
47
43
  public static String getServiceUrl() {
@@ -75,33 +71,12 @@ public class CodePush implements ReactPackage {
75
71
 
76
72
  mCurrentInstance = this;
77
73
 
78
- String publicKeyFromStrings = getCustomPropertyFromStringsIfExist("PublicKey");
79
- if (publicKeyFromStrings != null) mPublicKey = publicKeyFromStrings;
80
-
81
74
  String serverUrlFromStrings = getCustomPropertyFromStringsIfExist("ServerUrl");
82
75
  if (serverUrlFromStrings != null) mServerUrl = serverUrlFromStrings;
83
76
 
84
77
  initializeUpdateAfterRestart();
85
78
  }
86
79
 
87
- private String getPublicKeyByResourceDescriptor(int publicKeyResourceDescriptor){
88
- String publicKey;
89
- try {
90
- publicKey = mContext.getString(publicKeyResourceDescriptor);
91
- } catch (Resources.NotFoundException e) {
92
- throw new CodePushInvalidPublicKeyException(
93
- "Unable to get public key, related resource descriptor " +
94
- publicKeyResourceDescriptor +
95
- " can not be found", e
96
- );
97
- }
98
-
99
- if (publicKey.isEmpty()) {
100
- throw new CodePushInvalidPublicKeyException("Specified public key is empty");
101
- }
102
- return publicKey;
103
- }
104
-
105
80
  private String getCustomPropertyFromStringsIfExist(String propertyName) {
106
81
  String property;
107
82
 
@@ -133,10 +108,6 @@ public class CodePush implements ReactPackage {
133
108
  return mAssetsBundleFileName;
134
109
  }
135
110
 
136
- public String getPublicKey() {
137
- return mPublicKey;
138
- }
139
-
140
111
  public String getPackageFolder() {
141
112
  JSONObject codePushLocalPackage = mUpdateManager.getCurrentPackage();
142
113
  if (codePushLocalPackage == null) {
@@ -338,12 +309,6 @@ public class CodePush implements ReactPackage {
338
309
  nativeModules.add(dialogModule);
339
310
  return nativeModules;
340
311
  }
341
-
342
- // Deprecated in RN v0.47.
343
- public List<Class<? extends JavaScriptModule>> createJSModules() {
344
- return new ArrayList<>();
345
- }
346
-
347
312
  @Override
348
313
  public List<ViewManager> createViewManagers(ReactApplicationContext reactApplicationContext) {
349
314
  return new ArrayList<>();
@@ -24,7 +24,6 @@ public class CodePushConstants {
24
24
  public static final String RELATIVE_BUNDLE_PATH_KEY = "bundlePath";
25
25
  public static final String STATUS_FILE = "codepush.json";
26
26
  public static final String UNZIPPED_FOLDER_NAME = "unzipped";
27
- public static final String BUNDLE_JWT_FILE = ".codepushrelease";
28
27
  public static final String LATEST_ROLLBACK_INFO_KEY = "LATEST_ROLLBACK_INFO";
29
28
  public static final String LATEST_ROLLBACK_PACKAGE_HASH_KEY = "packageHash";
30
29
  public static final String LATEST_ROLLBACK_TIME_KEY = "time";
@@ -384,7 +384,7 @@ public class CodePushNativeModule extends ReactContextBaseJavaModule {
384
384
  .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
385
385
  .emit(CodePushConstants.DOWNLOAD_PROGRESS_EVENT_NAME, latestDownloadProgress.createWritableMap());
386
386
  }
387
- }, mCodePush.getPublicKey());
387
+ });
388
388
 
389
389
  JSONObject newPackage = mUpdateManager.getPackage(CodePushUtils.tryGetString(updatePackage, CodePushConstants.PACKAGE_HASH_KEY));
390
390
  promise.resolve(CodePushUtils.convertJsonObjectToWritable(newPackage));
@@ -144,8 +144,7 @@ public class CodePushUpdateManager {
144
144
  }
145
145
 
146
146
  public void downloadPackage(JSONObject updatePackage, String expectedBundleFileName,
147
- DownloadProgressCallback progressCallback,
148
- String stringPublicKey) throws IOException {
147
+ DownloadProgressCallback progressCallback) throws IOException {
149
148
  String newUpdateHash = updatePackage.optString(CodePushConstants.PACKAGE_HASH_KEY, null);
150
149
  String newUpdateFolderPath = getPackageFolderPath(newUpdateHash);
151
150
  String newUpdateMetadataPath = CodePushUtils.appendPathComponent(newUpdateFolderPath, CodePushConstants.PACKAGE_FILE_NAME);
@@ -266,32 +265,6 @@ public class CodePushUpdateManager {
266
265
  }
267
266
 
268
267
  CodePushUpdateUtils.verifyFolderHash(newUpdateFolderPath, newUpdateHash);
269
-
270
- boolean isSignatureVerificationEnabled = (stringPublicKey != null);
271
-
272
- String signaturePath = CodePushUpdateUtils.getSignatureFilePath(newUpdateFolderPath);
273
- boolean isSignatureAppearedInBundle = FileUtils.fileAtPathExists(signaturePath);
274
-
275
- if (isSignatureVerificationEnabled) {
276
- if (isSignatureAppearedInBundle) {
277
- CodePushUpdateUtils.verifyUpdateSignature(newUpdateFolderPath, newUpdateHash, stringPublicKey);
278
- } else {
279
- throw new CodePushInvalidUpdateException(
280
- "Error! Public key was provided but there is no JWT signature within app bundle to verify. " +
281
- "Possible reasons, why that might happen: \n" +
282
- "1. You've been released CodePush bundle update using version of CodePush CLI that is not support code signing.\n" +
283
- "2. You've been released CodePush bundle update without providing --privateKeyPath option."
284
- );
285
- }
286
- } else {
287
- if (isSignatureAppearedInBundle) {
288
- CodePushUtils.log(
289
- "Warning! JWT signature exists in codepush update but code integrity check couldn't be performed because there is no public key configured. " +
290
- "Please ensure that public key is properly configured within your application."
291
- );
292
- }
293
- }
294
-
295
268
  CodePushUtils.setJSONValueForKey(updatePackage, CodePushConstants.RELATIVE_BUNDLE_PATH_KEY, relativeBundlePath);
296
269
  }
297
270
  } else {
@@ -1,13 +1,6 @@
1
1
  package com.microsoft.codepush.react;
2
2
 
3
3
  import android.content.Context;
4
- import android.util.Base64;
5
-
6
- import com.nimbusds.jose.JWSVerifier;
7
- import com.nimbusds.jose.crypto.RSASSAVerifier;
8
- import com.nimbusds.jwt.SignedJWT;
9
-
10
- import java.security.interfaces.*;
11
4
 
12
5
  import org.json.JSONArray;
13
6
  import org.json.JSONException;
@@ -20,14 +13,10 @@ import java.io.FileNotFoundException;
20
13
  import java.io.IOException;
21
14
  import java.io.InputStream;
22
15
  import java.security.DigestInputStream;
23
- import java.security.KeyFactory;
24
16
  import java.security.MessageDigest;
25
17
  import java.security.NoSuchAlgorithmException;
26
- import java.security.PublicKey;
27
- import java.security.spec.X509EncodedKeySpec;
28
18
  import java.util.ArrayList;
29
19
  import java.util.Collections;
30
- import java.util.Map;
31
20
 
32
21
  public class CodePushUpdateUtils {
33
22
 
@@ -38,13 +27,10 @@ public class CodePushUpdateUtils {
38
27
  public static boolean isHashIgnored(String relativeFilePath) {
39
28
  final String __MACOSX = "__MACOSX/";
40
29
  final String DS_STORE = ".DS_Store";
41
- final String CODEPUSH_METADATA = ".codepushrelease";
42
30
 
43
31
  return relativeFilePath.startsWith(__MACOSX)
44
32
  || relativeFilePath.equals(DS_STORE)
45
- || relativeFilePath.endsWith("/" + DS_STORE)
46
- || relativeFilePath.equals(CODEPUSH_METADATA)
47
- || relativeFilePath.endsWith("/" + CODEPUSH_METADATA);
33
+ || relativeFilePath.endsWith("/" + DS_STORE);
48
34
  }
49
35
 
50
36
  private static void addContentsOfFolderToManifest(String folderPath, String pathPrefix, ArrayList<String> manifest) {
@@ -183,88 +169,4 @@ public class CodePushUpdateUtils {
183
169
  CodePushUtils.log("The update contents succeeded the data integrity check.");
184
170
  }
185
171
 
186
- public static Map<String, Object> verifyAndDecodeJWT(String jwt, PublicKey publicKey) {
187
- try {
188
- SignedJWT signedJWT = SignedJWT.parse(jwt);
189
- JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) publicKey);
190
- if (signedJWT.verify(verifier)) {
191
- Map<String, Object> claims = signedJWT.getJWTClaimsSet().getClaims();
192
- CodePushUtils.log("JWT verification succeeded, payload content: " + claims.toString());
193
- return claims;
194
- }
195
- return null;
196
- } catch (Exception ex) {
197
- CodePushUtils.log(ex.getMessage());
198
- CodePushUtils.log(ex.getStackTrace().toString());
199
- return null;
200
- }
201
- }
202
-
203
- public static PublicKey parsePublicKey(String stringPublicKey) {
204
- try {
205
- //remove unnecessary "begin/end public key" entries from string
206
- stringPublicKey = stringPublicKey
207
- .replace("-----BEGIN PUBLIC KEY-----", "")
208
- .replace("-----END PUBLIC KEY-----", "")
209
- .replace(NEW_LINE, "");
210
- byte[] byteKey = Base64.decode(stringPublicKey.getBytes(), Base64.DEFAULT);
211
- X509EncodedKeySpec X509Key = new X509EncodedKeySpec(byteKey);
212
- KeyFactory kf = KeyFactory.getInstance("RSA");
213
-
214
- return kf.generatePublic(X509Key);
215
- } catch (Exception e) {
216
- CodePushUtils.log(e.getMessage());
217
- CodePushUtils.log(e.getStackTrace().toString());
218
- return null;
219
- }
220
- }
221
-
222
- public static String getSignatureFilePath(String updateFolderPath) {
223
- return CodePushUtils.appendPathComponent(
224
- CodePushUtils.appendPathComponent(updateFolderPath, CodePushConstants.CODE_PUSH_FOLDER_PREFIX),
225
- CodePushConstants.BUNDLE_JWT_FILE
226
- );
227
- }
228
-
229
- public static String getSignature(String folderPath) {
230
- final String signatureFilePath = getSignatureFilePath(folderPath);
231
-
232
- try {
233
- return FileUtils.readFileToString(signatureFilePath);
234
- } catch (IOException e) {
235
- CodePushUtils.log(e.getMessage());
236
- CodePushUtils.log(e.getStackTrace().toString());
237
- return null;
238
- }
239
- }
240
-
241
- public static void verifyUpdateSignature(String folderPath, String packageHash, String stringPublicKey) throws CodePushInvalidUpdateException {
242
- CodePushUtils.log("Verifying signature for folder path: " + folderPath);
243
-
244
- final PublicKey publicKey = parsePublicKey(stringPublicKey);
245
- if (publicKey == null) {
246
- throw new CodePushInvalidUpdateException("The update could not be verified because no public key was found.");
247
- }
248
-
249
- final String signature = getSignature(folderPath);
250
- if (signature == null) {
251
- throw new CodePushInvalidUpdateException("The update could not be verified because no signature was found.");
252
- }
253
-
254
- final Map<String, Object> claims = verifyAndDecodeJWT(signature, publicKey);
255
- if (claims == null) {
256
- throw new CodePushInvalidUpdateException("The update could not be verified because it was not signed by a trusted party.");
257
- }
258
-
259
- final String contentHash = (String) claims.get("contentHash");
260
- if (contentHash == null) {
261
- throw new CodePushInvalidUpdateException("The update could not be verified because the signature did not specify a content hash.");
262
- }
263
-
264
- if (!contentHash.equals(packageHash)) {
265
- throw new CodePushInvalidUpdateException("The update contents failed the code signing check.");
266
- }
267
-
268
- CodePushUtils.log("The update contents succeeded the code signing check.");
269
- }
270
172
  }
@@ -1,4 +1,5 @@
1
1
  import fs from "fs";
2
+ import path from "path";
2
3
  import { prepareToBundleJS } from "../../functions/prepareToBundleJS.js";
3
4
  import { runReactNativeBundleCommand } from "../../functions/runReactNativeBundleCommand.js";
4
5
  import { runExpoBundleCommand } from "../../functions/runExpoBundleCommand.js";
@@ -17,6 +18,7 @@ export async function bundleCodePush(
17
18
  entryFile: string = ENTRY_FILE,
18
19
  jsBundleName: string, // JS bundle file name (not CodePush bundle file)
19
20
  bundleDirectory: string, // CodePush bundle output directory
21
+ outputMetroDir?: string,
20
22
  ): Promise<string> {
21
23
  if (fs.existsSync(outputRootPath)) {
22
24
  fs.rmSync(outputRootPath, { recursive: true });
@@ -49,6 +51,8 @@ export async function bundleCodePush(
49
51
 
50
52
  console.log('log: JS bundling complete');
51
53
 
54
+ copyMetroOutputsIfNeeded(outputRootPath, outputMetroDir, OUTPUT_CONTENT_PATH, _jsBundleName, SOURCEMAP_OUTPUT);
55
+
52
56
  await runHermesEmitBinaryCommand(
53
57
  _jsBundleName,
54
58
  OUTPUT_CONTENT_PATH,
@@ -61,3 +65,28 @@ export async function bundleCodePush(
61
65
 
62
66
  return codePushBundleFileName;
63
67
  }
68
+
69
+ function copyMetroOutputsIfNeeded(
70
+ outputRootPath: string,
71
+ outputMetroDir: string | undefined,
72
+ outputContentPath: string,
73
+ jsBundleName: string,
74
+ sourceMapOutputPath: string,
75
+ ) {
76
+ if (!outputMetroDir) {
77
+ return;
78
+ }
79
+
80
+ const resolvedOutputMetroDir = path.join(outputRootPath, outputMetroDir);
81
+
82
+ fs.mkdirSync(resolvedOutputMetroDir, { recursive: true });
83
+ fs.copyFileSync(
84
+ path.join(outputContentPath, jsBundleName),
85
+ path.join(resolvedOutputMetroDir, jsBundleName),
86
+ );
87
+ fs.copyFileSync(
88
+ sourceMapOutputPath,
89
+ path.join(resolvedOutputMetroDir, path.basename(sourceMapOutputPath)),
90
+ );
91
+ console.log(`log: Metro outputs copied to: ${resolvedOutputMetroDir}`);
92
+ }
@@ -9,6 +9,7 @@ type Options = {
9
9
  entryFile: string;
10
10
  bundleName: string;
11
11
  outputBundleDir: string;
12
+ outputMetroDir?: string;
12
13
  }
13
14
 
14
15
  program.command('bundle')
@@ -18,6 +19,7 @@ program.command('bundle')
18
19
  .option('-o, --output-path <string>', 'path to output root directory', ROOT_OUTPUT_DIR)
19
20
  .option('-e, --entry-file <string>', 'path to JS/TS entry file', ENTRY_FILE)
20
21
  .option('-b, --bundle-name <string>', 'bundle file name (default-ios: "main.jsbundle" / default-android: "index.android.bundle")')
22
+ .option('--output-metro-dir <string>', 'name of directory to copy the Metro JS bundle and sourcemap before Hermes compilation')
21
23
  .option('--output-bundle-dir <string>', 'name of directory containing the bundle file created by the "bundle" command', OUTPUT_BUNDLE_DIR)
22
24
  .action((options: Options) => {
23
25
  bundleCodePush(
@@ -27,5 +29,6 @@ program.command('bundle')
27
29
  options.entryFile,
28
30
  options.bundleName,
29
31
  `${options.outputPath}/${options.outputBundleDir}`,
32
+ options.outputMetroDir,
30
33
  )
31
34
  });
@@ -19,6 +19,7 @@ type Options = {
19
19
  skipBundle: boolean;
20
20
  skipCleanup: boolean;
21
21
  outputBundleDir: string;
22
+ outputMetroDir?: string;
22
23
  hashCalc?: boolean;
23
24
  }
24
25
 
@@ -39,6 +40,7 @@ program.command('release')
39
40
  .option('--skip-bundle <bool>', 'skip bundle process', parseBoolean, false)
40
41
  .option('--hash-calc <bool>', 'calculates the bundle file hash used for packageHash in the release history (Requires setting --skip-bundle to true)', parseBoolean)
41
42
  .option('--skip-cleanup <bool>', 'skip cleanup process', parseBoolean, false)
43
+ .option('--output-metro-dir <string>', 'name of directory to copy the Metro JS bundle and sourcemap before Hermes compilation')
42
44
  .option('--output-bundle-dir <string>', 'name of directory containing the bundle file created by the "bundle" command', OUTPUT_BUNDLE_DIR)
43
45
  .action(async (options: Options) => {
44
46
  const config = findAndReadConfigFile(process.cwd(), options.config);
@@ -71,6 +73,7 @@ program.command('release')
71
73
  options.skipBundle,
72
74
  options.skipCleanup,
73
75
  `${options.outputPath}/${options.outputBundleDir}`,
76
+ options.outputMetroDir,
74
77
  options.hashCalc,
75
78
  )
76
79
 
@@ -24,11 +24,12 @@ export async function release(
24
24
  skipBundle: boolean,
25
25
  skipCleanup: boolean,
26
26
  bundleDirectory: string,
27
+ outputMetroDir?: string,
27
28
  hashCalc?: boolean,
28
29
  ): Promise<void> {
29
30
  const bundleFileName = skipBundle
30
31
  ? readBundleFileNameFrom(bundleDirectory)
31
- : await bundleCodePush(framework, platform, outputPath, entryFile, jsBundleName, bundleDirectory);
32
+ : await bundleCodePush(framework, platform, outputPath, entryFile, jsBundleName, bundleDirectory, outputMetroDir);
32
33
  const bundleFilePath = `${bundleDirectory}/${bundleFileName}`;
33
34
 
34
35
  const packageHash = await (() => {
@@ -1,4 +1,5 @@
1
1
  import fs from "fs";
2
+ import path from "path";
2
3
  import { prepareToBundleJS } from "../../functions/prepareToBundleJS.js";
3
4
  import { runReactNativeBundleCommand } from "../../functions/runReactNativeBundleCommand.js";
4
5
  import { runExpoBundleCommand } from "../../functions/runExpoBundleCommand.js";
@@ -10,7 +11,8 @@ import { ROOT_OUTPUT_DIR, ENTRY_FILE } from "../../constant.js";
10
11
  * @return {Promise<string>} CodePush bundle file name (equals to packageHash)
11
12
  */
12
13
  export async function bundleCodePush(framework, platform = 'ios', outputRootPath = ROOT_OUTPUT_DIR, entryFile = ENTRY_FILE, jsBundleName, // JS bundle file name (not CodePush bundle file)
13
- bundleDirectory) {
14
+ bundleDirectory, // CodePush bundle output directory
15
+ outputMetroDir) {
14
16
  if (fs.existsSync(outputRootPath)) {
15
17
  fs.rmSync(outputRootPath, { recursive: true });
16
18
  }
@@ -26,9 +28,20 @@ bundleDirectory) {
26
28
  runReactNativeBundleCommand(_jsBundleName, OUTPUT_CONTENT_PATH, platform, SOURCEMAP_OUTPUT, entryFile);
27
29
  }
28
30
  console.log('log: JS bundling complete');
31
+ copyMetroOutputsIfNeeded(outputRootPath, outputMetroDir, OUTPUT_CONTENT_PATH, _jsBundleName, SOURCEMAP_OUTPUT);
29
32
  await runHermesEmitBinaryCommand(_jsBundleName, OUTPUT_CONTENT_PATH, SOURCEMAP_OUTPUT);
30
33
  console.log('log: Hermes compilation complete');
31
34
  const { bundleFileName: codePushBundleFileName } = await makeCodePushBundle(OUTPUT_CONTENT_PATH, bundleDirectory);
32
35
  console.log(`log: CodePush bundle created (file path: ./${bundleDirectory}/${codePushBundleFileName})`);
33
36
  return codePushBundleFileName;
34
37
  }
38
+ function copyMetroOutputsIfNeeded(outputRootPath, outputMetroDir, outputContentPath, jsBundleName, sourceMapOutputPath) {
39
+ if (!outputMetroDir) {
40
+ return;
41
+ }
42
+ const resolvedOutputMetroDir = path.join(outputRootPath, outputMetroDir);
43
+ fs.mkdirSync(resolvedOutputMetroDir, { recursive: true });
44
+ fs.copyFileSync(path.join(outputContentPath, jsBundleName), path.join(resolvedOutputMetroDir, jsBundleName));
45
+ fs.copyFileSync(sourceMapOutputPath, path.join(resolvedOutputMetroDir, path.basename(sourceMapOutputPath)));
46
+ console.log(`log: Metro outputs copied to: ${resolvedOutputMetroDir}`);
47
+ }
@@ -8,7 +8,8 @@ program.command('bundle')
8
8
  .option('-o, --output-path <string>', 'path to output root directory', ROOT_OUTPUT_DIR)
9
9
  .option('-e, --entry-file <string>', 'path to JS/TS entry file', ENTRY_FILE)
10
10
  .option('-b, --bundle-name <string>', 'bundle file name (default-ios: "main.jsbundle" / default-android: "index.android.bundle")')
11
+ .option('--output-metro-dir <string>', 'name of directory to copy the Metro JS bundle and sourcemap before Hermes compilation')
11
12
  .option('--output-bundle-dir <string>', 'name of directory containing the bundle file created by the "bundle" command', OUTPUT_BUNDLE_DIR)
12
13
  .action((options) => {
13
- bundleCodePush(options.framework, options.platform, options.outputPath, options.entryFile, options.bundleName, `${options.outputPath}/${options.outputBundleDir}`);
14
+ bundleCodePush(options.framework, options.platform, options.outputPath, options.entryFile, options.bundleName, `${options.outputPath}/${options.outputBundleDir}`, options.outputMetroDir);
14
15
  });
@@ -19,6 +19,7 @@ program.command('release')
19
19
  .option('--skip-bundle <bool>', 'skip bundle process', parseBoolean, false)
20
20
  .option('--hash-calc <bool>', 'calculates the bundle file hash used for packageHash in the release history (Requires setting --skip-bundle to true)', parseBoolean)
21
21
  .option('--skip-cleanup <bool>', 'skip cleanup process', parseBoolean, false)
22
+ .option('--output-metro-dir <string>', 'name of directory to copy the Metro JS bundle and sourcemap before Hermes compilation')
22
23
  .option('--output-bundle-dir <string>', 'name of directory containing the bundle file created by the "bundle" command', OUTPUT_BUNDLE_DIR)
23
24
  .action(async (options) => {
24
25
  const config = findAndReadConfigFile(process.cwd(), options.config);
@@ -30,7 +31,7 @@ program.command('release')
30
31
  console.error('--hash-calc option can be used only when --skip-bundle is set to true.');
31
32
  process.exit(1);
32
33
  }
33
- await release(config.bundleUploader, config.getReleaseHistory, config.setReleaseHistory, options.binaryVersion, options.appVersion, options.framework, options.platform, options.identifier, options.outputPath, options.entryFile, options.bundleName, options.mandatory, options.enable, options.rollout, options.skipBundle, options.skipCleanup, `${options.outputPath}/${options.outputBundleDir}`, options.hashCalc);
34
+ await release(config.bundleUploader, config.getReleaseHistory, config.setReleaseHistory, options.binaryVersion, options.appVersion, options.framework, options.platform, options.identifier, options.outputPath, options.entryFile, options.bundleName, options.mandatory, options.enable, options.rollout, options.skipBundle, options.skipCleanup, `${options.outputPath}/${options.outputBundleDir}`, options.outputMetroDir, options.hashCalc);
34
35
  console.log('🚀 Release completed.');
35
36
  });
36
37
  function parseBoolean(value) {
@@ -4,10 +4,10 @@ import { bundleCodePush } from "../bundleCommand/bundleCodePush.js";
4
4
  import { addToReleaseHistory } from "./addToReleaseHistory.js";
5
5
  import { generatePackageHashFromDirectory } from "../../utils/hash-utils.js";
6
6
  import { unzip } from "../../utils/unzip.js";
7
- export async function release(bundleUploader, getReleaseHistory, setReleaseHistory, binaryVersion, appVersion, framework, platform, identifier, outputPath, entryFile, jsBundleName, mandatory, enable, rollout, skipBundle, skipCleanup, bundleDirectory, hashCalc) {
7
+ export async function release(bundleUploader, getReleaseHistory, setReleaseHistory, binaryVersion, appVersion, framework, platform, identifier, outputPath, entryFile, jsBundleName, mandatory, enable, rollout, skipBundle, skipCleanup, bundleDirectory, outputMetroDir, hashCalc) {
8
8
  const bundleFileName = skipBundle
9
9
  ? readBundleFileNameFrom(bundleDirectory)
10
- : await bundleCodePush(framework, platform, outputPath, entryFile, jsBundleName, bundleDirectory);
10
+ : await bundleCodePush(framework, platform, outputPath, entryFile, jsBundleName, bundleDirectory, outputMetroDir);
11
11
  const bundleFilePath = `${bundleDirectory}/${bundleFileName}`;
12
12
  const packageHash = await (() => {
13
13
  if (skipBundle && hashCalc) {
@@ -48,12 +48,9 @@ class PackageManifest {
48
48
  static isIgnored(relativeFilePath) {
49
49
  const __MACOSX = '__MACOSX/';
50
50
  const DS_STORE = '.DS_Store';
51
- const CODEPUSH_METADATA = '.codepushrelease';
52
51
  return (relativeFilePath.startsWith(__MACOSX) ||
53
52
  relativeFilePath === DS_STORE ||
54
- relativeFilePath.endsWith('/' + DS_STORE) ||
55
- relativeFilePath === CODEPUSH_METADATA ||
56
- relativeFilePath.endsWith('/' + CODEPUSH_METADATA));
53
+ relativeFilePath.endsWith('/' + DS_STORE));
57
54
  }
58
55
  }
59
56
  export async function generatePackageHashFromDirectory(directoryPath, basePath) {
@@ -61,13 +61,10 @@ class PackageManifest {
61
61
  static isIgnored(relativeFilePath: string): boolean {
62
62
  const __MACOSX = '__MACOSX/';
63
63
  const DS_STORE = '.DS_Store';
64
- const CODEPUSH_METADATA = '.codepushrelease';
65
64
  return (
66
65
  relativeFilePath.startsWith(__MACOSX) ||
67
66
  relativeFilePath === DS_STORE ||
68
- relativeFilePath.endsWith('/' + DS_STORE) ||
69
- relativeFilePath === CODEPUSH_METADATA ||
70
- relativeFilePath.endsWith('/' + CODEPUSH_METADATA)
67
+ relativeFilePath.endsWith('/' + DS_STORE)
71
68
  );
72
69
  }
73
70
  }
@@ -102,7 +102,6 @@
102
102
  @property (readonly) NSDictionary *configuration;
103
103
  @property (copy) NSString *deploymentKey;
104
104
  @property (copy) NSString *serverURL;
105
- @property (copy) NSString *publicKey;
106
105
 
107
106
  + (instancetype)current;
108
107
 
@@ -140,7 +139,6 @@ failCallback:(void (^)(NSError *err))failCallback;
140
139
 
141
140
  + (void)downloadPackage:(NSDictionary *)updatePackage
142
141
  expectedBundleFileName:(NSString *)expectedBundleFileName
143
- publicKey:(NSString *)publicKey
144
142
  operationQueue:(dispatch_queue_t)operationQueue
145
143
  progressCallback:(void (^)(long long, long long))progressCallback
146
144
  doneCallback:(void (^)())doneCallback
@@ -203,20 +201,6 @@ failCallback:(void (^)(NSError *err))failCallback;
203
201
  expectedHash:(NSString *)expectedHash
204
202
  error:(NSError **)error;
205
203
 
206
- // remove BEGIN / END tags and line breaks from public key string
207
- + (NSString *)getKeyValueFromPublicKeyString:(NSString *)publicKeyString;
208
-
209
- + (NSString *)getSignatureFilePath:(NSString *)updateFolderPath;
210
-
211
- + (NSDictionary *) verifyAndDecodeJWT:(NSString *) jwt
212
- withPublicKey:(NSString *)publicKey
213
- error:(NSError **)error;
214
-
215
- + (BOOL)verifyUpdateSignatureFor:(NSString *)updateFolderPath
216
- expectedHash:(NSString *)newUpdateHash
217
- withPublicKey:(NSString *)publicKeyString
218
- error:(NSError **)error;
219
-
220
204
  @end
221
205
 
222
206
  void CPLog(NSString *formatString, ...);
@@ -1,4 +1,3 @@
1
- #if __has_include(<React/RCTAssert.h>)
2
1
  #import <React/RCTAssert.h>
3
2
  #import <React/RCTBridgeModule.h>
4
3
  #import <React/RCTConvert.h>
@@ -6,14 +5,6 @@
6
5
  #import <React/RCTRootView.h>
7
6
  #import <React/RCTUtils.h>
8
7
  #import <React/RCTReloadCommand.h>
9
- #else // back compatibility for RN version < 0.40
10
- #import "RCTAssert.h"
11
- #import "RCTBridgeModule.h"
12
- #import "RCTConvert.h"
13
- #import "RCTEventDispatcher.h"
14
- #import "RCTRootView.h"
15
- #import "RCTUtils.h"
16
- #endif
17
8
 
18
9
  #import "CodePush.h"
19
10
 
@@ -740,12 +731,9 @@ RCT_EXPORT_METHOD(downloadUpdate:(NSDictionary*)updatePackage
740
731
  _lastProgressEventTime = 0;
741
732
  }
742
733
 
743
- NSString * publicKey = [[CodePushConfig current] publicKey];
744
-
745
734
  [CodePushPackage
746
735
  downloadPackage:mutableUpdatePackage
747
736
  expectedBundleFileName:[bundleResourceName stringByAppendingPathExtension:bundleResourceExtension]
748
- publicKey:publicKey
749
737
  operationQueue:_methodQueue
750
738
  // The download is progressing forward
751
739
  progressCallback:^(long long expectedContentLength, long long receivedContentLength) {
@@ -12,7 +12,6 @@ static NSString * const BuildVersionConfigKey = @"buildVersion";
12
12
  static NSString * const ClientUniqueIDConfigKey = @"clientUniqueId";
13
13
  static NSString * const DeploymentKeyConfigKey = @"deploymentKey";
14
14
  static NSString * const ServerURLConfigKey = @"serverUrl";
15
- static NSString * const PublicKeyKey = @"publicKey";
16
15
 
17
16
  + (instancetype)current
18
17
  {
@@ -35,7 +34,6 @@ static NSString * const PublicKeyKey = @"publicKey";
35
34
  NSString *buildVersion = [infoDictionary objectForKey:(NSString *)kCFBundleVersionKey];
36
35
  NSString *deploymentKey = [infoDictionary objectForKey:@"CodePushDeploymentKey"];
37
36
  NSString *serverURL = [infoDictionary objectForKey:@"CodePushServerURL"];
38
- NSString *publicKey = [infoDictionary objectForKey:@"CodePushPublicKey"];
39
37
 
40
38
  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
41
39
  NSString *clientUniqueId = [userDefaults stringForKey:ClientUniqueIDConfigKey];
@@ -56,7 +54,6 @@ static NSString * const PublicKeyKey = @"publicKey";
56
54
  if (serverURL) [_configDictionary setObject:serverURL forKey:ServerURLConfigKey];
57
55
  if (clientUniqueId) [_configDictionary setObject:clientUniqueId forKey:ClientUniqueIDConfigKey];
58
56
  if (deploymentKey) [_configDictionary setObject:deploymentKey forKey:DeploymentKeyConfigKey];
59
- if (publicKey) [_configDictionary setObject:publicKey forKey:PublicKeyKey];
60
57
 
61
58
  return self;
62
59
  }
@@ -91,11 +88,6 @@ static NSString * const PublicKeyKey = @"publicKey";
91
88
  return [_configDictionary objectForKey:ClientUniqueIDConfigKey];
92
89
  }
93
90
 
94
- - (NSString *)publicKey
95
- {
96
- return [_configDictionary objectForKey:PublicKeyKey];
97
- }
98
-
99
91
  - (void)setAppVersion:(NSString *)appVersion
100
92
  {
101
93
  [_configDictionary setValue:appVersion forKey:AppVersionConfigKey];
@@ -111,6 +103,4 @@ static NSString * const PublicKeyKey = @"publicKey";
111
103
  [_configDictionary setValue:serverURL forKey:ServerURLConfigKey];
112
104
  }
113
105
 
114
- //no setter for PublicKey, because it's need to be hard coded within Info.plist for safety
115
-
116
106
  @end