Files
linux-cloud-router/debian-package/src/usr/sbin/vpn-router-token
T
2026-10-24 04:19:01 +02:00

80 lines
2.7 KiB
Python
Executable File

#!/usr/bin/python3
"""Make a token with the admin claim for the router's web service, with vpnrouter_auth.
The token is signed with the router's key and is valid for the lifetime given, without a
maximum. It may call every protected path, and it is the only token that may change the
admins group. The answer is the token on standard output, and a failure is a message on
standard error. With --json the answer is {"token", "expires"} on standard output, and a
failure is {"error": ...} there too. The exit status is 2 for an invalid request and 1 for
any other failure. -h or --help shows the options.
vpn-router-token [--json] (--minutes N | --hours N | --days N)
"""
import argparse
import json
import sys
sys.path.insert(0, '/usr/lib/vpn-router')
import vpnrouter_auth
#: The seconds of each unit of the lifetime.
UNITS = {'minutes': 60, 'hours': 3600, 'days': 86400}
class Failure(Exception):
"""A request that cannot be done; status is 2 invalid, 1 other."""
def __init__(self, message, status=1):
super().__init__(message)
self.status = status
class Parser(argparse.ArgumentParser):
"""An argument parser whose errors are Failures with status 2, so that --json answers them as JSON."""
def error(self, message):
raise Failure(f'{message}; see {self.prog} --help', 2)
def positive(value):
try:
number = int(value)
except ValueError:
number = 0
if number < 1:
raise argparse.ArgumentTypeError(f'{value!r} is not a positive whole number')
return number
def main(argv):
# A request that cannot be parsed is answered in JSON when --json is among the arguments.
as_json = '--json' in argv
try:
parser = Parser(prog='vpn-router-token', description='Make a token with the admin claim for the web service.')
parser.add_argument('--json', action='store_true', help='answer in JSON')
lifetime = parser.add_mutually_exclusive_group(required=True)
for unit in UNITS:
lifetime.add_argument(f'--{unit}', type=positive, metavar='N', help=f'valid for N {unit}')
options = parser.parse_args(argv)
as_json = options.json
seconds = next(getattr(options, unit) * factor for unit, factor in UNITS.items() if getattr(options, unit))
answer = vpnrouter_auth.admin_token(seconds)
except Failure as failure:
message, status = str(failure), failure.status
except OSError as exc:
message, status = str(exc), 1
else:
print(json.dumps(answer) if as_json else answer['token'])
return 0
if as_json:
print(json.dumps({'error': message}))
else:
print(f'vpn-router-token: {message}', file=sys.stderr)
return status
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))