Add CLI generation of salt

Salts and Passphrases are both strings used in cryptography.  This patch:
1. Adds CLI generation of salt
2. Adds unit test for CLI generation of salt
3. Updates passphrase.py code to be more generic as it is used to generate
both a passphrase and a salt
4. Update name of passphrase.py to be more generic
5. Update all references to, and tests of passphrase.py
6. Add documentation for CLI generation of salt

Co-Authored-By: chittibabu <cg329x@att.com>

Change-Id: I71858d63a2846290d22be96686ccfea3ba8aa6c0
This commit is contained in:
Alexander Hughes 2019-02-19 14:36:50 -06:00 committed by Alexander Hughes
parent 4b00a4340c
commit 671b77f6a7
7 changed files with 91 additions and 36 deletions

View File

@ -846,3 +846,34 @@ Example with length specified:
::
./pegleg.sh generate passphrase -l <length>
Salt
----
Generate a salt and print to ``stdout``.
**-l / --length** (Optional).
Length of salt to generate. By default length is 24.
Minimum length is 24. No maximum length.
Usage:
::
./pegleg.sh generate salt -l <length>
Examples
^^^^^^^^
Example without length specified:
::
./pegleg.sh generate salt
Example with length specified:
::
./pegleg.sh generate salt -l <length>

View File

@ -549,4 +549,19 @@ def generate():
'Length is >= 24, default length is 24, no maximum length')
def generate_passphrase(length):
click.echo("Generated Passhprase: {}".format(
engine.secrets.generate_passphrase(length)))
engine.secrets.generate_crypto_string(length)))
@generate.command(
'salt',
help='Command to generate a salt and print out to stdout')
@click.option(
'-l',
'--length',
'length',
default=24,
help='Generate a salt of the given length. '
'Length is >= 24, default length is 24, no maximum length')
def generate_salt(length):
click.echo("Generated Salt: {}".format(
engine.secrets.generate_crypto_string(length)))

View File

@ -18,8 +18,8 @@ import logging
from pegleg.engine.catalogs import passphrase_catalog
from pegleg.engine.catalogs.passphrase_catalog import PassphraseCatalog
from pegleg.engine.generators.base_generator import BaseGenerator
from pegleg.engine.util.cryptostring import CryptoString
from pegleg.engine.util import files
from pegleg.engine.util.passphrase import Passphrase
from pegleg.engine.util.pegleg_secret_management import PeglegSecretManagement
__all__ = ['PassphraseGenerator']
@ -49,7 +49,7 @@ class PassphraseGenerator(BaseGenerator):
sitename, save_location, author)
self._catalog = PassphraseCatalog(
self._sitename, documents=self._documents)
self._pass_util = Passphrase()
self._pass_util = CryptoString()
def generate(self, interactive=False):
"""
@ -67,7 +67,7 @@ class PassphraseGenerator(BaseGenerator):
prompt="Input passphrase for {}. Leave blank to "
"auto-generate:\n".format(p_name))
if not passphrase:
passphrase = self._pass_util.get_pass(
passphrase = self._pass_util.get_crypto_string(
self._catalog.get_length(p_name))
docs = list()
storage_policy = self._catalog.get_storage_policy(p_name)

View File

@ -16,9 +16,9 @@ import logging
import os
from pegleg.engine.generators.passphrase_generator import PassphraseGenerator
from pegleg.engine.util.cryptostring import CryptoString
from pegleg.engine.util import definition
from pegleg.engine.util import files
from pegleg.engine.util.passphrase import Passphrase
from pegleg.engine.util.pegleg_secret_management import PeglegSecretManagement
__all__ = ('encrypt', 'decrypt', 'generate_passphrases')
@ -132,12 +132,12 @@ def generate_passphrases(site_name, save_location, author, interactive=False):
interactive=interactive)
def generate_passphrase(length):
def generate_crypto_string(length):
"""
Create a passphrase.
Create a cryptographic string.
:param int length: Length of passphrase.
:param int length: Length of cryptographic string.
:rtype: string
"""
return Passphrase().get_pass(length)
return CryptoString().get_crypto_string(length)

View File

@ -17,17 +17,21 @@ from random import SystemRandom
from rstr import Rstr
import string
__all__ = ['Passphrase']
__all__ = ['CryptoString']
class Passphrase(object):
class CryptoString(object):
def __init__(self):
self._pool = string.ascii_letters + string.digits + string.punctuation
self._rs = Rstr(SystemRandom())
def get_pass(self, pass_len=24):
"""Create and return a random password, of the ``pass_len`` length."""
if pass_len < 24:
pass_len = 24
return self._rs.rstr(self._pool, pass_len)
def get_crypto_string(self, len=24):
"""
Create and return a random cryptographic string,
of the ``len`` length.
"""
if len < 24:
len = 24
return self._rs.rstr(self._pool, len)

View File

@ -19,7 +19,7 @@ import mock
import string
import yaml
from pegleg.engine.util.passphrase import Passphrase
from pegleg.engine.util.cryptostring import CryptoString
from pegleg.engine.generators.passphrase_generator import PassphraseGenerator
from pegleg.engine.util import encryption
from pegleg.engine import util
@ -99,30 +99,30 @@ TEST_SITE_DEFINITION = {
TEST_SITE_DOCUMENTS = [TEST_SITE_DEFINITION, TEST_PASSPHRASES_CATALOG]
def test_passphrase_default_len():
p_util = Passphrase()
passphrase = p_util.get_pass()
assert len(passphrase) == 24
def test_cryptostring_default_len():
s_util = CryptoString()
s = s_util.get_crypto_string()
assert len(s) == 24
alphabet = set(string.punctuation + string.ascii_letters + string.digits)
assert any(c in alphabet for c in passphrase)
assert any(c in alphabet for c in s)
def test_passphrase_short_len():
p_util = Passphrase()
p = p_util.get_pass(0)
assert len(p) == 24
p = p_util.get_pass(23)
assert len(p) == 24
p = p_util.get_pass(-1)
assert len(p) == 24
def test_cryptostring_short_len():
s_util = CryptoString()
s = s_util.get_crypto_string(0)
assert len(s) == 24
s = s_util.get_crypto_string(23)
assert len(s) == 24
s = s_util.get_crypto_string(-1)
assert len(s) == 24
def test_passphrase_long_len():
p_util = Passphrase()
p = p_util.get_pass(25)
assert len(p) == 25
p = p_util.get_pass(128)
assert len(p) == 128
def test_cryptostring_long_len():
s_util = CryptoString()
s = s_util.get_crypto_string(25)
assert len(s) == 25
s = s_util.get_crypto_string(128)
assert len(s) == 128
@mock.patch.object(

View File

@ -389,6 +389,11 @@ class TestGenerateActions(BaseCLIActionTest):
assert result.exit_code == 0, result.output
def test_generate_salt(self):
result = self.runner.invoke(cli.generate, ['salt'])
assert result.exit_code == 0, result.output
class TestRepoCliActions(BaseCLIActionTest):
"""Tests repo-level CLI actions."""