diff --git a/password-manager/README.md b/password-manager/README.md new file mode 100644 index 0000000..2b0917b --- /dev/null +++ b/password-manager/README.md @@ -0,0 +1,46 @@ +# Password manager + +Password manager takes an existing cape encrypted input and returns the specified account and password. + +## Using the password manager +To keep track of a list of passwords the best way is to use your own auth token. +Encryption of sensitive data is reliant on Cape encrypt. + + +## Local format +The local format for your password store is: + +Account|Label|encrypted output| + + +## App +We can just use a simple echo app to return the password in plaintext. + +### Commands + +There are a couple of commands that we can use to interact with the password manager app. +The syntax for interacting with the app is `:`. + +**name** +Specify the name of the account and password. + +**tag** +Returns all the secrets with the corresponding tag. + +**all** +Returns all the secrets stored in the password vault. + + +## Alternative design +We can encrypt the entire password store and pass two separate values one after the other. +In the form of password vault + tag/account and it will return a password. + +If we do this then one deployed webapp can work for everyone. + +However, if you want to add a new account you will have to decode everything and modify +the output. The first one design makes it easy to add an account. However, it requires +more code to run on the client side and doesn't offer storage on Cape. + +## Alternative design 2 +Embed the data in the function. Require a custom app to run this, lots more work on the user. + diff --git a/password-manager/manager/app.py b/password-manager/manager/app.py new file mode 100644 index 0000000..e1c6708 --- /dev/null +++ b/password-manager/manager/app.py @@ -0,0 +1,85 @@ +import json + +FILE_PATH = "./secret.json" + + +def open_secret(path=FILE_PATH): + with open(path) as f: + try: + data = json.load(f) + except Exception: + return None + return data + + +def store_secret(data, path=FILE_PATH): + with open(path, "w", encoding="utf-8") as f: + json.dump(data, f, ensure_ascii=False, indent=4) + + +def filter_by_identifier(vault, key, value): + ret = [] + for i in vault: + if i[key] == value: + ret.append(i) + return ret + + +def cape_handler(arg): + # Try to see if secret exists, if it does, process user input as string an non-json. + secret = open_secret() + if secret == None: + try: + user_input = json.loads(arg) + # Cache the secret in enclave storage + store_secret(user_input) + + except TypeError: + raise TypeError( + "expected secrets vault to passed in first in json format [{name, tag, username, password}]" + ) + + else: + if type(arg) is not str: + raise TypeError(f"expected input to be string, got {type(arg)}") + + if arg == "all": + return json.dumps(secret, indent=4) + + # Try to split the string to get key, value. + identifier = arg.split(":") + if len(identifier) != 2: + raise ValueError( + f"expected input of the form `name:`, or `tag:`, got: {arg}" + ) + cmd = identifier[0].strip() + + if cmd == "name": + # iterage over secret and find a name match + return json.dumps( + filter_by_identifier(secret, "name", identifier[1].strip()), indent=4 + ) + + elif cmd == "tag": + return json.dumps( + filter_by_identifier(secret, "tag", identifier[1].strip()), indent=4 + ) + + else: + return ValueError( + f"unknown command: {identifier[0]}, please use `all`, `name:`, or `tag:`" + ) + + +if __name__ == "__main__": + vault = [ + {"name": "aws", "tag": "grocery", "username": "bob", "password": "B013Pass"}, + {"name": "shop", "tag": "grocery", "username": "bob", "password": "B013Pass"}, + ] + serialized = json.dumps(vault) + + # print(cape_handler(serialized)) + print(cape_handler("all")) + + print(cape_handler("name: aws")) + print(cape_handler("tag: grocery")) diff --git a/password-manager/manager/secret.json b/password-manager/manager/secret.json new file mode 100644 index 0000000..e69de29