diff --git a/daemon.py b/daemon.py index cf74cf9a..38d701b0 100644 --- a/daemon.py +++ b/daemon.py @@ -194,6 +194,7 @@ from petnames import setPetName from followingCalendar import addPersonToCalendar from followingCalendar import removePersonFromCalendar from devices import E2EEdevicesCollection +from devices import E2EEvalidDevice import os @@ -5776,9 +5777,46 @@ class PubServer(BaseHTTPRequestHandler): postBytes, boundary) return pageNumber + def _cryptoAPIreadJson(self) -> {}: + messageBytes = None + maxCryptoMessageLength = 10240 + length = int(self.headers['Content-length']) + if length >= maxCryptoMessageLength: + print('WARN: post to crypto API is too long ' + + str(length) + ' bytes') + return {} + try: + messageBytes = self.rfile.read(length) + except SocketError as e: + if e.errno == errno.ECONNRESET: + print('WARN: POST messageBytes ' + + 'connection reset by peer') + else: + print('WARN: POST messageBytes socket error') + return {} + except ValueError as e: + print('ERROR: POST messageBytes rfile.read failed') + print(e) + return {} + + lenMessage = len(messageBytes) + if lenMessage > 10240: + print('WARN: post to crypto API is too long ' + + str(lenMessage) + ' bytes') + return {} + + return json.loads(messageBytes) + def _cryptoAPI(self, path: str, authorized: bool) -> None: # TODO if authorized and path.startswith('/api/v1/crypto/keys/upload'): + deviceKeys = self._cryptoAPIreadJson() + if not deviceKeys: + self._400() + return + if not E2EEvalidDevice(deviceKeys): + self._400() + return self._200() elif path.startswith('/api/v1/crypto/keys/query'): self._200() diff --git a/devices.py b/devices.py index b1d39f94..b81bf7f4 100644 --- a/devices.py +++ b/devices.py @@ -46,6 +46,52 @@ def E2EEremoveDevice(baseDir: str, nickname: str, domain: str, return False +def E2EEvalidDevice(deviceJson: {}) -> bool: + """Returns true if the given json contains valid device keys + """ + if not isinstance(deviceJson, dict): + return False + if not deviceJson.get('deviceId'): + return False + if not isinstance(deviceJson['deviceId'], str): + return False + if not deviceJson.get('type'): + return False + if not isinstance(deviceJson['type'], str): + return False + if deviceJson['type'] != 'Device': + return False + if not deviceJson.get('claim'): + return False + if not isinstance(deviceJson['claim'], str): + return False + if not deviceJson.get('fingerprintKey'): + return False + if not isinstance(deviceJson['fingerprintKey'], dict): + return False + if not deviceJson['fingerprintKey'].get('type'): + return False + if not isinstance(deviceJson['fingerprintKey']['type'], str): + return False + if not deviceJson['fingerprintKey'].get('publicKeyBase64'): + return False + if not isinstance(deviceJson['fingerprintKey']['publicKeyBase64'], str): + return False + if not deviceJson.get('identityKey'): + return False + if not isinstance(deviceJson['identityKey'], dict): + return False + if not deviceJson['identityKey'].get('type'): + return False + if not isinstance(deviceJson['identityKey']['type'], str): + return False + if not deviceJson['identityKey'].get('publicKeyBase64'): + return False + if not isinstance(deviceJson['identityKey']['publicKeyBase64'], str): + return False + return True + + def E2EEaddDevice(baseDir: str, nickname: str, domain: str, deviceId: str, name: str, claimUrl: str, fingerprintPublicKey: str,