#!/usr/bin/env python3 """Downloads the latest NPAPI or PPAPI Flash plugin directly from Adobe.""" # Copyright (c) 2014, 2016-2017 Scott Zeid. # Released under the X11 License: # import argparse import datetime import enum import html import io import json import os import platform import re import sys import tarfile import time import urllib.parse import urllib.request class APIs(enum.Enum): PPAPI = 1 #enum.auto() NPAPI = 2 #enum.auto() class MainError(Exception): pass class NamedBytesIO(io.BytesIO): name = None def main(argv): try: hep_easter_egg = len(argv) >= 2 and argv[1] == "--hep" if not hep_easter_egg: p = argparse.ArgumentParser( description=__doc__.splitlines()[0].rstrip(), ) p.add_argument("--hep", dest="_hep_easter_egg", action="store_true", help=argparse.SUPPRESS) p.add_argument("-a", "--arch", "--architecture", choices=["x86_64", "i686"], help="download for the given architecture") g = p.add_argument_group("APIs - exactly one of the following is required") m = g.add_mutually_exclusive_group(required=True) m.add_argument("-n", "--npapi", action="store_const", dest="api", const=APIs.NPAPI, help="download the NPAPI version (for use with Firefox and related" " browsers)") m.add_argument("-p", "--ppapi", "--pepper", action="store_const", dest="api", const=APIs.PPAPI, help="download the PPAPI version (for use with Chrome and related" " browsers)") g = p.add_argument_group("output options - at least one of the following is required") g.add_argument("-o", "--output", metavar="OUTPUT_TO", help="save the .tar.gz archive to the given filename or directory") g.add_argument("-e", "--extract", metavar="EXTRACT_TO", help="extract the .tar.gz archive to the given directory" " (will be created if necessary)") try: args = p.parse_args(argv[1:]) except SystemExit as exc: return exc.code if not args.output and not args.extract: try: p.error("at least one of the following are required: -o/--output, -e/--extract") except SystemExit as exc: return exc.code hep_easter_egg = args._hep_easter_egg if hep_easter_egg: print("Hep! Hep! I'm covered in sawlder! ... Eh? Nobody comes.") print("--Red Green, https://www.youtube.com/watch?v=qVeQWtVzkAQ#t=6m27s") return 0 archive = get_flash(args.api, args.arch) if args.output: filename = args.output if os.path.isdir(filename): filename = os.path.join(filename, archive.name) with open(filename, "wb") as f: f.write(archive.read()) archive.seek(0) if args.extract: if not os.path.exists(args.extract): os.makedirs(args.extract) if not os.path.isdir(args.extract): raise MainError("extract-to path exists but is not a directory") tf = tarfile.open(mode="r", fileobj=archive) tf.extractall(args.extract) tf.close() archive.seek(0) return 0 except MainError as e: print("get-flash: error: " + str(e), file=sys.stderr) return 1 def get_flash(api=None, arch=None): api = getattr(api, "name", api).upper() if api not in APIs.__members__.keys(): raise ValueError("unsupported API: %s" % api) api = api.lower() if arch is None: arch = platform.processor() if arch == "x86_64" or arch == "x86-64": arch = "x86-64" elif re.search(r"^i[0-9]86$", arch) or arch == "x86-32": arch = "x86-32" else: raise MainError("unsupported architecture: %s" % arch) url_landing = "https://get.adobe.com/flashplayer/otherversions/" request(url_landing) url_installers = "https://get.adobe.com/flashplayer/webservices/json/?platform_type=Linux&platform_dist=&platform_arch=%s&browser_arch=&browser_type=&browser_vers=&browser_dist=&eventname=flashplayerotherversions" url_installers %= arch time.sleep(0.463) installers = json.loads(request(url_installers, referer=url_landing).decode("utf-8")) url_download = name = None for i in installers: if api in i["download_url"] and ".tar.gz" in i["download_url"]: url_download = i["download_url"] name = i["queryName"] break if not url_download: raise MainError("could not find %s plugin download URL" % api.upper()) url_confirm = "https://get.adobe.com/flashplayer/download/?installer=%s&standalone=1" url_confirm %= html.escape(name) time.sleep(0.361) request(url_confirm, referer=url_installers) time.sleep(0.883) result = NamedBytesIO(request(url_download, referer=url_confirm)) result.name = os.path.basename(urllib.parse.urlparse(url_download).path) return result def request(url, referer=None): req = urllib.request.Request(url) req.add_header("User-Agent", user_agent()) if referer: req.add_header("Referer", referer) with urllib.request.urlopen(req) as f: return f.read() def firefox_version(today=None): """Returns (approximately) the latest major version of Firefox.""" if today != None and not isinstance(today, datetime.date): raise TypeError("today must be a datetime.date") epoch_date = datetime.date(2014, 2, 4) epoch_version = 27 today = today or datetime.date.today() days = (today - epoch_date).days weeks = days // 7 cycles = weeks // 6 return epoch_version + cycles def user_agent(today=None): """Returns a user agent string for (approximately) the latest major version of Firefox.""" tpl = "Mozilla/5.0 (X11; Linux x86_64; rv:{v}) Gecko/20100101 Firefox/{v}" version = str(firefox_version(today)) + ".0" return tpl.format(v=version) if __name__ == "__main__": try: sys.exit(main(sys.argv)) except KeyboardInterrupt: pass