@appzung/react-native-code-push 5.7.1

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 (191) hide show
  1. package/AlertAdapter.js +24 -0
  2. package/CONTRIBUTING.md +136 -0
  3. package/CodePush.js +666 -0
  4. package/CodePush.podspec +27 -0
  5. package/LICENSE.md +13 -0
  6. package/README.md +386 -0
  7. package/RestartManager.js +59 -0
  8. package/android/app/build.gradle +31 -0
  9. package/android/app/proguard-rules.pro +25 -0
  10. package/android/app/src/main/AndroidManifest.xml +10 -0
  11. package/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java +395 -0
  12. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushBuilder.java +37 -0
  13. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushConstants.java +34 -0
  14. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushDialog.java +102 -0
  15. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java +16 -0
  16. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushInvalidPublicKeyException.java +12 -0
  17. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushInvalidUpdateException.java +7 -0
  18. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushMalformedDataException.java +12 -0
  19. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java +641 -0
  20. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushNotInitializedException.java +12 -0
  21. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java +175 -0
  22. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushUnknownException.java +12 -0
  23. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java +369 -0
  24. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateState.java +15 -0
  25. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java +267 -0
  26. package/android/app/src/main/java/com/microsoft/codepush/react/CodePushUtils.java +236 -0
  27. package/android/app/src/main/java/com/microsoft/codepush/react/DownloadProgress.java +30 -0
  28. package/android/app/src/main/java/com/microsoft/codepush/react/DownloadProgressCallback.java +5 -0
  29. package/android/app/src/main/java/com/microsoft/codepush/react/FileUtils.java +190 -0
  30. package/android/app/src/main/java/com/microsoft/codepush/react/ReactInstanceHolder.java +17 -0
  31. package/android/app/src/main/java/com/microsoft/codepush/react/SettingsManager.java +173 -0
  32. package/android/build.gradle +20 -0
  33. package/android/codepush.gradle +113 -0
  34. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  35. package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  36. package/android/gradle.properties +20 -0
  37. package/android/gradlew +164 -0
  38. package/android/gradlew.bat +90 -0
  39. package/android/settings.gradle +1 -0
  40. package/docs/api-android.md +65 -0
  41. package/docs/api-ios.md +31 -0
  42. package/docs/api-js.md +592 -0
  43. package/docs/multi-deployment-testing-android.md +107 -0
  44. package/docs/multi-deployment-testing-ios.md +53 -0
  45. package/docs/setup-android.md +406 -0
  46. package/docs/setup-ios.md +229 -0
  47. package/docs/setup-windows.md +65 -0
  48. package/gulpfile.js +302 -0
  49. package/ios/CodePush/Base64/Base64/MF_Base64Additions.h +34 -0
  50. package/ios/CodePush/Base64/Base64/MF_Base64Additions.m +252 -0
  51. package/ios/CodePush/Base64/README.md +47 -0
  52. package/ios/CodePush/CodePush.h +235 -0
  53. package/ios/CodePush/CodePush.m +1041 -0
  54. package/ios/CodePush/CodePushConfig.m +116 -0
  55. package/ios/CodePush/CodePushDownloadHandler.m +130 -0
  56. package/ios/CodePush/CodePushErrorUtils.m +20 -0
  57. package/ios/CodePush/CodePushPackage.m +598 -0
  58. package/ios/CodePush/CodePushTelemetryManager.m +175 -0
  59. package/ios/CodePush/CodePushUpdateUtils.m +376 -0
  60. package/ios/CodePush/CodePushUtils.m +9 -0
  61. package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithm.h +69 -0
  62. package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmFactory.h +16 -0
  63. package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmFactory.m +51 -0
  64. package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmNone.h +15 -0
  65. package/ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmNone.m +55 -0
  66. package/ios/CodePush/JWT/Core/Algorithms/ESFamily/JWTAlgorithmESBase.h +24 -0
  67. package/ios/CodePush/JWT/Core/Algorithms/ESFamily/JWTAlgorithmESBase.m +41 -0
  68. package/ios/CodePush/JWT/Core/Algorithms/HSFamily/JWTAlgorithmHSBase.h +28 -0
  69. package/ios/CodePush/JWT/Core/Algorithms/HSFamily/JWTAlgorithmHSBase.m +205 -0
  70. package/ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolder.h +103 -0
  71. package/ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolder.m +322 -0
  72. package/ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolderChain.h +37 -0
  73. package/ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolderChain.m +145 -0
  74. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/JWTAlgorithmRSBase.h +35 -0
  75. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/JWTAlgorithmRSBase.m +551 -0
  76. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/JWTRSAlgorithm.h +23 -0
  77. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKey.h +43 -0
  78. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKey.m +230 -0
  79. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKeyExtractor.h +31 -0
  80. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKeyExtractor.m +113 -0
  81. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.h +38 -0
  82. package/ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m +500 -0
  83. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaim.h +18 -0
  84. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaim.m +214 -0
  85. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSet.h +23 -0
  86. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSet.m +29 -0
  87. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetSerializer.h +19 -0
  88. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetSerializer.m +68 -0
  89. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetVerifier.h +18 -0
  90. package/ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetVerifier.m +72 -0
  91. package/ios/CodePush/JWT/Core/Coding/JWTCoding+ResultTypes.h +67 -0
  92. package/ios/CodePush/JWT/Core/Coding/JWTCoding+ResultTypes.m +111 -0
  93. package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionOne.h +119 -0
  94. package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionOne.m +307 -0
  95. package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionThree.h +94 -0
  96. package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionThree.m +619 -0
  97. package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionTwo.h +164 -0
  98. package/ios/CodePush/JWT/Core/Coding/JWTCoding+VersionTwo.m +514 -0
  99. package/ios/CodePush/JWT/Core/Coding/JWTCoding.h +24 -0
  100. package/ios/CodePush/JWT/Core/Coding/JWTCoding.m +11 -0
  101. package/ios/CodePush/JWT/Core/FrameworkSupplement/JWT.h +52 -0
  102. package/ios/CodePush/JWT/Core/FrameworkSupplement/Map.modulemap +5 -0
  103. package/ios/CodePush/JWT/Core/Supplement/JWTBase64Coder.h +28 -0
  104. package/ios/CodePush/JWT/Core/Supplement/JWTBase64Coder.m +70 -0
  105. package/ios/CodePush/JWT/Core/Supplement/JWTDeprecations.h +22 -0
  106. package/ios/CodePush/JWT/Core/Supplement/JWTErrorDescription.h +34 -0
  107. package/ios/CodePush/JWT/Core/Supplement/JWTErrorDescription.m +73 -0
  108. package/ios/CodePush/JWT/LICENSE +19 -0
  109. package/ios/CodePush/JWT/README.md +489 -0
  110. package/ios/CodePush/RCTConvert+CodePushInstallMode.m +20 -0
  111. package/ios/CodePush/RCTConvert+CodePushUpdateState.m +20 -0
  112. package/ios/CodePush/SSZipArchive/Common.h +81 -0
  113. package/ios/CodePush/SSZipArchive/README.md +1 -0
  114. package/ios/CodePush/SSZipArchive/SSZipArchive.h +76 -0
  115. package/ios/CodePush/SSZipArchive/SSZipArchive.m +691 -0
  116. package/ios/CodePush/SSZipArchive/aes/aes.h +198 -0
  117. package/ios/CodePush/SSZipArchive/aes/aes_via_ace.h +541 -0
  118. package/ios/CodePush/SSZipArchive/aes/aescrypt.c +294 -0
  119. package/ios/CodePush/SSZipArchive/aes/aeskey.c +548 -0
  120. package/ios/CodePush/SSZipArchive/aes/aesopt.h +739 -0
  121. package/ios/CodePush/SSZipArchive/aes/aestab.c +391 -0
  122. package/ios/CodePush/SSZipArchive/aes/aestab.h +173 -0
  123. package/ios/CodePush/SSZipArchive/aes/brg_endian.h +126 -0
  124. package/ios/CodePush/SSZipArchive/aes/brg_types.h +219 -0
  125. package/ios/CodePush/SSZipArchive/aes/entropy.c +54 -0
  126. package/ios/CodePush/SSZipArchive/aes/entropy.h +16 -0
  127. package/ios/CodePush/SSZipArchive/aes/fileenc.c +144 -0
  128. package/ios/CodePush/SSZipArchive/aes/fileenc.h +121 -0
  129. package/ios/CodePush/SSZipArchive/aes/hmac.c +145 -0
  130. package/ios/CodePush/SSZipArchive/aes/hmac.h +103 -0
  131. package/ios/CodePush/SSZipArchive/aes/prng.c +155 -0
  132. package/ios/CodePush/SSZipArchive/aes/prng.h +82 -0
  133. package/ios/CodePush/SSZipArchive/aes/pwd2key.c +103 -0
  134. package/ios/CodePush/SSZipArchive/aes/pwd2key.h +57 -0
  135. package/ios/CodePush/SSZipArchive/aes/sha1.c +258 -0
  136. package/ios/CodePush/SSZipArchive/aes/sha1.h +73 -0
  137. package/ios/CodePush/SSZipArchive/minizip/crypt.h +130 -0
  138. package/ios/CodePush/SSZipArchive/minizip/ioapi.c +369 -0
  139. package/ios/CodePush/SSZipArchive/minizip/ioapi.h +175 -0
  140. package/ios/CodePush/SSZipArchive/minizip/mztools.c +284 -0
  141. package/ios/CodePush/SSZipArchive/minizip/mztools.h +31 -0
  142. package/ios/CodePush/SSZipArchive/minizip/unzip.c +1839 -0
  143. package/ios/CodePush/SSZipArchive/minizip/unzip.h +248 -0
  144. package/ios/CodePush/SSZipArchive/minizip/zip.c +1910 -0
  145. package/ios/CodePush/SSZipArchive/minizip/zip.h +202 -0
  146. package/ios/CodePush.xcodeproj/project.pbxproj +937 -0
  147. package/ios/CodePush.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  148. package/ios/CodePush.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  149. package/logging.js +6 -0
  150. package/package-mixins.js +69 -0
  151. package/package.json +47 -0
  152. package/request-fetch-adapter.js +52 -0
  153. package/scripts/generateBundledResourcesHash.js +125 -0
  154. package/scripts/getFilesInFolder.js +19 -0
  155. package/scripts/postlink/android/postlink.js +87 -0
  156. package/scripts/postlink/ios/postlink.js +116 -0
  157. package/scripts/postlink/run.js +11 -0
  158. package/scripts/postunlink/android/postunlink.js +74 -0
  159. package/scripts/postunlink/ios/postunlink.js +87 -0
  160. package/scripts/postunlink/run.js +11 -0
  161. package/scripts/recordFilesBeforeBundleCommand.js +41 -0
  162. package/scripts/tools/linkToolsAndroid.js +57 -0
  163. package/scripts/tools/linkToolsIos.js +130 -0
  164. package/typings/react-native-code-push.d.ts +446 -0
  165. package/windows/CodePush/CodePush.csproj +128 -0
  166. package/windows/CodePush/CodePushUtils.cs +47 -0
  167. package/windows/CodePush/FileUtils.cs +40 -0
  168. package/windows/CodePush/Properties/AssemblyInfo.cs +29 -0
  169. package/windows/CodePush/Properties/CodePush.rd.xml +33 -0
  170. package/windows/CodePush/UpdateManager.cs +305 -0
  171. package/windows/CodePush/UpdateUtils.cs +46 -0
  172. package/windows/CodePush.Net46/Adapters/Http/HttpProgress.cs +28 -0
  173. package/windows/CodePush.Net46/Adapters/Storage/ApplicationDataContainer.cs +106 -0
  174. package/windows/CodePush.Net46/CodePush.Net46.csproj +103 -0
  175. package/windows/CodePush.Net46/CodePushUtils.cs +158 -0
  176. package/windows/CodePush.Net46/FileUtils.cs +55 -0
  177. package/windows/CodePush.Net46/Properties/AssemblyInfo.cs +36 -0
  178. package/windows/CodePush.Net46/UpdateManager.cs +330 -0
  179. package/windows/CodePush.Net46/UpdateUtils.cs +70 -0
  180. package/windows/CodePush.Net46/packages.config +5 -0
  181. package/windows/CodePush.Shared/CodePush.Shared.projitems +22 -0
  182. package/windows/CodePush.Shared/CodePush.Shared.shproj +13 -0
  183. package/windows/CodePush.Shared/CodePushConstants.cs +35 -0
  184. package/windows/CodePush.Shared/CodePushNativeModule.cs +329 -0
  185. package/windows/CodePush.Shared/CodePushReactPackage.cs +235 -0
  186. package/windows/CodePush.Shared/CodePushUtils.cs +70 -0
  187. package/windows/CodePush.Shared/InstallMode.cs +9 -0
  188. package/windows/CodePush.Shared/MinimumBackgroundListener.cs +44 -0
  189. package/windows/CodePush.Shared/SettingsManager.cs +148 -0
  190. package/windows/CodePush.Shared/TelemetryManager.cs +250 -0
  191. package/windows/CodePush.Shared/UpdateState.cs +9 -0
@@ -0,0 +1,267 @@
1
+ package com.microsoft.codepush.react;
2
+
3
+ import android.content.Context;
4
+ import android.util.Base64;
5
+
6
+ import java.security.interfaces.*;
7
+
8
+ import com.nimbusds.jose.*;
9
+ import com.nimbusds.jose.crypto.*;
10
+ import com.nimbusds.jwt.*;
11
+
12
+ import org.json.JSONArray;
13
+ import org.json.JSONException;
14
+ import org.json.JSONObject;
15
+
16
+ import java.io.ByteArrayInputStream;
17
+ import java.io.File;
18
+ import java.io.FileInputStream;
19
+ import java.io.FileNotFoundException;
20
+ import java.io.IOException;
21
+ import java.io.InputStream;
22
+ import java.security.DigestInputStream;
23
+ import java.security.KeyFactory;
24
+ import java.security.MessageDigest;
25
+ import java.security.NoSuchAlgorithmException;
26
+ import java.security.PublicKey;
27
+ import java.security.spec.X509EncodedKeySpec;
28
+ import java.util.ArrayList;
29
+ import java.util.Collections;
30
+ import java.util.Map;
31
+
32
+ public class CodePushUpdateUtils {
33
+
34
+ public static final String NEW_LINE = System.getProperty("line.separator");
35
+
36
+ // Note: The hashing logic here must mirror the hashing logic in other native SDK's, as well as in the
37
+ // CLI. Ensure that any changes here are propagated to these other locations.
38
+ public static boolean isHashIgnored(String relativeFilePath) {
39
+ final String __MACOSX = "__MACOSX/";
40
+ final String DS_STORE = ".DS_Store";
41
+ final String CODEPUSH_METADATA = ".codepushrelease";
42
+
43
+ return relativeFilePath.startsWith(__MACOSX)
44
+ || relativeFilePath.equals(DS_STORE)
45
+ || relativeFilePath.endsWith("/" + DS_STORE)
46
+ || relativeFilePath.equals(CODEPUSH_METADATA)
47
+ || relativeFilePath.endsWith("/" + CODEPUSH_METADATA);
48
+ }
49
+
50
+ private static void addContentsOfFolderToManifest(String folderPath, String pathPrefix, ArrayList<String> manifest) {
51
+ File folder = new File(folderPath);
52
+ File[] folderFiles = folder.listFiles();
53
+ for (File file : folderFiles) {
54
+ String fileName = file.getName();
55
+ String fullFilePath = file.getAbsolutePath();
56
+ String relativePath = (pathPrefix.isEmpty() ? "" : (pathPrefix + "/")) + fileName;
57
+
58
+ if (CodePushUpdateUtils.isHashIgnored(relativePath)) {
59
+ continue;
60
+ }
61
+
62
+ if (file.isDirectory()) {
63
+ addContentsOfFolderToManifest(fullFilePath, relativePath, manifest);
64
+ } else {
65
+ try {
66
+ manifest.add(relativePath + ":" + computeHash(new FileInputStream(file)));
67
+ } catch (FileNotFoundException e) {
68
+ // Should not happen.
69
+ throw new CodePushUnknownException("Unable to compute hash of update contents.", e);
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ private static String computeHash(InputStream dataStream) {
76
+ MessageDigest messageDigest = null;
77
+ DigestInputStream digestInputStream = null;
78
+ try {
79
+ messageDigest = MessageDigest.getInstance("SHA-256");
80
+ digestInputStream = new DigestInputStream(dataStream, messageDigest);
81
+ byte[] byteBuffer = new byte[1024 * 8];
82
+ while (digestInputStream.read(byteBuffer) != -1) ;
83
+ } catch (NoSuchAlgorithmException | IOException e) {
84
+ // Should not happen.
85
+ throw new CodePushUnknownException("Unable to compute hash of update contents.", e);
86
+ } finally {
87
+ try {
88
+ if (digestInputStream != null) digestInputStream.close();
89
+ if (dataStream != null) dataStream.close();
90
+ } catch (IOException e) {
91
+ e.printStackTrace();
92
+ }
93
+ }
94
+
95
+ byte[] hash = messageDigest.digest();
96
+ return String.format("%064x", new java.math.BigInteger(1, hash));
97
+ }
98
+
99
+ public static void copyNecessaryFilesFromCurrentPackage(String diffManifestFilePath, String currentPackageFolderPath, String newPackageFolderPath) throws IOException {
100
+ FileUtils.copyDirectoryContents(currentPackageFolderPath, newPackageFolderPath);
101
+ JSONObject diffManifest = CodePushUtils.getJsonObjectFromFile(diffManifestFilePath);
102
+ try {
103
+ JSONArray deletedFiles = diffManifest.getJSONArray("deletedFiles");
104
+ for (int i = 0; i < deletedFiles.length(); i++) {
105
+ String fileNameToDelete = deletedFiles.getString(i);
106
+ File fileToDelete = new File(newPackageFolderPath, fileNameToDelete);
107
+ if (fileToDelete.exists()) {
108
+ fileToDelete.delete();
109
+ }
110
+ }
111
+ } catch (JSONException e) {
112
+ throw new CodePushUnknownException("Unable to copy files from current package during diff update", e);
113
+ }
114
+ }
115
+
116
+ public static String findJSBundleInUpdateContents(String folderPath, String expectedFileName) {
117
+ File folder = new File(folderPath);
118
+ File[] folderFiles = folder.listFiles();
119
+ for (File file : folderFiles) {
120
+ String fullFilePath = CodePushUtils.appendPathComponent(folderPath, file.getName());
121
+ if (file.isDirectory()) {
122
+ String mainBundlePathInSubFolder = findJSBundleInUpdateContents(fullFilePath, expectedFileName);
123
+ if (mainBundlePathInSubFolder != null) {
124
+ return CodePushUtils.appendPathComponent(file.getName(), mainBundlePathInSubFolder);
125
+ }
126
+ } else {
127
+ String fileName = file.getName();
128
+ if (fileName.equals(expectedFileName)) {
129
+ return fileName;
130
+ }
131
+ }
132
+ }
133
+
134
+ return null;
135
+ }
136
+
137
+ public static String getHashForBinaryContents(Context context, boolean isDebugMode) {
138
+ try {
139
+ return CodePushUtils.getStringFromInputStream(context.getAssets().open(CodePushConstants.CODE_PUSH_HASH_FILE_NAME));
140
+ } catch (IOException e) {
141
+ try {
142
+ return CodePushUtils.getStringFromInputStream(context.getAssets().open(CodePushConstants.CODE_PUSH_OLD_HASH_FILE_NAME));
143
+ } catch (IOException ex) {
144
+ if (!isDebugMode) {
145
+ // Only print this message in "Release" mode. In "Debug", we may not have the
146
+ // hash if the build skips bundling the files.
147
+ CodePushUtils.log("Unable to get the hash of the binary's bundled resources - \"codepush.gradle\" may have not been added to the build definition.");
148
+ }
149
+ }
150
+ return null;
151
+ }
152
+ }
153
+
154
+ // Hashing algorithm:
155
+ // 1. Recursively generate a sorted array of format <relativeFilePath>: <sha256FileHash>
156
+ // 2. JSON stringify the array
157
+ // 3. SHA256-hash the result
158
+ public static void verifyFolderHash(String folderPath, String expectedHash) {
159
+ CodePushUtils.log("Verifying hash for folder path: " + folderPath);
160
+ ArrayList<String> updateContentsManifest = new ArrayList<>();
161
+ addContentsOfFolderToManifest(folderPath, "", updateContentsManifest);
162
+ //sort manifest strings to make sure, that they are completely equal with manifest strings has been generated in cli!
163
+ Collections.sort(updateContentsManifest);
164
+ JSONArray updateContentsJSONArray = new JSONArray();
165
+ for (String manifestEntry : updateContentsManifest) {
166
+ updateContentsJSONArray.put(manifestEntry);
167
+ }
168
+
169
+ // The JSON serialization turns path separators into "\/", e.g. "CodePush\/assets\/image.png"
170
+ String updateContentsManifestString = updateContentsJSONArray.toString().replace("\\/", "/");
171
+ CodePushUtils.log("Manifest string: " + updateContentsManifestString);
172
+
173
+ String updateContentsManifestHash = computeHash(new ByteArrayInputStream(updateContentsManifestString.getBytes()));
174
+
175
+ CodePushUtils.log("Expected hash: " + expectedHash + ", actual hash: " + updateContentsManifestHash);
176
+ if (!expectedHash.equals(updateContentsManifestHash)) {
177
+ throw new CodePushInvalidUpdateException("The update contents failed the data integrity check.");
178
+ }
179
+
180
+ CodePushUtils.log("The update contents succeeded the data integrity check.");
181
+ }
182
+
183
+ public static Map<String, Object> verifyAndDecodeJWT(String jwt, PublicKey publicKey) {
184
+ try {
185
+ SignedJWT signedJWT = SignedJWT.parse(jwt);
186
+ JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey)publicKey);
187
+ if (signedJWT.verify(verifier)) {
188
+ Map<String, Object> claims = signedJWT.getJWTClaimsSet().getClaims();
189
+ CodePushUtils.log("JWT verification succeeded, payload content: " + claims.toString());
190
+ return claims;
191
+ }
192
+ return null;
193
+ } catch (Exception ex) {
194
+ CodePushUtils.log(ex.getMessage());
195
+ CodePushUtils.log(ex.getStackTrace().toString());
196
+ return null;
197
+ }
198
+ }
199
+
200
+ public static PublicKey parsePublicKey(String stringPublicKey) {
201
+ try {
202
+ //remove unnecessary "begin/end public key" entries from string
203
+ stringPublicKey = stringPublicKey
204
+ .replace("-----BEGIN PUBLIC KEY-----", "")
205
+ .replace("-----END PUBLIC KEY-----", "")
206
+ .replace(NEW_LINE, "");
207
+ byte[] byteKey = Base64.decode(stringPublicKey.getBytes(), Base64.DEFAULT);
208
+ X509EncodedKeySpec X509Key = new X509EncodedKeySpec(byteKey);
209
+ KeyFactory kf = KeyFactory.getInstance("RSA");
210
+
211
+ return kf.generatePublic(X509Key);
212
+ } catch (Exception e) {
213
+ CodePushUtils.log(e.getMessage());
214
+ CodePushUtils.log(e.getStackTrace().toString());
215
+ return null;
216
+ }
217
+ }
218
+
219
+ public static String getSignatureFilePath(String updateFolderPath){
220
+ return CodePushUtils.appendPathComponent(
221
+ CodePushUtils.appendPathComponent(updateFolderPath, CodePushConstants.CODE_PUSH_FOLDER_PREFIX),
222
+ CodePushConstants.BUNDLE_JWT_FILE
223
+ );
224
+ }
225
+
226
+ public static String getSignature(String folderPath) {
227
+ final String signatureFilePath = getSignatureFilePath(folderPath);
228
+
229
+ try {
230
+ return FileUtils.readFileToString(signatureFilePath);
231
+ } catch (IOException e) {
232
+ CodePushUtils.log(e.getMessage());
233
+ CodePushUtils.log(e.getStackTrace().toString());
234
+ return null;
235
+ }
236
+ }
237
+
238
+ public static void verifyUpdateSignature(String folderPath, String packageHash, String stringPublicKey) throws CodePushInvalidUpdateException {
239
+ CodePushUtils.log("Verifying signature for folder path: " + folderPath);
240
+
241
+ final PublicKey publicKey = parsePublicKey(stringPublicKey);
242
+ if (publicKey == null) {
243
+ throw new CodePushInvalidUpdateException("The update could not be verified because no public key was found.");
244
+ }
245
+
246
+ final String signature = getSignature(folderPath);
247
+ if (signature == null) {
248
+ throw new CodePushInvalidUpdateException("The update could not be verified because no signature was found.");
249
+ }
250
+
251
+ final Map<String, Object> claims = verifyAndDecodeJWT(signature, publicKey);
252
+ if (claims == null) {
253
+ throw new CodePushInvalidUpdateException("The update could not be verified because it was not signed by a trusted party.");
254
+ }
255
+
256
+ final String contentHash = (String)claims.get("contentHash");
257
+ if (contentHash == null) {
258
+ throw new CodePushInvalidUpdateException("The update could not be verified because the signature did not specify a content hash.");
259
+ }
260
+
261
+ if (!contentHash.equals(packageHash)) {
262
+ throw new CodePushInvalidUpdateException("The update contents failed the code signing check.");
263
+ }
264
+
265
+ CodePushUtils.log("The update contents succeeded the code signing check.");
266
+ }
267
+ }
@@ -0,0 +1,236 @@
1
+ package com.microsoft.codepush.react;
2
+
3
+ import android.util.Log;
4
+
5
+ import com.facebook.react.bridge.Arguments;
6
+ import com.facebook.react.bridge.NoSuchKeyException;
7
+ import com.facebook.react.bridge.ReadableArray;
8
+ import com.facebook.react.bridge.ReadableMap;
9
+ import com.facebook.react.bridge.ReadableMapKeySetIterator;
10
+ import com.facebook.react.bridge.ReadableType;
11
+ import com.facebook.react.bridge.WritableArray;
12
+ import com.facebook.react.bridge.WritableMap;
13
+
14
+ import org.json.JSONArray;
15
+ import org.json.JSONException;
16
+ import org.json.JSONObject;
17
+
18
+ import java.io.BufferedReader;
19
+ import java.io.File;
20
+ import java.io.IOException;
21
+ import java.io.InputStream;
22
+ import java.io.InputStreamReader;
23
+ import java.util.Iterator;
24
+
25
+ public class CodePushUtils {
26
+
27
+ public static String appendPathComponent(String basePath, String appendPathComponent) {
28
+ return new File(basePath, appendPathComponent).getAbsolutePath();
29
+ }
30
+
31
+ public static WritableArray convertJsonArrayToWritable(JSONArray jsonArr) {
32
+ WritableArray arr = Arguments.createArray();
33
+ for (int i=0; i<jsonArr.length(); i++) {
34
+ Object obj = null;
35
+ try {
36
+ obj = jsonArr.get(i);
37
+ } catch (JSONException jsonException) {
38
+ // Should not happen.
39
+ throw new CodePushUnknownException(i + " should be within bounds of array " + jsonArr.toString(), jsonException);
40
+ }
41
+
42
+ if (obj instanceof JSONObject)
43
+ arr.pushMap(convertJsonObjectToWritable((JSONObject) obj));
44
+ else if (obj instanceof JSONArray)
45
+ arr.pushArray(convertJsonArrayToWritable((JSONArray) obj));
46
+ else if (obj instanceof String)
47
+ arr.pushString((String) obj);
48
+ else if (obj instanceof Double)
49
+ arr.pushDouble((Double) obj);
50
+ else if (obj instanceof Integer)
51
+ arr.pushInt((Integer) obj);
52
+ else if (obj instanceof Boolean)
53
+ arr.pushBoolean((Boolean) obj);
54
+ else if (obj == null)
55
+ arr.pushNull();
56
+ else
57
+ throw new CodePushUnknownException("Unrecognized object: " + obj);
58
+ }
59
+
60
+ return arr;
61
+ }
62
+
63
+ public static WritableMap convertJsonObjectToWritable(JSONObject jsonObj) {
64
+ WritableMap map = Arguments.createMap();
65
+ Iterator<String> it = jsonObj.keys();
66
+ while(it.hasNext()){
67
+ String key = it.next();
68
+ Object obj = null;
69
+ try {
70
+ obj = jsonObj.get(key);
71
+ } catch (JSONException jsonException) {
72
+ // Should not happen.
73
+ throw new CodePushUnknownException("Key " + key + " should exist in " + jsonObj.toString() + ".", jsonException);
74
+ }
75
+
76
+ if (obj instanceof JSONObject)
77
+ map.putMap(key, convertJsonObjectToWritable((JSONObject) obj));
78
+ else if (obj instanceof JSONArray)
79
+ map.putArray(key, convertJsonArrayToWritable((JSONArray) obj));
80
+ else if (obj instanceof String)
81
+ map.putString(key, (String) obj);
82
+ else if (obj instanceof Double)
83
+ map.putDouble(key, (Double) obj);
84
+ else if (obj instanceof Long)
85
+ map.putDouble(key, ((Long) obj).doubleValue());
86
+ else if (obj instanceof Integer)
87
+ map.putInt(key, (Integer) obj);
88
+ else if (obj instanceof Boolean)
89
+ map.putBoolean(key, (Boolean) obj);
90
+ else if (obj == null)
91
+ map.putNull(key);
92
+ else
93
+ throw new CodePushUnknownException("Unrecognized object: " + obj);
94
+ }
95
+
96
+ return map;
97
+ }
98
+
99
+ public static JSONArray convertReadableToJsonArray(ReadableArray arr) {
100
+ JSONArray jsonArr = new JSONArray();
101
+ for (int i=0; i<arr.size(); i++) {
102
+ ReadableType type = arr.getType(i);
103
+ switch (type) {
104
+ case Map:
105
+ jsonArr.put(convertReadableToJsonObject(arr.getMap(i)));
106
+ break;
107
+ case Array:
108
+ jsonArr.put(convertReadableToJsonArray(arr.getArray(i)));
109
+ break;
110
+ case String:
111
+ jsonArr.put(arr.getString(i));
112
+ break;
113
+ case Number:
114
+ Double number = arr.getDouble(i);
115
+ if ((number == Math.floor(number)) && !Double.isInfinite(number)) {
116
+ // This is a whole number.
117
+ jsonArr.put(number.longValue());
118
+ } else {
119
+ try {
120
+ jsonArr.put(number.doubleValue());
121
+ } catch (JSONException jsonException) {
122
+ throw new CodePushUnknownException("Unable to put value " + arr.getDouble(i) + " in JSONArray");
123
+ }
124
+ }
125
+ break;
126
+ case Boolean:
127
+ jsonArr.put(arr.getBoolean(i));
128
+ break;
129
+ case Null:
130
+ jsonArr.put(null);
131
+ break;
132
+ }
133
+ }
134
+
135
+ return jsonArr;
136
+ }
137
+
138
+ public static JSONObject convertReadableToJsonObject(ReadableMap map) {
139
+ JSONObject jsonObj = new JSONObject();
140
+ ReadableMapKeySetIterator it = map.keySetIterator();
141
+ while (it.hasNextKey()) {
142
+ String key = it.nextKey();
143
+ ReadableType type = map.getType(key);
144
+ try {
145
+ switch (type) {
146
+ case Map:
147
+ jsonObj.put(key, convertReadableToJsonObject(map.getMap(key)));
148
+ break;
149
+ case Array:
150
+ jsonObj.put(key, convertReadableToJsonArray(map.getArray(key)));
151
+ break;
152
+ case String:
153
+ jsonObj.put(key, map.getString(key));
154
+ break;
155
+ case Number:
156
+ jsonObj.put(key, map.getDouble(key));
157
+ break;
158
+ case Boolean:
159
+ jsonObj.put(key, map.getBoolean(key));
160
+ break;
161
+ case Null:
162
+ jsonObj.put(key, null);
163
+ break;
164
+ default:
165
+ throw new CodePushUnknownException("Unrecognized type: " + type + " of key: " + key);
166
+ }
167
+ } catch (JSONException jsonException) {
168
+ throw new CodePushUnknownException("Error setting key: " + key + " in JSONObject", jsonException);
169
+ }
170
+ }
171
+
172
+ return jsonObj;
173
+ }
174
+
175
+ public static String getStringFromInputStream(InputStream inputStream) throws IOException {
176
+ BufferedReader bufferedReader = null;
177
+ try {
178
+ StringBuilder buffer = new StringBuilder();
179
+ bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
180
+
181
+ String line;
182
+ while ((line = bufferedReader.readLine()) != null) {
183
+ buffer.append(line);
184
+ buffer.append("\n");
185
+ }
186
+
187
+ return buffer.toString().trim();
188
+ } finally {
189
+ if (bufferedReader != null) bufferedReader.close();
190
+ if (inputStream != null) inputStream.close();
191
+ }
192
+ }
193
+
194
+ public static JSONObject getJsonObjectFromFile(String filePath) throws IOException {
195
+ String content = FileUtils.readFileToString(filePath);
196
+ try {
197
+ return new JSONObject(content);
198
+ } catch (JSONException jsonException) {
199
+ // Should not happen
200
+ throw new CodePushMalformedDataException(filePath, jsonException);
201
+ }
202
+ }
203
+
204
+ public static void log(String message) {
205
+ Log.d(CodePushConstants.REACT_NATIVE_LOG_TAG, "[CodePush] " + message);
206
+ }
207
+
208
+ public static void log(Throwable tr) {
209
+ Log.e(CodePushConstants.REACT_NATIVE_LOG_TAG, "[CodePush] Exception", tr);
210
+ }
211
+
212
+ public static void logBundleUrl(String path) {
213
+ log("Loading JS bundle from \"" + path + "\"");
214
+ }
215
+
216
+ public static void setJSONValueForKey(JSONObject json, String key, Object value) {
217
+ try {
218
+ json.put(key, value);
219
+ } catch (JSONException e) {
220
+ throw new CodePushUnknownException("Unable to set value " + value + " for key " + key + " to JSONObject");
221
+ }
222
+ }
223
+
224
+ public static String tryGetString(ReadableMap map, String key) {
225
+ try {
226
+ return map.getString(key);
227
+ } catch (NoSuchKeyException e) {
228
+ return null;
229
+ }
230
+ }
231
+
232
+ public static void writeJsonToFile(JSONObject json, String filePath) throws IOException {
233
+ String jsonString = json.toString();
234
+ FileUtils.writeStringToFile(jsonString, filePath);
235
+ }
236
+ }
@@ -0,0 +1,30 @@
1
+ package com.microsoft.codepush.react;
2
+
3
+ import com.facebook.react.bridge.WritableMap;
4
+ import com.facebook.react.bridge.WritableNativeMap;
5
+
6
+ class DownloadProgress {
7
+ private long mTotalBytes;
8
+ private long mReceivedBytes;
9
+
10
+ public DownloadProgress (long totalBytes, long receivedBytes){
11
+ mTotalBytes = totalBytes;
12
+ mReceivedBytes = receivedBytes;
13
+ }
14
+
15
+ public WritableMap createWritableMap() {
16
+ WritableMap map = new WritableNativeMap();
17
+ if (mTotalBytes < Integer.MAX_VALUE) {
18
+ map.putInt("totalBytes", (int) mTotalBytes);
19
+ map.putInt("receivedBytes", (int) mReceivedBytes);
20
+ } else {
21
+ map.putDouble("totalBytes", mTotalBytes);
22
+ map.putDouble("receivedBytes", mReceivedBytes);
23
+ }
24
+ return map;
25
+ }
26
+
27
+ public boolean isCompleted() {
28
+ return mTotalBytes == mReceivedBytes;
29
+ }
30
+ }
@@ -0,0 +1,5 @@
1
+ package com.microsoft.codepush.react;
2
+
3
+ interface DownloadProgressCallback {
4
+ void call(DownloadProgress downloadProgress);
5
+ }