diff --git a/.gitignore b/.gitignore index 2261832..6b2c835 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .vscode __pycache__ .env -client.py .idea/ diff --git a/README.md b/README.md index 6360010..6f7efb0 100644 --- a/README.md +++ b/README.md @@ -66,3 +66,42 @@ pipenv run python app.py ``` By default, it would run at port `8000`. + +## Usage + +#### Get Admin Credentials + +Run the following commands in your uotp directory +```shell +pipenv run python scripts/get-admin.py +``` + +#### Create Auth Account (or any account) + +Run the following command in your uotp directory: +```shell +pipenv run python client create \ + --name auth --realm ungleich-auth \ + --admin-name admin --admin-realm ungleich-admin \ + --admin-seed admin_seed_here +``` + +In response, you would get a JSON object containing Message and +Credentials of newly created account. + +#### List All Accounts with credentials +```shell +pipenv run python client.py list \ + --admin-name admin_name_jere --admin-realm admin_realm_here \ + --admin-seed admin_seed_here +``` + +#### Verify OTP Credentials +```shell +pipenv run python client.py verify \ + --name user_name_here --realm user_realm_here \ + --seed user_seed_here --auth-name auth_name_here \ + --auth-realm auth_realm_here --auth-seed auth_seed_here +``` + +#### Delete OTP Account diff --git a/app.py b/app.py index 2773a90..a4d07fb 100644 --- a/app.py +++ b/app.py @@ -46,11 +46,13 @@ class Create(Resource): _value = {"seed": pyotp.random_base32(), "realm": realms} etcd_client.put(_key, _value, value_in_json=True) return { - "message": "Account Created\n" - "name: {}, realm: {}, seed: {}".format( - data["name"], data["realm"], _value["seed"] - ) - } + "message": "Account Created", + "credentials": { + "name": data["name"], + "realm": _value["realm"], + "seed": _value["seed"] + } + }, 200 else: return schema.get_errors(), 400 diff --git a/client.py b/client.py new file mode 100644 index 0000000..7c50913 --- /dev/null +++ b/client.py @@ -0,0 +1,81 @@ +import requests +import decouple +import pyotp +import argparse + +arg_parser = argparse.ArgumentParser() +arg_parser.add_argument("action", choices=["list", "create", "verify", "delete"]) +arg_parser.add_argument("--name") +arg_parser.add_argument("--realm") +arg_parser.add_argument("--seed") +arg_parser.add_argument("--admin-name") +arg_parser.add_argument("--admin-realm") +arg_parser.add_argument("--admin-seed") +arg_parser.add_argument("--auth-name") +arg_parser.add_argument("--auth-realm") +arg_parser.add_argument("--auth-seed") + +args = arg_parser.parse_args() + +action = args.action + +if action == "list": + assert args.admin_name and args.admin_realm and args.admin_seed, \ + "You must pass --admin-name, --admin-realm and --admin-seed" + + data = \ + { + "admin_name": args.admin_name, + "admin_realm": args.admin_realm, + "admin_token": pyotp.TOTP(args.admin_seed).now() + } + r = requests.get("http://localhost:{}/list".format(decouple.config('PORT')), + json=data) + print(r.content.decode("utf-8")) + +elif action == "create": + assert args.name and args.realm and args.admin_name and args.admin_realm and args.admin_seed, \ + "You must pass --name, --realm, --admin-name, --admin-realm and --admin-seed" + + data = \ + { + "name": args.name, + "realm": args.realm, + "admin_name": args.admin_name, + "admin_realm": args.admin_realm, + "admin_token": pyotp.TOTP(args.admin_seed).now() + } + r = requests.post("http://localhost:{}/create".format(decouple.config('PORT')), + json=data) + print(r.content.decode("utf-8")) + +elif action == "verify": + assert args.name and args.realm and args.seed and args.auth_name and args.auth_realm and args.auth_seed, \ + "You must pass --name, --realm, --seed, --auth-name, --auth-realm and --auth-seed" + data = \ + { + "name": args.name, + "realm": args.realm, + "token": pyotp.TOTP(args.seed).now(), + "auth_name": args.auth_name, + "auth_realm": args.auth_realm, + "auth_token": pyotp.TOTP(args.auth_seed).now() + } + r = requests.get("http://localhost:{}/verify".format(decouple.config('PORT')), + json=data) + print(r.content.decode("utf-8")) + +elif action == "delete": + assert args.name and args.admin_name and args.admin_realm and args.admin_seed, \ + "You must pass --name, --admin-name, --admin-realm and --admin-seed" + + data = \ + { + "name": args.name, + "admin_name": args.admin_name, + "admin_realm": args.admin_realm, + "admin_token": pyotp.TOTP(args.admin_seed).now() + } + r = requests.post("http://localhost:{}/delete".format(decouple.config('PORT')), + json=data) + print(r.content.decode("utf-8")) \ No newline at end of file diff --git a/scripts/get-admin.py b/scripts/get-admin.py index ec5f90b..c0c1c92 100644 --- a/scripts/get-admin.py +++ b/scripts/get-admin.py @@ -3,6 +3,6 @@ import decouple from os.path import join as join_path from etcd3_wrapper import Etcd3Wrapper -client = Etcd3Wrapper(port=decouple.config('PORT')) +client = Etcd3Wrapper() admin_uotp = client.get(join_path(decouple.config('BASE_PREFIX'), 'admin')) print(admin_uotp.value) \ No newline at end of file