diff --git a/README.md b/README.md index a13c757..d887e26 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,10 @@ I then added some convenience features, like storing the list of keys which is d You can still use this tool along with a regular password manager (for mobile sync), it would replace the manager's random password generation, and you would still get the benefit of always having access to your passwords regardless of the manager's availability. +## Download +- Windows: Check [Releases Page](https://github.com/hassanselim0/PassGen/releases/latest) +- Linux/MacOS: `pip install passgen-py` + ## FAQ - **Q: Isn't storing a hash of the master password a bad idea?** - A: It's the old security vs convenience balance, also the hash is generated using salted PBKDF2 HMAC-SHA256 (in v2 keylists). However I do intend to add the ability to disable that convenience. @@ -25,7 +29,7 @@ You can still use this tool along with a regular password manager (for mobile sy - **Q: Android Version?** - A: I initially wanted to build an Android version for this tool, but I gave up and used a password manager for the few passwords that I use on my phone, feel free to build your own and ping me. - **Q: Linux Version?** -- A: I do have a very rough python script that reads the keylist file and generates passwords, but it obviously lacks a lot of convenience features. I might add it to this repo or as a gist. +- A: Yes! Thanks to @mariamrf there is now a Python CLI version of PassGen that can run anywhere where Python runs! - **Q: This code is ugly and doesn't use MVVM!** - A: This is a hobby-project initially made for personal use, very few hours were put into the first version of this. - **Q: I don't see a value in this tool.** diff --git a/passgen-py/setup.py b/passgen-py/setup.py index fb336d7..4897778 100644 --- a/passgen-py/setup.py +++ b/passgen-py/setup.py @@ -1,17 +1,17 @@ from setuptools import setup, find_packages setup( - name = 'passgen-py', - packages = find_packages(), - version = '0.1.1', - description = 'Generate Passwords Deterministically based on a Master Password.', - classifiers = [ - 'Development Status :: 3 - Alpha', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3' - ], - python_requires='>=3.6, <4', - entry_points={ + name='passgen-py', + packages=find_packages(), + version='1.1', + description='Generate Passwords Deterministically based on a Master Password.', + classifiers=[ + 'Development Status :: 3 - Alpha', + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python :: 3' + ], + python_requires='>=3.6, <4', + entry_points={ 'console_scripts': [ 'passgen=src:cli', ], diff --git a/passgen-py/src/__init__.py b/passgen-py/src/__init__.py index 4bee926..bd83e48 100644 --- a/passgen-py/src/__init__.py +++ b/passgen-py/src/__init__.py @@ -39,7 +39,7 @@ def init(master_password, iter_count, keylist_path): '-p', '--master-password', prompt=True, hide_input=True, type=str) @click.option( - '-l', '--label', help='Case-insensitive label for passwords.', + '-l', '--label', help='Case-sensitive label for passwords.', prompt=True) @click.option( '-kp', '--keylist-path', @@ -49,7 +49,6 @@ def generate(master_password, label, keylist_path): keylist = utils.load_keylist(keylist_path) abort_if_incorrect_master(master_password, keylist, keylist_path) - label = label.lower() key = keylist.get_key(label) if key is None: max_length = click.prompt('Max Length', type=int, default=-1) @@ -72,7 +71,7 @@ def generate(master_password, label, keylist_path): '-p', '--master-password', prompt=True, hide_input=True, type=str) @click.option( - '-l', '--label', help='Case-insensitive label for passwords.', + '-l', '--label', help='Case-sensitive label for passwords.', prompt=True) @click.option( '-kp', '--keylist-path', @@ -83,8 +82,6 @@ def reset(ctx, master_password, label, keylist_path): keylist = utils.load_keylist(keylist_path) abort_if_incorrect_master(master_password, keylist, keylist_path) - label = label.lower() - keylist.remove_key(label) utils.save_keylist(keylist_path, keylist) ctx.invoke(generate, master_password, label, keylist_path) diff --git a/passgen-py/src/models.py b/passgen-py/src/models.py index f471dc2..9d216da 100644 --- a/passgen-py/src/models.py +++ b/passgen-py/src/models.py @@ -2,7 +2,7 @@ class KeyList: - def __init__(self, master, keys=[], version=1): + def __init__(self, master, keys=[], version=2): self.master = master self.version = version self.keys = keys diff --git a/passgen-py/tests/fixtures/test_keylist.keys.json b/passgen-py/tests/fixtures/test_keylist.keys.json index 7624d5a..7c4afd7 100644 --- a/passgen-py/tests/fixtures/test_keylist.keys.json +++ b/passgen-py/tests/fixtures/test_keylist.keys.json @@ -1 +1,25 @@ -{"Master": {"Hash": "iW1VFYWsCf20F9uCVKy+xiZg3Dx9+U6vhZcdaPLcHgw=", "Salt": "SWM4psr0po5UVU+eGBTgJ2D406hAQ3a1NxOCILXd7/s=", "IterCount": 1000}, "Version": 1, "Keys": [{"Label": "somelabel", "GenMode": "Base64", "MaxLength": 5}, {"Label": "anotherlabel", "GenMode": "Base64", "MaxLength": null}, {"Label": "onemorelabel", "GenMode": "AlphaNum", "MaxLength": null}]} \ No newline at end of file +{ + "Master": { + "Hash": "iW1VFYWsCf20F9uCVKy+xiZg3Dx9+U6vhZcdaPLcHgw=", + "Salt": "SWM4psr0po5UVU+eGBTgJ2D406hAQ3a1NxOCILXd7/s=", + "IterCount": 1000 + }, + "Version": 2, + "Keys": [ + { + "Label": "somelabel", + "GenMode": "Base64", + "MaxLength": 5 + }, + { + "Label": "anotherlabel", + "GenMode": "Base64", + "MaxLength": null + }, + { + "Label": "onemorelabel", + "GenMode": "AlphaNum", + "MaxLength": null + } + ] +} \ No newline at end of file