@@ -234,26 +234,69 @@ export async function getRootCommand(adbClient: Adb.DeviceClient): Promise<RootC
234
234
export async function hasCertInstalled (
235
235
adbClient : Adb . DeviceClient ,
236
236
certHash : string ,
237
- certFingerprint : string
237
+ expectedFingerprint : string
238
238
) {
239
- try {
240
- const certPath = `/system/etc/security/cacerts/${ certHash } .0` ;
241
- const certStream = await adbClient . pull ( certPath ) ;
239
+ // We have to check both of these paths. If /system exists but /apex does not, then something
240
+ // has gone wrong and we need to reinstall the cert to fix it.
241
+ const systemCertPath = `/system/etc/security/cacerts/${ certHash } .0` ;
242
+ const apexCertPath = `/apex/com.android.conscrypt/cacerts/${ certHash } .0` ;
242
243
243
- // Wait until it's clear that the read is successful
244
- const data = await streamToBuffer ( certStream ) ;
244
+ try {
245
+ const existingCertChecks = await Promise . all ( [
246
+ adbClient . pull ( systemCertPath )
247
+ . then ( async ( certStream ) => {
248
+ if ( await isMatchingCert ( certStream , expectedFingerprint ) ) {
249
+ console . log ( 'Matching /system cacert exists' ) ;
250
+ return true ;
251
+ } else {
252
+ console . log ( '/system cacert exists but mismatched' ) ;
253
+ return false ;
254
+ }
255
+ } ) ,
256
+
257
+ run ( adbClient , [ 'ls' , '/apex/com.android.conscrypt' ] )
258
+ . then ( async ( lsOutput ) => {
259
+ if ( lsOutput . includes ( 'cacerts' ) ) {
260
+ const certStream = await adbClient . pull ( apexCertPath ) ;
261
+ if ( await isMatchingCert ( certStream , expectedFingerprint ) ) {
262
+ console . log ( 'Matching /apex cacert exists' ) ;
263
+ return true ;
264
+ } else {
265
+ console . log ( '/apex cacert exists but mismatched' ) ;
266
+ return false ;
267
+ }
268
+ } else {
269
+ console . log ( 'No need for /apex cacerts injection' ) ;
270
+ // If apex dir doesn't exist, we don't need to inject anything
271
+ return true ;
272
+ }
273
+ } )
274
+ ] ) ;
245
275
246
- // The device already has an HTTP Toolkit cert. But is it the right one?
247
- const existingCert = parseCert ( data . toString ( 'utf8' ) ) ;
248
- const existingFingerprint = getCertificateFingerprint ( existingCert ) ;
249
- return certFingerprint === existingFingerprint ;
250
- } catch ( e ) {
276
+ return existingCertChecks . every ( result => result === true ) ;
277
+ } catch ( e : any ) {
251
278
// Couldn't read the cert, or some other error - either way, we probably
252
279
// don't have a working system cert installed.
280
+ console . log ( `Couldn't detect cert via ADB: ${ e . message } ` ) ;
253
281
return false ;
254
282
}
255
283
}
256
284
285
+ // The device already has an HTTP Toolkit cert. But is it the right one?
286
+ const isMatchingCert = async ( certStream : stream . Readable , expectedFingerprint : string ) => {
287
+ // Wait until it's clear that the read is successful
288
+ const data = await streamToBuffer ( certStream ) ;
289
+
290
+ // Note that due to https://github.com/DeviceFarmer/adbkit/issues/464 we may see
291
+ // 'empty' data for files that are actually missing entirely.
292
+ if ( data . byteLength === 0 ) return false ;
293
+
294
+ const certData = data . toString ( 'utf8' ) ;
295
+ const existingCert = parseCert ( certData ) ;
296
+ const existingFingerprint = getCertificateFingerprint ( existingCert ) ;
297
+ return expectedFingerprint === existingFingerprint ;
298
+ }
299
+
257
300
export async function injectSystemCertificate (
258
301
adbClient : Adb . DeviceClient ,
259
302
runAsRoot : RootCmd ,
@@ -306,6 +349,10 @@ export async function injectSystemCertificate(
306
349
# this globally as APEX mounts are namespaced per process, so we need to inject a
307
350
# bind mount for this directory into every mount namespace.
308
351
352
+ # First we mount for the shell itself, for completeness and so we can see this
353
+ # when we check for correct installation on later runs
354
+ mount --bind /system/etc/security/cacerts /apex/com.android.conscrypt/cacerts
355
+
309
356
# First we get the Zygote process(es), which launch each app
310
357
ZYGOTE_PID=$(pidof zygote || true)
311
358
ZYGOTE64_PID=$(pidof zygote64 || true)
0 commit comments