From 62ac4aeb030a61e738323fba21116127ca34e959 Mon Sep 17 00:00:00 2001 From: Javier Cacheiro Date: Wed, 13 Apr 2022 16:12:31 +0200 Subject: [PATCH 1/2] Use logging instead of directly printing messages to sys.stderr --- websockify/token_plugins.py | 50 ++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/websockify/token_plugins.py b/websockify/token_plugins.py index 0484023..4dc29de 100644 --- a/websockify/token_plugins.py +++ b/websockify/token_plugins.py @@ -1,8 +1,12 @@ +import logging import os import sys import time import re +logger = logging.getLogger(__name__) + + class BasePlugin(): def __init__(self, src): self.source = src @@ -35,7 +39,7 @@ class ReadOnlyTokenFile(BasePlugin): tok, target = re.split(':\s', line) self._targets[tok] = target.strip().rsplit(':', 1) except ValueError: - print("Syntax error in %s on line %d" % (self.source, index), file=sys.stderr) + logger.error("Syntax error in %s on line %d" % (self.source, index)) index += 1 def lookup(self, token): @@ -108,7 +112,7 @@ class JWTTokenApi(BasePlugin): with open(self.source, 'rb') as key_file: key_data = key_file.read() except Exception as e: - print("Error loading key file: %s" % str(e), file=sys.stderr) + logger.error("Error loading key file: %s" % str(e)) return None try: @@ -117,7 +121,7 @@ class JWTTokenApi(BasePlugin): try: key.import_key(k=key_data.decode('utf-8'),kty='oct') except: - print('Failed to correctly parse key data!', file=sys.stderr) + logger.error('Failed to correctly parse key data!') return None try: @@ -129,40 +133,40 @@ class JWTTokenApi(BasePlugin): token = jwt.JWT(key=key, jwt=token.claims) parsed = json.loads(token.claims) - + if 'nbf' in parsed: # Not Before is present, so we need to check it if time.time() < parsed['nbf']: - print('Token can not be used yet!', file=sys.stderr) + logger.warning('Token can not be used yet!') return None if 'exp' in parsed: # Expiration time is present, so we need to check it if time.time() > parsed['exp']: - print('Token has expired!', file=sys.stderr) + logger.warning('Token has expired!') return None return (parsed['host'], parsed['port']) except Exception as e: - print("Failed to parse token: %s" % str(e), file=sys.stderr) + logger.error("Failed to parse token: %s" % str(e)) return None - except ImportError as e: - print("package jwcrypto not found, are you sure you've installed it correctly?", file=sys.stderr) + except ImportError: + logger.error("package jwcrypto not found, are you sure you've installed it correctly?") return None class TokenRedis(): """ The TokenRedis plugin expects the format of the data in a form of json. - + Prepare data with: redis-cli set hello '{"host":"127.0.0.1:5000"}' - + Verify with: redis-cli --raw get hello - + Spawn a test "server" using netcat nc -l 5000 -v - + Note: you have to install also the 'redis' and 'simplejson' modules pip install redis simplejson """ @@ -172,14 +176,14 @@ class TokenRedis(): import redis import simplejson self._server, self._port = src.split(":") - print("TokenRedis backend initilized (%s:%s)" % - (self._server, self._port), file=sys.stderr) + logger.info("TokenRedis backend initilized (%s:%s)" % + (self._server, self._port)) except ValueError: - print("The provided --token-source='%s' is not in an expected format :" % - src, file=sys.stderr) + logger.error("The provided --token-source='%s' is not in an expected format :" % + src) sys.exit() except ImportError: - print("package redis or simplejson not found, are you sure you've installed them correctly?", file=sys.stderr) + logger.error("package redis or simplejson not found, are you sure you've installed them correctly?") sys.exit() def lookup(self, token): @@ -187,20 +191,20 @@ class TokenRedis(): import redis import simplejson except ImportError: - print("package redis or simplejson not found, are you sure you've installed them correctly?", file=sys.stderr) + logger.error("package redis or simplejson not found, are you sure you've installed them correctly?") sys.exit() - print("resolving token '%s'" % token, file=sys.stderr) + logger.info("resolving token '%s'" % token) client = redis.Redis(host=self._server, port=self._port) stuff = client.get(token) if stuff is None: return None else: responseStr = stuff.decode("utf-8") - print("response from redis : %s" % responseStr, file=sys.stderr) + logger.debug("response from redis : %s" % responseStr) combo = simplejson.loads(responseStr) (host, port) = combo["host"].split(':') - print("host: %s, port: %s" % (host,port), file=sys.stderr) + logger.debug("host: %s, port: %s" % (host,port)) return [host, port] @@ -228,5 +232,5 @@ class UnixDomainSocketDirectory(BasePlugin): return [ 'unix_socket', uds_path ] except Exception as e: - print("Error finding unix domain socket: %s" % str(e), file=sys.stderr) + logger.error("Error finding unix domain socket: %s" % str(e)) return None From e1f903b9e84c96d3e591279c1061d04c09a6361d Mon Sep 17 00:00:00 2001 From: Javier Cacheiro Date: Wed, 13 Apr 2022 17:02:05 +0200 Subject: [PATCH 2/2] Apply configuration to the root logger --- websockify/websocketproxy.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/websockify/websocketproxy.py b/websockify/websocketproxy.py index 09d7882..035ba63 100644 --- a/websockify/websocketproxy.py +++ b/websockify/websocketproxy.py @@ -35,15 +35,15 @@ Traffic Legend: < - Client send <. - Client send partial """ - + def send_auth_error(self, ex): self.send_response(ex.code, ex.msg) self.send_header('Content-Type', 'text/html') for name, val in ex.headers.items(): self.send_header(name, val) - + self.end_headers() - + def validate_connection(self): if not self.server.token_plugin: return @@ -72,7 +72,7 @@ Traffic Legend: except (TypeError, AttributeError, KeyError): # not a SSL connection or client presented no certificate with valid data pass - + try: self.server.auth_plugin.authenticate( headers=self.headers, target_host=self.server.target_host, @@ -403,7 +403,7 @@ def select_ssl_version(version): # It so happens that version names sorted lexicographically form a list # from the least to the most secure keys = list(SSL_OPTIONS.keys()) - keys.sort() + keys.sort() fallback = keys[-1] logger = logging.getLogger(WebSocketProxy.log_prefix) logger.warn("TLS version %s unsupported. Falling back to %s", @@ -420,7 +420,8 @@ def websockify_init(): stderr_handler.setLevel(logging.DEBUG) log_formatter = logging.Formatter("%(message)s") stderr_handler.setFormatter(log_formatter) - logger.addHandler(stderr_handler) + root = logging.getLogger() + root.addHandler(stderr_handler) # Setup optparse. usage = "\n %prog [options]" @@ -552,7 +553,8 @@ def websockify_init(): log_file_handler = logging.FileHandler(opts.log_file) log_file_handler.setLevel(logging.DEBUG) log_file_handler.setFormatter(log_formatter) - logger.addHandler(log_file_handler) + root = logging.getLogger() + root.addHandler(log_file_handler) del opts.log_file @@ -585,7 +587,8 @@ def websockify_init(): legacy=opts.legacy_syslog) syslog_handler.setLevel(logging.DEBUG) syslog_handler.setFormatter(log_formatter) - logger.addHandler(syslog_handler) + root = logging.getLogger() + root.addHandler(syslog_handler) del opts.syslog del opts.legacy_syslog