Skip to content

Commit 38d8d1e

Browse files
ilteooodjbroma
andauthored
feat: verify script signature for fs loader (#1186)
Co-authored-by: Jakub Romańczyk <lorczyslav@gmail.com>
1 parent e67ec2b commit 38d8d1e

3 files changed

Lines changed: 39 additions & 5 deletions

File tree

.changeset/whole-rabbits-share.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@callstack/repack": minor
3+
---
4+
5+
the signature of the JavaScript code is now verified even if the bundle is loaded from the file system

packages/repack/android/src/main/java/com/callstack/repack/FileSystemScriptLoader.kt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,33 @@ import java.io.File
66
import java.io.FileInputStream
77

88
class FileSystemScriptLoader(private val reactContext: ReactContext, private val nativeLoader: NativeScriptLoader) {
9+
fun verifyBundle(code: ByteArray, config: ScriptConfig): ByteArray {
10+
val (bundle, token) = code?.let {
11+
CodeSigningUtils.extractBundleAndToken(code)
12+
} ?: Pair(null, null)
13+
14+
if (config.verifyScriptSignature == "strict" || (config.verifyScriptSignature == "lax" && token != null)) {
15+
CodeSigningUtils.verifyBundle(reactContext, token, bundle)
16+
}
17+
18+
return bundle
19+
}
20+
921
fun load(config: ScriptConfig, promise: Promise) {
1022
try {
23+
val code: ByteArray;
24+
1125
if (config.absolute) {
1226
val path = config.url.path
1327
val file = File(path)
14-
val code: ByteArray = FileInputStream(file).use { it.readBytes() }
15-
nativeLoader.evaluate(code, config.sourceUrl, promise)
28+
code = FileInputStream(file).use { it.readBytes() }
1629
} else {
1730
val assetName = config.url.file.split("/").last()
1831
val inputStream = reactContext.assets.open(assetName)
19-
val code: ByteArray = inputStream.use { it.readBytes() }
20-
nativeLoader.evaluate(code, config.sourceUrl, promise)
32+
code = inputStream.use { it.readBytes() }
2133
}
34+
val bundle: ByteArray = verifyBundle(code, config)
35+
nativeLoader.evaluate(bundle, config.sourceUrl, promise)
2236
} catch (error: Exception) {
2337
promise.reject(
2438
ScriptLoadingError.ScriptEvalFailure.code,

packages/repack/ios/ScriptManager.mm

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,22 @@ - (void)executeFromFilesystem:(ScriptConfig *)config
304304
filesystemScriptUrl = [[NSBundle mainBundle] URLForResource:scriptName withExtension:scriptExtension];
305305
}
306306
NSData *data = [[NSData alloc] initWithContentsOfFile:[filesystemScriptUrl path]];
307-
[self evaluateJavascript:data url:config.sourceUrl resolve:resolve reject:reject];
307+
308+
NSDictionary<NSString *, id> *result = [CodeSigningUtils extractBundleAndTokenWithFileContent:data];
309+
NSData *bundle = (result[@"bundle"] != [NSNull null]) ? result[@"bundle"] : nil;
310+
NSString *token = (result[@"token"] != [NSNull null]) ? result[@"token"] : nil;
311+
312+
if ([config.verifyScriptSignature isEqualToString:@"strict"] ||
313+
([config.verifyScriptSignature isEqualToString:@"lax"] && token != nil)) {
314+
NSError *codeSigningError = nil;
315+
[CodeSigningUtils verifyBundleWithToken:token fileContent:bundle error:&codeSigningError];
316+
if (codeSigningError != nil) {
317+
reject(CodeExecutionFailure, codeSigningError.localizedDescription, nil);
318+
return;
319+
}
320+
}
321+
322+
[self evaluateJavascript:bundle url:config.sourceUrl resolve:resolve reject:reject];
308323
} @catch (NSError *error) {
309324
reject(CodeExecutionFailure, error.localizedDescription, nil);
310325
}

0 commit comments

Comments
 (0)