Skip to content

Commit

Permalink
Refactor download_headless.py
Browse files Browse the repository at this point in the history
- Support usage as a library
- Optionally get license from a environment variable
- Quiet output option
  • Loading branch information
plafosse committed Sep 18, 2020
1 parent d7f0132 commit c2a04aa
Showing 1 changed file with 100 additions and 41 deletions.
141 changes: 100 additions & 41 deletions scripts/download_headless.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
'''Note that this script will only function for headless licenses at this time.'''
import argparse
import json
import os
import requests
Expand All @@ -9,46 +8,106 @@

from pathlib import Path

class DownloadException(Exception):
pass

url='https://master.binary.ninja/headless-download'
env_lic = 'HEADLESS_LICENSE'
min_download = 8192

def get_system_license_path() -> Path:
"""Returns the default path to the Binary Ninja license.dat on the current platform
if sys.platform == "darwin":
userpath = Path.home() / 'Library' / 'Application Support' / 'Binary Ninja'
elif sys.platform.startswith("linux"):
userpath = Path.home() / '.binaryninja'
else:
userpath = Path.home() / 'AppData' / 'Roaming' / 'Binary Ninja'

serial = ''
parser = argparse.ArgumentParser(description='Download a Binary Ninja installer with a headless license')
parser.add_argument("--serial", help="serial number")
parser.add_argument('--dev', dest='dev', default=False, action='store_true')
args = parser.parse_args()

if args.serial:
serial = args.serial
elif userpath.is_dir():
if (userpath / 'license.dat').is_file():
with open(userpath / 'license.dat') as f:
licenses = json.load(f)
for license in licenses:
if 'headless' in license['product']:
serial = license['serial']

if serial == '':
parser.print_help()
sys.exit(-1)

params = {'serial': serial, 'dev': str(args.dev).lower()}

r = requests.get(url, params)
results = json.loads(r.text)
if results['ok']:
url = results['url']
r = requests.get(url, allow_redirects=True)
filename = os.path.basename(urllib.parse.urlparse(url).path)
if len(r.content) < 2**13:
print(f'Error downloading from {url}')
:return: Path object to the license.dat file.
:rtype: Path
"""
if sys.platform == "darwin":
return Path.home() / 'Library' / 'Application Support' / 'Binary Ninja' / 'license.dat'
elif sys.platform.startswith("linux"):
return Path.home() / '.binaryninja' / 'license.dat'
else:
open(filename, 'wb').write(r.content)
else:
print('Download failed.')
return Path.home() / 'AppData' / 'Roaming' / 'Binary Ninja' / 'license.dat'


def get_serial_from_license(path: str) -> str:
"""Extracts the serial number from the license specified in path
:param path: path to license file
:type path: str
:raises ValueError: When no headless license is found in the provided license.dat
:return: returns the serial number of the headless license
:rtype: str
"""
with open(path) as f:
for license in [l for l in json.load(f) if 'Headless' in l['product']]:
return license['serial']
raise ValueError(f'No "computer" license in {path}')


def get_serial_from_environment(env: str='HEADLESS_LICENSE') -> str:
"""Extracts the serial number from the license file referenced by the env
:param env: environment variable containing headless license path, defaults to 'HEADLESS_LICENSE'
:type env: str, optional
:raises ValueError: When provided envronment variable doesn't exist or license doesn't contain a headless license.
:return: the serial number
:rtype: str
"""
if env not in os.environ:
raise ValueError(f'Please add an environment variable {env} pointing to your headless Binary Ninja license')

return get_serial_from_license(os.environ[env])


def download_headless(serial: str, output_path: str=None, dev: bool=False) -> str:
"""Downloads the headless Binary Ninja installation binaries.
:param serial: Serial number for verification
:type serial: str
:param output_path: path to write the binaries to, defaults to None
:type output_path: str, optional
:param dev: set to True if you wish to download 'dev' branch, defaults to False
:type dev: bool, optional
:raises DownloadException: On failure to download the requested binaries.
"""
r = requests.get(url, {'serial': serial, 'dev': str(dev).lower()})
results = json.loads(r.text)
if not results['ok']:
raise DownloadException('Download failed.')

req_url = results['url']
content = requests.get(req_url, allow_redirects=True)
if len(content.content) < min_download:
raise DownloadException(f'Error downloading from {req_url}')

if output_path is None:
output_path = os.path.basename(urllib.parse.urlparse(req_url).path)
with open(output_path, 'wb') as f:
f.write(content.content)
return output_path

if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description='Download a Binary Ninja installer given a headless license')
parser.add_argument('--serial', default=None, help='serial number')
parser.add_argument('--env', default=False, action='store_true', help='will extract serial from enviroment variable "HEADLESS_LICENSE" if not specfied')
parser.add_argument('--dev', default=False, action='store_true', help='download the development branch')
parser.add_argument('--output', default=None, help='path to write the file to (defaults to current directory)')
parser.add_argument('-q', '--quiet', default=False, action='store_true', help='Don\'t show any output')
args = parser.parse_args()

try:
if args.serial is None:
if args.env:
args.serial = get_serial_from_environment()
else:
args.serial = get_serial_from_license(get_system_license_path())

download_path = download_headless(args.serial, args.output, args.dev)
if not args.quiet:
print(f"Successfully downloaded to: {download_path}")
sys.exit(0)
except Exception as e:
if not args.quiet:
print(e)
sys.exit(1)

0 comments on commit c2a04aa

Please sign in to comment.