diff --git a/.changeset/whole-rabbits-share.md b/.changeset/whole-rabbits-share.md new file mode 100644 index 000000000..0b9c0e378 --- /dev/null +++ b/.changeset/whole-rabbits-share.md @@ -0,0 +1,5 @@ +--- +"@callstack/repack": minor +--- + +the signature of the JavaScript code is now verified even if the bundle is loaded from the file system diff --git a/packages/repack/android/src/main/java/com/callstack/repack/FileSystemScriptLoader.kt b/packages/repack/android/src/main/java/com/callstack/repack/FileSystemScriptLoader.kt index 0db75adf6..4a767f104 100644 --- a/packages/repack/android/src/main/java/com/callstack/repack/FileSystemScriptLoader.kt +++ b/packages/repack/android/src/main/java/com/callstack/repack/FileSystemScriptLoader.kt @@ -6,19 +6,33 @@ import java.io.File import java.io.FileInputStream class FileSystemScriptLoader(private val reactContext: ReactContext, private val nativeLoader: NativeScriptLoader) { + fun verifyBundle(code: ByteArray, config: ScriptConfig): ByteArray { + val (bundle, token) = code?.let { + CodeSigningUtils.extractBundleAndToken(code) + } ?: Pair(null, null) + + if (config.verifyScriptSignature == "strict" || (config.verifyScriptSignature == "lax" && token != null)) { + CodeSigningUtils.verifyBundle(reactContext, token, bundle) + } + + return bundle + } + fun load(config: ScriptConfig, promise: Promise) { try { + val code: ByteArray; + if (config.absolute) { val path = config.url.path val file = File(path) - val code: ByteArray = FileInputStream(file).use { it.readBytes() } - nativeLoader.evaluate(code, config.sourceUrl, promise) + code = FileInputStream(file).use { it.readBytes() } } else { val assetName = config.url.file.split("/").last() val inputStream = reactContext.assets.open(assetName) - val code: ByteArray = inputStream.use { it.readBytes() } - nativeLoader.evaluate(code, config.sourceUrl, promise) + code = inputStream.use { it.readBytes() } } + val bundle: ByteArray = verifyBundle(code, config) + nativeLoader.evaluate(bundle, config.sourceUrl, promise) } catch (error: Exception) { promise.reject( ScriptLoadingError.ScriptEvalFailure.code, diff --git a/packages/repack/ios/ScriptManager.mm b/packages/repack/ios/ScriptManager.mm index a0d21226a..3b2afbbee 100644 --- a/packages/repack/ios/ScriptManager.mm +++ b/packages/repack/ios/ScriptManager.mm @@ -304,7 +304,22 @@ - (void)executeFromFilesystem:(ScriptConfig *)config filesystemScriptUrl = [[NSBundle mainBundle] URLForResource:scriptName withExtension:scriptExtension]; } NSData *data = [[NSData alloc] initWithContentsOfFile:[filesystemScriptUrl path]]; - [self evaluateJavascript:data url:config.sourceUrl resolve:resolve reject:reject]; + + NSDictionary *result = [CodeSigningUtils extractBundleAndTokenWithFileContent:data]; + NSData *bundle = (result[@"bundle"] != [NSNull null]) ? result[@"bundle"] : nil; + NSString *token = (result[@"token"] != [NSNull null]) ? result[@"token"] : nil; + + if ([config.verifyScriptSignature isEqualToString:@"strict"] || + ([config.verifyScriptSignature isEqualToString:@"lax"] && token != nil)) { + NSError *codeSigningError = nil; + [CodeSigningUtils verifyBundleWithToken:token fileContent:bundle error:&codeSigningError]; + if (codeSigningError != nil) { + reject(CodeExecutionFailure, codeSigningError.localizedDescription, nil); + return; + } + } + + [self evaluateJavascript:bundle url:config.sourceUrl resolve:resolve reject:reject]; } @catch (NSError *error) { reject(CodeExecutionFailure, error.localizedDescription, nil); }