Ejemplo n.º 1
0
 def broadcastOnlineStatus(self):
     '''Queue a status notification message for each of our trusted contacts'''
     print("Outgoing postman is broadcasting the status...")
     self._broadcasting = True
     profileList = DbI.getTrustedProfiles()
     if profileList:
         msg = StatusNotifyMessage(online=True, ping=True, profileHash=None)
         msg.recipients = [c['torid'] for c in profileList]
         DbI.addToOutbox(msg)
     self._broadcasting = False
     self.flushSignal.emit()
Ejemplo n.º 2
0
 def sendReferRequestMessage(sendToId, requestedId, intro):
     '''Send a message to sendToId, to ask that they recommend you to requestedId'''
     sendToProfile = DbI.getProfile(sendToId)
     if sendToProfile and sendToProfile.get("status", "nostatus") == "trusted" \
       and requestedId != DbI.getOwnTorid():
         print("Send message to", sendToId, "requesting referral of",
               requestedId)
         notify = ContactReferRequestMessage(friendId=requestedId,
                                             introMessage=intro)
         notify.recipients = [sendToId]
         DbI.addToOutbox(notify)
Ejemplo n.º 3
0
 def keyFingerprintChecked(torId):
     '''The fingerprint of this contact's public key has been checked (over a separate channel)'''
     # Check that userid exists and that status is currently "untrusted" (trusted also doesn't hurt)
     profile = DbI.getProfile(torId)
     if profile and profile["status"] in ["untrusted", "trusted"]:
         # Update the user's status to trusted
         DbI.updateProfile(torId, {"status": "trusted"})
         # Trigger a StatusNotify to tell them we're online
         notify = StatusNotifyMessage(online=True,
                                      ping=True,
                                      profileHash=None)
         notify.recipients = [torId]
         DbI.addToOutbox(notify)
Ejemplo n.º 4
0
 def sendReferralMessages(friendId1, friendId2, intro):
     '''Send messages to both friendId1 and friendId2, to recommend they become friends with each other'''
     friend1Profile = DbI.getProfile(friendId1)
     friend2Profile = DbI.getProfile(friendId2)
     if friend1Profile and friend1Profile.get("status", "nostatus") == "trusted" \
       and friend2Profile and friend2Profile.get("status", "nostatus") == "trusted":
         print("Send message to", friendId1, "referring the details of",
               friendId2)
         notify = ContactReferralMessage(friendId=friendId2,
                                         friendName=None,
                                         introMessage=intro)
         notify.recipients = [friendId1]
         DbI.addToOutbox(notify)
         print("Send message to", friendId2, "referring the details of",
               friendId1)
         notify = ContactReferralMessage(friendId=friendId1,
                                         friendName=None,
                                         introMessage=intro)
         notify.recipients = [friendId2]
         DbI.addToOutbox(notify)
Ejemplo n.º 5
0
	def testOutbox(self):
		'''Test the storage and retrieval of messages in the outbox'''
		db = supersimpledb.MurmeliDb()
		DbI.setDb(db)
		self.assertEqual(len(DbI.getOutboxMessages()), 0, "Outbox should be empty")
		# Add profile for this the target recipient
		DbI.updateProfile("ABC312", {"keyid":"ZYXW987", "status":"trusted", "name":"Best friend"})

		# add one message to the outbox
		DbI.addToOutbox(ExampleMessage(["ABC312"], "Doesn't matter really what the message is"))
		self.assertEqual(len(DbI.getOutboxMessages()), 1, "Outbox should have one message")
		self.checkMessageIndexes(DbI.getOutboxMessages())
		DbI.addToOutbox(ExampleMessage(["ABC312"], "A second message"))
		self.assertEqual(len(DbI.getOutboxMessages()), 2, "Outbox should have 2 messages")
		self.checkMessageIndexes(DbI.getOutboxMessages())
		self.assertTrue(DbI.deleteFromOutbox(0))
		self.assertEqual(len(DbI.getOutboxMessages()), 1, "Outbox should only have 1 message (1 empty)")
		nonEmptyMessages = DbI.getOutboxMessages()
		self.assertEqual(len(nonEmptyMessages), 1, "Outbox should only have 1 non-empty message")
		self.assertEqual(nonEmptyMessages[0]["_id"], 1, "Message 0 should have index 1")
		# See if index of third message is properly assigned
		DbI.addToOutbox(ExampleMessage(["ABC312"], "A third message"))
		self.assertEqual(len(DbI.getOutboxMessages()), 2, "Outbox should have 2 messages again")
		self.assertEqual(DbI.getOutboxMessages()[0]["_id"], 1, "Message 0 should have index 1")
		self.assertEqual(DbI.getOutboxMessages()[1]["_id"], 2, "Message 1 should have index 2")

		# done
		DbI.releaseDb()
Ejemplo n.º 6
0
 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)
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
    def servePage(self, view, url, params):
        self.requirePageResources(
            ['button-compose.png', 'default.css', 'jquery-3.1.1.js'])
        DbI.exportAllAvatars(Config.getWebCacheDir())

        messageList = None
        if url == "/send":
            print("send message of type '%(messageType)s' to id '%(sendTo)s'" %
                  params)
            if params['messageType'] == "contactresponse":
                torId = params['sendTo']
                if params.get("accept", "0") == "1":
                    ContactMaker.handleAccept(torId)
                    # Make sure this new contact has an empty avatar
                    DbI.exportAllAvatars(Config.getWebCacheDir())
                    outmsg = message.ContactResponseMessage(
                        message=params['messageBody'])
                else:
                    ContactMaker.handleDeny(torId)
                    outmsg = message.ContactDenyMessage()
                # Construct a ContactResponse message object for sending
                outmsg.recipients = [params['sendTo']]
                DbI.addToOutbox(outmsg)
        elif url.startswith("/delete/"):
            DbI.deleteFromInbox(params.get("msgId", ""))
        elif url in ["/search", "/search/"]:
            messageList = DbI.searchInboxMessages(params.get("searchTerm"))

        # Make dictionary to convert ids to names
        contactNames = {
            c['torid']: c['displayName']
            for c in DbI.getProfiles()
        }
        unknownSender = I18nManager.getText("messages.sender.unknown")
        unknownRecpt = I18nManager.getText("messages.recpt.unknown")
        # Get contact requests, responses and mails from inbox
        conreqs = []
        conresps = []
        mailTree = MessageTree()
        if messageList is None:
            messageList = DbI.getInboxMessages()
        # TODO: Paging options?
        for m in messageList:
            if not m:
                continue
            m['msgId'] = str(m.get("_id", ""))
            if m['messageType'] == "contactrequest":
                conreqs.append(m)
            elif m['messageType'] == "contactrefer":
                senderId = m.get('fromId', None)
                m['senderName'] = contactNames.get(senderId, unknownSender)
                conreqs.append(m)
            elif m['messageType'] == "contactresponse":
                if not m.get('accepted', False):
                    m['messageBody'] = I18nManager.getText(
                        "messages.contactrequest.refused")
                    m['fromName'] = DbI.getProfile(m['fromId'])["displayName"]
                elif not m.get('messageBody', False):
                    m['messageBody'] = I18nManager.getText(
                        "messages.contactrequest.accepted")
                conresps.append(m)
            else:
                senderId = m.get('fromId', None)
                if not senderId and m.get('signatureKeyId', None):
                    senderId = DbI.findUserIdFromKeyId(m['signatureKeyId'])
                m['senderName'] = contactNames.get(senderId, unknownSender)
                m['sentTimeStr'] = self.makeLocalTimeString(m['timestamp'])
                # Split m['recipients'] by commas, and look up each id with contactNames
                recpts = m.get('recipients', '')
                if recpts:
                    replyAll = recpts.split(",")
                    m['recipients'] = ", ".join(
                        [contactNames.get(i, unknownRecpt) for i in replyAll])
                    replyAll.append(senderId)
                    m['replyAll'] = ",".join(replyAll)
                else:
                    m['recipients'] = unknownRecpt
                    m['replyAll'] = ""
                mailTree.addMsg(m)
        mails = mailTree.build()
        bodytext = self.messagestemplate.getHtml({
            "contactrequests":
            conreqs,
            "contactresponses":
            conresps,
            "mails":
            mails,
            "nummessages":
            len(conreqs) + len(conresps) + len(mails),
            "webcachedir":
            Config.getWebCacheDir()
        })
        contents = self.buildPage({
            'pageTitle':
            I18nManager.getText("messages.title"),
            'pageBody':
            bodytext,
            'pageFooter':
            "<p>Footer</p>"
        })
        view.setHtml(contents)
Ejemplo n.º 9
0
    def servePage(self, view, url, params):
        self.requirePageResources([
            'button-addperson.png', 'button-drawgraph.png', 'avatar-none.jpg'
        ])
        DbI.exportAllAvatars(Config.getWebCacheDir())
        if url == "/add" or url == "/add/":
            contents = self.generateAddPage()
            view.setHtml(contents)
            return
        elif url == "/submitaddrequest":
            print("Submit add request!:", url)
            if len(params) > 0:
                # request to add a new friend
                recipientid = params.get('murmeliid', '')
                dispname = params.get('displayname', '')
                intromessage = params.get('intromessage', '')
                if len(recipientid) == 16:
                    # TODO: How to react if: person already added (untrusted/trusted); request already sent (requested)
                    # update the database accordingly
                    ContactMaker.handleInitiate(recipientid, dispname)
                    print("I should send an add request to '%s' now." %
                          recipientid)
                    outmsg = message.ContactRequestMessage(
                        introMessage=intromessage)
                    outmsg.recipients = [recipientid]
                    DbI.addToOutbox(outmsg)
                else:
                    print("Hmm, show an error message here?")
                # in any case, go back to contact list
                url = "/" + recipientid
                # ensure that picture is generated for new id
                DbI.exportAllAvatars(Config.getWebCacheDir())
        contents = None
        userid = None
        pageParams = {}
        # Split url into components /userid/command
        command = [i for i in url.split("/") if i != ""]
        if len(command) > 0 and len(command[0]) == 16 and re.match(
                "([a-zA-Z0-9]+)$", command[0]):
            userid = command[0]
            # check for command edit or submit-edit
            if len(command) == 2:
                if command[1] == "edit":
                    contents = self.generateListPage(
                        doEdit=True, userid=userid)  # show edit fields
                elif command[1] == "submitedit":
                    DbI.updateProfile(userid, params, Config.getWebCacheDir())
                    # TODO: If we've updated our own details, can we trigger a broadcast?
                    # don't generate contents, go back to details
                elif command[1] == "delete":
                    ContactMaker.handleDeleteContact(userid)
                    userid = None
                elif command[1] == "checkfingerprint":
                    contents = self.generateFingerprintsPage(userid)
                elif command[1] == "checkedfingerprint":
                    givenAnswer = int(params.get('answer', -1))
                    fc = self._makeFingerprintChecker(userid)
                    expectedAnswer = fc.getCorrectAnswer()
                    if expectedAnswer == givenAnswer:
                        ContactMaker.keyFingerprintChecked(userid)
                        # Show page again
                        contents = self.generateFingerprintsPage(userid)
                    else:
                        # Add a message to show when the list page is re-generated
                        pageParams['fingerprint_check_failed'] = True
            elif len(command) == 3 and command[1] == "refer" and len(
                    command[2]) == 16:
                intro = str(params.get('introMessage', ""))
                ContactMaker.sendReferralMessages(command[0], command[2],
                                                  intro)
                pageParams['message_sent'] = True
                # go back to details page
            elif len(command) == 3 and command[1] == "requestrefer" and len(
                    command[2]) == 16:
                intro = str(params.get('introMessage', ""))
                ContactMaker.sendReferRequestMessage(command[0], command[2],
                                                     intro)
                pageParams['message_sent'] = True
                # go back to details page

        # If we haven't got any contents yet, then do a show details
        if not contents:
            # Show details for selected userid (or for self if userid is None)
            contents = self.generateListPage(doEdit=False,
                                             userid=userid,
                                             extraParams=pageParams)

        view.setHtml(contents)