3 # Copyright (C) 2017, Michael Poehn <michael.poehn@fsfe.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Affero General Public License for more details.
15 # You should have received a copy of the GNU Affero General Public License
16 # along with this program. If not, see <https://www.gnu.org/licenses/>.
18 from argparse import ArgumentParser
28 from .exception import FDroidException
31 def extract_signature(apkpath):
33 if not os.path.exists(apkpath):
34 raise FDroidException("file APK does not exists '{}'".format(apkpath))
35 if not common.verify_apk_signature(apkpath):
36 raise FDroidException("no valid signature in '{}'".format(apkpath))
37 logging.debug('signature okay: %s', apkpath)
39 appid, vercode, _ignored = common.get_apk_id_aapt(apkpath)
40 sigdir = common.metadata_get_sigdir(appid, vercode)
41 if not os.path.exists(sigdir):
43 common.apk_extract_signatures(apkpath, sigdir)
48 def extract(config, options):
50 # Create tmp dir if missing…
52 if not os.path.exists(tmp_dir):
55 if not options.APK or len(options.APK) <= 0:
56 logging.critical(_('no APK supplied'))
59 # iterate over supplied APKs downlaod and extract them…
60 httpre = re.compile('https?:\/\/')
61 for apk in options.APK:
63 if os.path.isfile(apk):
64 sigdir = extract_signature(apk)
65 logging.info(_("Fetched signatures for '{apkfilename}' -> '{sigdir}'")
66 .format(apkfilename=apk, sigdir=sigdir))
67 elif httpre.match(apk):
68 if apk.startswith('https') or options.no_check_https:
70 tmp_apk = os.path.join(tmp_dir, 'signed.apk')
71 net.download_file(apk, tmp_apk)
72 sigdir = extract_signature(tmp_apk)
73 logging.info(_("Fetched signatures for '{apkfilename}' -> '{sigdir}'")
74 .format(apkfilename=apk, sigdir=sigdir))
76 if tmp_apk and os.path.exists(tmp_apk):
79 logging.warn(_('refuse downloading via insecure HTTP connection (use HTTPS or specify --no-https-check): {apkfilename}').format(apkfilename=apk))
80 except FDroidException as e:
81 logging.warning(_("Failed fetching signatures for '{apkfilename}': {error}")
82 .format(apkfilename=apk, error=e))
84 logging.debug(e.detail)
89 global config, options
91 # Parse command line...
92 parser = ArgumentParser(usage="%(prog)s [options] APK [APK...]")
93 common.setup_global_opts(parser)
94 parser.add_argument("APK", nargs='*',
95 help=_("signed APK, either a file-path or HTTPS URL."))
96 parser.add_argument("--no-check-https", action="store_true", default=False)
97 options = parser.parse_args()
100 config = common.read_config(options)
102 extract(config, options)