#!/usr/bin/env python2.7
import os
import sys
import glob
import shutil
import urllib2
import hashlib
import subprocess
EXTERNAL_PATH = os . path . dirname ( os . path . abspath ( __file__ ) )
if os . path . exists ( " /init.qcom.rc " ) :
# android
APKPATCH = os . path . join ( EXTERNAL_PATH , ' tools/apkpatch_android ' )
SIGNAPK = os . path . join ( EXTERNAL_PATH , ' tools/signapk_android ' )
else :
APKPATCH = os . path . join ( EXTERNAL_PATH , ' tools/apkpatch ' )
SIGNAPK = os . path . join ( EXTERNAL_PATH , ' tools/signapk ' )
APKS = {
' com.waze ' : {
' src ' : ' https://apkcache.s3.amazonaws.com/com.waze_1021278.apk ' ,
' src_sha256 ' : ' f00957e93e2389f9e30502ac54994b98ac769314b0963c263d4e8baa625ab0c2 ' ,
' patch ' : ' com.waze.apkpatch ' ,
' out_sha256 ' : ' fee880a91a44c738442cd05fd1b6d9b5817cbf755aa61c86325ada2bc443d5cf '
} ,
' com.spotify.music ' : {
' src ' : ' https://apkcache.s3.amazonaws.com/com.spotify.music_24382006.apk ' ,
' src_sha256 ' : ' 0610fea68ee7ba5f8e4e0732ad429d729dd6cbb8bc21222c4c99db6cb09fbff4 ' ,
' patch ' : ' com.spotify.music.apkpatch ' ,
' out_sha256 ' : ' 5a3d6f478c7e40403a98ccc8906d7e0ae12b06543b41f5df52149dd09c647c11 '
} ,
}
def sha256_path ( path ) :
with open ( path , ' rb ' ) as f :
return hashlib . sha256 ( f . read ( ) ) . hexdigest ( )
def remove ( path ) :
try :
os . remove ( path )
except OSError :
pass
def process ( download , patch ) :
# clean up any junk apks
for out_apk in glob . glob ( os . path . join ( EXTERNAL_PATH , ' out/*.apk ' ) ) :
app = os . path . basename ( out_apk ) [ : - 4 ]
if app not in APKS :
print " remove junk " , out_apk
remove ( out_apk )
complete = True
for k , v in APKS . iteritems ( ) :
apk_path = os . path . join ( EXTERNAL_PATH , ' out ' , k + ' .apk ' )
print " checking " , apk_path
if os . path . exists ( apk_path ) and sha256_path ( apk_path ) == v [ ' out_sha256 ' ] :
# nothing to do
continue
complete = False
remove ( apk_path )
src_path = os . path . join ( EXTERNAL_PATH , ' src ' , v [ ' src_sha256 ' ] )
if not os . path . exists ( src_path ) or sha256_path ( src_path ) != v [ ' src_sha256 ' ] :
if not download :
continue
print " downloading " , v [ ' src ' ] , " to " , src_path
# download it
resp = urllib2 . urlopen ( v [ ' src ' ] )
data = resp . read ( )
with open ( src_path , ' wb ' ) as src_f :
src_f . write ( data )
if sha256_path ( src_path ) != v [ ' src_sha256 ' ] :
print " download was corrupted... "
continue
if not patch :
continue
# ignoring lots of TOCTTOU here...
apk_temp = " /tmp/ " + k + " .patched "
remove ( apk_temp )
apk_temp2 = " /tmp/ " + k + " .signed "
remove ( apk_temp2 )
try :
print " patching " , v [ ' patch ' ]
subprocess . check_call ( [ APKPATCH , ' apply ' , src_path , apk_temp , os . path . join ( EXTERNAL_PATH , v [ ' patch ' ] ) ] )
print " signing " , apk_temp
subprocess . check_call ( [ SIGNAPK ,
os . path . join ( EXTERNAL_PATH , ' tools/certificate.pem ' ) , os . path . join ( EXTERNAL_PATH , ' tools/key.pk8 ' ) ,
apk_temp , apk_temp2 ] )
out_sha256 = sha256_path ( apk_temp2 ) if os . path . exists ( apk_temp2 ) else None
if out_sha256 == v [ ' out_sha256 ' ] :
print " done " , apk_path
shutil . move ( apk_temp2 , apk_path )
else :
print " patch was corrupted " , apk_temp2 , out_sha256
finally :
remove ( apk_temp )
remove ( apk_temp2 )
return complete
if __name__ == " __main__ " :
ret = True
if len ( sys . argv ) == 2 and sys . argv [ 1 ] == " download " :
ret = process ( True , False )
elif len ( sys . argv ) == 2 and sys . argv [ 1 ] == " patch " :
ret = process ( False , True )
else :
ret = process ( True , True )
sys . exit ( 0 if ret else 1 )