Run scripts from the Internet more securely than `curl | bash` (experimental)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

105 lines
2.7 KiB

#!/usr/bin/env python3
import requests
import subprocess
import sys
import os
import argparse
import shlex
def launch(command, data):
if isinstance(command, str):
command = [command]
elif isinstance(command, tuple):
command = list(command)
elif not isinstance(command, list):
raise ValueError("`command` must be `list`, `tuple`, or `str`")
return subprocess.run(command, input=data)
def yn(question, options="yn"):
options = options.lower()
options_display = f"[{'/'.join(options)}]"
full_question = f"{question} {options_display} "
response = "WILL NEVER OCCUR IN OPTIONS"
while not response in options:
response = input(full_question).lower().strip()[0]
return response
parser = argparse.ArgumentParser(
description="Securely run a script from the Internet"
)
parser.add_argument("url", help="URL of the script")
parser.add_argument(
"-i",
"--interpreter",
help="Choose interpreter to use (default: `bash`)",
default="bash",
)
group = parser.add_mutually_exclusive_group()
group.add_argument(
"-p",
"--pager",
help="Choose pager to use (default: `less`)",
default="less",
)
group.add_argument(
"-s",
"--skip-pager",
action="store_true",
help="Skip pager and confirmation; run script immediately",
)
group.add_argument(
"-q",
"--quiet",
action="store_true",
help="Skip pager and confirmation; run script immediately; do not print anything",
)
args = parser.parse_args()
url = args.url
pager = shlex.split(args.pager)
interpreter = shlex.split(args.interpreter)
while True:
if not args.quiet:
print(f"Downloading `{url}`...")
response = requests.get(url, allow_redirects=False)
if response.status_code == 200:
content = response.content
break
else:
try:
print(f"{response.status_code} {response.reason} (redirect to `{response.headers['location']}`)")
if yn("Do you want to follow this redirect?") == 'y':
url = response.headers['location']
else:
print("Not redirecting.")
sys.exit(0)
except KeyError:
print(f"Download failed: {response.status_code} {response.reason}")
sys.exit(0)
if not args.quiet:
print("Download successful.")
print("=" * os.get_terminal_size().columns)
if args.skip_pager or args.quiet:
launch(interpreter, content)
else:
launch(pager, content)
response = yn("Do you want to run this script?")
if response == "y":
print("=" * os.get_terminal_size().columns)
launch(interpreter, content)
else:
print("=" * os.get_terminal_size().columns)
print("Script not run.")