add auth support
This commit is contained in:
79
pytorrent/cli.py
Normal file
79
pytorrent/cli.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import getpass
|
||||
import sys
|
||||
|
||||
from .db import connect, init_db, utcnow
|
||||
from .services.auth import password_hash
|
||||
|
||||
|
||||
def reset_password(username: str, password: str) -> bool:
|
||||
"""Note: Reset the selected user password hash without changing role or permissions."""
|
||||
username = (username or "").strip()
|
||||
if not username:
|
||||
raise ValueError("Username is required")
|
||||
if password is None or password == "":
|
||||
raise ValueError("Password cannot be empty")
|
||||
|
||||
init_db()
|
||||
now = utcnow()
|
||||
hashed = password_hash(password)
|
||||
with connect() as conn:
|
||||
row = conn.execute("SELECT id FROM users WHERE username=?", (username,)).fetchone()
|
||||
if not row:
|
||||
return False
|
||||
conn.execute(
|
||||
"UPDATE users SET password_hash=?, updated_at=? WHERE username=?",
|
||||
(hashed, now, username),
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def _password_from_args(args: argparse.Namespace) -> str:
|
||||
"""Note: Allow the password to be passed as an argument or entered securely in interactive mode."""
|
||||
if args.password is not None:
|
||||
return args.password
|
||||
first = getpass.getpass("New password: ")
|
||||
second = getpass.getpass("Repeat password: ")
|
||||
if first != second:
|
||||
raise ValueError("Passwords do not match")
|
||||
return first
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
"""Note: Define simple administrative commands launched with python -m pytorrent.cli."""
|
||||
parser = argparse.ArgumentParser(description="pyTorrent CLI")
|
||||
sub = parser.add_subparsers(dest="command", required=True)
|
||||
|
||||
reset = sub.add_parser("reset-password", help="Reset password for an existing user")
|
||||
reset.add_argument("username", help="User login")
|
||||
reset.add_argument("password", nargs="?", help="New password; omit to type it interactively")
|
||||
reset.set_defaults(func=_cmd_reset_password)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def _cmd_reset_password(args: argparse.Namespace) -> int:
|
||||
"""Note: Run the password reset and return a readable terminal status."""
|
||||
password = _password_from_args(args)
|
||||
if reset_password(args.username, password):
|
||||
print(f"Password reset for user: {args.username}")
|
||||
return 0
|
||||
print(f"User not found: {args.username}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
"""Note: Main CLI entrypoint with error handling and without starting the web app."""
|
||||
parser = build_parser()
|
||||
args = parser.parse_args(argv)
|
||||
try:
|
||||
return int(args.func(args) or 0)
|
||||
except Exception as exc:
|
||||
print(f"Error: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user