diff --git a/daemon.py b/daemon.py index 2d1ec172..ca8ed0b1 100644 --- a/daemon.py +++ b/daemon.py @@ -1079,6 +1079,8 @@ class PubServer(BaseHTTPRequestHandler): elif self.headers.get('content-length'): headersDict['content-length'] = self.headers['content-length'] + originalMessageJson = messageJson.copy() + # For follow activities add a 'to' field, which is a copy # of the object field messageJson, toFieldExists = \ @@ -1097,7 +1099,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.httpPrefix, nickname, self.server.domainFull, - messageJson, + messageJson, originalMessageJson, messageBytesDecoded, headersDict, self.path, diff --git a/inbox.py b/inbox.py index d0c35733..37a476dc 100644 --- a/inbox.py +++ b/inbox.py @@ -313,6 +313,7 @@ def inboxPermittedMessage(domain: str, messageJson: {}, def savePostToInboxQueue(baseDir: str, httpPrefix: str, nickname: str, domain: str, postJsonObject: {}, + originalPostJsonObject: {}, messageBytes: str, httpHeaders: {}, postPath: str, debug: bool) -> str: @@ -437,6 +438,7 @@ def savePostToInboxQueue(baseDir: str, httpPrefix: str, 'httpHeaders': httpHeaders, 'path': postPath, 'post': postJsonObject, + 'original': originalPostJsonObject, 'digest': digest, 'filename': filename, 'destination': destination @@ -2703,24 +2705,30 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int, if debug: print('DEBUG: http header signature check success') - if not queueJson['post'].get('signature'): - print('WARN: jsonld inbox signature signature missing from ' + - keyId) -# else: -# if not jsonldVerify(queueJson['post'], pubKey): -# hasJsonSig = False -# if debug: -# print('**************************************') -# print('WARN: jsonld signature check failed ' + -# str(queueJson['post'])) -# print('--------------------------------------') -# print(keyId) -# print(pubKey) -# print('**************************************') -# else: -# if debug: -# print('jsonld inbox signature check success') -# + # should the json signature be checked? + checkJsonSignature = False + if queueJson['original'].get('@context'): + checkJsonSignature = True + if not queueJson['original'].get('signature'): + print('WARN: jsonld inbox signature signature missing from ' + + keyId) + checkJsonSignature = False + + # check json signature + if checkJsonSignature: + # use the original json message received, not one which may have + # been modified along the way + if not jsonldVerify(queueJson['original'], pubKey): + print('WARN: jsonld signature check failed ' + + keyId + ' ' + pubKey + ' ' + + str(queueJson['original'])) + if os.path.isfile(queueFilename): + os.remove(queueFilename) + if len(queue) > 0: + queue.pop(0) + continue + else: + print('jsonld inbox signature check success') # set the id to the same as the post filename # This makes the filename and the id consistent diff --git a/jsonldsig.py b/jsonldsig.py index 30a09e96..df7e93a5 100644 --- a/jsonldsig.py +++ b/jsonldsig.py @@ -116,6 +116,9 @@ def jsonldSign(jldDocument: {}, privateKeyPem: str) -> {}: """ Produces a signed JSON-LD document with a Json Web Signature """ + if not jldDocument.get('@context'): + print('WARN: json document must have @context to sign') + return jldDocument jldDocument = deepcopy(jldDocument) normalizedJldHash = _jsonldNormalize(jldDocument) jwsSignature = _signJws(normalizedJldHash, privateKeyPem) @@ -135,6 +138,11 @@ def jsonldVerify(signedJldDocument: {}, publicKeyPem: str) -> bool: """ Verifies the Json Web Signature of a signed JSON-LD Document """ + if not isinstance(signedJldDocument, dict): + return False + if not signedJldDocument.get('@context'): + print('json document must have @context') + return False signedJldDocument = deepcopy(signedJldDocument) signature = signedJldDocument.pop('signature') jwsSignature = signature['signatureValue'].encode('utf-8') diff --git a/pyjsonld.py b/pyjsonld.py index f0f55b41..5f31ca0e 100644 --- a/pyjsonld.py +++ b/pyjsonld.py @@ -234,7 +234,7 @@ def link(input_, ctx, options=None): return frame(input, frame, options) -def normalize(input_, options=None): +def normalize(input_: {}, options=None): """ Performs JSON-LD normalization. @@ -1016,6 +1016,13 @@ class JsonLdProcessor(object): 'Could not convert input to RDF dataset before normalization.', 'jsonld.NormalizeError', cause=cause) + # check that the data is not empty + if '@default' in dataset: + if not dataset['@default']: + raise JsonLdError( + 'Could not convert input to RDF dataset.', + 'jsonld.NormalizeError', cause=None) + # do normalization return self._normalize(dataset, options) diff --git a/tests.py b/tests.py index 70421cd3..bc900348 100644 --- a/tests.py +++ b/tests.py @@ -1978,6 +1978,7 @@ def testRemoveTextFormatting(): def testJsonld(): print("testJsonld") jldDocument = { + "@context": "https://www.w3.org/ns/activitystreams", "description": "My json document", "numberField": 83582, "object": { @@ -2031,10 +2032,11 @@ def testJsonld(): assert(signedDocument['signature']['type'] == 'RsaSignatureSuite2017') assert(jsonldVerify(signedDocument, publicKeyPem)) # alter the signed document - # signedDocument['object']['content'] = 'forged content' - # assert(not jsonldVerify(signedDocument, publicKeyPem)) + signedDocument['object']['content'] = 'forged content' + assert(not jsonldVerify(signedDocument, publicKeyPem)) jldDocument2 = { + "@context": "https://www.w3.org/ns/activitystreams", "description": "Another json document", "numberField": 13353, "object": { @@ -2049,8 +2051,8 @@ def testJsonld(): if signedDocument['signature']['signatureValue'] == \ signedDocument2['signature']['signatureValue']: print('json signature has not changed for different documents') -# assert(signedDocument['signature']['signatureValue'] != -# signedDocument2['signature']['signatureValue']) + assert(signedDocument['signature']['signatureValue'] != + signedDocument2['signature']['signatureValue']) def testSiteIsActive():