Ejemplo n.º 1
0
def check_and_demangle_item(item):
    """Return demangled item if it is a valid mangled item,
       otherwise throw an exception (not necessarily of class error.Error).
       Ensures: either an exception is thrown or ret is a dictionary
       whose keys include 'type'."""

    # note: not sure if this ough to be here...

    import crypto.RSA
    import hash
    import safe_pickle

    item_type = item['type']
    if item_type == 'identity offline demangled':
        raise error.Error('impostor')
    
    elif item_type == 'identity offline':
        demangle = safe_pickle.loads(item['package'])
        if not crypto.RSA.construct(demangle['key']).verify(
            hash.hash_of(item['package']),item['signature']):
            raise error.Error('bad signature')

        demangle['type'] = 'identity offline demangled'
        return demangle
    else:
        return item
Ejemplo n.º 2
0
    def decrypt(self, crypt):
        # Todo: catch errors
        self.lock.acquire()
        try:
            encrypted_key, encrypted_text = crypt

            key = self.key.decrypt((encrypted_key,))
            while len(key) < 16:
                key = chr(0)+key

            decryptor = crypto.rijndael.rijndael(key, 16)
            text      = decryptor.decrypt_cbc(encrypted_text)

            return safe_pickle.loads(text)
        finally:
            self.lock.release()
Ejemplo n.º 3
0
    def handle(self, request, address,call_id):
        check.check_matches(request, (types.StringType,))  #=@R34
        check.check_is_af_inet_address(address)  #=@R31
        
        self.lock.acquire()
        try:
            if request[0] == 'chat look':
                return (not self.quiet, self.activity)
            if request[0] in ['chat message 2']:
                unpacked = safe_pickle.loads(request[1])
                # TODO check unpacked against template
                # TODO don't unpack twice (here and in receive task)
                sender = unpacked['from']
                recipients = unpacked['to']
                    
                for recipient in recipients:
                    if recipient[0] == self.app.name_server.public_key_name:
                        break
                    if recipient[2][:1] == '#' and \
                         self.channels.is_listening_to(recipient[2]) and \
                         sender[0] != self.app.name_server.public_key_name:
                        break
                else:
                    return None
            
                if not self.repeated(address,call_id):
                    if self.quiet:
                        new_item = (request, address, time.time())
                        check.check_matches(new_item,
                                            unread_message_list_item_tmpl)
                        # Proof: @R34,@R31, and not having modified request or
                        # address, and the relevant types being immutable
                        # (partly by @E11).  time.time() returns float.
                        # Relevance: @R.I15.
                        self.unread_message_list.append(new_item)
                        self.set_prompt()
                        del new_item
                    else:
                        self.receive(request,address,self.quiet,time.time())
                        # Proof of @R33: @R31; deep immutability by @E11.
                        # Proof of @R35: time.time() returns float.

                return (not self.quiet, self.activity)

        finally:
            self.lock.release()
Ejemplo n.º 4
0
    def receive(self, request, address, quiet, send_time, add_to_history=1):
        """send_time should be as if from time.time() (i.e. a float expressing seconds
           since the local machine's epoch) rather than the standardized timestamps
           sent over the network (i.e. a long expressing seconds since the Unix epoch
           of 1970)."""

        # TODO: more checking of message format
        # TODO: search for people not in acq list

        check.check_is_opt_address(address)  #=@R33  fixme callers
        check.check_has_type(send_time, types.FloatType)  #=@R35  fixme callers
        # fixme: should probably require that request be a tuple with 5+ elems.

        if 1:
            if not self.is_visible():
                self.n_unseen_messages = self.n_unseen_messages + 1
                if self.n_unseen_messages == 1:
                    title = _('1 unseen message')
                else:
                    title = _('%d unseen messages') % self.n_unseen_messages
                self.app.set_title(title)

            if request[0] == 'chat message 2':
                package = safe_pickle.loads(request[1])
                text = package['text']
                augmentation = package.get('aug')
                has_attachment = package.has_key('attach')
                attachment = package.get('attach')
                sender_key_name, sender_name = package['from']
                recipients = package['to']

                verify_text = request[1]
                verify_sig = request[2]

            else:
                # Legacy message format
                text = request[3]
                augmentation = None
                has_attachment = (len(request) == 6)
                if has_attachment:
                    attachment = safe_pickle.loads(request[4])

                recipients = request[2]

                if type(request[1]) == type(()):
                    sender_key_name = request[1][0]
                    sender_name = request[1][1]
                else:
                    # Used not to send username with key name
                    sender_key_name = request[1]
                    sender_name = 'unknown'

                if has_attachment:
                    verify_text = request[3].encode('utf8')+request[4]
                    verify_sig = request[5]
                else:
                    verify_text = request[3]
                    verify_sig = request[4]

            if not augmentation:
                augmentation = chr(128) * len(text)


            self.show_received_message(sender_name,sender_key_name,address,recipients,
                                       text,verify_text,verify_sig,quiet,
                                       send_time,augmentation,has_attachment,attachment)

        #except error.Error:
        #    self.show(_('Bad message received from ') + repr(address) + '\n')

        if add_to_history:
            self.lock.acquire()
            try:
                new_item = (request, send_time)
                check.check_matches(new_item, incoming_message_history_item_tmpl)
                # Proof: @R35, immutability of float, send_time not reassigned
                # in this function.
                # Relevance: @I16.
                self.incoming_message_history.append(new_item)

                while len(self.incoming_message_history) > settings.incoming_message_history_size:
                    del self.incoming_message_history[0]
            finally:
                self.lock.release()
Ejemplo n.º 5
0
        def gossip_fetch_thread(self,acq):
            self.fetch_threads+=1
            
            if not self.running:
                self.fetch_threads-=1
                return

            if acq.distance != None:
                #acq.start_watching(self.node, 1)
                
                acq.lock.acquire()
                online = acq.online
                address = acq.address
                distance = acq.distance
                acq.lock.release()

                if distance == None or not online:
                    self.fetch_threads-=1
                    return

                pos = 0
                fetch_timeout = node.make_timeout(settings.gossip_fetch_time) 
                while not node.is_timed_out(fetch_timeout):
                    try:
                        ticket, template, wait = self.node.call(address,('gossip list',pos,pos+20))
                        if wait: yield 'call',(self.node,ticket)
                        result = self.node.get_reply(ticket,template)
                        
                        if not check.matches(result,
                                             [(types.IntType, 'any', 'any')]):
                            node.bad_peer(address,
                                     _("Bad reply to 'gossip list': ") + `result`)
                            break
                        if len(result) == 0:
                            break

                        all_ok = 1
                        # effic: sort self.gossip, sort the returned results,
                        # to speed up searches for signatures.  However, I
                        # haven't yet seen gossip_fetch_task come up in
                        # profiles.
                        for item in result:
                            already_there = 0

                            for wodge in self.gossip:
                                if wodge.signature == item[2]:
                                    #if wodge.distance(self.app.name_server) > from_fixed(item[0])+distance:
                                    #  # TODO: What to do with unit_decay_time?
                                    #  wodge.initial_distance = from_fixed(item[0])+distance
                                    #  wodge.initial_time     = time.time()
                                    wodge.opinions[acq.name] = from_fixed(item[0]) - wodge.decay()
                                    already_there = 1
                                    break

                            if already_there:
                                continue

                            try:
                                ticket, template, wait = self.node.call(
                                    address,('gossip get',item[2]))
                                if wait: yield 'call',(self.node,ticket)
                                string = self.node.get_reply(ticket, template)
                                wodgewodge = safe_pickle.loads(string)
                            except error.Error:
                                all_ok = 0
                                break

                            #TODO: Confirm signature of known people

                            wodge = Wodge({
                                'wodge': wodgewodge,
                                'string': string,
                                'signature': item[2],
                                'initial_time': time.time(),
                                'initial_distance': None,
                                #'initial_distance': from_fixed(item[0]) + distance
                                'unit_decay_time': item[1],
                                'opinions': { acq.name : from_fixed(item[0]) },
                                'collapsed': 0})

                            if not self.insert_wodge(wodge):
                                all_ok = 0
                                break

                        if not all_ok:
                            break
                        
                        pos = pos + 18
                    except error.Error:
                        break
            self.fetch_threads-=1