Pārlūkot izejas kodu

Format update

pull/398/head
Guillaume Vincent pirms 5 gadiem
vecāks
revīzija
b310f00cb8
9 mainītis faili ar 158 papildinājumiem un 166 dzēšanām
  1. +1
    -1
      cli/lesspass/__init__.py
  2. +85
    -63
      cli/lesspass/cli.py
  3. +1
    -0
      cli/lesspass/clipboard.py
  4. +9
    -8
      cli/lesspass/core.py
  5. +2
    -2
      cli/lesspass/profile.py
  6. +1
    -1
      cli/lesspass/version.py
  7. +2
    -1
      cli/tests/test_interaction.py
  8. +57
    -31
      cli/tests/test_password_generation.py
  9. +0
    -59
      cli/tests/test_validator.py

+ 1
- 1
cli/lesspass/__init__.py Parādīt failu

@@ -1,2 +1,2 @@
name = "lesspass"
description = "Lesspass is a stateless password manager."
description = "LessPass is a stateless password manager."

+ 85
- 63
cli/lesspass/cli.py Parādīt failu

@@ -5,8 +5,7 @@ from lesspass import version
from lesspass import name
from lesspass import description

examples = \
"""
EXAMPLES = """
examples:
# no symbols
lesspass site login masterpassword --no-symbols
@@ -21,84 +20,107 @@ examples:
LESSPASS_MASTER_PASSWORD="masterpassword" lesspass site login
"""

copyright = \
"""
COPYRIGHT = """
copyright:
Copyright © 2018 Guillaume Vincent <contact@lesspass.com>. License GPLv3: GNU GPL version 3 <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law
"""


def parse_args(args):
parser = argparse.ArgumentParser(
# we override usage here to match original help output
# and to indicate SITE as a required argument, either via
# cli or via the prompt flag
usage="lesspass SITE [LOGIN] [MASTER_PASSWORD] [OPTIONS]",
description=description,
epilog=examples+copyright,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("-v", "--version", action="version",
version=version.__version__)
# technically this is required, but we can't require it here because
# the user can still provide this via --prompt
parser.add_argument("site",
nargs="?",
help="site used in the password generation. " +
"(required)")
parser.add_argument("login", nargs="?",
help="login used in the password generation." +
" Default to '' if not provided")
epilog=EXAMPLES + COPYRIGHT,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
"-v", "--version", action="version", version=version.__version__
)
parser.add_argument("site", help="site used in the password generation (required)")
parser.add_argument(
"login", nargs="?", help="login used in the password generation. Default to ''."
)
parser.add_argument(
"master_password",
default=os.environ.get("LESSPASS_MASTER_PASSWORD", None),
nargs="?",
help="master password used in password generation. Default " +
"to LESSPASS_MASTER_PASSWORD env variable or prompt."
)
parser.add_argument("-L", "--length", default=16, type=int,
help="password length (default: 16, max: 35)")
parser.add_argument("-C", "--counter", default=1, type=int,
help="password counter (default: 1)")
parser.add_argument("-p", "--prompt", dest="prompt",
action="store_true",
help="prompt for values interactively")
help="master password used in password generation. Default to LESSPASS_MASTER_PASSWORD env variable or prompt.",
)
parser.add_argument(
"-c", "--copy", "--clipboard", dest="clipboard", action="store_true",
help="attempt to copy to password to clipboard"
"-L",
"--length",
default=16,
type=int,
help="password length (default: 16, max: 35)",
)
parser.add_argument(
"-C", "--counter", default=1, type=int, help="password counter (default: 1)"
)
parser.add_argument(
"-p",
"--prompt",
dest="prompt",
action="store_true",
help="prompt for values interactively",
)
parser.add_argument(
"-c",
"--copy",
dest="clipboard",
action="store_true",
help="copy to password to clipboard",
)

lowercase_excl = parser.add_mutually_exclusive_group()
lowercase_excl.add_argument("-l", "--lowercase",
help="add lowercase in password",
dest="l",
action="store_true")
lowercase_excl.add_argument("--no-lowercase",
help="remove lowercase from password",
dest="nl",
action="store_true")

uppercase_excl = parser.add_mutually_exclusive_group()
uppercase_excl.add_argument("-u", "--uppercase", dest="u",
help="add uppercase in password",
action="store_true")
uppercase_excl.add_argument("--no-uppercase", dest="nu",
help="remove uppercase from password",
action="store_true")
lowercase_group = parser.add_mutually_exclusive_group()
lowercase_group.add_argument(
"-l",
"--lowercase",
help="add lowercase in password",
dest="l",
action="store_true",
)
lowercase_group.add_argument(
"--no-lowercase",
help="remove lowercase from password",
dest="nl",
action="store_true",
)

digits_excl = parser.add_mutually_exclusive_group()
uppercase_group = parser.add_mutually_exclusive_group()
uppercase_group.add_argument(
"-u",
"--uppercase",
dest="u",
help="add uppercase in password",
action="store_true",
)
uppercase_group.add_argument(
"--no-uppercase",
dest="nu",
help="remove uppercase from password",
action="store_true",
)

digits_excl.add_argument("-d", "--digits", dest="d",
help="add digits in password",
action="store_true")
digits_excl.add_argument("--no-digits", dest="nd",
help="remove digits from password",
action="store_true")
digits_group = parser.add_mutually_exclusive_group()
digits_group.add_argument(
"-d", "--digits", dest="d", help="add digits in password", action="store_true"
)
digits_group.add_argument(
"--no-digits",
dest="nd",
help="remove digits from password",
action="store_true",
)

symbols_excl = parser.add_mutually_exclusive_group()
symbols_excl.add_argument("-s", "--symbols", dest="s",
help="add symbols in password",
action="store_true")
symbols_excl.add_argument("--no-symbols", dest="ns",
help="remove symbols from password",
action="store_true")
symbols_group = parser.add_mutually_exclusive_group()
symbols_group.add_argument(
"-s", "--symbols", dest="s", help="add symbols in password", action="store_true"
)
symbols_group.add_argument(
"--no-symbols",
dest="ns",
help="remove symbols from password",
action="store_true",
)
return parser.parse_args(args)

+ 1
- 0
cli/lesspass/clipboard.py Parādīt failu

@@ -36,6 +36,7 @@ commands = {
"xclip": ["xclip", "-selection", "clipboard"],
}


def copy(text):
command = get_system_copy_command()
if command is None:


+ 9
- 8
cli/lesspass/core.py Parādīt failu

@@ -12,11 +12,14 @@ from lesspass.clipboard import copy, get_system_copy_command

signal.signal(signal.SIGINT, lambda s, f: sys.exit(0))


def main(args=sys.argv[1:]):
args = parse_args(args)
if args.clipboard and not get_system_copy_command():
print("ERROR To use the option -c (--copy) you need pbcopy " +
"on OSX, xsel or xclip on Linux, and clip on Windows")
print(
"ERROR To use the option -c (--copy) you need pbcopy "
+ "on OSX, xsel or xclip on Linux, and clip on Windows"
)
sys.exit(3)

if args.prompt:
@@ -24,15 +27,12 @@ def main(args=sys.argv[1:]):
args.login = getpass.getpass("Login: ")
if not args.master_password:
args.master_password = getpass.getpass("Master Password: ")
# if by this point we don't have SITE or the master password,
# we should stop.

if not args.site:
print("ERROR argument SITE is required but was not provided.")
sys.exit(4)
if not args.master_password:
print("ERROR argument MASTER_PASSWORD is required but " +
"was not provided")
print("ERROR argument MASTER_PASSWORD is required but was not provided")
sys.exit(5)

profile, master_password = create_profile(args)
@@ -54,5 +54,6 @@ def main(args=sys.argv[1:]):
else:
print(generated_password)

if __name__ == '__main__':

if __name__ == "__main__":
main()

+ 2
- 2
cli/lesspass/profile.py Parādīt failu

@@ -2,8 +2,8 @@ def create_profile(args):
profile = {
"lowercase": False if args.nl else True,
"uppercase": False if args.nu else True,
"digits": False if args.nd else True,
"symbols": False if args.ns else True,
"digits": False if args.nd else True,
"symbols": False if args.ns else True,
"length": args.length,
"counter": args.counter,
"site": args.site,


+ 1
- 1
cli/lesspass/version.py Parādīt failu

@@ -1 +1 @@
__version__ = '6.1.0'
__version__ = "7.0.0"

+ 2
- 1
cli/tests/test_interaction.py Parādīt failu

@@ -3,9 +3,10 @@ import pexpect
import signal
import time


class TestInteraction(unittest.TestCase):
def test_keyboard_interrupt(self):
p = pexpect.spawn('python3 lesspass/core.py --prompt')
p = pexpect.spawn("python3 lesspass/core.py --prompt")
p.expect("Site: ")
p.kill(signal.SIGINT)
p.expect(pexpect.EOF)


+ 57
- 31
cli/tests/test_password_generation.py Parādīt failu

@@ -89,10 +89,11 @@ class TestPassword(unittest.TestCase):
"login": "contact@example.org",
"counter": 1,
}
master_password = 'password'
master_password = "password"

self.assertEqual(
password._calc_entropy(password_profile, master_password), b'dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e'
password._calc_entropy(password_profile, master_password),
b"dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e",
)

def test_get_configured_rules_empty_when_no_rules_in_profile(self):
@@ -108,67 +109,92 @@ class TestPassword(unittest.TestCase):
"symbols": True,
}

self.assertListEqual(password._get_configured_rules(password_profile), ['uppercase', 'symbols'])
self.assertListEqual(
password._get_configured_rules(password_profile), ["uppercase", "symbols"]
)

def test_get_set_of_characters_without_rule(self):
self.assertEqual(password._get_set_of_characters(), 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~')
self.assertEqual(
password._get_set_of_characters(),
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
)

def test_get_set_of_characters_with_single_rule(self):
self.assertEqual(password._get_set_of_characters(["lowercase"]), "abcdefghijklmnopqrstuvwxyz")
self.assertEqual(password._get_set_of_characters(["uppercase"]), "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
self.assertEqual(
password._get_set_of_characters(["lowercase"]), "abcdefghijklmnopqrstuvwxyz"
)
self.assertEqual(
password._get_set_of_characters(["uppercase"]), "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
)
self.assertEqual(password._get_set_of_characters(["digits"]), "0123456789")
self.assertEqual(password._get_set_of_characters(["symbols"]), "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")
self.assertEqual(
password._get_set_of_characters(["symbols"]),
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
)

def test_get_set_of_characters_with_several_rules(self):
self.assertEqual(password._get_set_of_characters(["lowercase", "digits"]), "abcdefghijklmnopqrstuvwxyz0123456789")
self.assertEqual(
password._get_set_of_characters(["lowercase", "digits"]),
"abcdefghijklmnopqrstuvwxyz0123456789",
)

def test_consume_entropy(self):
entropy = b'dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e'
entropy = b"dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e"

password_value, password_entropy = password._consume_entropy(
generated_password="",
quotient=int(entropy, 16),
set_of_characters="abcdefghijklmnopqrstuvwxyz0123456789",
max_length=12
password_value, password_entropy = password._consume_entropy(
generated_password="",
quotient=int(entropy, 16),
set_of_characters="abcdefghijklmnopqrstuvwxyz0123456789",
max_length=12,
)

self.assertEqual(password_value, 'gsrwvjl3d0sn')
self.assertEqual(password_entropy, 21019920789038193790619410818194537836313158091882651458040)
self.assertEqual(password_value, "gsrwvjl3d0sn")
self.assertEqual(
password_entropy,
21019920789038193790619410818194537836313158091882651458040,
)

def test_get_one_char_per_rule_without_rules(self):
self.assertListEqual(
password._get_one_char_per_rule( entropy=21019920789038193790619410818194537836313158091882651458040, rules=[] ),
['', 21019920789038193790619410818194537836313158091882651458040]
password._get_one_char_per_rule(
entropy=21019920789038193790619410818194537836313158091882651458040,
rules=[],
),
["", 21019920789038193790619410818194537836313158091882651458040],
)

def test_get_one_char_per_rule_with_several_rules(self):
self.assertListEqual(
password._get_one_char_per_rule(
entropy=21019920789038193790619410818194537836313158091882651458040,
rules=['lowercase', 'digits']
entropy=21019920789038193790619410818194537836313158091882651458040,
rules=["lowercase", "digits"],
),
['a0', 80845849188608437656228503146902068601204454199548659454]
["a0", 80845849188608437656228503146902068601204454199548659454],
)

def test_insert_string_pseudo_randomly(self):
self.assertEqual(
password._insert_string_pseudo_randomly(
generated_password='gsrwvjl3d0sn',
entropy=80845849188608437656228503146902068601204454199548659454,
string='a0'
), 'gsrwvjl03d0asn'
generated_password="gsrwvjl3d0sn",
entropy=80845849188608437656228503146902068601204454199548659454,
string="a0",
),
"gsrwvjl03d0asn",
)

def test_render_password(self):
password_profile = {
password_profile = {
"site": "example.org",
"login": "contact@example.org",
"digits": True,
"lowercase": True,
"length": 14,
"counter": 1
"counter": 1,
}
master_password = 'password'
master_password = "password"
entropy = password._calc_entropy(password_profile, master_password)

self.assertEqual(password._render_password(entropy, password_profile), 'gsrwvjl03d0asn')
self.assertEqual(
password._render_password(entropy, password_profile), "gsrwvjl03d0asn"
)


+ 0
- 59
cli/tests/test_validator.py Parādīt failu

@@ -1,59 +0,0 @@
# import unittest

# from lesspass.cli import parse_args
# from lesspass.validator import validate_args


# class TestValidateArgs(unittest.TestCase):
# def test_validate_args_no_opposite_rules_lowercase(self):
# error, message = validate_args(parse_args(["site", "-l", "--no-lowercase"]))
# self.assertTrue(error)
# self.assertTrue(
# "Can't have -l (--lowercase) and --no-lowercase at the same time" in message
# )

# def test_validate_args_no_opposite_rules_uppercase(self):
# error, message = validate_args(parse_args(["site", "-u", "--no-uppercase"]))
# self.assertTrue(error)
# self.assertTrue(
# "Can't have -u (--uppercase) and --no-uppercase at the same time" in message
# )

# def test_validate_args_no_opposite_rules_digits(self):
# error, message = validate_args(parse_args(["site", "-d", "--no-digits"]))
# self.assertTrue(error)
# self.assertTrue(
# "Can't have -d (--digits) and --no-digits at the same time" in message
# )

# def test_validate_args_no_opposite_rules_symbols(self):
# error, message = validate_args(parse_args(["site", "-s", "--no-symbols"]))
# self.assertTrue(error)
# self.assertTrue(
# "Can't have -s (--symbols) and --no-symbols at the same time" in message
# )

# def test_validate_args_concat_errors(self):
# _, message = validate_args(
# parse_args(["site", "-u", "--no-uppercase", "-l", "--no-lowercase"])
# )
# self.assertTrue(
# "Can't have -l (--lowercase) and --no-lowercase at the same time" in message
# )
# self.assertTrue(
# "Can't have -u (--uppercase) and --no-uppercase at the same time" in message
# )

# def test_validate_args_no_site(self):
# error, message = validate_args(parse_args([]))
# self.assertTrue(error)
# self.assertTrue(
# "SITE is a required argument" in message
# )

# def test_validate_args_site_optional_with_prompt(self):
# error, message = validate_args(parse_args(["--prompt"]))
# self.assertFalse(error)
# self.assertTrue(
# "SITE is a required argument" not in message
# )

Notiek ielāde…
Atcelt
Saglabāt