version 0.5 of spiller
This commit is contained in:
@@ -26,7 +26,7 @@ classifiers = [
|
|||||||
dependencies = []
|
dependencies = []
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
spill="spiller.spiller:main"
|
spill="spiller:main"
|
||||||
|
|
||||||
[tool.hatch.version]
|
[tool.hatch.version]
|
||||||
path = "spiller/__init__.py"
|
path = "spiller/__init__.py"
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ setup(
|
|||||||
packages=["spiller"],
|
packages=["spiller"],
|
||||||
version=version,
|
version=version,
|
||||||
description="Very simple password storage, that encrypts with GPG cmdline tool.",
|
description="Very simple password storage, that encrypts with GPG cmdline tool.",
|
||||||
author="Ville Rantanen",
|
author="Q",
|
||||||
author_email="q@six9.net",
|
author_email="q@six9.net",
|
||||||
entry_points={
|
entry_points={
|
||||||
"console_scripts": [
|
"console_scripts": [
|
||||||
"spill = spiller.spiller:main",
|
"spill = spiller:main",
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,2 +1,117 @@
|
|||||||
__version__ = "0.4"
|
import argparse
|
||||||
from spiller.spiller import Spiller, decrypt, encrypt
|
import os
|
||||||
|
|
||||||
|
from spiller.spiller import DEFAULT_CONFIG, DEFAULT_STORAGE, Spiller, decrypt, encrypt
|
||||||
|
|
||||||
|
__version__ = "0.5"
|
||||||
|
|
||||||
|
|
||||||
|
def get_opts():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
prog="spill",
|
||||||
|
description=f"""Key/value storage that uses JSON and GPG as backend.
|
||||||
|
Values are encrypted symmetrically with the key provided, or a random string is generated.
|
||||||
|
Encryption key can be passed from a variable SPILLER_KEY instead of a switch.
|
||||||
|
Storage file can be changed with SPILLER_STORAGE env variable, in a
|
||||||
|
"SPILLER_STORAGE": key in a JSON file read at {DEFAULT_STORAGE}
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
parser.add_argument("--version", action="version", version=__version__)
|
||||||
|
parser.add_argument("-q", "--quiet", action="store_true", default=False)
|
||||||
|
|
||||||
|
subparsers = parser.add_subparsers(dest="command", help="Command")
|
||||||
|
set_parser = subparsers.add_parser("set")
|
||||||
|
get_parser = subparsers.add_parser("get")
|
||||||
|
del_parser = subparsers.add_parser("list")
|
||||||
|
del_parser = subparsers.add_parser("del")
|
||||||
|
|
||||||
|
set_parser.add_argument(
|
||||||
|
"name",
|
||||||
|
action="store",
|
||||||
|
help="Name of secret",
|
||||||
|
)
|
||||||
|
set_parser.add_argument(
|
||||||
|
"data",
|
||||||
|
action="store",
|
||||||
|
nargs="?",
|
||||||
|
help="Data to store. Must use this or --data-file.",
|
||||||
|
)
|
||||||
|
set_parser.add_argument(
|
||||||
|
"--data-file",
|
||||||
|
action="store",
|
||||||
|
type=argparse.FileType("r"),
|
||||||
|
help="Read the data to store from a file. Must use this or [data]. Will strip newlines at the end.",
|
||||||
|
)
|
||||||
|
set_parser.add_argument("--plain", action="store_true", default=False, help="Do not encrypt")
|
||||||
|
set_parser.add_argument(
|
||||||
|
"--key",
|
||||||
|
action="store",
|
||||||
|
default=os.getenv("SPILLER_KEY", None),
|
||||||
|
help="Encryption key (or use SPILLER_KEY)",
|
||||||
|
)
|
||||||
|
set_parser.add_argument(
|
||||||
|
"--key-file",
|
||||||
|
action="store",
|
||||||
|
default=None,
|
||||||
|
type=argparse.FileType("r"),
|
||||||
|
help="Read encryption key stored in a file",
|
||||||
|
)
|
||||||
|
get_parser.add_argument(
|
||||||
|
"name",
|
||||||
|
action="store",
|
||||||
|
help="Name of secret",
|
||||||
|
)
|
||||||
|
get_parser.add_argument(
|
||||||
|
"--key",
|
||||||
|
action="store",
|
||||||
|
default=os.getenv("SPILLER_KEY", None),
|
||||||
|
help="Decryption key (or use SPILLER_KEY)",
|
||||||
|
)
|
||||||
|
get_parser.add_argument(
|
||||||
|
"--key-file",
|
||||||
|
action="store",
|
||||||
|
default=None,
|
||||||
|
type=argparse.FileType("r"),
|
||||||
|
help="Read encryption key stored in a file. Will strip newlines at the end.",
|
||||||
|
)
|
||||||
|
del_parser.add_argument(
|
||||||
|
"name",
|
||||||
|
action="store",
|
||||||
|
help="Name of secret to delete",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
if args.command is None:
|
||||||
|
raise parser.error("Command missing")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if args.key_file:
|
||||||
|
with args.key_file as fp:
|
||||||
|
args.key = fp.read().rstrip("\n")
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if args.command == "set":
|
||||||
|
if args.data and args.data_file:
|
||||||
|
raise parser.error("Can not use both [data] and --data-file")
|
||||||
|
if args.data is None and args.data_file is None:
|
||||||
|
raise parser.error("Must use either [data] or --data-file")
|
||||||
|
if args.data_file:
|
||||||
|
with args.data_file as fp:
|
||||||
|
args.data = fp.read().rstrip("\n")
|
||||||
|
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
opts = get_opts()
|
||||||
|
spill = Spiller()
|
||||||
|
spill.verbose = not opts.quiet
|
||||||
|
|
||||||
|
if opts.command == "set":
|
||||||
|
spill.store(opts.name, opts.data, opts.key, opts.plain)
|
||||||
|
if opts.command == "get":
|
||||||
|
print(spill.retrieve(opts.name, opts.key), end="")
|
||||||
|
if opts.command == "list":
|
||||||
|
print(spill.format_storage())
|
||||||
|
if opts.command == "del":
|
||||||
|
spill.del_storage(opts.name)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import argparse
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
@@ -9,98 +8,8 @@ import string
|
|||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
DEFAULT_CONFIG = os.path.expanduser("~/.config/spiller/config.json")
|
||||||
def get_opts():
|
DEFAULT_STORAGE = os.path.expanduser("~/.config/spiller/storage.json")
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
prog="spill",
|
|
||||||
description="""Key/value storage that uses JSON and GPG as backend.
|
|
||||||
Values are encrypted symmetrically with the key provided, or a random string is generated.
|
|
||||||
Encryption key can be passed from a variable SPILLER_KEY instead of a switch.
|
|
||||||
Storage file can be changed with SPILLER_STORAGE env variable, in a
|
|
||||||
"SPILLER_STORAGE": key in a JSON file read at ~/.config/spill/config.json
|
|
||||||
""",
|
|
||||||
)
|
|
||||||
subparsers = parser.add_subparsers(dest="command", help="Command")
|
|
||||||
set_parser = subparsers.add_parser("set")
|
|
||||||
get_parser = subparsers.add_parser("get")
|
|
||||||
del_parser = subparsers.add_parser("list")
|
|
||||||
del_parser = subparsers.add_parser("del")
|
|
||||||
|
|
||||||
set_parser.add_argument(
|
|
||||||
"name",
|
|
||||||
action="store",
|
|
||||||
help="Name of secret",
|
|
||||||
)
|
|
||||||
set_parser.add_argument(
|
|
||||||
"data",
|
|
||||||
action="store",
|
|
||||||
nargs="?",
|
|
||||||
help="Data to store. Must use this or --data-file.",
|
|
||||||
)
|
|
||||||
set_parser.add_argument(
|
|
||||||
"--data-file",
|
|
||||||
action="store",
|
|
||||||
type=argparse.FileType("r"),
|
|
||||||
help="Read the data to store from a file. Must use this or [data]. Will strip newlines at the end.",
|
|
||||||
)
|
|
||||||
set_parser.add_argument("--plain", action="store_true", default=False, help="Do not encrypt")
|
|
||||||
set_parser.add_argument(
|
|
||||||
"--key",
|
|
||||||
action="store",
|
|
||||||
default=os.getenv("SPILLER_KEY", None),
|
|
||||||
help="Encryption key (or use SPILLER_KEY)",
|
|
||||||
)
|
|
||||||
set_parser.add_argument(
|
|
||||||
"--key-file",
|
|
||||||
action="store",
|
|
||||||
default=None,
|
|
||||||
type=argparse.FileType("r"),
|
|
||||||
help="Read encryption key stored in a file",
|
|
||||||
)
|
|
||||||
get_parser.add_argument(
|
|
||||||
"name",
|
|
||||||
action="store",
|
|
||||||
help="Name of secret",
|
|
||||||
)
|
|
||||||
get_parser.add_argument(
|
|
||||||
"--key",
|
|
||||||
action="store",
|
|
||||||
default=os.getenv("SPILLER_KEY", None),
|
|
||||||
help="Decryption key (or use SPILLER_KEY)",
|
|
||||||
)
|
|
||||||
get_parser.add_argument(
|
|
||||||
"--key-file",
|
|
||||||
action="store",
|
|
||||||
default=None,
|
|
||||||
type=argparse.FileType("r"),
|
|
||||||
help="Read encryption key stored in a file. Will strip newlines at the end.",
|
|
||||||
)
|
|
||||||
del_parser.add_argument(
|
|
||||||
"name",
|
|
||||||
action="store",
|
|
||||||
help="Name of secret to delete",
|
|
||||||
)
|
|
||||||
args = parser.parse_args()
|
|
||||||
if args.command is None:
|
|
||||||
raise parser.error("Command missing")
|
|
||||||
|
|
||||||
try:
|
|
||||||
if args.key_file:
|
|
||||||
with args.key_file as fp:
|
|
||||||
args.key = fp.read().rstrip("\n")
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if args.command == "set":
|
|
||||||
if args.data and args.data_file:
|
|
||||||
raise parser.error("Can not use both [data] and --data-file")
|
|
||||||
if args.data is None and args.data_file is None:
|
|
||||||
raise parser.error("Must use either [data] or --data-file")
|
|
||||||
if args.data_file:
|
|
||||||
with args.data_file as fp:
|
|
||||||
args.data = fp.read().rstrip("\n")
|
|
||||||
|
|
||||||
return args
|
|
||||||
|
|
||||||
|
|
||||||
class Spiller:
|
class Spiller:
|
||||||
@@ -114,10 +23,10 @@ class Spiller:
|
|||||||
self.verbose = False
|
self.verbose = False
|
||||||
|
|
||||||
def get_config(self):
|
def get_config(self):
|
||||||
default_config = {"SPILLER_STORAGE": os.path.expanduser("~/.config/spiller/storage.json")}
|
default_config = {"SPILLER_STORAGE": DEFAULT_STORAGE}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(os.path.expanduser("~/.config/spiller/config.json"), "rt") as fp:
|
with open(DEFAULT_CONFIG, "rt") as fp:
|
||||||
default_config.update(json.load(fp))
|
default_config.update(json.load(fp))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
@@ -165,13 +74,13 @@ class Spiller:
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def del_storage(name):
|
def del_storage(self, name):
|
||||||
"""writes directly !"""
|
"""writes directly !"""
|
||||||
|
|
||||||
del self.storage[name]
|
del self.storage[name]
|
||||||
self.save_storage()
|
self.save_storage()
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
print("Deleted " + name)
|
print("Deleted " + name, file=sys.stderr)
|
||||||
|
|
||||||
def store(self, name, data, key, plain):
|
def store(self, name, data, key, plain):
|
||||||
"""
|
"""
|
||||||
@@ -193,7 +102,7 @@ class Spiller:
|
|||||||
if key == None:
|
if key == None:
|
||||||
key = get_random_key()
|
key = get_random_key()
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
print("Random key: " + key)
|
print("Random key: " + key, file=sys.stderr)
|
||||||
entry["data"], ec = self.encrypt(data, key)
|
entry["data"], ec = self.encrypt(data, key)
|
||||||
if ec != 0:
|
if ec != 0:
|
||||||
raise ValueError("Encryption Failed")
|
raise ValueError("Encryption Failed")
|
||||||
@@ -234,7 +143,7 @@ class Spiller:
|
|||||||
if encrypted == "":
|
if encrypted == "":
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
print("Encrypt failed!", file=sys.stderr)
|
print("Encrypt failed!", file=sys.stderr)
|
||||||
None, 1
|
return None, 1
|
||||||
return encrypted, 0
|
return encrypted, 0
|
||||||
|
|
||||||
def decrypt(self, encrypted, key):
|
def decrypt(self, encrypted, key):
|
||||||
@@ -271,18 +180,3 @@ def get_random_key():
|
|||||||
return "-".join(
|
return "-".join(
|
||||||
["".join([random.choice(string.ascii_letters + string.digits) for x in range(8)]) for x in range(5)]
|
["".join([random.choice(string.ascii_letters + string.digits) for x in range(8)]) for x in range(5)]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
opts = get_opts()
|
|
||||||
spill = Spiller()
|
|
||||||
spill.verbose = True
|
|
||||||
|
|
||||||
if opts.command == "set":
|
|
||||||
spill.store(opts.name, opts.data, opts.key, opts.plain)
|
|
||||||
if opts.command == "get":
|
|
||||||
print(spill.retrieve(opts.name, opts.key))
|
|
||||||
if opts.command == "list":
|
|
||||||
print(spill.format_storage())
|
|
||||||
if opts.command == "del":
|
|
||||||
spill.del_storage(opts.name)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user