From 8b9b105d5d66dda6f0739f7c989b4ef91138fdc6 Mon Sep 17 00:00:00 2001 From: Violet Evergarden <2929724643@qq.com> Date: Sun, 17 May 2026 17:06:13 +0800 Subject: [PATCH] feat: add HTTP Basic Auth support for nginx reverse proxy Add --auth-user and --auth-password CLI args (also configurable via TOML) for servers behind nginx with auth_basic. Same approach as aw-watcher-window: replace aw-client's _get/_post/_delete methods to inject Authorization headers. --- aw_watcher_afk/afk.py | 35 +++++++++++++++++++++++++++++++++++ aw_watcher_afk/config.py | 24 ++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/aw_watcher_afk/afk.py b/aw_watcher_afk/afk.py index 8e95163..720c213 100755 --- a/aw_watcher_afk/afk.py +++ b/aw_watcher_afk/afk.py @@ -1,6 +1,8 @@ +import json import logging import os import platform +import requests from datetime import datetime, timedelta, timezone from time import sleep @@ -28,6 +30,34 @@ td1ms = timedelta(milliseconds=1) +def _patch_client_auth(client, user, password): + """Replace aw-client HTTP methods to inject Basic Auth credentials.""" + from aw_client.client import always_raise_for_request_errors + + auth = requests.auth.HTTPBasicAuth(user, password) + _url = client._url + + @always_raise_for_request_errors + def _get(self_ref, endpoint, params=None): + return requests.get(_url(endpoint), params=params, auth=auth) + + @always_raise_for_request_errors + def _post(self_ref, endpoint, data, params=None): + headers = {"Content-type": "application/json", "charset": "utf-8"} + return requests.post(_url(endpoint), data=bytes(json.dumps(data), "utf8"), headers=headers, params=params, auth=auth) + + @always_raise_for_request_errors + def _delete(self_ref, endpoint, data=None): + if data is None: + data = {} + headers = {"Content-type": "application/json"} + return requests.delete(_url(endpoint), data=json.dumps(data), headers=headers, auth=auth) + + client._get = lambda endpoint, params=None: _get(client, endpoint, params) + client._post = lambda endpoint, data, params=None: _post(client, endpoint, data, params) + client._delete = lambda endpoint, data=None: _delete(client, endpoint, data) + + class Settings: def __init__(self, config_section, timeout=None, poll_time=None): # Time without input before we're considering the user as AFK @@ -48,6 +78,11 @@ def __init__(self, args, testing=False): self.client = ActivityWatchClient( "aw-watcher-afk", host=args.host, port=args.port, testing=testing ) + + if args.auth_user and args.auth_password: + _patch_client_auth(self.client, args.auth_user, args.auth_password) + logger.info("HTTP Basic Auth enabled for user: %s", args.auth_user) + self.bucketname = "{}_{}".format( self.client.client_name, self.client.client_hostname ) diff --git a/aw_watcher_afk/config.py b/aw_watcher_afk/config.py index 59c1f9e..cbb0d9a 100644 --- a/aw_watcher_afk/config.py +++ b/aw_watcher_afk/config.py @@ -7,6 +7,10 @@ [aw-watcher-afk] timeout = 180 poll_time = 5 +host = "" +port = "" +auth_user = "" +auth_password = "" [aw-watcher-afk-testing] timeout = 20 @@ -26,12 +30,16 @@ def parse_args(): default_poll_time = config["poll_time"] default_timeout = config["timeout"] + default_host = config.get("host", "") or None + default_port = config.get("port", "") or None + default_auth_user = config.get("auth_user", "") + default_auth_password = config.get("auth_password", "") parser = argparse.ArgumentParser( description="A watcher for keyboard and mouse input to detect AFK state." ) - parser.add_argument("--host", dest="host") - parser.add_argument("--port", dest="port") + parser.add_argument("--host", dest="host", default=default_host) + parser.add_argument("--port", dest="port", default=default_port) parser.add_argument( "--testing", dest="testing", action="store_true", help="run in testing mode" ) @@ -47,5 +55,17 @@ def parse_args(): parser.add_argument( "--poll-time", dest="poll_time", type=float, default=default_poll_time ) + parser.add_argument( + "--auth-user", + dest="auth_user", + default=default_auth_user, + help="Username for HTTP Basic Auth (for nginx-proxied servers)", + ) + parser.add_argument( + "--auth-password", + dest="auth_password", + default=default_auth_password, + help="Password for HTTP Basic Auth (for nginx-proxied servers)", + ) parsed_args = parser.parse_args() return parsed_args