Beispiel #1
0
 def sendMessage(self, message, whoto):
     # Check status of recipient in profile
     profile = DbI.getProfile(whoto)
     status = profile['status'] if profile else "deleted"
     if status in ['deleted', 'blocked']:
         return self.RC_MESSAGE_IGNORED
     print("Trying to send message to '%s'" % whoto)
     if whoto is not None and len(whoto) == 16:
         try:
             s = socks.socksocket()
             s.setproxy(socks.PROXY_TYPE_SOCKS4, "localhost", 11109)
             s.connect((whoto + ".onion", 11009))
             numsent = s.send(message)
             s.close()
             if numsent != len(message):
                 print("Oops - num bytes sent:", numsent,
                       "but message has length:", len(message))
                 # For really long messages, maybe need to chunk into 4k blocks or something?
             else:
                 Contacts.instance().comeOnline(whoto)
                 return self.RC_MESSAGE_SENT
         except Exception as e:
             print("Woah, that threw something:", e)
     print("Bailed from the send attempt, returning failure")
     return self.RC_MESSAGE_FAILED  # it didn't work
Beispiel #2
0
 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)
Beispiel #3
0
 def _createSubpayload(self):
     '''Use the stored fields to pack the payload contents together'''
     if self.profileHash is None or self.profileHash == "":
         self.profileHash = dbutils.calculateHash(DbI.getProfile())
     return self.packBytesTogether([
         self.encodeNumberToBytes(1 if self.online else 0, 1),
         self.encodeNumberToBytes(1 if self.ping else 0, 1),
         self.profileHash
     ])
Beispiel #4
0
 def testProfileResponse(self):
     m = message.InfoResponseMessage(
         message.InfoRequestMessage.INFO_PROFILE)
     output = m.createUnencryptedOutput()
     bac = message.Message.MessageFromReceivedData(output, False)
     self.assertIsNotNone(bac, "couldn't decode the data")
     self.assertEqual(message.InfoRequestMessage.INFO_PROFILE, bac.infoType)
     mydescription = DbI.getProfile()['description']
     bacProfile = bac.profile
     self.assertEqual(mydescription, bacProfile['description'])
Beispiel #5
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)
Beispiel #6
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)
Beispiel #7
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)
Beispiel #8
0
 def _createSubpayload(self):
     '''Pack the specific fields into the subpayload'''
     # Get own name
     if self.senderName is None:
         self.senderName = DbI.getProfile().get('name', self.senderId)
     myPublicKey = self.getOwnPublicKey()
     messageAsBytes = self.message.encode('utf-8')
     nameAsBytes = self.senderName.encode('utf-8')
     subpayload = Message.packBytesTogether([
         self.encodeNumberToBytes(len(nameAsBytes), 4), nameAsBytes,
         self.encodeNumberToBytes(len(messageAsBytes), 4), messageAsBytes,
         myPublicKey
     ])
     return subpayload
Beispiel #9
0
 def _createSubpayload(self):
     '''Use the stored fields to pack the payload contents together'''
     ownProfile = DbI.getProfile()
     if self.infoType is None:
         self.infoType = InfoRequestMessage.INFO_PROFILE
     if self.profileString is None:
         self.profileString = dbutils.getProfileAsString(ownProfile)
     self.profileHash = dbutils.calculateHash(ownProfile)
     return self.packBytesTogether([
         self.encodeNumberToBytes(self.infoType),
         self.encodeNumberToBytes(len(self.profileString),
                                  4), self.profileString,
         self.encodeNumberToBytes(len(self.profileHash), 4),
         self.profileHash
     ])
Beispiel #10
0
    def getSharedAndPossibleContacts(torid):
        '''Check which contacts we share with the given torid and which ones we could recommend to each other'''
        nameMap = {}
        ourContactIds = set()
        trustedContactIds = set()
        theirContactIds = set()
        # Get our id so we can exclude it from the sets
        myTorId = DbI.getOwnTorid()
        if torid == myTorId:
            return (None, None, None, None)
        # Find the contacts of the specified person
        selectedProfile = DbI.getProfile(torid)
        selectedContacts = selectedProfile.get(
            'contactlist', None) if selectedProfile else None
        if selectedContacts:
            for s in selectedContacts.split(","):
                if s and len(s) >= 16:
                    foundid = s[0:16]
                    if foundid != myTorId:
                        foundName = s[16:]
                        theirContactIds.add(foundid)
                        nameMap[foundid] = foundName
        foundTheirContacts = len(theirContactIds) > 0
        # Now get information about our contacts
        for c in DbI.getMessageableProfiles():
            foundid = c['torid']
            ourContactIds.add(foundid)
            if c['status'] == 'trusted' and foundid != torid:
                trustedContactIds.add(foundid)
            nameMap[foundid] = c['displayName']
            # Should we check the contact information too?
            if not foundTheirContacts:
                foundContacts = c.get('contactlist', None)
                if foundContacts:
                    for s in foundContacts.split(","):
                        if s[0:16] == torid:
                            theirContactIds.add(foundid)
        # Now we have three sets of torids: our contacts, our trusted contacts, and their contacts.
        sharedContactIds = ourContactIds.intersection(
            theirContactIds)  # might be empty
        suggestionsForThem = trustedContactIds.difference(theirContactIds)
        possibleForMe = theirContactIds.difference(ourContactIds)
        # TODO: Maybe subtract requested contacts from the "possibleForMe" set?

        # Some or all of these sets may be empty, but we still return the map so we can look up names
        return (sharedContactIds, suggestionsForThem, possibleForMe, nameMap)
Beispiel #11
0
 def _createSubpayload(self):
     '''Pack the specific fields into the subpayload'''
     # Get own name
     if not self.friendName:
         self.friendName = DbI.getProfile(self.friendId).get(
             'name', self.friendId)
     publicKey = self.getPublicKey(torid=self.friendId)
     # TODO: Complain if publicKey is empty
     messageAsBytes = self.message.encode('utf-8')
     nameAsBytes = self.friendName.encode('utf-8')
     subpayload = Message.packBytesTogether([
         self.friendId,
         self.encodeNumberToBytes(len(nameAsBytes), 4), nameAsBytes,
         self.encodeNumberToBytes(len(messageAsBytes), 4), messageAsBytes,
         publicKey
     ])
     return subpayload
Beispiel #12
0
 def _createSubpayload(self):
     '''Use the stored fields to pack the payload contents together'''
     if self.senderKey is None: self.senderKey = self.getOwnPublicKey()
     # Get own torid and name
     if not self.senderId: self.senderId = DbI.getOwnTorid()
     if not self.senderName:
         self.senderName = DbI.getProfile().get('name', self.senderId)
     if not self.introMessage: self.introMessage = ""
     nameAsBytes = self.senderName.encode('utf-8')
     messageAsBytes = self.introMessage.encode('utf-8')
     print("Packing contact request with senderId", self.senderId)
     return self.packBytesTogether([
         self.senderId,
         self.encodeNumberToBytes(len(nameAsBytes), 4), nameAsBytes,
         self.encodeNumberToBytes(len(messageAsBytes), 4), messageAsBytes,
         self.senderKey
     ])
Beispiel #13
0
 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)
Beispiel #14
0
    def dealWithMessage(message):
        '''Examine the received message and decide what to do with it'''
        print("Hmm, the MessageShuffler has been given some kind of message")
        # We must be online if we've received a message
        Contacts.instance().comeOnline(DbI.getOwnTorid())

        if message.senderMustBeTrusted:
            sender = DbI.getProfile(message.senderId)
            if not sender or sender['status'] != "trusted":
                return  # throw message away

        if not message.isComplete():
            print("A message of type", message.encryptionType,
                  "was received but it's not complete - throwing away")
            return  # throw message away

        # if it's not encrypted, it's for us -> save in inbox
        if message.encryptionType == Message.ENCTYPE_NONE:
            MessageShuffler.dealWithUnencryptedMessage(message)

        elif message.encryptionType == Message.ENCTYPE_SYMM:
            # if it's symmetric, forget it for now
            pass

        elif message.encryptionType == Message.ENCTYPE_ASYM:
            MessageShuffler.dealWithAsymmetricMessage(message)

        elif message.encryptionType == Message.ENCTYPE_RELAY:
            # Get received bytes of message, and add to Outbox, send to everybody EXCEPT the sender
            bytesToSend = message.createOutput(None)
            if bytesToSend:
                # add to outbox, but don't send it back to message.senderId
                DbI.addRelayMessageToOutbox(bytesToSend, message.senderId)
        else:
            print("Hä?  What kind of encryption type is that? ",
                  message.encryptionType)

        # Log receipt of message (do we want to know about relays at all?)
        if message.encryptionType in [
                Message.ENCTYPE_NONE, Message.ENCTYPE_ASYM
        ]:
            logMessage = "Message of type: %s received from %s" % (
                message.getMessageTypeKey(), message.senderId)
            MessageShuffler.getTannoy().shout(logMessage)
Beispiel #15
0
    def generateFingerprintsPage(self, userid):
        '''Build the page for checking the fingerprints of the selected user'''
        # First, get the name of the user
        person = DbI.getProfile(userid)
        dispName = person['displayName']
        fullName = person['name']
        if dispName != fullName:
            fullName = dispName + " (" + fullName + ")"
        fc = self._makeFingerprintChecker(userid)
        # check it's ok to generate
        status = person.get('status', '')
        if not fc.valid \
          or status not in ['untrusted', 'trusted']:
            print("Not generating fingerprints page because status is", status)
            return None

        # Get one set of words for us and three sets for them
        printsAlreadyChecked = (person.get('status', '') == "trusted")
        bodytext = self.fingerprintstemplate.getHtml({
            "mywords":
            fc.getCodeWords(True, 0, "en"),
            "theirwords0":
            fc.getCodeWords(False, 0, "en"),
            "theirwords1":
            fc.getCodeWords(False, 1, "en"),
            "theirwords2":
            fc.getCodeWords(False, 2, "en"),
            "fullname":
            fullName,
            "shortname":
            dispName,
            "userid":
            userid,
            "alreadychecked":
            printsAlreadyChecked
        })
        return self.buildPage({
            'pageTitle':
            I18nManager.getText("contacts.title"),
            'pageBody':
            bodytext,
            'pageFooter':
            "<p>Footer</p>"
        })
Beispiel #16
0
    def handleAccept(torId):
        '''We want to accept a contact request, so we need to find the request(s),
		and use it/them to update our keyring and our database entry'''

        # Get this person's current status from the db, if available
        profile = DbI.getProfile(torId)
        status = profile.get("status", None) if profile else None

        # Look for the contact request(s) in the inbox, and extract the name and publicKey
        senderName, senderKeystr, directRequest = ContactMaker.getContactRequestDetails(
            torId)
        keyValid = senderKeystr and len(senderKeystr) > 20

        if keyValid:
            if status in [None, "requested"]:
                # add key to keyring
                keyId = CryptoClient.importPublicKey(senderKeystr)
                # work out what name and status to stores
                storedSenderName = profile["name"] if profile else None
                nameToStore = storedSenderName if storedSenderName else senderName
                statusToStore = "untrusted" if directRequest else "pending"
                # add or update the profile
                DbI.updateProfile(
                    torId, {
                        "status": statusToStore,
                        "keyid": keyId,
                        "name": nameToStore,
                        "displayName": nameToStore
                    })
                ContactMaker.processPendingContacts(torId)
            elif status == "pending":
                print("Request already pending, nothing to do")
            elif status in ["untrusted", "trusted"]:
                # set status to untrusted?  Send response?
                print("Trying to handle an accept but status is already",
                      status)
            # Move all corresponding requests to be regular messages instead
            DbI.changeRequestMessagesToRegular(torId)
        else:
            print("Trying to handle an accept but key isn't valid")
Beispiel #17
0
 def _isProfileStatusOk(torId, allowedStatuses):
     profile = DbI.getProfile(torId)
     status = profile.get("status", None) if profile else None
     return status in allowedStatuses
Beispiel #18
0
    def servePage(self, view, url, params):
        print("Special function:", url)
        if url == "/selectprofilepic":
            # Get home directory for file dialog
            homedir = os.path.expanduser("~/")
            fname = QFileDialog.getOpenFileName(
                view,
                I18nManager.getText("gui.dialogtitle.openimage"), homedir,
                I18nManager.getText("gui.fileselection.filetypes.jpg"))
            if fname:
                view.page().mainFrame().evaluateJavaScript(
                    "updateProfilePic('" + fname + "');")
        elif url == "/friendstorm":
            if not DbI.hasFriends():
                view.page().mainFrame().evaluateJavaScript(
                    "window.alert('No friends :(');")
                return
            # Launch a storm
            self.bs = Brainstorm(I18nManager.getText("contacts.storm.title"))
            self.bs.show()
            storm = Storm()
            # Build up Nodes and Edges using our contact list and if possible our friends' contact lists
            myTorId = DbI.getOwnTorid()
            friends = {}
            friendsOfFriends = {}
            for c in DbI.getMessageableProfiles():
                # print("Contact: id:'%s' name:'%s'" % (c['torid'], c['displayName']))
                nodeid = storm.getUnusedNodeId()
                torid = c['torid']
                friends[torid] = nodeid
                storm.addNode(Node(None, nodeid, c['displayName']))
                friendsOfFriends[torid] = c.get('contactlist', "")
            # Also add ourselves
            c = DbI.getProfile()
            nodeid = storm.getUnusedNodeId()
            friends[c['torid']] = nodeid
            storm.addNode(Node(None, nodeid, c['displayName']))
            # Add edges
            for torid in friends:
                if torid != myTorId:
                    storm.addEdge(friends[torid], friends[myTorId])
            for torid in friendsOfFriends:
                if torid != myTorId:
                    ffList = friendsOfFriends[torid]
                    if ffList:
                        for ff in ffList.split(","):
                            if ff and len(ff) > 16:
                                ffTorid = ff[:16]
                                ffName = ff[16:]
                                if ffTorid != myTorId:
                                    if not friends.get(ffTorid, None):
                                        # Friend's friend is not in the list yet - add it
                                        nodeid = storm.getUnusedNodeId()
                                        friends[ffTorid] = nodeid
                                        storm.addNode(
                                            Node(None, nodeid, ffName))
                                    # Add edge from torid to ffTorid
                                    storm.addEdge(friends[torid],
                                                  friends[ffTorid])

            self.bs.setStorm(storm)
Beispiel #19
0
    def generateListPage(self, doEdit=False, userid=None, extraParams=None):
        self.requirePageResources([
            'avatar-none.jpg', 'status-self.png', 'status-requested.png',
            'status-untrusted.png', 'status-trusted.png', 'status-pending.png'
        ])
        # List of contacts, and show details for the selected one (or self if userid=None)
        selectedprofile = DbI.getProfile(userid)
        if not selectedprofile:
            selectedprofile = DbI.getProfile()
        userid = selectedprofile['torid']
        ownPage = userid == DbI.getOwnTorid()

        # Build list of contacts
        userboxes = []
        currTime = datetime.datetime.now()
        for p in DbI.getProfiles():
            box = Bean()
            box.dispName = p['displayName']
            box.torid = p['torid']
            box.tilestyle = "contacttile" + ("selected"
                                             if p['torid'] == userid else "")
            box.status = p['status']
            isonline = Contacts.instance().isOnline(box.torid)
            lastSeen = Contacts.instance().lastSeen(box.torid)
            lastSeenTime = str(lastSeen.timetz())[:5] if lastSeen and (
                currTime - lastSeen).total_seconds() < 18000 else None
            if lastSeenTime:
                box.lastSeen = I18nManager.getText(
                    "contacts.onlinesince"
                    if isonline else "contacts.offlinesince") % lastSeenTime
            elif isonline:
                box.lastSeen = I18nManager.getText("contacts.online")
            else:
                box.lastSeen = None
            userboxes.append(box)

        # expand templates using current details
        lefttext = self.listtemplate.getHtml({
            'webcachedir':
            Config.getWebCacheDir(),
            'contacts':
            userboxes
        })
        pageProps = {
            "webcachedir": Config.getWebCacheDir(),
            'person': selectedprofile
        }
        # Add extra parameters if necessary
        if extraParams:
            pageProps.update(extraParams)

        # See which contacts we have in common with this person
        (sharedContactIds, possIdsForThem, possIdsForMe,
         nameMap) = ContactMaker.getSharedAndPossibleContacts(userid)
        sharedContacts = self._makeIdAndNameBeanList(sharedContactIds, nameMap)
        pageProps.update({"sharedcontacts": sharedContacts})
        possibleContacts = self._makeIdAndNameBeanList(possIdsForThem, nameMap)
        pageProps.update({"possiblecontactsforthem": possibleContacts})
        possibleContacts = self._makeIdAndNameBeanList(possIdsForMe, nameMap)
        pageProps.update({"possiblecontactsforme": possibleContacts})

        # Which template to use depends on whether we're just showing or also editing
        if doEdit:
            # Use two different details templates, one for self and one for others
            detailstemplate = self.editowndetailstemplate if ownPage else self.editdetailstemplate
            righttext = detailstemplate.getHtml(pageProps)
        else:
            detailstemplate = self.detailstemplate  # just show
            righttext = detailstemplate.getHtml(pageProps)

        contents = self.buildTwoColumnPage({
            'pageTitle':
            I18nManager.getText("contacts.title"),
            'leftColumn':
            lefttext,
            'rightColumn':
            righttext,
            'pageFooter':
            "<p>Footer</p>"
        })
        return contents
Beispiel #20
0
 def getPublicKey(self, torid):
     '''Use the keyid stored in the db, and get the corresponding public key from the Crypto module'''
     profile = DbI.getProfile(torid)
     keyid = profile.get('keyid', None) if profile else None
     if keyid:
         return CryptoClient.getPublicKey(keyid)
Beispiel #21
0
 def _makeFingerprintChecker(self, userid):
     '''Use the given userid to make a FingerprintChecker between me and them'''
     person = DbI.getProfile(userid)
     ownFingerprint = CryptoClient.getFingerprint(DbI.getOwnKeyid())
     usrFingerprint = CryptoClient.getFingerprint(person['keyid'])
     return FingerprintChecker(ownFingerprint, usrFingerprint)
Beispiel #22
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)
Beispiel #23
0
except ImportError:
    canStartMurmeli = False

# if it all looks ok so far, we need to check the database
db = None
dbFilePath = Config.getSsDatabaseFile()
if not os.path.exists(dbFilePath):
    canStartMurmeli = False

if canStartMurmeli:
    print("I think I can start Murmeli, checking database status")
    db = MurmeliDb(dbFilePath)
    DbI.setDb(db)

    try:
        ownprofile = DbI.getProfile()
        if ownprofile is None or ownprofile.get("keyid", None) is None:
            print(
                "I didn't get a profile or didn't get a key, so I can't start Murmeli"
            )
            canStartMurmeli = False
        else:
            print("I think I got a profile and a keyid: '",
                  ownprofile.get("keyid", ""),
                  "' so I'm going to start Murmeli")
    except Exception as e:
        print(
            "Exception thrown trying to get profile, so I can't start Murmeli:",
            e)
        canStartMurmeli = False  # maybe authentication failed?
Beispiel #24
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)