Skip to content

Commit

Permalink
hsm.secret-token-backup.get: add -r/--random and -p/--print-lookup op…
Browse files Browse the repository at this point in the history
…tions
  • Loading branch information
mk-fg committed Feb 23, 2024
1 parent fad5808 commit d29f7ad
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 12 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2963,10 +2963,10 @@ on how to use this binary with a typical dracut/systemd boot process.
#### [secret-token-backup](hsm/secret-token-backup)

Python wrapper around ["age" encryption tool] and sqlite to encrypt any tokens
with optional comment strings to an sqlite db file, or retrieve/decrypt those.
with optional comment strings to a db file, or retrieve/decrypt those later.

Stores fixed list of recipient keys in the db on its creation ("init" script
command), and always uses those afterwards for all secrets stored there,
Stores fixed list of recipient keys in the database on its creation ("init"
script command), and always uses those afterwards for all secrets stored there,
in one neat self-contained file.

My use-case for this is a simple asymmetric-encryption backup for secrets
Expand Down
29 changes: 20 additions & 9 deletions hsm/secret-token-backup
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ class TokenDB:
c.execute('select ct, ts from tokens where lookup = ?', (lookup,))
if row := c.fetchone(): ct, ts = row; return ct, ts

def get_random(self):
with self() as c:
c.execute( 'select lookup, ct, ts from tokens'
' where lookup != ? order by random() limit 1', ('',) )
if row := c.fetchone(): lookup, ct, ts = row; return lookup, ct, ts

def export_tokens(self):
with self() as c:
c.execute('select lookup, ts, ct from tokens where lookup != ?', ('',))
Expand Down Expand Up @@ -150,9 +156,6 @@ def main(argv=None):
Public key: age1...
% ./secret-token-backup init -c 'Test Storage\nNothing of value here' age1...
% ./secret-token-backup info
...
% ./secret-token-backup set -c 'my token\n\twith a comment' test1 <<< secret1
% ./secret-token-backup info --list
...
Expand Down Expand Up @@ -228,8 +231,10 @@ def main(argv=None):
cmd.add_argument('lookup', nargs='?', help=dd('''
Lookup-key to find encrypted token. Missing key in db will raise an error.
Will be read from stdin, if not specified.'''))
cmd.add_argument('-p', '--print-lookup', action='store_true', help=dd('''
Print lookup key on the first line, prefixed by # characters.'''))
cmd.add_argument('-c', '--comment', action='store_true', help=dd('''
Query and print comment string before decrypted token, prefixed by # character(s).'''))
Query and print comment string before decrypted token, prefixed by # characters.'''))
cmd.add_argument('-C', '--comment-value', action='store_true', help=dd('''
Only print comment field for the lookup-key as-is, without anything else.'''))
cmd.add_argument('-t', '--timestamp', action='store_true', help=dd('''
Expand All @@ -240,6 +245,8 @@ def main(argv=None):
in db unencrypted, not using "identity" option in any way.'''))
cmd.add_argument('-o', '--output-file', metavar='file', help=dd('''
Use specified output file instead of stdout stream, or fd with %% prefix.'''))
cmd.add_argument('-r', '--random', action='store_true', help=dd('''
Pick random lookup key from db. Any specified key won't be used. For quick testing.'''))

cmd = cmds.add_parser('wrap',
formatter_class=argparse.RawTextHelpFormatter,
Expand Down Expand Up @@ -296,14 +303,14 @@ def main(argv=None):

@cl.contextmanager
def out_file(path):
if not path or path == '-': yield lambda s,end='': print(s, end=end); return
if not path or path == '-': return (yield lambda s,end='': print(s, end=end))
if path[0] == '%': dst_file = open(int(path[1:]), 'w')
else: dst_file = safe_replacement(path)
with dst_file as dst: yield lambda s,end='': print(s, file=dst, end=end)

@cl.contextmanager
def in_file(path):
if not path or path == '-': yield sys.stdin; return
if not path or path == '-': return (yield sys.stdin)
if path[0] == '%': path = int(path[1:])
with open(path) as src: yield src

Expand Down Expand Up @@ -353,16 +360,20 @@ def main(argv=None):
print(f'# {n:>3d} [ {lookup} ] - {ts_repr(ts)} - {_size_str(len(ct))}')

elif cmd == 'set':
db.set(lookup, encrypt(db.keys(), sys.stdin.read(), str_comment(opts.comment)))
db.set(opts.lookup, encrypt(db.keys(), sys.stdin.read(), str_comment(opts.comment)))

elif cmd == 'get':
if not (data := db.get(lookup := opts.lookup or sys.stdin.read().strip())):
if opts.random:
if not (data := db.get_random()): return p_err('Database is empty')
lookup, ct, ts = data
elif not (data := db.get(lookup := opts.lookup or sys.stdin.read().strip())):
return p_err(f'Lookup-key not found in db: {lookup}')
ct, ts = data
else: ct, ts = data
with out_file(opts.output_file) as out, ident_path(opts.identity) as ident:
if opts.timestamp_value: return out(ts)
token, comment = decrypt(ident, ct)
if opts.comment_value: return out(comment)
if opts.print_lookup: out(f'### {lookup}\n')
if opts.comment:
for line in comment.splitlines(): out(f'## {line}\n')
if opts.timestamp: out(f'## Last updated: {ts_repr(ts)}\n')
Expand Down

0 comments on commit d29f7ad

Please sign in to comment.