def update_conversation(sender_local_key_id, recipient_local_key_id, payload_type, payload_time, payload_message_id): conversation_id = get_conversation_id(sender_local_key_id, recipient_local_key_id, payload_type) if conversation_id is None: lg.err('failed to update conversation, local_key_id was not found') return None sql = 'SELECT * FROM conversations WHERE conversation_id=?' params = [conversation_id, ] found_conversation = list(cur().execute(sql, params)) if found_conversation: sql = 'UPDATE conversations SET last_updated_time=?, last_message_id=? WHERE conversation_id=?' params = [payload_time, payload_message_id, conversation_id, ] else: sql = 'INSERT INTO conversations (conversation_id, payload_type, started_time, last_updated_time, last_message_id) VALUES (?, ?, ?, ?, ?)' params = [conversation_id, payload_type, payload_time, payload_time, payload_message_id, ] if _Debug: lg.args(_DebugLevel, conversation_id=conversation_id, found_conversation=len(found_conversation), params=params) cur().execute(sql, params) db().commit() if not found_conversation: listeners.push_snapshot('conversation', snap_id=conversation_id, data=build_json_conversation( conversation_id=conversation_id, type=MESSAGE_TYPE_CODES.get(int(payload_type), 'private_message'), started=payload_time, last_updated=payload_time, last_message_id=payload_message_id, )) return conversation_id
def populate_messages(recipient_id=None, sender_id=None, message_types=[], offset=0, limit=100): if recipient_id: if not recipient_id.count('@'): from contacts import contactsdb recipient_idurl = contactsdb.find_correspondent_by_nickname( recipient_id) if not recipient_idurl: lg.err('recipient %r was not found' % recipient_id) return recipient_id = global_id.UrlToGlobalID(recipient_idurl) recipient_glob_id = global_id.ParseGlobalID(recipient_id) if not recipient_glob_id['idurl']: lg.err('wrong recipient_id') return recipient_id = global_id.MakeGlobalID(**recipient_glob_id) if not my_keys.is_valid_key_id(recipient_id): lg.err('invalid recipient_id: %s' % recipient_id) return if sender_id: sender_local_key_id = my_keys.get_local_key_id(sender_id) if sender_local_key_id is None: return if recipient_id: recipient_local_key_id = my_keys.get_local_key_id(recipient_id) if recipient_local_key_id is None: lg.warn('recipient %r local key id was not registered' % recipient_id) return for row in query_messages( sender_id=sender_id, recipient_id=recipient_id, bidirectional=False, message_types=message_types, offset=offset, limit=limit, raw_results=True, ): conversation_id = get_conversation_id(row[0], row[2], int(row[5])) if conversation_id is None: continue snap_id = '{}/{}'.format(conversation_id, row[7]) listeners.push_snapshot('message', snap_id=snap_id, created=row[6], data=build_json_message( sender=row[1], recipient=row[3], direction='in' if row[4] == 0 else 'out', conversation_id=conversation_id, message_type=MESSAGE_TYPE_CODES.get( int(row[5]), 'private_message'), message_time=row[6], message_id=row[7], data=json.loads(row[8]), ))
def load_key(key_id, keys_folder=None): global _LatestLocalKeyID if not is_valid_key_id(key_id): lg.warn('key is not valid: %r' % key_id) return False key_dict = read_key_file(key_id, keys_folder=keys_folder) try: key_object = rsa_key.RSAKey() key_object.fromDict(key_dict) except: lg.exc() return False if not key_object.isPublic(): if not validate_key(key_object): lg.warn('validation failed for: %r' % key_id) return False known_keys()[key_id] = key_object if key_dict.get('need_to_convert'): save_key(key_id, keys_folder=keys_folder) lg.info('key %r format converted to JSON' % key_id) else: if key_object.local_key_id is not None: if _LatestLocalKeyID < key_object.local_key_id: _LatestLocalKeyID = key_object.local_key_id save_latest_local_key_id(keys_folder=keys_folder) local_keys()[key_object.local_key_id] = key_id local_keys_index()[ key_object.toPublicString()] = key_object.local_key_id if _Debug: lg.out( _DebugLevel, 'my_keys.load_key %r label=%r is_private=%r local_key_id=%r from %s' % ( key_id, key_object.label, not key_object.isPublic(), key_object.local_key_id, keys_folder, )) else: lg.warn('for key %r local_key_id was not set' % key_id) events.send('key-loaded', data=dict( key_id=key_id, label=key_object.label, key_size=key_object.size(), )) listeners.push_snapshot('key', snap_id=key_id, data=make_key_info( key_object=key_object, key_id=key_id, event='key-loaded', include_private=False, include_local_id=True, include_signature=True, include_label=True, )) return True
def populate_conversations(message_types=[], offset=0, limit=100, order_by_time=True): for conv in fetch_conversations( order_by_time=order_by_time, message_types=message_types, offset=offset, limit=limit, ): listeners.push_snapshot('conversation', snap_id=conv['conversation_id'], data=conv)
def populate_services(): services_list = reversed(boot_up_order()) for name in services_list: svc = services().get(name, None) if not svc: continue svc_data = svc.to_json() svc_data['event'] = None listeners.push_snapshot('service', snap_id=name, data=svc_data)
def populate_keys(): for key_id, key_object in known_keys().items(): listeners.push_snapshot('key', snap_id=key_id, data=make_key_info( key_object=key_object, key_id=key_id, event=None, include_private=False, include_local_id=True, include_signature=True, include_label=True, ))
def sign_key(key_id, keys_folder=None, ignore_shared_keys=False, save=True): key_id = latest_key_id(strng.to_text(key_id)) if not is_key_registered(key_id): lg.warn('key %s is not found' % key_id) return False if not keys_folder: keys_folder = settings.KeyStoreDir() key_object = known_keys()[key_id] if key_object.signed: if key_object.signed[1] != key.MyPublicKey(): if ignore_shared_keys: if _Debug: lg.dbg( _DebugLevel, 'skip generating signature for shared key: %r' % key_id) return True raise Exception( 'must not generate and overwrite existing signature for shared key: %r' % key_id) signed_key_info = make_key_info( key_object=key_object, key_id=key_id, include_private=not key_object.isPublic(), generate_signature=True, ) key_object.signed = ( signed_key_info['signature'], signed_key_info['signature_pubkey'], ) known_keys()[key_id] = key_object if save: save_key(key_id, keys_folder=keys_folder) events.send('key-signed', data=dict( key_id=key_id, label=key_object.label, key_size=key_object.size(), )) listeners.push_snapshot('key', snap_id=key_id, data=make_key_info( key_object=key_object, key_id=key_id, event='key-signed', include_private=False, include_local_id=True, include_signature=True, include_label=True, )) return key_object
def on_service_callback(result, service_name): if _Debug: lg.out(_DebugLevel, 'driver.on_service_callback %s : [%s]' % (service_name, result)) svc = services().get(service_name, None) if not svc: raise ServiceNotFound(service_name) if result == 'started': if _Debug: lg.out(_DebugLevel, '[%s] STARTED' % service_name) events.send('service-started', data=dict(name=service_name)) relative_services = [] for other_name in services().keys(): if other_name == service_name: continue other_service = services().get(other_name, None) if not other_service: raise ServiceNotFound(other_name) if other_service.state == 'ON': continue for depend_name in other_service.dependent_on(): if depend_name == service_name: relative_services.append(other_service) if len(relative_services) > 0: for relative_service in relative_services: if not relative_service.enabled(): continue if relative_service.state == 'ON': continue relative_service.automat('start') elif result == 'stopped': if _Debug: lg.out(_DebugLevel, '[%s] STOPPED' % service_name) events.send('service-stopped', data=dict(name=service_name)) for depend_name in svc.dependent_on(): depend_service = services().get(depend_name, None) if not depend_service: raise ServiceNotFound(depend_name) depend_service.automat('depend-service-stopped') elif result == 'depends_off': if _Debug: lg.out(_DebugLevel, '[%s] DEPENDS_OFF' % service_name) for depend_name in svc.dependent_on(): depend_service = services().get(depend_name, None) if not depend_service: raise ServiceNotFound(depend_name) depend_service.automat('depend-service-stopped') svc_data = svc.to_json() svc_data['event'] = result listeners.push_snapshot('service', snap_id=service_name, data=svc_data) return result
def add_correspondent(idurl, nickname=''): """ Add correspondent, execute notification callback and return its position in the list. """ global _CorrespondentsList global _CorrespondentsChangedCallback curlist = list(_CorrespondentsList) idurl = id_url.field(idurl) _CorrespondentsList.append((idurl.to_bin(), nickname, )) if _CorrespondentsChangedCallback is not None: _CorrespondentsChangedCallback(curlist, _CorrespondentsList) listeners.push_snapshot('correspondent', snap_id=idurl.to_bin(), data=dict( idurl=idurl.to_bin(), nickname=nickname, )) return len(curlist)
def generate_key(key_id, label='', key_size=4096, keys_folder=None): global _LatestLocalKeyID key_id = latest_key_id(key_id) if is_key_registered(key_id): lg.warn('key %r already registered' % key_id) return None if not label: label = 'key%s' % utime.make_timestamp() if _Debug: lg.out( _DebugLevel, 'my_keys.generate_key %r of %d bits, label=%r' % (key_id, key_size, label)) _LatestLocalKeyID += 1 save_latest_local_key_id(keys_folder=keys_folder) key_object = rsa_key.RSAKey() key_object.generate(key_size) key_object.label = label key_object.local_key_id = _LatestLocalKeyID known_keys()[key_id] = key_object if _Debug: lg.out(_DebugLevel, ' key %r generated' % key_id) if not keys_folder: keys_folder = settings.KeyStoreDir() save_key(key_id, keys_folder=keys_folder) events.send('key-generated', data=dict( key_id=key_id, label=label, key_size=key_size, )) listeners.push_snapshot('key', snap_id=key_id, data=make_key_info( key_object=key_object, key_id=key_id, event='key-generated', include_private=False, include_local_id=True, include_signature=True, include_label=True, )) return key_object
def remove_correspondent(idurl): """ Remove correspondent with given IDURL, execute notification callback and return True if success. """ global _CorrespondentsList global _CorrespondentsChangedCallback curlist = list(_CorrespondentsList) idurl = id_url.field(idurl) for tupl in _CorrespondentsList: if idurl.to_bin() == id_url.field(tupl[0]).to_bin(): _CorrespondentsList.remove(tupl) if _CorrespondentsChangedCallback is not None: _CorrespondentsChangedCallback(curlist, _CorrespondentsList) listeners.push_snapshot('correspondent', snap_id=idurl.to_bin(), deleted=True, data=dict( idurl=idurl.to_bin(), nickname=tupl[1], )) return True return False
def state_changed(self, oldstate, newstate, event, *args, **kwargs): """ Method to catch the moment when `online_status()` state were changed. """ if _Debug: lg.out(_DebugLevel - 2, '%s : [%s]->[%s]' % (self.name, oldstate, newstate)) if newstate == 'CONNECTED': lg.info('remote node connected : %s' % self.idurl) events.send('node-connected', data=dict( global_id=self.idurl.to_id(), idurl=self.idurl, old_state=oldstate, new_state=newstate, )) listeners.push_snapshot('online_status', snap_id=self.idurl.to_bin(), data=self.to_json()) if newstate == 'OFFLINE' and oldstate != 'AT_STARTUP': lg.info('remote node disconnected : %s' % self.idurl) events.send('node-disconnected', data=dict( global_id=self.idurl.to_id(), idurl=self.idurl, old_state=oldstate, new_state=newstate, )) listeners.push_snapshot('online_status', snap_id=self.idurl.to_bin(), data=self.to_json()) if newstate == 'PING?' and oldstate != 'AT_STARTUP': listeners.push_snapshot('online_status', snap_id=self.idurl.to_bin(), data=self.to_json())
def erase_key(key_id, keys_folder=None): key_id = latest_key_id(key_id) if not is_key_registered(key_id): lg.warn('key %s is not registered' % key_id) return False if not keys_folder: keys_folder = settings.KeyStoreDir() if key_obj(key_id).isPublic(): key_filepath = os.path.join(keys_folder, key_id + '.public') is_private = False else: key_filepath = os.path.join(keys_folder, key_id + '.private') is_private = True try: os.remove(key_filepath) except: lg.exc() return False k_obj = known_keys().pop(key_id) local_keys().pop(k_obj.local_key_id, None) local_keys_index().pop(k_obj.toPublicString(), None) gc.collect() if _Debug: lg.out(_DebugLevel, ' key %s removed, file %s deleted' % (key_id, key_filepath)) events.send('key-erased', data=dict(key_id=key_id, is_private=is_private)) listeners.push_snapshot('key', snap_id=key_id, deleted=True, data=make_key_info( key_object=None, key_id=key_id, event='key-erased', include_private=False, include_local_id=True, include_signature=True, include_label=True, )) return True
def populate_online_statuses(): for online_s in online_statuses().values(): listeners.push_snapshot('online_status', snap_id=online_s.idurl.to_bin(), data=online_s.to_json())
def insert_message(data, message_id, message_time=None, sender=None, recipient=None, message_type=None, direction=None): """ Writes JSON message to the message database. """ payload_time = message_time or utime.utcnow_to_sec1970() payload_message_id = strng.to_text(message_id) payload_type = MESSAGE_TYPES.get(message_type, 1) if not sender: sender = my_id.getGlobalID(key_alias='master') if not recipient: recipient = my_id.getGlobalID(key_alias='master') if direction is None: if message_type in [ 'private_message', None, ]: direction = 'out' if sender == my_id.getGlobalID( key_alias='master') else 'in' else: direction = 'in' else: direction = direction.replace('incoming', 'in').replace('outgoing', 'out') if _Debug: lg.args(_DebugLevel, sender=sender, recipient=recipient, typ=payload_type, dir=direction, message_id=payload_message_id) recipient_local_key_id = my_keys.get_local_key_id(recipient) if payload_type in [ 3, 4, ]: sender_local_key_id = recipient_local_key_id else: sender_local_key_id = my_keys.get_local_key_id(sender) if sender_local_key_id is None or recipient_local_key_id is None: lg.err( 'failed to store message because local_key_id is not found, sender=%r recipient=%r' % ( sender_local_key_id, recipient_local_key_id, )) return None cur().execute( '''INSERT INTO history ( sender_local_key_id, sender_id, recipient_local_key_id, recipient_id, direction, payload_type, payload_time, payload_message_id, payload_body ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)''', ( sender_local_key_id, sender, recipient_local_key_id, recipient, 0 if direction == 'in' else 1, payload_type, payload_time, payload_message_id, data, )) db().commit() conversation_id = update_conversation(sender_local_key_id, recipient_local_key_id, payload_type, payload_time, payload_message_id) snap_id = '{}/{}'.format(conversation_id, payload_message_id) message_json = build_json_message( sender=sender, recipient=recipient, direction=direction, conversation_id=conversation_id, message_type=MESSAGE_TYPE_CODES.get(int(payload_type), 'private_message'), message_time=payload_time, message_id=payload_message_id, data=data, ) listeners.push_snapshot('message', snap_id=snap_id, created=payload_time, data=message_json) return message_json
def register_key(key_id, key_object_or_string, label='', keys_folder=None): global _LatestLocalKeyID key_id = latest_key_id(key_id) if is_key_registered(key_id): lg.warn('key %s already registered' % key_id) return None if not keys_folder: keys_folder = settings.KeyStoreDir() if not label: label = 'key%s' % utime.make_timestamp() if strng.is_string(key_object_or_string): key_object_or_string = strng.to_bin(key_object_or_string) if _Debug: lg.out( _DebugLevel, 'my_keys.register_key %r from %d bytes openssh_input_string' % (key_id, len(key_object_or_string))) key_object = unserialize_key_to_object(key_object_or_string) if not key_object: lg.warn( 'invalid openssh string, unserialize_key_to_object() failed') return None else: if _Debug: lg.out(_DebugLevel, 'my_keys.register_key %r from object' % key_id) key_object = key_object_or_string known_local_key_id = local_keys_index().get(key_object.toPublicString()) if known_local_key_id is not None: known_key_id = local_keys().get(known_local_key_id) if known_key_id is not None: known_key_id = latest_key_id(known_key_id) if known_key_id != key_id: raise Exception( 'must not register same key with local_key_id=%r twice with different key_id: %r ~ %r' % ( known_local_key_id, known_key_id, key_id, )) new_local_key_id = known_local_key_id if new_local_key_id is None: _LatestLocalKeyID += 1 save_latest_local_key_id(keys_folder=keys_folder) new_local_key_id = _LatestLocalKeyID key_object.local_key_id = new_local_key_id known_keys()[key_id] = key_object if _Debug: lg.out(_DebugLevel, ' key %r registered' % key_id) save_key(key_id, keys_folder=keys_folder) events.send('key-registered', data=dict( key_id=key_id, label=label, key_size=key_object.size(), )) listeners.push_snapshot('key', snap_id=key_id, data=make_key_info( key_object=key_object, key_id=key_id, event='key-registered', include_private=False, include_local_id=True, include_signature=True, include_label=True, )) return key_object
def populate_correspondents(): for corr in correspondents(): listeners.push_snapshot('correspondent', snap_id=corr[0], data=dict( idurl=corr[0], nickname=corr[1], ))