summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDevaev Maxim <[email protected]>2019-02-10 02:46:38 +0300
committerDevaev Maxim <[email protected]>2019-02-10 02:46:38 +0300
commit8ae714ab3caaa77de94bdafef02548a1b068f41f (patch)
tree3303b3ec50482f6eff33165c531922855f3a2697
parentd743b2780ab686fb216ff68373fa94ebe69a455a (diff)
kvmd-htpasswd
-rw-r--r--Makefile2
-rw-r--r--configs/kvmd/htpasswd2
-rw-r--r--kvmd/application.py4
-rw-r--r--kvmd/apps/cleanup/__init__.py2
-rw-r--r--kvmd/apps/htpasswd/__init__.py91
-rw-r--r--kvmd/apps/htpasswd/__main__.py2
-rw-r--r--kvmd/apps/kvmd/__init__.py2
-rwxr-xr-xsetup.py2
8 files changed, 101 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index 21187949..01e1f58a 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ TESTENV_CMD ?= /bin/bash -c " \
&& ln -s $(TESTENV_VIDEO) /dev/kvmd-video \
&& (losetup -d /dev/kvmd-msd || true) \
&& losetup /dev/kvmd-msd /root/loop.img \
- && python -m kvmd.apps.kvmd -c /etc/kvmd/kvmd.yaml \
+ && python -m kvmd.apps.kvmd \
"
diff --git a/configs/kvmd/htpasswd b/configs/kvmd/htpasswd
index e62e44d0..a6cbfca9 100644
--- a/configs/kvmd/htpasswd
+++ b/configs/kvmd/htpasswd
@@ -1 +1 @@
-admin:$apr1$INC0KeyU$YdLQ9qosXzNVlhxQPUf7A/
+admin:$apr1$.6mu9N8n$xOuGesr4JZZkdiZo/j318.
diff --git a/kvmd/application.py b/kvmd/application.py
index 8a3c40a0..4b8af949 100644
--- a/kvmd/application.py
+++ b/kvmd/application.py
@@ -23,8 +23,8 @@ from .yamlconf.loader import load_yaml_file
# =====
-def init() -> Tuple[argparse.ArgumentParser, List[str], Section]:
- args_parser = argparse.ArgumentParser(add_help=False)
+def init(prog: str=sys.argv[0], add_help: bool=True) -> Tuple[argparse.ArgumentParser, List[str], Section]:
+ args_parser = argparse.ArgumentParser(prog=prog, add_help=add_help)
args_parser.add_argument("-c", "--config", dest="config_path", default="/etc/kvmd/kvmd.yaml", metavar="<file>")
args_parser.add_argument("-o", "--set-options", dest="set_options", default=[], nargs="+")
args_parser.add_argument("-m", "--dump-config", dest="dump_config", action="store_true")
diff --git a/kvmd/apps/cleanup/__init__.py b/kvmd/apps/cleanup/__init__.py
index 53f46259..281f60cb 100644
--- a/kvmd/apps/cleanup/__init__.py
+++ b/kvmd/apps/cleanup/__init__.py
@@ -10,7 +10,7 @@ from ... import gpio
# =====
def main() -> None:
- config = init()[2].kvmd
+ config = init("kvmd-cleanup")[2].kvmd
logger = get_logger(0)
logger.info("Cleaning up ...")
diff --git a/kvmd/apps/htpasswd/__init__.py b/kvmd/apps/htpasswd/__init__.py
new file mode 100644
index 00000000..0eaf89f3
--- /dev/null
+++ b/kvmd/apps/htpasswd/__init__.py
@@ -0,0 +1,91 @@
+import sys
+import os
+import re
+import getpass
+import tempfile
+import contextlib
+import argparse
+
+from typing import Generator
+
+import passlib.apache
+
+from ...yamlconf import Section
+
+from ...application import init
+
+
+# =====
+def _get_htpasswd_for_write(config: Section) -> Generator[passlib.apache.HtpasswdFile, None, None]:
+ path = config.kvmd.auth.htpasswd
+ (tmp_fd, tmp_path) = tempfile.mkstemp(prefix=".", dir=os.path.dirname(path))
+ try:
+ try:
+ with open(path, "rb") as htpasswd_file:
+ os.write(tmp_fd, htpasswd_file.read())
+ finally:
+ os.close(tmp_fd)
+ htpasswd = passlib.apache.HtpasswdFile(tmp_path)
+ yield htpasswd
+ htpasswd.save()
+ os.rename(tmp_path, path)
+ finally:
+ if os.path.exists(tmp_path):
+ os.remove(tmp_path)
+
+
+def _valid_user(user: str) -> str:
+ stripped = user.strip()
+ if re.match(r"^[a-z_][a-z0-9_-]*$", stripped):
+ return stripped
+ raise SystemExit("Invalid user %r" % (user))
+
+
+# ====
+def _cmd_list(config: Section, _: argparse.Namespace) -> None:
+ for user in passlib.apache.HtpasswdFile(config.kvmd.auth.htpasswd).users():
+ print(user)
+
+
+def _cmd_set(config: Section, options: argparse.Namespace) -> None:
+ if options.read_stdin:
+ passwd = input()
+ else:
+ passwd = getpass.getpass("Password: ", stream=sys.stderr)
+ if getpass.getpass("Repeat: ", stream=sys.stderr) != passwd:
+ raise SystemExit("Sorry, passwords do not match")
+ with _get_htpasswd_for_write(config) as htpasswd:
+ htpasswd.set_password(options.user, passwd)
+
+
+def _cmd_delete(config: Section, options: argparse.Namespace) -> None:
+ with _get_htpasswd_for_write(config) as htpasswd:
+ htpasswd.delete(options.user)
+
+
+# =====
+def main() -> None:
+ (parent_parser, argv, config) = init(add_help=False)
+ parser = argparse.ArgumentParser(
+ prog="kvmd-htpasswd",
+ description="Manage KVMD users",
+ parents=[parent_parser],
+ )
+ parser.set_defaults(cmd=(lambda *_: parser.print_help()))
+ subparsers = parser.add_subparsers()
+
+ cmd_list_parser = subparsers.add_parser("list", help="List users")
+ cmd_list_parser.set_defaults(cmd=_cmd_list)
+
+ cmd_set_parser = subparsers.add_parser("set", help="Create user or change password")
+ cmd_set_parser.add_argument("user", type=_valid_user)
+ cmd_set_parser.add_argument("-i", "--read-stdin", action="store_true", help="Read password from stdin")
+ cmd_set_parser.set_defaults(cmd=_cmd_set)
+
+ cmd_delete_parser = subparsers.add_parser("del", help="Delete user")
+ cmd_delete_parser.add_argument("user", type=_valid_user)
+ cmd_delete_parser.set_defaults(cmd=_cmd_delete)
+
+ options = parser.parse_args(argv[1:])
+ options.cmd(config, options)
diff --git a/kvmd/apps/htpasswd/__main__.py b/kvmd/apps/htpasswd/__main__.py
new file mode 100644
index 00000000..031df43e
--- /dev/null
+++ b/kvmd/apps/htpasswd/__main__.py
@@ -0,0 +1,2 @@
+from . import main
+main()
diff --git a/kvmd/apps/kvmd/__init__.py b/kvmd/apps/kvmd/__init__.py
index 57844cc5..08dfe0dd 100644
--- a/kvmd/apps/kvmd/__init__.py
+++ b/kvmd/apps/kvmd/__init__.py
@@ -17,7 +17,7 @@ from .server import Server
# =====
def main() -> None:
- config = init()[2].kvmd
+ config = init("kvmd")[2].kvmd
with gpio.bcm():
loop = asyncio.get_event_loop()
diff --git a/setup.py b/setup.py
index bef01a3f..28429656 100755
--- a/setup.py
+++ b/setup.py
@@ -21,6 +21,7 @@ def main() -> None:
"kvmd.yamlconf",
"kvmd.apps",
"kvmd.apps.kvmd",
+ "kvmd.apps.htpasswd",
"kvmd.apps.cleanup",
],
@@ -31,6 +32,7 @@ def main() -> None:
entry_points={
"console_scripts": [
"kvmd = kvmd.apps.kvmd:main",
+ "kvmd-htpasswd = kvmd.apps.htpasswd:main",
"kvmd-cleanup = kvmd.apps.cleanup:main",
],
},