multi-key signing implementation
This commit is contained in:
parent
7eb0a8cf7e
commit
e53f1f60eb
@ -18,10 +18,6 @@ class Controller(object):
|
||||
if max_age is not None:
|
||||
headers["Cache-Control"] = "max-age: {0}".format(max_age)
|
||||
for key, value in headers.items():
|
||||
if isinstance(value, list):
|
||||
for v in value:
|
||||
self.handler.send_header(key, v)
|
||||
else:
|
||||
self.handler.send_header(key, value)
|
||||
self.handler.end_headers()
|
||||
if type(content) == str:
|
||||
|
@ -6,16 +6,17 @@ from datetime import datetime
|
||||
class ReceiverIdController(Controller):
|
||||
def __init__(self, handler, request, options):
|
||||
super().__init__(handler, request, options)
|
||||
self.authHeaders = []
|
||||
self.authHeader = None
|
||||
|
||||
def send_response(self, content, code=200, content_type="text/html", last_modified: datetime = None, max_age=None, headers=None):
|
||||
if self.authHeader is not None:
|
||||
if headers is None:
|
||||
headers = {}
|
||||
headers['Authorization'] = self.authHeaders
|
||||
headers['Authorization'] = self.authHeader
|
||||
super().send_response(content, code=code, content_type=content_type, last_modified=last_modified, max_age=max_age, headers=headers)
|
||||
pass
|
||||
|
||||
def handle_request(self):
|
||||
headers = self.request.headers.get_all("Authorization", [])
|
||||
self.authHeaders = [ReceiverId.getResponseHeader(h) for h in headers]
|
||||
if "Authorization" in self.request.headers:
|
||||
self.authHeader = ReceiverId.getResponseHeader(self.request.headers['Authorization'])
|
||||
super().handle_request()
|
||||
|
@ -2,7 +2,7 @@ import re
|
||||
import logging
|
||||
import hashlib
|
||||
import hmac
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from owrx.config import Config
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -38,18 +38,18 @@ class KeyChallenge(object):
|
||||
|
||||
|
||||
class KeyResponse(object):
|
||||
def __init__(self, source, id, time: datetime, signature):
|
||||
def __init__(self, source, id, time, signature):
|
||||
self.source = source
|
||||
self.id = id
|
||||
self.time = time
|
||||
self.signature = signature
|
||||
|
||||
def __str__(self):
|
||||
return "Time={time}, Response={source}-{id}-{signature}".format(
|
||||
return "{source}-{id}-{time}-{signature}".format(
|
||||
source=self.source,
|
||||
id=self.id,
|
||||
time=self.time,
|
||||
signature=self.signature,
|
||||
time=self.time
|
||||
)
|
||||
|
||||
|
||||
@ -59,12 +59,17 @@ class ReceiverId(object):
|
||||
matches = headerRegex.match(requestHeader)
|
||||
if not matches:
|
||||
raise KeyException("invalid authorization header")
|
||||
challenge = KeyChallenge(matches.group(1))
|
||||
challenges = [KeyChallenge(i) for i in matches.group(1).split(",")]
|
||||
|
||||
def signChallenge(challenge):
|
||||
key = ReceiverId.findKey(challenge)
|
||||
if key is None:
|
||||
return {}
|
||||
return
|
||||
return ReceiverId.signChallenge(challenge, key)
|
||||
|
||||
responses = [signChallenge(c) for c in challenges]
|
||||
return ",".join(str(r) for r in responses if r is not None)
|
||||
|
||||
@staticmethod
|
||||
def findKey(challenge):
|
||||
def parseKey(keyString):
|
||||
@ -81,8 +86,9 @@ class ReceiverId(object):
|
||||
|
||||
@staticmethod
|
||||
def signChallenge(challenge, key):
|
||||
now = datetime.utcnow().isoformat()
|
||||
now = datetime.utcnow().replace(microsecond=0, tzinfo=timezone.utc)
|
||||
now_bytes = int(now.timestamp()).to_bytes(4, byteorder="big")
|
||||
m = hmac.new(bytes.fromhex(key.secret), digestmod=hashlib.sha256)
|
||||
m.update(bytes.fromhex(challenge.challenge))
|
||||
m.update(now.encode('utf8'))
|
||||
return KeyResponse(challenge.source, challenge.id, now, m.hexdigest())
|
||||
m.update(now_bytes)
|
||||
return KeyResponse(challenge.source, challenge.id, now_bytes.hex(), m.hexdigest())
|
||||
|
Loading…
Reference in New Issue
Block a user