def processPendingContacts(torId): print("Process pending contact accept responses from:", torId) foundReq = False for resp in DbI.getPendingContactMessages(torId): name = resp.get("fromName", None) if not name: profile = DbI.getProfile(torId) name = profile["displayName"] print("Found pending contact accept request from: ", name) # Check signature using keyring _, signatureKey = CryptoClient.decryptAndCheckSignature( resp.get("encryptedMsg", None)) if signatureKey: foundReq = True # Insert new message into inbox with message contents rowToStore = { "messageType": "contactresponse", "fromId": resp.get("fromId", None), "fromName": name, "accepted": True, "messageBody": resp.get("messageBody", ""), "timestamp": resp.get("timestamp", None), "messageRead": True, "messageReplied": True, "recipients": DbI.getOwnTorid() } DbI.addToInbox(rowToStore) if foundReq: DbI.updateProfile(torId, {"status": "untrusted"}) # Delete all pending contact responses from this torId DbI.deletePendingContactMessages(torId)
def dealWithUnencryptedMessage(message): '''Decide what to do with the given unencrypted message''' if message.messageType == Message.TYPE_CONTACT_REQUEST: print("Received a contact request from", message.senderId) # Check config to see whether we accept these or not if Config.getProperty(Config.KEY_ALLOW_FRIEND_REQUESTS) \ and MessageShuffler._isProfileStatusOk(message.senderId, [None, 'requested', 'untrusted', 'trusted']): # Store new message in inbox rowToStore = { "messageType": "contactrequest", "fromId": message.senderId, "fromName": message.senderName, "messageBody": message.message, "publicKey": message.publicKey, "timestamp": message.timestamp, "messageRead": False, "messageReplied": False } DbI.addToInbox(rowToStore) elif message.messageType == Message.TYPE_CONTACT_RESPONSE: print( "It's an unencrypted contact response, so it must be a refusal" ) sender = DbI.getProfile(message.senderId) if MessageShuffler._isProfileStatusOk(message.senderId, ['requested']): senderName = sender.get("displayName") if sender else "" ContactMaker.handleReceiveDeny(message.senderId) # Store new message in inbox rowToStore = { "messageType": "contactresponse", "fromId": message.senderId, "fromName": senderName, "messageBody": "", "accepted": False, "messageRead": False, "messageReplied": False, "timestamp": message.timestamp, "recipients": DbI.getOwnTorid() } DbI.addToInbox(rowToStore) else: print("Hä? It's unencrypted but the message type is", message.messageType)
def testConversationIds(self): '''Test the increment of conversation ids''' db = supersimpledb.MurmeliDb() DbI.setDb(db) # If we start with an empty db, the id should start at 1 for i in range(100): self.assertEqual(DbI.getNewConversationId(), i+1, "id should be 1 more than i") # Add profiles for us and a messages sender DbI.updateProfile("F055", {"keyid":"ZYXW987", "status":"self", "name":"That's me"}) DbI.updateProfile("ABC312", {"keyid":"ZYXW987", "status":"trusted", "name":"Best friend"}) # Add an inbox message with a conversation id DbI.addToInbox({"messageBody":"Gorgonzola and Camembert", "timestamp":"early 2017", "fromId":"ABC312"}) # Get this message again, and check the conversation id, should be 101 msg0 = DbI.getInboxMessages()[0] self.assertEqual(msg0.get("conversationid", 0), 101, "Id should now be 101") # Add another message with the parent hash referring to the first one DbI.addToInbox({"messageBody":"Fried egg sandwich", "timestamp":"middle 2017", "fromId":"ABC312", "parentHash":'40e98bae7a811c23b59b89bd0f11b0a0'}) msg1 = DbI.getInboxMessages()[0] self.assertTrue("Fried egg" in msg1.get("messageBody", ""), "Fried egg should be first") self.assertEqual(msg1.get("conversationid", 0), 101, "Id should now also be 101") # Add another message with an unrecognised parent hash DbI.addToInbox({"messageBody":"Red wine and chocolate", "timestamp":"late 2017", "fromId":"ABC312", "parentHash":'ff3'}) msg2 = DbI.getInboxMessages()[0] self.assertTrue("Red wine" in msg2.get("messageBody", ""), "Red wine should be first") self.assertEqual(msg2.get("conversationid", 0), 102, "Id should take 102") # done DbI.releaseDb()
def testSearching(self): '''Test the searching of the inbox''' db = supersimpledb.MurmeliDb() DbI.setDb(db) # Add some inbox messages with different text DbI.addToInbox({"messageBody":"There were some children playing in the park", "timestamp":"", "fromId":"ABC312"}) DbI.addToInbox({"messageBody":"There was a child playing in the castle", "timestamp":"", "fromId":"ABC312"}) DbI.addToInbox({"messageBody":"Children were making far too much noise", "timestamp":"", "fromId":"ABC312"}) # Get this message again, and check the conversation id, should be 101 self.assertEqual(len(DbI.getInboxMessages()), 3, "Inbox has 3") search1 = DbI.searchInboxMessages("child") self.assertEqual(len(search1), 2, "Only 2 match 'child'") search2 = DbI.searchInboxMessages("children") self.assertEqual(len(search2), 1, "Only 1 matches 'children'") search3 = DbI.searchInboxMessages("") self.assertEqual(len(search3), 3, "All match empty search string") search4 = DbI.searchInboxMessages("hild") self.assertEqual(len(search4), 3, "All match 'hild'") search5 = DbI.searchInboxMessages("noisy") self.assertEqual(len(search5), 0, "None are noisy") search6 = DbI.searchInboxMessages("Child") self.assertEqual(len(search6), 1, "Only 1 matches 'Child'") # done DbI.releaseDb()
def dealWithAsymmetricMessage(message): '''Decide what to do with the given asymmetric message''' if message.senderId == DbI.getOwnTorid(): print("*** Shouldn't receive a message from myself!") return # Sort message according to type if message.messageType == Message.TYPE_CONTACT_RESPONSE: print("Received a contact accept from", message.senderId, "name", message.senderName) if MessageShuffler._isProfileStatusOk( message.senderId, ['pending', 'requested', 'untrusted']): print(message.senderName, "'s public key is", message.senderKey) ContactMaker.handleReceiveAccept(message.senderId, message.senderName, message.senderKey) # Store new message in inbox rowToStore = { "messageType": "contactresponse", "fromId": message.senderId, "fromName": message.senderName, "messageBody": message.introMessage, "accepted": True, "messageRead": False, "messageReplied": False, "timestamp": message.timestamp, "recipients": DbI.getOwnTorid() } DbI.addToInbox(rowToStore) elif MessageShuffler._isProfileStatusOk(message.senderId, [None, 'blocked']): print( "Received a contact response but I didn't send them a request!" ) print("Encrypted contents are:", message.encryptedContents) rowToStore = { "messageType": "contactresponse", "fromId": message.senderId, "fromName": message.senderName, "messageBody": message.introMessage, "accepted": True, "timestamp": message.timestamp, "encryptedMsg": message.encryptedContents } DbI.addMessageToPendingContacts(rowToStore) elif message.messageType == Message.TYPE_STATUS_NOTIFY: if message.online: print("One of our contacts has just come online- ", message.senderId, "and hash is", message.profileHash) prof = DbI.getProfile(message.senderId) if prof: storedHash = prof.get("profileHash", "empty") if message.profileHash != storedHash: reply = InfoRequestMessage( infoType=InfoRequestMessage.INFO_PROFILE) reply.recipients = [message.senderId] DbI.addToOutbox(reply) if message.ping: print("Now sending back a pong, too") reply = StatusNotifyMessage(online=True, ping=False, profileHash=None) reply.recipients = [message.senderId] DbI.addToOutbox(reply) else: print("It's already a pong so I won't reply") Contacts.instance().comeOnline(message.senderId) else: print("One of our contacts is going offline -", message.senderId) Contacts.instance().goneOffline(message.senderId) elif message.messageType == Message.TYPE_INFO_REQUEST: print("I've received an info request message for type", message.infoType) if MessageShuffler._isProfileStatusOk(message.senderId, ['trusted']): reply = InfoResponseMessage(message.messageType) reply.recipients = [message.senderId] DbI.addToOutbox(reply) elif message.messageType == Message.TYPE_INFO_RESPONSE: if message.profile and MessageShuffler._isProfileStatusOk( message.senderId, ['trusted', 'untrusted']): if message.profileHash: message.profile['profileHash'] = message.profileHash DbI.updateProfile(message.senderId, message.profile, Config.getWebCacheDir()) elif message.messageType == Message.TYPE_FRIEND_REFERRAL: print("I've received a friend referral message from:", message.senderId, "for:", message.friendName) if MessageShuffler._isProfileStatusOk(message.senderId, ['trusted']): # Store new referral message in inbox rowToStore = { "messageType": "contactrefer", "fromId": message.senderId, "friendId": message.friendId, "friendName": message.friendName, "messageBody": message.message, "publicKey": message.publicKey, "timestamp": message.timestamp, "messageRead": False, "messageReplied": False } DbI.addToInbox(rowToStore) elif message.messageType == Message.TYPE_FRIENDREFER_REQUEST: print("I've received a friend referral request from:", message.senderId, "who wants me to refer:", message.friendId) if MessageShuffler._isProfileStatusOk(message.senderId, ['trusted']): # Store message in the inbox rowToStore = { "messageType": "referrequest", "fromId": message.senderId, "friendId": message.friendId, "friendName": message.friendName, "messageBody": message.message, "publicKey": message.publicKey, "timestamp": message.timestamp, "messageRead": False, "messageReplied": False } DbI.addToInbox(rowToStore) elif message.messageType == Message.TYPE_ASYM_MESSAGE: print( "It's a general kind of message, this should go in the Inbox, right?" ) if MessageShuffler._isProfileStatusOk(message.senderId, ['trusted', 'untrusted']): rowToStore = { "messageType": "normal", "fromId": message.senderId, "messageBody": message.messageBody, "timestamp": message.timestamp, "messageRead": False, "messageReplied": False, "recipients": message.sendTo, "parentHash": message.replyToHash } DbI.addToInbox(rowToStore) Contacts.instance().comeOnline(message.senderId) else: # It's another asymmetric message type print("Hä? What kind of asymmetric message type is that? ", message.messageType)
def servePage(self, view, url, params): print("Compose: %s, params %s" % (url, repr(params))) if url == "/start": self.requirePageResources(['default.css', 'jquery-3.1.1.js']) DbI.exportAllAvatars(Config.getWebCacheDir()) parentHash = params.get("reply", None) recpts = params.get("sendto", None) # Build list of contacts to whom we can send userboxes = [] for p in DbI.getMessageableProfiles(): box = Bean() box.dispName = p['displayName'] box.torid = p['torid'] userboxes.append(box) pageParams = { "contactlist": userboxes, "parenthash": parentHash if parentHash else "", "webcachedir": Config.getWebCacheDir(), "recipientids": recpts } contents = self.buildPage({ 'pageTitle': I18nManager.getText("composemessage.title"), 'pageBody': self.composetemplate.getHtml(pageParams), 'pageFooter': "<p>Footer</p>" }) view.setHtml(contents) # If we've got no friends, then warn, can't send to anyone if not DbI.hasFriends(): view.page().mainFrame().evaluateJavaScript( "window.alert('No friends :(');") elif url == "/send": print("Submit new message with params:", params) msgBody = params[ 'messagebody'] # TODO: check body isn't empty, throw an exception? parentHash = params.get("parenthash", None) recpts = params['sendto'] # Make a corresponding message object and pass it on msg = message.RegularMessage(sendTo=recpts, messageBody=msgBody, replyToHash=parentHash) msg.recipients = recpts.split(",") DbI.addToOutbox(msg) # Save a copy of the sent message sentMessage = { "messageType": "normal", "fromId": DbI.getOwnTorid(), "messageBody": msgBody, "timestamp": msg.timestamp, "messageRead": True, "messageReplied": False, "recipients": recpts, "parentHash": parentHash } DbI.addToInbox(sentMessage) # Close window after successful send contents = self.buildPage({ 'pageTitle': I18nManager.getText("messages.title"), 'pageBody': self.closingtemplate.getHtml(), 'pageFooter': "<p>Footer</p>" }) view.setHtml(contents)