diff options
author | Devaev Maxim <[email protected]> | 2019-02-10 02:46:38 +0300 |
---|---|---|
committer | Devaev Maxim <[email protected]> | 2019-02-10 02:46:38 +0300 |
commit | 8ae714ab3caaa77de94bdafef02548a1b068f41f (patch) | |
tree | 3303b3ec50482f6eff33165c531922855f3a2697 | |
parent | d743b2780ab686fb216ff68373fa94ebe69a455a (diff) |
kvmd-htpasswd
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | configs/kvmd/htpasswd | 2 | ||||
-rw-r--r-- | kvmd/application.py | 4 | ||||
-rw-r--r-- | kvmd/apps/cleanup/__init__.py | 2 | ||||
-rw-r--r-- | kvmd/apps/htpasswd/__init__.py | 91 | ||||
-rw-r--r-- | kvmd/apps/htpasswd/__main__.py | 2 | ||||
-rw-r--r-- | kvmd/apps/kvmd/__init__.py | 2 | ||||
-rwxr-xr-x | setup.py | 2 |
8 files changed, 101 insertions, 6 deletions
@@ -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() @@ -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", ], }, |