kvmd-htpasswd

This commit is contained in:
Devaev Maxim 2019-02-10 02:46:38 +03:00
parent d743b2780a
commit 8ae714ab3c
8 changed files with 101 additions and 6 deletions

View File

@ -12,7 +12,7 @@ TESTENV_CMD ?= /bin/bash -c " \
&& ln -s $(TESTENV_VIDEO) /dev/kvmd-video \ && ln -s $(TESTENV_VIDEO) /dev/kvmd-video \
&& (losetup -d /dev/kvmd-msd || true) \ && (losetup -d /dev/kvmd-msd || true) \
&& losetup /dev/kvmd-msd /root/loop.img \ && losetup /dev/kvmd-msd /root/loop.img \
&& python -m kvmd.apps.kvmd -c /etc/kvmd/kvmd.yaml \ && python -m kvmd.apps.kvmd \
" "

View File

@ -1 +1 @@
admin:$apr1$INC0KeyU$YdLQ9qosXzNVlhxQPUf7A/ admin:$apr1$.6mu9N8n$xOuGesr4JZZkdiZo/j318.

View File

@ -23,8 +23,8 @@ from .yamlconf.loader import load_yaml_file
# ===== # =====
def init() -> Tuple[argparse.ArgumentParser, List[str], Section]: def init(prog: str=sys.argv[0], add_help: bool=True) -> Tuple[argparse.ArgumentParser, List[str], Section]:
args_parser = argparse.ArgumentParser(add_help=False) 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("-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("-o", "--set-options", dest="set_options", default=[], nargs="+")
args_parser.add_argument("-m", "--dump-config", dest="dump_config", action="store_true") args_parser.add_argument("-m", "--dump-config", dest="dump_config", action="store_true")

View File

@ -10,7 +10,7 @@ from ... import gpio
# ===== # =====
def main() -> None: def main() -> None:
config = init()[2].kvmd config = init("kvmd-cleanup")[2].kvmd
logger = get_logger(0) logger = get_logger(0)
logger.info("Cleaning up ...") logger.info("Cleaning up ...")

View File

@ -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
# =====
@contextlib.contextmanager
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)

View File

@ -0,0 +1,2 @@
from . import main
main()

View File

@ -17,7 +17,7 @@ from .server import Server
# ===== # =====
def main() -> None: def main() -> None:
config = init()[2].kvmd config = init("kvmd")[2].kvmd
with gpio.bcm(): with gpio.bcm():
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()

View File

@ -21,6 +21,7 @@ def main() -> None:
"kvmd.yamlconf", "kvmd.yamlconf",
"kvmd.apps", "kvmd.apps",
"kvmd.apps.kvmd", "kvmd.apps.kvmd",
"kvmd.apps.htpasswd",
"kvmd.apps.cleanup", "kvmd.apps.cleanup",
], ],
@ -31,6 +32,7 @@ def main() -> None:
entry_points={ entry_points={
"console_scripts": [ "console_scripts": [
"kvmd = kvmd.apps.kvmd:main", "kvmd = kvmd.apps.kvmd:main",
"kvmd-htpasswd = kvmd.apps.htpasswd:main",
"kvmd-cleanup = kvmd.apps.cleanup:main", "kvmd-cleanup = kvmd.apps.cleanup:main",
], ],
}, },