diff --git a/scripts/guru-sophos-password b/scripts/guru-sophos-password new file mode 100755 index 0000000..598c0d9 --- /dev/null +++ b/scripts/guru-sophos-password @@ -0,0 +1,7 @@ +#! /bin/bash +set -e + +BASE_PW=$(op read "op://t4auhpfxnrrtyvfml4kysvgb2i/rqinfxfqr7z5e2gmix6beiqcxy/password") +OTP=$(op read "op://t4auhpfxnrrtyvfml4kysvgb2i/rqinfxfqr7z5e2gmix6beiqcxy/one-time password?attribute=otp") + +echo ${BASE_PW}${OTP} \ No newline at end of file diff --git a/scripts/guru-vpn b/scripts/guru-vpn index 187fc10..5e772cc 100755 --- a/scripts/guru-vpn +++ b/scripts/guru-vpn @@ -1,142 +1,37 @@ -#! /usr/bin/env python3 -import argparse -import sys -import subprocess -from typing import Optional +#! /bin/bash +set -e +# Require 1 argument (connect or disconnect) +if [ -z "$1" ]; then + echo "Usage: guru-vpn " + exit 1 +fi -def has_ykman() -> bool: - try: - subprocess.run(["ykman", "--version"], check=True, stdout=subprocess.DEVNULL) - return True - except subprocess.CalledProcessError: - return False +# If we are told to disconnect +if [ "$1" == "disconnect" ]; then + echo "Disconnecting..." + nmcli connection down "Guru VPN" + exit 0 +fi +# If we are told to connect +if [ "$1" == "connect" ]; then + # Attempt to disconnect, just in case we are on a stale connection + echo "Attempting to leave stale connection if it exists" + nmcli connection down "Guru VPN" | true -def has_yk_plugged_in() -> bool: - devices = subprocess.run(["ykman", "list"], check=True, stdout=subprocess.PIPE) - devices = devices.stdout.decode("utf-8").split("\n") - return len(devices) > 1 + # Generate the password + echo "Constructing one-time password" + vpn_pass=$(guru-sophos-password) + # Connect + echo "Connecting..." + nmcli connection modify "Guru VPN" vpn.secrets "password=${vpn_pass}" + nmcli connection up "Guru VPN" -def is_interface_up(interface: str) -> bool: - try: - subprocess.run( - ["ip", "link", "show", interface], check=True, stdout=subprocess.DEVNULL - ) - return True - except subprocess.CalledProcessError: - return False + exit 0 +fi - -def get_oath_code(service: str) -> Optional[int]: - response = subprocess.run( - ["ykman", "oath", "accounts", "code", "Guru"], - check=True, - stdout=subprocess.PIPE, - ) - output = response.stdout.decode("utf-8") - if not output: - return None - return int(output.split("\n")[0].split(" ")[-1]) - - -def get_password(label: str, ns: str, key: str) -> str: - # Try to find it - try: - result = subprocess.run( - ["secret-tool", "lookup", ns, key], check=True, stdout=subprocess.PIPE - ) - return result.stdout.decode("utf-8") - except subprocess.CalledProcessError: - # If we are here, it doesn't exist - print(f"Enter your {label}") - subprocess.run(["secret-tool", "store", "--label", label, ns, key], check=True) - return get_password(label, ns, key) - - -def handle_connect(args: argparse.Namespace) -> int: - if not has_yk_plugged_in(): - print("Could not find YubiKey. Is it plugged in?", file=sys.stderr) - return 1 - - # If we are connected to AS54041, we need to briefly kill the connection - if args.wireguard_support and is_interface_up("vpn"): - print("Bringing down AS54041 VPN") - subprocess.run(["sudo", "wg-quick", "down", "vpn"], check=True) - - # Get the base password - base_password = get_password("Guru VPN Password", "guru-vpn", "base-password") - - # Fetch the credentials from the Yubikey - oath_code = get_oath_code("Guru") - print(f"Using OATH code: {oath_code}") - if not len(str(oath_code)) == 6: - print("Invalid OATH code length. Try again in a minute.", file=sys.stderr) - return 1 - - # Construct the one-time password - password = f"{base_password}{oath_code}" - - # Connect via nmcli - print("Bringing up Guru VPN") - subprocess.run( - [ - "nmcli", - "connection", - "modify", - "Guru VPN", - "vpn.secrets", - f"password={password}", - ], - check=True, - ) - subprocess.run(["nmcli", "connection", "up", "Guru VPN"], check=True) - - # Bring AS54041 back up - print("Bringing up AS54041 VPN") - if args.wireguard_support: - subprocess.run(["sudo", "wg-quick", "up", "vpn"], check=True) - - -def handle_disconnect(args: argparse.Namespace) -> int: - # Disconnect from Guru VPN - print("Bringing down Guru VPN") - result = subprocess.run(["nmcli", "connection", "down", "Guru VPN"]) - return 0 - - - -def main() -> int: - # Handle program arguments - ap = argparse.ArgumentParser( - prog="guru-vpn", description="Utility for connecting to the Guru VPN" - ) - ap.add_argument( - "operation", - choices=["connect", "disconnect", "reconnect"], - help="Operation to perform", - ) - ap.add_argument( - "-w", - "--wireguard-support", - help="Handles wireguard interfaces", - action="store_true", - ) - args = ap.parse_args() - - # Ensure we can actually get credentials from the Yubikey - if not has_ykman(): - print("Could not execute `ykman`. Is it installed?", file=sys.stderr) - return 1 - - # Handle subcommands - cmd_fns = { - "connect": lambda args: handle_disconnect(args) or handle_connect(args), - "disconnect": handle_disconnect, - } - return cmd_fns[args.operation](args) - - -if __name__ == "__main__": - sys.exit(main()) +# If we are here, we were given an invalid command +echo "Usage: guru-vpn " +exit 1 \ No newline at end of file