22
33import assert = require( "assert" ) ;
44import childProcess = require( "child_process" ) ;
5- import crypto = require( "crypto" ) ;
65import fs = require( "fs" ) ;
76import mkdirp = require( "mkdirp" ) ;
87import os = require( "os" ) ;
@@ -15,6 +14,8 @@ import Q = require("q");
1514
1615import del = require( "del" ) ;
1716
17+ import { codeSigningPublicKey , signAndRecordUpdateArchive , setupTamperedSignatureUpdateScenario } from "./codesign" ;
18+
1819function ensureAndroidCleartextTraffic ( androidManifestPath : string ) : void {
1920 const androidManifestContents = fs . readFileSync ( androidManifestPath , "utf8" ) ;
2021
@@ -69,47 +70,6 @@ function installExpoBundleTooling(projectPath: string): Q.Promise<void> {
6970 ) . then ( ( ) => { return null ; } ) ;
7071}
7172
72- const CODEPUSH_METADATA_FILE_NAME = ".codepushrelease" ;
73-
74- function isHashIgnored ( relativePath : string ) : boolean {
75- return relativePath . startsWith ( "__MACOSX/" )
76- || relativePath === ".DS_Store"
77- || relativePath . endsWith ( "/.DS_Store" )
78- || relativePath === CODEPUSH_METADATA_FILE_NAME
79- || relativePath . endsWith ( `/${ CODEPUSH_METADATA_FILE_NAME } ` ) ;
80- }
81-
82- /**
83- * Computes the same content hash that the native SDKs compute over an installed update folder, so the mock server
84- * can hand back a package_hash that will actually match what the client expects.
85- */
86- function computeUpdateContentsHash ( folderPath : string ) : string {
87- const manifest : string [ ] = [ ] ;
88-
89- const walk = ( currentPath : string , relativePrefix : string ) => {
90- for ( const entryName of fs . readdirSync ( currentPath ) ) {
91- const entryPath = path . join ( currentPath , entryName ) ;
92- const relativePath = relativePrefix ? `${ relativePrefix } /${ entryName } ` : entryName ;
93-
94- if ( isHashIgnored ( relativePath ) ) {
95- continue ;
96- }
97-
98- if ( fs . statSync ( entryPath ) . isDirectory ( ) ) {
99- walk ( entryPath , relativePath ) ;
100- } else {
101- const fileHash = crypto . createHash ( "sha256" ) . update ( fs . readFileSync ( entryPath ) ) . digest ( "hex" ) ;
102- manifest . push ( `${ relativePath } :${ fileHash } ` ) ;
103- }
104- }
105- } ;
106-
107- walk ( folderPath , "" ) ;
108- manifest . sort ( ) ;
109-
110- return crypto . createHash ( "sha256" ) . update ( JSON . stringify ( manifest ) ) . digest ( "hex" ) ;
111- }
112-
11373//////////////////////////////////////////////////////////////////////////////////////////
11474// Create the platforms to run the tests on.
11575
@@ -209,6 +169,7 @@ class RNAndroid extends Platform.Android implements RNPlatform {
209169 const string = path . join ( innerprojectDirectory , "android" , "app" , "src" , "main" , "res" , "values" , "strings.xml" ) ;
210170 TestUtil . replaceString ( string , TestUtil . SERVER_URL_PLACEHOLDER , this . getServerUrl ( ) ) ;
211171 TestUtil . replaceString ( string , TestUtil . ANDROID_KEY_PLACEHOLDER , this . getDefaultDeploymentKey ( ) ) ;
172+ TestUtil . replaceString ( string , "</resources>" , `<string moduleConfig="true" name="CodePushPublicKey">${ codeSigningPublicKey } </string>\n</resources>` ) ;
212173 TestUtil . replaceString ( AndroidManifest , "\\${usesCleartextTraffic}" , "true" ) ;
213174
214175
@@ -283,7 +244,7 @@ class RNIOS extends Platform.IOS implements RNPlatform {
283244 // Put the IOS deployment key in the Info.plist
284245 . then ( TestUtil . replaceString . bind ( undefined , infoPlistPath ,
285246 "</dict>\n</plist>" ,
286- "<key>CodePushDeploymentKey</key>\n\t<string>" + this . getDefaultDeploymentKey ( ) + "</string>\n\t<key>CodePushServerURL</key>\n\t<string>" + this . getServerUrl ( ) + "</string>\n\t</dict>\n</plist>" ) )
247+ "<key>CodePushDeploymentKey</key>\n\t<string>" + this . getDefaultDeploymentKey ( ) + "</string>\n\t<key>CodePushServerURL</key>\n\t<string>" + this . getServerUrl ( ) + "</string>\n\t<key>CodePushPublicKey</key>\n\t<string>" + codeSigningPublicKey + "</string>\n\t< /dict>\n</plist>") )
287248 // Set the app version to 1.0.0 instead of 1.0 in the Info.plist
288249 . then ( TestUtil . replaceString . bind ( undefined , infoPlistPath , "1.0" , "1.0.0" ) )
289250 // Remove dependence of CFBundleShortVersionString from project.pbxproj
@@ -539,28 +500,19 @@ class RNProjectManager extends ProjectManager {
539500 . then ( TestUtil . getProcessOutput . bind ( undefined , "npx expo prebuild --platform " + targetPlatform . getName ( ) , { cwd : path . join ( projectDirectory , TestConfig . TestAppName ) , noLogStdOut : true } ) )
540501 . then ( TestUtil . getProcessOutput . bind ( undefined , "npx react-native bundle --entry-file index.js --platform " + targetPlatform . getName ( ) + " --bundle-output " + bundlePath + " --assets-dest " + bundleFolder + " --dev false" ,
541502 { cwd : path . join ( projectDirectory , TestConfig . TestAppName ) , noLogStdOut : true } ) )
503+ . then ( ( ) => signAndRecordUpdateArchive ( bundleFolder , isDiff ) )
542504 . then < string > ( TestUtil . archiveFolder . bind ( undefined , bundleFolder , "" , path . join ( projectDirectory , TestConfig . TestAppName , "update.zip" ) , isDiff ) )
543- . then < string > ( this . updateMockPackageHash . bind ( this , bundleFolder , isDiff ) )
544505 . then ( ( result ) => { console . log ( `[TIMING] createUpdateArchive(${ projectDirectory } , ${ targetPlatform . getName ( ) } ) took ${ Date . now ( ) - t0 } ms` ) ; return result ; } ) ;
545506 } else {
546507 return deferred . promise
547508 . then ( TestUtil . getProcessOutput . bind ( undefined , "npx react-native bundle --entry-file index.js --platform " + targetPlatform . getName ( ) + " --bundle-output " + bundlePath + " --assets-dest " + bundleFolder + " --dev false" ,
548509 { cwd : path . join ( projectDirectory , TestConfig . TestAppName ) , noLogStdOut : true } ) )
510+ . then ( ( ) => signAndRecordUpdateArchive ( bundleFolder , isDiff ) )
549511 . then < string > ( TestUtil . archiveFolder . bind ( undefined , bundleFolder , "" , path . join ( projectDirectory , TestConfig . TestAppName , "update.zip" ) , isDiff ) )
550- . then < string > ( this . updateMockPackageHash . bind ( this , bundleFolder , isDiff ) )
551512 . then ( ( result ) => { console . log ( `[TIMING] createUpdateArchive(${ projectDirectory } , ${ targetPlatform . getName ( ) } ) took ${ Date . now ( ) - t0 } ms` ) ; return result ; } ) ;
552513 }
553514 }
554515
555- // Records the real hash of bundleFolder of an archive, so the mock server can hand back a
556- // package_hash that matches what the client's verifyFolderHash integrity check will compute.
557- private updateMockPackageHash ( bundleFolder : string , isDiff : boolean , archivePath : string ) : string {
558- // TODO(RA-4875): Diff updates clear it instead, since they are poorly implemented in the entire test harness.
559- // It's going to be a bigger refactor, so for now we just clear the known package hash to avoid using a stale value in diff tests.
560- ServerUtil . setKnownPackageHash ( isDiff ? undefined : computeUpdateContentsHash ( bundleFolder ) ) ;
561- return archivePath ;
562- }
563-
564516 /** JSON file containing the platforms the plugin is currently installed for.
565517 * Keys must match targetPlatform.getName()!
566518 *
@@ -1050,6 +1002,27 @@ PluginTestingFramework.initializeTests(new RNProjectManager(), supportedTargetPl
10501002 } ) ;
10511003 } , ScenarioInstall ) ;
10521004
1005+ TestBuilder . describe ( "#localPackage.install.codeSigning" ,
1006+ ( ) => {
1007+ TestBuilder . it ( "localPackage.install.codeSigning.tamperedSignature" , false ,
1008+ async ( done : Mocha . Done ) => {
1009+ try {
1010+ ServerUtil . updateResponse = { update_info : ServerUtil . createUpdateResponse ( false , targetPlatform ) } ;
1011+
1012+ /* create a normal update, then tamper with its signature after it's been signed */
1013+ const updatePath = await setupTamperedSignatureUpdateScenario ( projectManager , targetPlatform , UpdateNotifyApplicationReady , "Tampered Update" ) ;
1014+ ServerUtil . updatePackagePath = updatePath ;
1015+ projectManager . runApplication ( TestConfig . testRunDirectory , targetPlatform ) ;
1016+ await ServerUtil . expectTestMessages ( [
1017+ ServerUtil . TestMessage . CHECK_UPDATE_AVAILABLE ,
1018+ ServerUtil . TestMessage . DOWNLOAD_ERROR ] ) ;
1019+ done ( ) ;
1020+ } catch ( e ) {
1021+ done ( e ) ;
1022+ }
1023+ } ) ;
1024+ } , ScenarioInstall ) ;
1025+
10531026 TestBuilder . describe ( "#localPackage.install.revert" ,
10541027 ( ) => {
10551028 TestBuilder . it ( "localPackage.install.revert.dorevert" , false ,
0 commit comments