Add require_user_urlparam config option that makes the ?l=<user> query optional.

This commit is contained in:
s3lph 2021-09-29 03:52:07 +02:00
parent c535ae8f1a
commit adc699aeed
6 changed files with 49 additions and 11 deletions

View file

@ -1,5 +1,19 @@
# EasyWKS Changelog # EasyWKS Changelog
<!-- BEGIN RELEASE v0.1.4 -->
## Version 0.1.4
Fix HTTP server, compatibility with older HTTP clients
### Changes
<!-- BEGIN CHANGES 0.1.4 -->
- Fix config loading bug in webserver.
- Add `require_user_urlparam` config option that makes the `?l=<user>` query optional.
<!-- END CHANGES 0.1.4 -->
<!-- END RELEASE v0.1.4 -->
<!-- BEGIN RELEASE v0.1.3 --> <!-- BEGIN RELEASE v0.1.3 -->
## Version 0.1.3 ## Version 0.1.3

View file

@ -94,6 +94,9 @@ permit_unsigned_response: false
httpd: httpd:
host: 127.0.0.1 host: 127.0.0.1
port: 8080 port: 8080
# Some older HTTP clients omit the ?l=<userid> query suffix. Set
# this to false in order to permit such clients to retrieve keys.
#require_user_urlparam: true
# Defaults to stdout, supported: stdout, smtp # Defaults to stdout, supported: stdout, smtp
mailing_method: smtp mailing_method: smtp

View file

@ -39,10 +39,21 @@ def _validate_smtp_config(value):
def _validate_httpd_config(value): def _validate_httpd_config(value):
if not isinstance(value, dict): if not isinstance(value, dict):
return f'must be a map, got {type(value)}' return f'must be a map, got {type(value)}'
if 'host' in value:
if not isinstance(value['host'], str): if not isinstance(value['host'], str):
return f'host must be a str, got {type(value["host"])}' return f'host must be a str, got {type(value["host"])}'
else:
value['host'] = 'localhost'
if 'port' in value:
if not isinstance(value['port'], int): if not isinstance(value['port'], int):
return f'port must be a int, got {type(value["port"])}' return f'port must be a int, got {type(value["port"])}'
else:
value['port'] = 8080
if 'require_user_urlparam' in value:
if not isinstance(value['require_user_urlparam'], bool):
return f'port must be a bool, got {type(value["require_user_urlparam"])}'
else:
value['require_user_urlparam'] = True
def _validate_lmtpd_config(value): def _validate_lmtpd_config(value):
@ -141,7 +152,8 @@ Config = _GlobalConfig(
permit_unsigned_response=_ConfigOption('permit_unsigned_response', bool, False), permit_unsigned_response=_ConfigOption('permit_unsigned_response', bool, False),
httpd=_ConfigOption('httpd', dict, { httpd=_ConfigOption('httpd', dict, {
'host': 'localhost', 'host': 'localhost',
'port': 8080 'port': 8080,
'require_user_urlparam': True
}, validator=_validate_httpd_config), }, validator=_validate_httpd_config),
smtp=_ConfigOption('smtp', dict, { smtp=_ConfigOption('smtp', dict, {
'host': 'localhost', 'host': 'localhost',

View file

@ -52,6 +52,12 @@ def read_public_key(domain, user):
return key return key
def read_hashed_public_key(domain, hu):
keyfile = os.path.join(Config.working_directory, domain, 'hu', hu)
key, _ = PGPKey.from_file(keyfile)
return key
def write_public_key(domain, user, key): def write_public_key(domain, user, key):
hu = hash_user_id(user) hu = hash_user_id(user)
keyfile = os.path.join(Config.working_directory, domain, 'hu', hu) keyfile = os.path.join(Config.working_directory, domain, 'hu', hu)

View file

@ -1,6 +1,6 @@
from .config import Config from .config import Config
from .files import read_public_key, make_submission_address_file, make_policy_file from .files import read_hashed_public_key, make_submission_address_file, make_policy_file
from .util import hash_user_id from .util import hash_user_id
from bottle import get, run, abort, response, request from bottle import get, run, abort, response, request
@ -26,12 +26,12 @@ def policy(domain: str):
def hu(domain: str, userhash: str): def hu(domain: str, userhash: str):
if domain not in Config.domains: if domain not in Config.domains:
abort(404, 'Not Found') abort(404, 'Not Found')
if Config.httpd['require_user_urlparam']:
userid = request.query.l userid = request.query.l
print(userid, userhash, hash_user_id(userid))
if not userid or hash_user_id(userid) != userhash: if not userid or hash_user_id(userid) != userhash:
abort(404, 'Not Found') abort(404, 'Not Found')
try: try:
pubkey = read_public_key(domain, userid) pubkey = read_hashed_public_key(domain, userhash)
response.add_header('Content-Type', 'application/octet-stream') response.add_header('Content-Type', 'application/octet-stream')
return bytes(pubkey) return bytes(pubkey)
except FileNotFoundError: except FileNotFoundError:

View file

@ -18,6 +18,9 @@
httpd: httpd:
host: "::1" host: "::1"
port: 8080 port: 8080
# Some older HTTP clients omit the ?l=<userid> query suffix. Set
# this to false in order to permit such clients to retrieve keys.
#require_user_urlparam: true
# Defaults to stdout, supported: stdout, smtp # Defaults to stdout, supported: stdout, smtp
mailing_method: smtp mailing_method: smtp