<s> import os . path , json , time <EOL> from twisted . application import service <EOL> from twisted . python import log <EOL> from nacl . public import PrivateKey <EOL> from nacl . signing import SigningKey , VerifyKey <EOL> from nacl . encoding import HexEncoder as Hex <EOL> from . import invitation , rrid <EOL> from . errors import CommandError , ContactNotReadyError <EOL> from . mailbox import channel , retrieval <EOL> from . eventual import eventually <EOL> class Agent ( service . MultiService ) : <EOL> def __init__ ( self , db , basedir , mailbox_server ) : <EOL> service . MultiService . __init__ ( self ) <EOL> self . db = db <EOL> self . mailbox_server = mailbox_server <EOL> self . mailbox_retrievers = set ( ) <EOL> c = self . db . execute ( "<STR_LIT>" ) . fetchone ( ) <EOL> self . advertise_local_mailbox = bool ( c [ "<STR_LIT>" ] ) <EOL> mboxes = { } <EOL> if self . advertise_local_mailbox : <EOL> local_tid = mailbox_server . get_local_transport ( ) <EOL> local_mbrec = mailbox_server . get_mailbox_record ( local_tid ) <EOL> mboxes [ "<STR_LIT>" ] = local_mbrec [ "<STR_LIT>" ] <EOL> for row in self . db . execute ( "<STR_LIT>" ) . fetchall ( ) : <EOL> mbrec = json . loads ( row [ "<STR_LIT>" ] ) <EOL> mboxes [ row [ "<STR_LIT:id>" ] ] = mbrec [ "<STR_LIT>" ] <EOL> for mbid , rrec in mboxes . items ( ) : <EOL> rc = self . build_retriever ( mbid , rrec ) <EOL> self . subscribe_to_mailbox ( rc ) <EOL> row = self . db . execute ( "<STR_LIT>" ) . fetchone ( ) <EOL> relay_url = row [ "<STR_LIT:url>" ] . encode ( "<STR_LIT:ascii>" ) <EOL> self . im = invitation . InvitationManager ( db , relay_url ) <EOL> def startService ( self ) : <EOL> service . MultiService . startService ( self ) <EOL> for i in self . im . thaw_invitations ( ) : <EOL> self . _activate_invitation ( i ) <EOL> def build_retriever ( self , mbid , rrec ) : <EOL> def got_msgC ( msgC ) : <EOL> self . msgC_received ( mbid , msgC ) <EOL> retrieval_type = rrec [ "<STR_LIT:type>" ] <EOL> if retrieval_type == "<STR_LIT:http>" : <EOL> return retrieval . HTTPRetriever ( rrec , got_msgC ) <EOL> elif retrieval_type == "<STR_LIT>" : <EOL> return retrieval . LocalRetriever ( rrec , got_msgC , self . mailbox_server ) <EOL> else : <EOL> raise CommandError ( "<STR_LIT>" <EOL> % retrieval_type ) <EOL> def subscribe_to_mailbox ( self , rc ) : <EOL> self . mailbox_retrievers . add ( rc ) <EOL> rc . setServiceParent ( self ) <EOL> def msgC_received ( self , tid , msgC ) : <EOL> assert msgC . startswith ( "<STR_LIT>" ) <EOL> cid , seqnum , payload_json = channel . process_msgC ( self . db , msgC ) <EOL> self . payload_received ( cid , seqnum , payload_json ) <EOL> def payload_received ( self , cid , seqnum , payload_json ) : <EOL> self . db . insert ( "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" , <EOL> ( cid , seqnum , time . time ( ) , payload_json ) , <EOL> "<STR_LIT>" ) <EOL> self . db . commit ( ) <EOL> def command_invite ( self , petname , maybe_code = None , reqid = None , <EOL> override_transports = None , offer_mailbox = False , <EOL> accept_mailbox_offer = False , <EOL> _debug_when_done = None ) : <EOL> if maybe_code : <EOL> count = self . db . execute ( "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" , <EOL> ( invitation . INVITE_COMPLETE , maybe_code ) <EOL> ) . fetchone ( ) [ <NUM_LIT:0> ] <EOL> if count : <EOL> raise CommandError ( "<STR_LIT>" ) <EOL> my_signkey = SigningKey . generate ( ) <EOL> channel_key = PrivateKey . generate ( ) <EOL> my_CID_key = os . urandom ( <NUM_LIT:32> ) <EOL> base_transports = self . get_transports ( ) <EOL> if override_transports : <EOL> base_transports = override_transports <EOL> transports = self . individualize_transports ( base_transports ) <EOL> channel = { "<STR_LIT>" : channel_key . public_key . encode ( Hex ) , <EOL> "<STR_LIT>" : my_CID_key . encode ( "<STR_LIT>" ) , <EOL> "<STR_LIT>" : transports . values ( ) , <EOL> } <EOL> payload = { "<STR_LIT>" : channel } <EOL> if offer_mailbox : <EOL> tid = self . mailbox_server . allocate_transport ( remote = True ) <EOL> payload [ "<STR_LIT>" ] = self . mailbox_server . get_mailbox_record ( tid ) <EOL> encoded_payload = json . dumps ( payload ) . encode ( "<STR_LIT:utf-8>" ) <EOL> sigkeypayload = ( b"<STR_LIT>" + my_signkey . verify_key . encode ( ) <EOL> + my_signkey . sign ( encoded_payload ) ) <EOL> cid = self . db . insert ( <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" , <EOL> ( petname , accept_mailbox_offer , <EOL> invitation . INVITE_WAITING_FOR_CODE , time . time ( ) , maybe_code , <EOL> sigkeypayload . encode ( "<STR_LIT>" ) , <EOL> <NUM_LIT:1> , my_signkey . encode ( Hex ) , <EOL> my_CID_key . encode ( "<STR_LIT>" ) , None , <EOL> <NUM_LIT:0> , <EOL> channel_key . encode ( Hex ) , <EOL> channel_key . encode ( Hex ) , <EOL> ) , <EOL> "<STR_LIT>" , { "<STR_LIT>" : reqid } ) <EOL> i = self . im . create_invitation ( cid ) <EOL> self . db . commit ( ) <EOL> self . _activate_invitation ( i , cid , _debug_when_done ) <EOL> return { "<STR_LIT>" : cid , "<STR_LIT>" : petname , <EOL> "<STR_LIT>" : "<STR_LIT>" % ( petname , cid ) } <EOL> def _activate_invitation ( self , i , cid , _debug_when_done = None ) : <EOL> d = i . activate ( ) <EOL> d . addCallbacks ( self . invitation_success , self . invitation_failed , <EOL> callbackArgs = ( cid , _debug_when_done ) , <EOL> errbackArgs = ( cid , _debug_when_done ) ) <EOL> return d <EOL> def petname_for_cid ( self , cid ) : <EOL> c = self . db . execute ( "<STR_LIT>" , <EOL> ( cid , ) ) <EOL> petname = c . fetchone ( ) [ "<STR_LIT>" ] <EOL> return petname <EOL> def invitation_success ( self , sigkeypayload , cid , _debug_when_done ) : <EOL> if not sigkeypayload . startswith ( "<STR_LIT>" ) : <EOL> raise ValueError ( "<STR_LIT>" % sigkeypayload [ : <NUM_LIT:20> ] ) <EOL> their_verfkey = VerifyKey ( sigkeypayload [ <NUM_LIT:3> : <NUM_LIT:3> + <NUM_LIT:32> ] ) <EOL> encoded_payload = their_verfkey . verify ( sigkeypayload [ <NUM_LIT:3> + <NUM_LIT:32> : ] ) <EOL> payload = json . loads ( encoded_payload . decode ( "<STR_LIT:utf-8>" ) ) <EOL> self . db . update ( <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" , <EOL> ( invitation . INVITE_COMPLETE , None , None , <EOL> time . time ( ) , <EOL> json . dumps ( payload . get ( "<STR_LIT>" ) ) , <EOL> json . dumps ( payload [ "<STR_LIT>" ] ) , <EOL> <NUM_LIT:0> , their_verfkey . encode ( ) . encode ( "<STR_LIT>" ) , <EOL> cid ) , "<STR_LIT>" , cid ) <EOL> self . maybe_accept_mailbox ( cid ) <EOL> self . db . commit ( ) <EOL> log . msg ( "<STR_LIT>" % <EOL> self . petname_for_cid ( cid ) ) <EOL> if _debug_when_done : <EOL> eventually ( _debug_when_done . callback , cid ) <EOL> def invitation_failed ( self , err , cid , _debug_when_done ) : <EOL> log . msg ( "<STR_LIT>" % <EOL> ( self . petname_for_cid ( cid ) , err ) ) <EOL> self . db . delete ( "<STR_LIT>" , ( cid , ) , <EOL> "<STR_LIT>" , cid ) <EOL> self . db . commit ( ) <EOL> if _debug_when_done : <EOL> eventually ( _debug_when_done . callback , err ) <EOL> def maybe_accept_mailbox ( self , cid ) : <EOL> c = self . db . execute ( "<STR_LIT>" , ( cid , ) ) <EOL> row = c . fetchone ( ) <EOL> mailbox_json = row [ "<STR_LIT>" ] <EOL> accept_mailbox_offer = row [ "<STR_LIT>" ] <EOL> if mailbox_json and accept_mailbox_offer : <EOL> mailbox = json . loads ( mailbox_json ) <EOL> mbid = self . db . insert ( "<STR_LIT>" <EOL> "<STR_LIT>" , <EOL> ( cid , json . dumps ( mailbox ) , ) , "<STR_LIT>" ) <EOL> rc = self . build_retriever ( mbid , mailbox [ "<STR_LIT>" ] ) <EOL> self . subscribe_to_mailbox ( rc ) <EOL> def command_control_accept_mailbox_offer ( self , cid , accept ) : <EOL> c = self . db . execute ( "<STR_LIT>" , <EOL> ( cid , ) ) <EOL> old_accept = bool ( c . fetchone ( ) [ "<STR_LIT>" ] ) <EOL> if accept != old_accept : <EOL> self . db . update ( "<STR_LIT>" <EOL> "<STR_LIT>" , ( accept , cid ) , <EOL> "<STR_LIT>" , cid ) <EOL> self . db . commit ( ) <EOL> return "<STR_LIT>" <EOL> def command_send_basic_message ( self , cid , message ) : <EOL> try : <EOL> self . send_message ( cid , { "<STR_LIT>" : message } ) <EOL> except ContactNotReadyError : <EOL> raise CommandError ( "<STR_LIT>" % cid ) <EOL> return "<STR_LIT>" <EOL> def send_message ( self , cid , payload ) : <EOL> row = self . db . execute ( "<STR_LIT>" <EOL> "<STR_LIT>" , ( cid , ) ) . fetchone ( ) <EOL> if not row [ "<STR_LIT>" ] or not row [ "<STR_LIT>" ] : <EOL> raise ContactNotReadyError ( "<STR_LIT>" % cid ) <EOL> self . db . insert ( "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" , <EOL> ( cid , time . time ( ) , json . dumps ( payload ) ) , <EOL> "<STR_LIT>" ) <EOL> self . db . commit ( ) <EOL> c = channel . OutboundChannel ( self . db , cid ) <EOL> return c . send ( payload ) <EOL> def get_transports ( self ) : <EOL> transports = { } <EOL> if self . advertise_local_mailbox : <EOL> local_tid = self . mailbox_server . get_local_transport ( ) <EOL> local_mbrec = self . mailbox_server . get_mailbox_record ( local_tid ) <EOL> transports [ "<STR_LIT>" ] = local_mbrec <EOL> for row in self . db . execute ( "<STR_LIT>" ) . fetchall ( ) : <EOL> transports [ row [ "<STR_LIT:id>" ] ] = json . loads ( row [ "<STR_LIT>" ] ) <EOL> return transports <EOL> def individualize_transports ( self , base_transports ) : <EOL> transports = { } <EOL> for mbid , base in base_transports . items ( ) : <EOL> t = base [ "<STR_LIT>" ] [ "<STR_LIT>" ] . copy ( ) <EOL> TT0 = base [ "<STR_LIT>" ] [ "<STR_LIT>" ] [ "<STR_LIT>" ] . decode ( "<STR_LIT>" ) <EOL> t [ "<STR_LIT>" ] = rrid . randomize ( TT0 ) . encode ( "<STR_LIT>" ) <EOL> transports [ mbid ] = t <EOL> return transports <EOL> def command_list_addressbook ( self ) : <EOL> resp = [ ] <EOL> for row in self . db . execute ( "<STR_LIT>" ) . fetchall ( ) : <EOL> entry = { } <EOL> entry [ "<STR_LIT>" ] = row [ "<STR_LIT:id>" ] <EOL> entry [ "<STR_LIT>" ] = row [ "<STR_LIT>" ] <EOL> entry [ "<STR_LIT>" ] = bool ( row [ "<STR_LIT>" ] ) <EOL> entry [ "<STR_LIT>" ] = { <EOL> "<STR_LIT>" : row [ "<STR_LIT>" ] , <EOL> "<STR_LIT:code>" : row [ "<STR_LIT>" ] , <EOL> } <EOL> sk = SigningKey ( row [ "<STR_LIT>" ] . decode ( "<STR_LIT>" ) ) <EOL> entry [ "<STR_LIT>" ] = sk . verify_key . encode ( Hex ) <EOL> if row [ "<STR_LIT>" ] is not None : <EOL> entry [ "<STR_LIT>" ] [ "<STR_LIT>" ] = row [ "<STR_LIT>" ] <EOL> if row [ "<STR_LIT>" ] is not None : <EOL> entry [ "<STR_LIT>" ] = str ( row [ "<STR_LIT>" ] ) <EOL> if row [ "<STR_LIT>" ] is not None : <EOL> entry [ "<STR_LIT>" ] = json . loads ( row [ "<STR_LIT>" ] ) <EOL> resp . append ( entry ) <EOL> return resp <EOL> def command_set_petname ( self , cid , petname ) : <EOL> self . db . update ( "<STR_LIT>" , <EOL> ( petname , cid ) , <EOL> "<STR_LIT>" , cid ) <EOL> self . db . commit ( ) <EOL> def command_fetch_all_messages ( self ) : <EOL> c = self . db . execute ( "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" ) <EOL> return [ { "<STR_LIT:id>" : row [ "<STR_LIT:id>" ] , <EOL> "<STR_LIT>" : row [ "<STR_LIT>" ] , <EOL> "<STR_LIT>" : row [ "<STR_LIT>" ] , <EOL> "<STR_LIT>" : row [ "<STR_LIT>" ] , <EOL> "<STR_LIT>" : json . loads ( row [ "<STR_LIT>" ] ) , <EOL> } <EOL> for row in c . fetchall ( ) ] </s>
