aboutsummaryrefslogtreecommitdiff
path: root/http2irc.py
diff options
context:
space:
mode:
Diffstat (limited to 'http2irc.py')
-rw-r--r--http2irc.py52
1 files changed, 35 insertions, 17 deletions
diff --git a/http2irc.py b/http2irc.py
index 730820c..31ae084 100644
--- a/http2irc.py
+++ b/http2irc.py
@@ -154,7 +154,7 @@ class Config(dict):
raise InvalidConfig(f'Invalid map key {key!r}')
if not isinstance(map_, collections.abc.Mapping):
raise InvalidConfig(f'Invalid map for {key!r}')
- if any(x not in ('webpath', 'ircchannel', 'auth', 'module', 'moduleargs', 'overlongmode') for x in map_):
+ if any(x not in ('webpath', 'ircchannel', 'auth', 'postauth', 'getauth', 'module', 'moduleargs', 'overlongmode') for x in map_):
raise InvalidConfig(f'Unknown key(s) found in map {key!r}')
if 'webpath' not in map_:
@@ -180,11 +180,19 @@ class Config(dict):
if len(map_['ircchannel']) > 200:
raise InvalidConfig(f'Invalid map {key!r} IRC channel: too long')
+ # For backward compatibility, 'auth' gets treated as 'postauth'
if 'auth' in map_:
- if map_['auth'] is not False and not isinstance(map_['auth'], str):
- raise InvalidConfig(f'Invalid map {key!r} auth: must be false or a string')
- if isinstance(map_['auth'], str) and ':' not in map_['auth']:
- raise InvalidConfig(f'Invalid map {key!r} auth: must contain a colon')
+ if 'postauth' in map_:
+ raise InvalidConfig(f'auth and postauth are aliases and cannot be used together')
+ map_['postauth'] = map_['auth']
+ del map_['auth']
+ for k in ('postauth', 'getauth'):
+ if k not in map_:
+ continue
+ if map_[k] is not False and not isinstance(map_[k], str):
+ raise InvalidConfig(f'Invalid map {key!r} {k}: must be false or a string')
+ if isinstance(map_[k], str) and ':' not in map_[k]:
+ raise InvalidConfig(f'Invalid map {key!r} {k}: must contain a colon')
if 'module' in map_:
# If the path is relative, try to evaluate it relative to either the config file or this file; some modules are in the repo, but this also allows overriding them.
@@ -217,8 +225,10 @@ class Config(dict):
for key, map_ in obj['maps'].items():
# webpath is already set above for duplicate checking
# ircchannel is set above for validation
- if 'auth' not in map_:
- map_['auth'] = False
+ if 'postauth' not in map_:
+ map_['postauth'] = False
+ if 'getauth' not in map_:
+ map_['getauth'] = False
if 'module' not in map_:
map_['module'] = None
if 'moduleargs' not in map_:
@@ -937,7 +947,9 @@ class WebServer:
self.ircClient = ircClient
self.config = config
- self._paths = {} # '/path' => ('#channel', auth, module, moduleargs) where auth is either False (no authentication) or the HTTP header value for basic auth
+ self._paths = {}
+ # '/path' => ('#channel', postauth, getauth, module, moduleargs, overlongmode)
+ # {post,get}auth are either False (access denied) or the HTTP header value for basic auth
self._app = aiohttp.web.Application()
self._app.add_routes([
@@ -951,7 +963,14 @@ class WebServer:
self.stopEvent = None
def update_config(self, config):
- self._paths = {map_['webpath']: (map_['ircchannel'], f'Basic {base64.b64encode(map_["auth"].encode("utf-8")).decode("utf-8")}' if map_['auth'] else False, map_['module'], map_['moduleargs'], map_['overlongmode']) for map_ in config['maps'].values()}
+ self._paths = {map_['webpath']: (
+ map_['ircchannel'],
+ f'Basic {base64.b64encode(map_["postauth"].encode("utf-8")).decode("utf-8")}' if map_['postauth'] else False,
+ f'Basic {base64.b64encode(map_["getauth"].encode("utf-8")).decode("utf-8")}' if map_['getauth'] else False,
+ map_['module'],
+ map_['moduleargs'],
+ map_['overlongmode']
+ ) for map_ in config['maps'].values()}
needRebind = self.config['web'] != config['web']
self.config = config
if needRebind:
@@ -981,15 +1000,14 @@ class WebServer:
except KeyError:
self.logger.info(f'Bad request {id(request)}: no path {request.path!r}')
raise aiohttp.web.HTTPNotFound()
- auth = pathConfig[1]
- if auth:
- authHeader = request.headers.get('Authorization')
- if not authHeader or authHeader != auth:
- self.logger.info(f'Bad request {id(request)}: authentication failed: {authHeader!r} != {auth}')
- raise aiohttp.web.HTTPForbidden()
+ auth = pathConfig[1] if request.method == 'POST' else pathConfig[2]
+ authHeader = request.headers.get('Authorization')
+ if not authHeader or not auth or authHeader != auth:
+ self.logger.info(f'Bad request {id(request)}: authentication failed: {authHeader!r} != {auth}')
+ raise aiohttp.web.HTTPForbidden()
return (await func(request, *pathConfig))
- async def post(self, request, channel, auth, module, moduleargs, overlongmode):
+ async def post(self, request, channel, postauth, getauth, module, moduleargs, overlongmode):
if module is not None:
self.logger.debug(f'Processing request {id(request)} using {module!r}')
try:
@@ -1026,7 +1044,7 @@ class WebServer:
raise aiohttp.web.HTTPBadRequest()
return message
- async def get(self, request, channel, auth, module, moduleargs, overlongmode):
+ async def get(self, request, channel, postauth, getauth, module, moduleargs, overlongmode):
self.logger.info(f'Subscribing listener from request {id(request)} for {channel}')
queue = self.irc2httpBroadcaster.subscribe(channel)
response = aiohttp.web.StreamResponse()