def read_account( syndicatemail_password, email_addr ): try: email_addr_parsed = contact.parse_addr( email_addr ) except: log.error("Invalid email address %s" % email_addr) return None gateway_name = read_gateway_name() if gateway_name is None: log.error("Failed to load gateway name") return None gateway_port = read_gateway_port() if gateway_port is None: log.error("Failed to read gateway port") return None volume_pubkey_pem = read_volume_pubkey( email_addr_parsed.volume ) if volume_pubkey_pem is None: log.error("Failed to read volume public key") return None gateway_privkey_pem = read_gateway_privkey( syndicatemail_password, gateway_name ) if gateway_privkey_pem is None: log.error("Failed to read gateway private key") return None account = SyndicateAccountInfo( gateway_name=gateway_name, gateway_port=gateway_port, volume_pubkey_pem=volume_pubkey_pem, gateway_privkey_pem=gateway_privkey_pem ) return account
def read_message_from_volume( vol_inst, sender_pubkey_str, receiver_pubkey_str, receiver_privkey_str, incoming_message ): try: sender_addr_parsed = contact.parse_addr( incoming_message.sender_addr ) except Exception, e: log.exception(e) log.error("Could not parse email") return None
def sender_volume_from_incoming_message( incoming_message, gateway_privkey_pem, storage_root ): try: parsed_addr = contact.parse_addr( incoming_message.sender_addr ) except Exception, e: log.exception(e) log.error("Failed to parse %s" % incoming_message.sender_addr ) return None
def download_user_pubkey(addr, allow_mismatch=False, use_http=False): try: parsed_addr = contact.parse_addr(addr) except Exception, e: log.exception(e) log.error("Failed to read contact %s" % addr) return None
def download_user_mail_pubkey_sig(addr, use_http=False): try: parsed_addr = contact.parse_addr(addr) except Exception, e: log.exception(e) log.error("Invalid email address %s" % addr) return None
def delete_account( privkey_str, email, volume, syndicate_user_id, remove_gateway=False, syndicate_user_privkey_str=None, syndicate_user_verifykey_str=None, test=False ): # NOTE: verify user first! try: parsed_email = contact.parse_addr( email ) except Exception, e: log.exception(e) log.error("Invalid email %s" % email) return False
def read_account_volume_pubkey( email_addr, storage_root=None ): try: email_addr_parsed = contact.parse_addr( email_addr ) except: log.error("Invalid email address %s" % email_addr) return None volume_pubkey_pem = read_volume_pubkey( email_addr_parsed.volume, prefix=storage_root ) return volume_pubkey_pem
def do_login( config, email, password, syndicate_oid_username, syndicate_oid_password, user_signing_privkey_pem=None, user_verifying_pubkey_pem=None, volume_pubkey_pem=None, create_on_absent=False): # TODO: remove need for OID login/password global SESSION_LENGTH try: parsed_email = contact.parse_addr( email ) except Exception, e: log.exception(e) raise Exception("Invalid email '%s'" % email)
def clear_incoming_messages(privkey_str, addr, use_http=False): # called by the endpoint # tell server that we have all new messages up to a timestamp # FIXME: pagination, streaming, ? try: parsed_addr = contact.parse_addr(addr) except Exception, e: log.exception(e) log.error("Invalid address '%s'" % addr) return None
def get_incoming_messages(addr, use_http=False): # called by the endpoint. # get all incoming messages. # FIXME: streaming/paging solution # FIXME: sign/verify messages? try: parsed_addr = contact.parse_addr(addr) except Exception, e: log.exception(e) log.error("Invalid address '%s'" % addr) return None
def do_first_login( config, password, syndicate_oid_username, syndicate_oid_password, user_signing_privkey_pem, user_verifying_pubkey_pem, volume_pubkey_pem ): try: parsed_email = contact.parse_addr( config['email'] ) except: raise Exception("Invalid email '%s'" % config['email'] ) account_privkey_pem = account.create_account( config['mail_username'], password, config['mail_server'], password, config['MS'], syndicate_oid_username, syndicate_oid_password, user_signing_privkey_pem, user_verifying_pubkey_pem, parsed_email.volume, volume_pubkey_pem ) if account_privkey_pem is None or account_privkey_pem == False: raise Exception("Failed to create an account for %s" % config['email'] ) return account_privkey_pem
def send_message( pubkey_str, privkey_str, sender_addr, receiver_addrs, cc_addrs, bcc_addrs, subject, body, attachments={}, folder=unicode(SENT_FOLDER), fake_time=None, fake_id=None, use_http=False ): now = int(time.time()) msg_id = uuid.uuid4().get_hex() if fake_time is not None: now = fake_time if fake_id is not None: msg_id = fake_id handle = message_handle( now, msg_id ) # sanity check... if receiver_addrs == None: receiver_addrs = [] if cc_addrs == None: cc_addrs = [] if bcc_addrs == None: bcc_addrs = [] subject = unicode(subject) body = unicode(body) folder = unicode(folder) assert isinstance( receiver_addrs, list ), "Invalid argument for receiver_addrs" assert isinstance( cc_addrs, list ), "Invalid argument for cc_addrs" assert isinstance( bcc_addrs, list ), "Invalid argument for bcc_addrs" assert isinstance( folder, unicode ), "Invalid argument for folder" for addr in [sender_addr] + receiver_addrs + cc_addrs + bcc_addrs: assert isinstance(addr, str) or isinstance(addr, unicode), "Invalid address '%s'" % addr # parse addresses sender_addr_parsed = contact.parse_addr( sender_addr ) parsed_addrs = {} contacts = [] new_contacts = [] missing = [] send_via_gateway = [] for (addr_bundle_name, addrs) in [("receipient address", receiver_addrs), ("CC address", cc_addrs), ("BCC address", bcc_addrs)]: if not parsed_addrs.has_key(addr_bundle_name): parsed_addrs[addr_bundle_name] = [] for addr in addrs: try: parsed_addr = contact.parse_addr( addr ) parsed_addrs[ addr_bundle_name ].append( parsed_addr ) except Exception, e: # not a SyndicateMail address. Is it an email address? if not contact.is_valid_email( addr ): # not a valid email address raise Exception("Invalid %s '%s'" % (addr_bundle_name, addr)) else: # send via gateway, since this isn't a syndicate address send_via_gateway.append( addr ) log.info("Send to %s via normal email" % addr)
log.error("Failed to serialize") return False sig = keys.sign_data(sender_privkey_pem, data) sig_b64 = base64.b64encode(sig) forms = { "sender": encrypted_incoming_message.sender_addr, "receiver": encrypted_incoming_message.receiver_addr, "signature": sig_b64, "message": data, } try: parsed_receiver_addr = contact.parse_addr(encrypted_incoming_message.receiver_addr) except Exception, e: log.exception(e) log.error("Failed to parse '%s'" % encrypted_incoming_message.receiver_addr) return False # get receiver syndicatemail receiver_server = parsed_receiver_addr.server scheme = "https://" if use_http or "localhost" in receiver_server: scheme = "http://" server_url = storage.path_join(scheme + receiver_server, "/MAIL") resp_data = upload(server_url, forms) if resp_data is not None:
def do_test_login( config, email, password, volume=None ): privkey_str = """ -----BEGIN RSA PRIVATE KEY----- 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 -----END RSA PRIVATE KEY----- """.strip() try: parsed_email = contact.parse_addr( email ) except: raise Exception("Invalid email '%s'" % email) privkey = CryptoKey.importKey( privkey_str ) config['privkey'] = privkey config['pubkey'] = privkey.publickey() config['session_expires'] = time.time() + SESSION_LENGTH config['volume_name'] = parsed_email.volume config['volume'] = volume return True