94 lines
2 KiB
Python
94 lines
2 KiB
Python
#! /usr/bin/env python3
|
|
# encoding: utf-8
|
|
|
|
# ----------------------------------------------------------------
|
|
|
|
def flatten_dict(root, glue=" ", prefix=[]):
|
|
lines = []
|
|
|
|
for k, v in root.items():
|
|
new_prefix = prefix + [k]
|
|
|
|
if type(v) == dict:
|
|
lines.extend(flatten_dict(v, glue, new_prefix))
|
|
else:
|
|
lines.append((glue.join(new_prefix), v))
|
|
|
|
return lines
|
|
|
|
# ----------------------------------------------------------------
|
|
|
|
def clamp(A, low, high):
|
|
"""
|
|
Clamps integer A to <low; high>
|
|
"""
|
|
|
|
if A < low:
|
|
return low
|
|
elif A > high:
|
|
return high
|
|
else:
|
|
return A
|
|
|
|
# ----------------------------------------------------------------
|
|
|
|
import random
|
|
|
|
PASSPHRASE_VOWELS = "aeiuAEU"
|
|
PASSPHRASE_CONSONANTS = "bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ23456789"
|
|
|
|
def random_bytes(length):
|
|
return open("/dev/urandom", "rb").read(length)
|
|
|
|
def random_syllable():
|
|
return random.choice(PASSPHRASE_CONSONANTS) + random.choice(PASSPHRASE_VOWELS) + random.choice(PASSPHRASE_CONSONANTS)
|
|
|
|
def random_word(syllables=3):
|
|
parts = []
|
|
|
|
for _ in range(syllables):
|
|
parts.append(random_syllable())
|
|
|
|
return "".join(parts)
|
|
|
|
# ----------------------------------------------------------------
|
|
|
|
import hashlib
|
|
|
|
def hash_password(p, hexdigest=True):
|
|
h = hashlib.blake2b()
|
|
|
|
h.update(p.encode("utf-8"))
|
|
|
|
return h.hexdigest() if hexdigest else h.digest()
|
|
|
|
# ----------------------------------------------------------------
|
|
|
|
class DeleteOverlay:
|
|
pass
|
|
|
|
def overlay_tree(base, overlay):
|
|
"""
|
|
For every key path in `overlay`, sets the leaf value of the same
|
|
key path in `base`. Any missing non-leaf keys will be created.
|
|
|
|
To delete a key, set its overlay value to DeleteOverlay.
|
|
"""
|
|
|
|
stack = [(base, overlay)]
|
|
|
|
while stack:
|
|
base_p, over_p = stack.pop()
|
|
|
|
for k, v in over_p.items():
|
|
if v is DeleteOverlay:
|
|
del base_p[k]
|
|
else:
|
|
if type(v) is dict:
|
|
if k not in base_p or type(base_p[k]) is not dict:
|
|
base_p[k] = {}
|
|
|
|
stack.append((base_p[k], over_p[k]))
|
|
|
|
else:
|
|
base_p[k] = v
|