install: function to fetch, verify and install the F-Droid.apk
This commit is contained in:
parent
681d705da0
commit
c7bc8d0fea
@ -20,6 +20,7 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import glob
|
import glob
|
||||||
|
import locale
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
@ -83,6 +84,60 @@ def download_fdroid_apk():
|
|||||||
return net.download_using_mirrors([mirror])
|
return net.download_using_mirrors([mirror])
|
||||||
|
|
||||||
|
|
||||||
|
def install_fdroid_apk(privacy_mode=False):
|
||||||
|
"""Download and install F-Droid.apk using all tricks we can muster.
|
||||||
|
|
||||||
|
By default, this first tries to fetch the official install APK
|
||||||
|
which is offered when someone clicks the "download" button on
|
||||||
|
https://f-droid.org/. Then it will try all the mirrors and
|
||||||
|
methods until it gets something successful, or runs out of
|
||||||
|
options.
|
||||||
|
|
||||||
|
There is privacy_mode which tries to download from mirrors first,
|
||||||
|
so that this downloads from a mirror that has many different kinds
|
||||||
|
of files available, thereby breaking the clear link to F-Droid.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
None for success or the error message.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if locale.getlocale()[0].split('_')[-1] in ('CN', 'HK', 'IR', 'TM'):
|
||||||
|
logging.warning(_('Privacy mode was enabled based on your locale.'))
|
||||||
|
privacy_mode = True
|
||||||
|
|
||||||
|
if privacy_mode or not (config and config.get('jarsigner')):
|
||||||
|
download_methods = [download_fdroid_apk]
|
||||||
|
else:
|
||||||
|
download_methods = [download_apk, download_fdroid_apk]
|
||||||
|
for method in download_methods:
|
||||||
|
try:
|
||||||
|
f = method()
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
logging.info(e)
|
||||||
|
else:
|
||||||
|
return _('F-Droid.apk could not be downloaded from any known source!')
|
||||||
|
|
||||||
|
if config and config['apksigner']:
|
||||||
|
# TODO this should always verify, but that requires APK sig verification in Python #94
|
||||||
|
logging.info(_('Verifying package {path} with apksigner.').format(path=f))
|
||||||
|
common.verify_apk_signature(f)
|
||||||
|
fingerprint = common.apk_signer_fingerprint(f)
|
||||||
|
if fingerprint.upper() != common.FDROIDORG_FINGERPRINT:
|
||||||
|
return _('{path} has the wrong fingerprint ({fingerprint})!').format(
|
||||||
|
path=f, fingerprint=fingerprint
|
||||||
|
)
|
||||||
|
|
||||||
|
if config and config.get('adb'):
|
||||||
|
if devices():
|
||||||
|
install_apks_to_devices([f])
|
||||||
|
os.remove(f)
|
||||||
|
else:
|
||||||
|
os.remove(f)
|
||||||
|
return _('No devices found for `adb install`! Please plug one in.')
|
||||||
|
|
||||||
|
|
||||||
def devices():
|
def devices():
|
||||||
"""Get the list of device serials for use with adb commands."""
|
"""Get the list of device serials for use with adb commands."""
|
||||||
p = common.SdkToolsPopen(['adb', "devices"])
|
p = common.SdkToolsPopen(['adb', "devices"])
|
||||||
@ -162,17 +217,16 @@ def main():
|
|||||||
common.set_console_logging(options.verbose)
|
common.set_console_logging(options.verbose)
|
||||||
|
|
||||||
if not options.appid and not options.all:
|
if not options.appid and not options.all:
|
||||||
parser.error(
|
# TODO implement me, including a -y/--yes flag
|
||||||
_("option %s: If you really want to install all the signed apps, use --all")
|
print('TODO prompt the user if they want to download and install F-Droid.apk')
|
||||||
% "all"
|
|
||||||
)
|
|
||||||
|
|
||||||
config = common.read_config()
|
config = common.read_config()
|
||||||
|
|
||||||
output_dir = 'repo'
|
output_dir = 'repo'
|
||||||
if not os.path.isdir(output_dir):
|
if (options.appid or options.all) and not os.path.isdir(output_dir):
|
||||||
logging.info(_("No signed output directory - nothing to do"))
|
logging.error(_("No signed output directory - nothing to do"))
|
||||||
sys.exit(0)
|
# TODO prompt user if they want to download from f-droid.org
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
if options.appid:
|
if options.appid:
|
||||||
vercodes = common.read_pkg_args(options.appid, True)
|
vercodes = common.read_pkg_args(options.appid, True)
|
||||||
@ -196,13 +250,16 @@ def main():
|
|||||||
raise FDroidException(_("No signed APK available for %s") % appid)
|
raise FDroidException(_("No signed APK available for %s") % appid)
|
||||||
install_apks_to_devices(apks.values())
|
install_apks_to_devices(apks.values())
|
||||||
|
|
||||||
else:
|
elif options.all:
|
||||||
apks = {
|
apks = {
|
||||||
common.publishednameinfo(apkfile)[0]: apkfile
|
common.publishednameinfo(apkfile)[0]: apkfile
|
||||||
for apkfile in sorted(glob.glob(os.path.join(output_dir, '*.apk')))
|
for apkfile in sorted(glob.glob(os.path.join(output_dir, '*.apk')))
|
||||||
}
|
}
|
||||||
install_apks_to_devices(apks.values())
|
install_apks_to_devices(apks.values())
|
||||||
|
|
||||||
|
else:
|
||||||
|
sys.exit(install_fdroid_apk())
|
||||||
|
|
||||||
logging.info('\n' + _('Finished'))
|
logging.info('\n' + _('Finished'))
|
||||||
|
|
||||||
|
|
||||||
|
@ -171,13 +171,54 @@ class InstallTest(unittest.TestCase):
|
|||||||
common.fill_config_defaults(common.config)
|
common.fill_config_defaults(common.config)
|
||||||
self.assertEqual([], fdroidserver.install.devices())
|
self.assertEqual([], fdroidserver.install.devices())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _download_raise(privacy_mode):
|
||||||
|
raise Exception('fake failed download')
|
||||||
|
|
||||||
|
@patch('fdroidserver.install.download_apk')
|
||||||
|
@patch('fdroidserver.install.download_fdroid_apk')
|
||||||
|
def test_install_fdroid_apk_privacy_mode_true(
|
||||||
|
self, download_fdroid_apk, download_apk
|
||||||
|
):
|
||||||
|
download_apk.side_effect = self._download_raise
|
||||||
|
download_fdroid_apk.side_effect = self._download_raise
|
||||||
|
fdroidserver.common.config = {'jarsigner': 'fakepath'}
|
||||||
|
install.install_fdroid_apk(privacy_mode=True)
|
||||||
|
download_apk.assert_not_called()
|
||||||
|
download_fdroid_apk.assert_called_once()
|
||||||
|
|
||||||
|
@patch('fdroidserver.install.download_apk')
|
||||||
|
@patch('fdroidserver.install.download_fdroid_apk')
|
||||||
|
def test_install_fdroid_apk_privacy_mode_false(
|
||||||
|
self, download_fdroid_apk, download_apk
|
||||||
|
):
|
||||||
|
download_apk.side_effect = self._download_raise
|
||||||
|
download_fdroid_apk.side_effect = self._download_raise
|
||||||
|
fdroidserver.common.config = {'jarsigner': 'fakepath'}
|
||||||
|
install.install_fdroid_apk(privacy_mode=False)
|
||||||
|
download_apk.assert_not_called()
|
||||||
|
download_fdroid_apk.assert_called_once()
|
||||||
|
|
||||||
|
@patch('fdroidserver.install.download_apk')
|
||||||
|
@patch('fdroidserver.install.download_fdroid_apk')
|
||||||
|
@patch('locale.getlocale', lambda: ('zh_CN', 'UTF-8'))
|
||||||
|
def test_install_fdroid_apk_privacy_mode_locale_auto(
|
||||||
|
self, download_fdroid_apk, download_apk
|
||||||
|
):
|
||||||
|
download_apk.side_effect = self._download_raise
|
||||||
|
download_fdroid_apk.side_effect = self._download_raise
|
||||||
|
fdroidserver.common.config = {'jarsigner': 'fakepath'}
|
||||||
|
install.install_fdroid_apk(privacy_mode=None)
|
||||||
|
download_apk.assert_not_called()
|
||||||
|
download_fdroid_apk.assert_called_once()
|
||||||
|
|
||||||
@patch('fdroidserver.net.download_using_mirrors', lambda m: 'testvalue')
|
@patch('fdroidserver.net.download_using_mirrors', lambda m: 'testvalue')
|
||||||
def test_download_fdroid_apk_smokecheck(self):
|
def test_download_fdroid_apk_smokecheck(self):
|
||||||
self.assertEqual('testvalue', install.download_fdroid_apk())
|
self.assertEqual('testvalue', install.download_fdroid_apk())
|
||||||
|
|
||||||
@unittest.skipUnless(os.getenv('test_download_fdroid_apk'), 'requires net access')
|
@unittest.skipUnless(os.getenv('test_download_fdroid_apk'), 'requires net access')
|
||||||
def test_download_fdroid_apk(self):
|
def test_download_fdroid_apk(self):
|
||||||
f = fdroidserver.install.download_fdroid_apk()
|
f = install.download_fdroid_apk()
|
||||||
self.assertTrue(Path(f).exists())
|
self.assertTrue(Path(f).exists())
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user