def __init__(self, engine, db): assert type(engine) is chord.ChordEngine self.engine = engine self.db = db self.loop = engine.loop self.latest_version_number = None self.latest_version_data = None self.auto_publish_enabled = True self.auto_scan_enabled = True self.csrf_token = base58.encode(os.urandom(64)) self._dmail_engine = None self._running = False self._data_key =\ mbase32.decode("sp1nara3xhndtgswh7fznt414we4mi3y6kdwbkz4jmt8ocb6x"\ "4w1faqjotjkcrefta11swe3h53dt6oru3r13t667pr7cpe3ocxeuma") self._path = b"latest_version" self._dmail_autoscan_processes = {}
def _count_unread_dmails(dispatcher, addr=None, tag=None): if addr and type(addr) not in (bytes, bytearray): addr = mbase32.decode(addr) def dbcall(): with dispatcher.node.db.open_session() as sess: q = sess.query(func.count("*")) q = q.filter(DmailMessage.read == False) if addr: q = q.filter(DmailMessage.address.has(DmailAddress.site_key == addr)) if tag == "Trash": q = q.filter(DmailMessage.hidden == True).filter(DmailMessage.deleted == False) return q.scalar() if tag: q = q.filter(DmailMessage.tags.any(DmailTag.name == tag)) q = q.filter(DmailMessage.hidden == False) return q.scalar() cnt = yield from dispatcher.node.loop.run_in_executor(None, dbcall) return cnt
def main(): log.info("Testing...") r = generate_targeted_block(\ mbase32.decode("yyyyyyyy"), 20, b"test data message", 0, 4) log.info("Done, r=[{}].".format(r))
def scan_dmail_address(self, addr, significant_bits, key_callback=None): if log.isEnabledFor(logging.INFO): log.info("Scanning dmail [{}].".format(mbase32.encode(addr))) def dbcall(): with self.db.open_session() as sess: q = sess.query(db.DmailAddress)\ .filter(db.DmailAddress.site_key == addr) dmail_address = q.first() if dmail_address: dmail_address.keys sess.expunge_all() return dmail_address dmail_address = yield from self.loop.run_in_executor(None, dbcall) if dmail_address: log.info("Found DmailAddress locally, using local settings.") target = dmail_address.keys[0].target_key significant_bits = dmail_address.keys[0].difficulty else: log.info("DmailAddress not found locally, fetching settings from"\ " the network.") addr, dsite = yield from\ self.fetch_recipient_dmail_site(addr, significant_bits) if not dsite: raise DmailException("Dmail site not found.") target = dsite.root["target"] significant_bits = dsite.root["difficulty"] target = mbase32.decode(target) start = target while True: data_rw = yield from self.task_engine.send_find_key(\ start, target_key=target, significant_bits=significant_bits,\ retry_factor=100) key = data_rw.data_key if not key: break if log.isEnabledFor(logging.INFO): log.info("Found dmail key: [{}].".format(mbase32.encode(key))) if key_callback: key_callback(key) start = key
def decode_key(encoded): assert consts.NODE_ID_BITS == 512 assert type(encoded) is str, type(encoded) significant_bits = None kl = len(encoded) if kl == 128: data_key = bytes.fromhex(encoded) elif kl in (102, 103): data_key = bytes(mbase32.decode(encoded)) if len(data_key) < consts.NODE_ID_BYTES: significant_bits = 5 * kl else: data_key = mbase32.decode(encoded, False) significant_bits = 5 * kl return data_key, significant_bits
def dbcall(): with self.db.open_session() as sess: dmailaddress = db.DmailAddress() dmailaddress.site_key = data_key dmailaddress.site_privatekey = privkey._encode_key() dmailkey = db.DmailKey() dmailkey.x = sshtype.encodeMpint(dms.dh.x) dmailkey.target_key = mbase32.decode(dms.root["target"]) dmailkey.difficulty = difficulty dmailaddress.keys.append(dmailkey) sess.add(dmailaddress) sess.commit()
def dbcall(): with self.db.open_session() as sess: dmailaddress = db.DmailAddress() dmailaddress.site_key = data_key dmailaddress.site_privatekey = privkey._encode_key() dmailaddress.scan_interval = 60 dmailkey = db.DmailKey() dmailkey.x = sshtype.encodeMpint(dms.dh.x) dmailkey.target_key = mbase32.decode(dms.root["target"]) dmailkey.difficulty = difficulty dmailaddress.keys.append(dmailkey) sess.add(dmailaddress) sess.commit()
def send_store_targeted_data(\ self, data, store_key=False, key_callback=None): data_enc = base58.encode(data) r = yield from\ self.send_command(\ "storetargetedblockenc {} {}".format(data_enc, store_key)) p0 = r.find(b']') data_key = mbase32.decode(r[10:p0].decode("UTF-8")) key_callback(data_key) p0 = r.find(b"storing_nodes=[", p0) + 15 p1 = r.find(b']', p0) return int(r[p0:p1])
def do_findkey(self, arg): "<DATA_KEY_PREFIX> [TARGET_ID] [SIGNIFICANT_BITS] search the network" " for the given key." args = arg.split(" ") data_key, significant_bits = decode_key(args[0]) target_key = mbase32.decode(args[1]) if len(args) >= 2 else None if len(args) == 3: significant_bits = int(args[2]) start = datetime.today() data_rw = yield from self.peer.engine.tasks.send_find_key( data_key, significant_bits=significant_bits, target_key=target_key ) diff = datetime.today() - start data_key_enc = mbase32.encode(data_rw.data_key) if data_rw.data_key else None self.writeln("data_key=[{}].".format(data_key_enc)) self.writeln("send_find_key(..) took: {}.".format(diff))
def _empty_trash(dispatcher, addr_enc): addr_site_key = mbase32.decode(addr_enc) def dbcall(): with dispatcher.node.db.open_session() as sess: # Immediately delete messages that we sent. q = ( sess.query(DmailMessage) .filter(DmailMessage.address.has(DmailAddress.site_key == addr_site_key)) .filter(DmailMessage.hidden == True) .filter(DmailMessage.destination_dmail_key != None) ) q.delete(synchronize_session=False) # Mark messages that we received for deletion later. We can't # actually delete them until we no longer check the target_id they # came from, else we will pick them up again. q = ( sess.query(DmailMessage) .filter(DmailMessage.address.has(DmailAddress.site_key == addr_site_key)) .filter(DmailMessage.hidden == True) ) msgs = q.all() for msg in msgs: msg.tags.clear() msg.sender_dmail_key = None msg.destination_dmail_key = None msg.destination_significant_bits = None msg.subject = "" msg.date = mutil.utc_datetime() msg.parts.clear() msg.read = False msg.hidden = True msg.deleted = True sess.commit() yield from dispatcher.node.loop.run_in_executor(None, dbcall)
def do_findkey(self, arg): "<DATA_KEY_PREFIX> [TARGET_ID] [SIGNIFICANT_BITS] search the network" " for the given key." args = arg.split(' ') data_key, significant_bits = decode_key(args[0]) target_key = mbase32.decode(args[1]) if len(args) >= 2 else None if len(args) == 3: significant_bits = int(args[2]) start = datetime.today() data_rw = yield from\ self.peer.engine.tasks.send_find_key(\ data_key, significant_bits=significant_bits,\ target_key=target_key) diff = datetime.today() - start data_key_enc =\ mbase32.encode(data_rw.data_key) if data_rw.data_key else None self.writeln("data_key=[{}].".format(data_key_enc)) self.writeln("send_find_key(..) took: {}.".format(diff))
def send_store_updateable_key(\ self, data, privkey, path=None, version=None, store_key=True,\ key_callback=None): privkey_enc = base58.encode(privkey._encode_key()) data_enc = base58.encode(data) cmd = "storeukeyenc {} {} {} {}"\ .format(privkey_enc, data_enc, version, store_key) r = yield from self.send_command(cmd) if not r: return 0 if key_callback: p1 = r.find(b']', 10) r = r[10:p1].decode() key_enc = r key_callback(mbase32.decode(key_enc)) return 1 #FIXME: The shell API doesn't return this value as of yet.
def send_find_key(self, prefix, target_key=None, significant_bits=None): cmd = "findkey " + mbase32.encode(prefix) if target_key: cmd += " " + mbase32.encode(target_key) if significant_bits: cmd += " " + str(significant_bits) r = yield from self.send_command(cmd) p0 = r.find(b"data_key=[") + 10 p1 = r.find(b']', p0) data_key = r[p0:p1].decode() if data_key == "None": data_key = None else: data_key = mbase32.decode(data_key) data_rw = chord_tasks.DataResponseWrapper(data_key) return data_rw
def _load_dmails_for_tag(dispatcher, addr, tag): if type(addr) not in (bytes, bytearray): addr = mbase32.decode(addr) def dbcall(): with dispatcher.node.db.open_session() as sess: q = sess.query(DmailMessage).filter(DmailMessage.address.has(DmailAddress.site_key == addr)) if tag == "Trash": q = q.filter(DmailMessage.hidden == True).filter(DmailMessage.deleted == False) else: q = q.filter(DmailMessage.tags.any(DmailTag.name == tag)).filter(DmailMessage.hidden == False) q = q.order_by(DmailMessage.read, DmailMessage.date.desc()) msgs = q.all() sess.expunge_all() return msgs msgs = yield from dispatcher.node.loop.run_in_executor(None, dbcall) return msgs
def __init__(self, engine, db): assert type(engine) is chord.ChordEngine self.engine = engine self.db = db self.loop = engine.loop self.latest_version_number = None self.latest_version_data = None self.auto_publish_enabled = True self.csrf_token = base58.encode(os.urandom(64)) self._dmail_engine = None self._running = False self._data_key =\ mbase32.decode("sp1nara3xhndtgswh7fznt414we4mi3y6kdwbkz4jmt8ocb6x"\ "4w1faqjotjkcrefta11swe3h53dt6oru3r13t667pr7cpe3ocxeuma") self._path = b"latest_version" self._dmail_autoscan_processes = {}
def __main(): global loop log.info("mcc running.") parser = argparse.ArgumentParser() parser.add_argument(\ "--address",\ help="The address of the Morphis node to connect to.",\ default="127.0.0.1:4250") parser.add_argument(\ "--create-dmail",\ help="Generate and upload a new dmail site.",\ action="store_true") parser.add_argument(\ "--dburl",\ help="Specify the database url to use.") parser.add_argument(\ "--fetch-dmail", help="Fetch dmail for specified key_id.") parser.add_argument(\ "-i",\ help="Read file as stdin.") parser.add_argument("--nn", type=int,\ help="Node instance number.") parser.add_argument(\ "--prefix",\ help="Specify the prefix for various things (currently --create-dmail"\ ").") parser.add_argument(\ "--scan-dmail",\ help="Scan the network for available dmails.") parser.add_argument(\ "--send-dmail",\ help="Send stdin as a dmail with the specified subject. The"\ " sender and recipients may be specified at the beginning of the"\ " data as with email headers: 'from: ' and 'to: '.") parser.add_argument(\ "--stat",\ help="Report node status.",\ action="store_true") parser.add_argument("-l", dest="logconf",\ help="Specify alternate logging.ini [IF SPECIFIED, THIS MUST BE THE"\ " FIRST PARAMETER!].") parser.add_argument(\ "--dmail-target",\ help="Specify the dmail target to validate dmail against.") parser.add_argument(\ "-x",\ help="Specify the x (Diffie-Hellman private secret) to use.") args = parser.parse_args() # Load or generate client mcc key. key_filename = "data/mcc_key-rsa.mnk" if os.path.exists(key_filename): log.info("mcc private key file found, loading.") client_key = rsakey.RsaKey(filename=key_filename) else: log.info("mcc private key file missing, generating.") client_key = rsakey.RsaKey.generate(bits=4096) client_key.write_private_key_file(key_filename) # Connect a Morphis Client (lightweight Node) instance. mc = client.Client(loop, client_key=client_key, address=args.address) r = yield from mc.connect() if not r: log.warning("Connection failed; exiting.") loop.stop() return dbase = init_db(args) de = dmail.DmailEngine(mc, dbase) log.info("Processing command requests...") if args.stat: r = yield from mc.send_command("stat") print(r.decode("UTF-8"), end='') if args.create_dmail: log.info("Creating and uploading dmail site.") privkey, data_key, dms =\ yield from de.generate_dmail_address(args.prefix) print("privkey: {}".format(base58.encode(privkey._encode_key()))) print("x: {}".format(base58.encode(sshtype.encodeMpint(dms.dh.x)))) print("dmail address: {}".format(mbase32.encode(data_key))) if args.send_dmail: log.info("Sending dmail.") if args.i: with open(args.i, "rb") as fh: dmail_data = fh.read().decode() else: dmail_data = stdin.read() if log.isEnabledFor(logging.DEBUG): log.debug("dmail_data=[{}].".format(dmail_data)) yield from de.send_dmail_text(args.send_dmail, dmail_data) if args.scan_dmail: log.info("Scanning dmail address.") addr, sig_bits = mutil.decode_key(args.scan_dmail) def key_callback(key): print("dmail key: [{}].".format(mbase32.encode(key))) yield from de.scan_dmail_address(\ addr, sig_bits, key_callback=key_callback) if args.fetch_dmail: log.info("Fetching dmail for key=[{}].".format(args.fetch_dmail)) key = mbase32.decode(args.fetch_dmail) if args.x: l, x_int = sshtype.parseMpint(base58.decode(args.x)) else: x_int = None dmail_target = args.dmail_target dm, valid_sig = yield from de.fetch_dmail(key, x_int, dmail_target) if not dm: raise Exception("No dmail found.") if not x_int: print("Encrypted dmail data=[\n{}].".format(mutil.hex_dump(dm))) else: print("Subject: {}\n".format(dm.subject)) if dm.sender_pubkey: print("From: {}"\ .format(mbase32.encode(enc.generate_ID(dm.sender_pubkey)))) i = 0 for part in dm.parts: print("DmailPart[{}]:\n mime-type=[{}]\n data=[{}]\n"\ .format(i, part.mime_type, part.data)) i += 1 log.info("Disconnecting.") yield from mc.disconnect() loop.stop()
def __send_dmail(self, from_asymkey, recipient, dmail): assert type(recipient) is DmailSite root = recipient.root sse = sshtype.parseMpint(base58.decode(root["sse"]))[1] target = root["target"] difficulty = root["difficulty"] dh = dhgroup14.DhGroup14() dh.generate_x() dh.generate_e() dh.f = sse k = dh.calculate_k() target_key = mbase32.decode(target) key = self._generate_encryption_key(target_key, k) dmail_bytes = dmail.encode() m, r = enc.encrypt_data_block(dmail_bytes, key) if m: if r: m = m + r else: m = r dw = DmailWrapper() dw.ssm = _dh_method_name dw.sse = sse dw.ssf = dh.e if from_asymkey: dw.signature = from_asymkey.calc_rsassa_pss_sig(m) else: dw.signature = b'' dw.data_len = len(dmail_bytes) dw.data_enc = m tb = mp.TargetedBlock() tb.target_key = target_key tb.noonce = int(0).to_bytes(64, "big") tb.block = dw tb_data = tb.encode() tb_header = tb_data[:mp.TargetedBlock.BLOCK_OFFSET] if log.isEnabledFor(logging.INFO): log.info(\ "Attempting work on dmail (target=[{}], difficulty=[{}])."\ .format(target, difficulty)) def threadcall(): return brute.generate_targeted_block(\ target_key, difficulty, tb_header,\ mp.TargetedBlock.NOONCE_OFFSET,\ mp.TargetedBlock.NOONCE_SIZE) noonce_bytes = yield from self.loop.run_in_executor(None, threadcall) if log.isEnabledFor(logging.INFO): log.info("Work found noonce [{}].".format(noonce_bytes)) mp.TargetedBlock.set_noonce(tb_data, noonce_bytes) if log.isEnabledFor(logging.INFO): mp.TargetedBlock.set_noonce(tb_header, noonce_bytes) log.info("hash=[{}]."\ .format(mbase32.encode(enc.generate_ID(tb_header)))) key = None def key_callback(val): nonlocal key key = val log.info("Sending dmail to the network.") if log.isEnabledFor(logging.DEBUG): log.debug("dmail block data=[\n{}]."\ .format(mutil.hex_dump(tb_data))) total_storing = 0 retry = 0 while True: storing_nodes = yield from\ self.task_engine.send_store_targeted_data(\ tb_data, store_key=True, key_callback=key_callback,\ retry_factor=retry * 10) total_storing += storing_nodes if total_storing >= 3: break if retry > 32: break elif retry > 3: yield from asyncio.sleep(1) retry += 1 key_enc = mbase32.encode(key) id_enc = mbase32.encode(enc.generate_ID(key)) if log.isEnabledFor(logging.INFO): log.info("Dmail sent; key=[{}], id=[{}], storing_nodes=[{}]."\ .format(key_enc, id_enc, total_storing)) return total_storing
def scan_dmail_address(self, addr, significant_bits, key_callback=None): addr_enc = mbase32.encode(addr) if log.isEnabledFor(logging.INFO): log.info("Scanning dmail [{}].".format(addr_enc)) def dbcall(): with self.db.open_session() as sess: q = sess.query(db.DmailAddress)\ .filter(db.DmailAddress.site_key == addr) dmail_address = q.first() if dmail_address: dmail_address.keys sess.expunge_all() return dmail_address dmail_address = yield from self.loop.run_in_executor(None, dbcall) if dmail_address: log.info("Found DmailAddress locally, using local settings.") target = dmail_address.keys[0].target_key significant_bits = dmail_address.keys[0].difficulty else: log.info("DmailAddress not found locally, fetching settings from"\ " the network.") dsites = yield from\ self.fetch_recipient_dmail_sites(\ [(addr_enc, addr, significant_bits)]) if not dsites: raise DmailException("Dmail site not found.") dsite = dsites[0] target = dsite.root["target"] significant_bits = dsite.root["difficulty"] target = mbase32.decode(target) start = target while True: data_rw = yield from self.task_engine.send_find_key(\ start, target_key=target, significant_bits=significant_bits,\ retry_factor=100) key = data_rw.data_key if not key: break if log.isEnabledFor(logging.INFO): log.info("Found dmail key: [{}].".format(mbase32.encode(key))) if key_callback: key_callback(key) start = key
def _send_dmail(self, from_asymkey, recipient, dmail_bytes, signature): assert type(recipient) is DmailSite # Read in recipient DmailSite. root = recipient.root sse = sshtype.parseMpint(base58.decode(root["sse"]))[1] target_enc = root["target"] difficulty = root["difficulty"] # Calculate a shared secret. dh = dhgroup14.DhGroup14() dh.generate_x() dh.generate_e() dh.f = sse k = dh.calculate_k() target_key = mbase32.decode(target_enc) key = self._generate_encryption_key(target_key, k) # Encrypt the Dmail bytes. m, r = enc.encrypt_data_block(dmail_bytes, key) if m: if r: m = m + r else: m = r # Store it in a DmailWrapper. dw = DmailWrapper() dw.ssm = _dh_method_name dw.sse = sse dw.ssf = dh.e dw.data_len = len(dmail_bytes) dw.data_enc = m # Store the DmailWrapper in a TargetedBlock. tb = mp.TargetedBlock() tb.target_key = target_key tb.nonce = int(0).to_bytes(64, "big") tb.block = dw tb_data = tb.encode() tb_header = tb_data[:mp.TargetedBlock.BLOCK_OFFSET] # Do the POW on the TargetedBlock. if log.isEnabledFor(logging.INFO): log.info(\ "Attempting work on dmail (target=[{}], difficulty=[{}])."\ .format(target_enc, difficulty)) def threadcall(): return brute.generate_targeted_block(\ target_key, difficulty, tb_header,\ mp.TargetedBlock.NOONCE_OFFSET,\ mp.TargetedBlock.NOONCE_SIZE) nonce_bytes = yield from self.loop.run_in_executor(None, threadcall) if log.isEnabledFor(logging.INFO): log.info("Work found nonce [{}].".format(nonce_bytes)) mp.TargetedBlock.set_nonce(tb_data, nonce_bytes) if log.isEnabledFor(logging.INFO): mp.TargetedBlock.set_nonce(tb_header, nonce_bytes) log.info("Message key=[{}]."\ .format(mbase32.encode(enc.generate_ID(tb_header)))) key = None def key_callback(val): nonlocal key key = val if log.isEnabledFor(logging.DEBUG): log.debug("TargetedBlock dump=[\n{}]."\ .format(mutil.hex_dump(tb_data))) # Upload the TargetedBlock to the network. log.info("Sending dmail to the network.") total_storing = 0 retry = 0 while True: storing_nodes = yield from\ self.task_engine.send_store_targeted_data(\ tb_data, store_key=True, key_callback=key_callback,\ retry_factor=retry * 10) total_storing += storing_nodes if total_storing >= 3: break if retry > 32: break elif retry > 3: yield from asyncio.sleep(1) retry += 1 key_enc = mbase32.encode(key) id_enc = mbase32.encode(enc.generate_ID(key)) if log.isEnabledFor(logging.INFO): log.info("Dmail sent; key=[{}], id=[{}], storing_nodes=[{}]."\ .format(key_enc, id_enc, total_storing)) return total_storing
def _list_dmails_for_tag(dispatcher, addr, tag): msgs = yield from _load_dmails_for_tag(dispatcher, addr, tag) if type(addr) is str: addr_enc = addr else: addr_enc = mbase32.decode(addr) if not msgs: dispatcher.send_partial_content('<tr><td colspan="6">No messages.</td><tr></table>') return row_template = templates.dmail_msg_list_list_row[0] show_sender = tag not in ("Outbox", "Sent", "Drafts") for msg in msgs: unread = "" if msg.read else "new-mail" mail_icon = "new-mail-icon" if unread else "mail-icon" subject = msg.subject if subject: subject = subject.replace('"', """) else: subject = "[no subject]" safe_reply_subject = generate_safe_reply_subject(msg) if show_sender: addr_key = msg.sender_dmail_key if addr_key: addr_key_enc = mbase32.encode(addr_key) if msg.sender_valid: addr_value = addr_key_enc else: addr_value = '<span class="strikethrough">' + addr_key_enc + "</span>" else: addr_value = None else: addr_key = msg.destination_dmail_key if addr_key: addr_value = mbase32.encode(addr_key) else: addr_value = None if not addr_value: addr_value = "[Anonymous]" row = row_template.format( csrf_token=dispatcher.client_engine.csrf_token, mail_icon=mail_icon, tag=tag, unread=unread, addr=addr_enc, msg_id=msg.id, subject=subject, safe_reply_subject=safe_reply_subject, sender=addr_value, timestamp=mutil.format_human_no_ms_datetime(msg.date), ) dispatcher.send_partial_content(row)
def __main(): global loop log.info("mcc running.") parser = argparse.ArgumentParser() parser.add_argument(\ "--address",\ help="The address of the Morphis node to connect to.",\ default="127.0.0.1:4250") parser.add_argument(\ "--create-dmail",\ help="Generate and upload a new dmail site.",\ action="store_true") parser.add_argument(\ "--dburl",\ help="Specify the database url to use.") parser.add_argument(\ "--fetch-dmail", help="Fetch dmail for specified key_id.") parser.add_argument(\ "-i",\ help="Read file as stdin.") parser.add_argument("--nn", type=int,\ help="Node instance number.") parser.add_argument(\ "--prefix",\ help="Specify the prefix for various things (currently --create-dmail"\ ").") parser.add_argument(\ "--scan-dmail",\ help="Scan the network for available dmails.") parser.add_argument(\ "--send-dmail",\ help="Send stdin as a dmail with the specified subject. The"\ " sender and recipients may be specified at the beginning of the"\ " data as with email headers: 'from: ' and 'to: '.") parser.add_argument(\ "--stat",\ help="Report node status.",\ action="store_true") parser.add_argument("-l", dest="logconf",\ help="Specify alternate logging.ini [IF SPECIFIED, THIS MUST BE THE"\ " FIRST PARAMETER!].") parser.add_argument(\ "--dmail-target",\ help="Specify the dmail target to validate dmail against.") parser.add_argument(\ "-x",\ help="Specify the x (Diffie-Hellman private secret) to use.") args = parser.parse_args() # Load or generate client mcc key. key_filename = "data/mcc_key-rsa.mnk" if os.path.exists(key_filename): log.info("mcc private key file found, loading.") client_key = rsakey.RsaKey(filename=key_filename) else: log.info("mcc private key file missing, generating.") client_key = rsakey.RsaKey.generate(bits=4096) client_key.write_private_key_file(key_filename) # Connect a Morphis Client (lightweight Node) instance. mc = client.Client(loop, client_key=client_key, address=args.address) r = yield from mc.connect() if not r: log.warning("Connection failed; exiting.") loop.stop() return dbase = init_db(args) de = dmail.DmailEngine(mc, dbase) log.info("Processing command requests...") if args.stat: r = yield from mc.send_command("stat") print(r.decode("UTF-8"), end='') if args.create_dmail: log.info("Creating and uploading dmail site.") privkey, data_key, dms, storing_nodes =\ yield from de.generate_dmail_address(args.prefix) print("privkey: {}".format(base58.encode(privkey._encode_key()))) print("x: {}".format(base58.encode(sshtype.encodeMpint(dms.dh.x)))) print("dmail address: {}".format(mbase32.encode(data_key))) print("storing_nodes=[{}]."\ .format(base58.encode(privkey._encode_key()))) if args.send_dmail: log.info("Sending dmail.") if args.i: with open(args.i, "rb") as fh: dmail_data = fh.read().decode() else: dmail_data = stdin.read() if log.isEnabledFor(logging.DEBUG): log.debug("dmail_data=[{}].".format(dmail_data)) yield from de.send_dmail_text(args.send_dmail, dmail_data) if args.scan_dmail: log.info("Scanning dmail address.") addr, sig_bits = mutil.decode_key(args.scan_dmail) def key_callback(key): print("dmail key: [{}].".format(mbase32.encode(key))) yield from de.scan_dmail_address(\ addr, sig_bits, key_callback=key_callback) if args.fetch_dmail: log.info("Fetching dmail for key=[{}].".format(args.fetch_dmail)) key = mbase32.decode(args.fetch_dmail) if args.x: l, x_int = sshtype.parseMpint(base58.decode(args.x)) else: x_int = None dmail_target = args.dmail_target dm, valid_sig = yield from de.fetch_dmail(key, x_int, dmail_target) if not dm: raise Exception("No dmail found.") if not x_int: print("Encrypted dmail data=[\n{}].".format(mutil.hex_dump(dm))) else: print("Subject: {}\n".format(dm.subject)) if dm.sender_pubkey: print("From: {}"\ .format(mbase32.encode(enc.generate_ID(dm.sender_pubkey)))) i = 0 for part in dm.parts: print("DmailPart[{}]:\n mime-type=[{}]\n data=[{}]\n"\ .format(i, part.mime_type, part.data)) i += 1 log.info("Disconnecting.") yield from mc.disconnect() loop.stop()
def serve_get(dispatcher, rpath): global top_tags log.info("Service .dmail request.") req = rpath[len(s_dmail) :] # if log.isEnabledFor(logging.INFO): # log.info("req=[{}].".format(req)) if req == "" or req == "/" or req == "/goto_new_mail" or req.startswith("/wrapper/"): cacheable = False if req == "/goto_new_mail": tag = "Inbox" addr = yield from _load_first_address_with_new_mail(dispatcher) if addr: log.info("NEW") addr_enc = mbase32.encode(addr.site_key) else: log.info("NO NEW") addr_enc = "" qline = None elif req.startswith("/wrapper/"): params = req[9:] pq = params.find("?") if pq != -1: qline = params[pq + 1 :] params = params[:pq] else: qline = None p0 = params.find("/") if p0 == -1: p0 = len(params) tag = "Inbox" else: tag = params[p0 + 1 :] addr_enc = params[:p0] if addr_enc: cacheable = True if dispatcher.handle_cache(req): return else: tag = "Inbox" addr_enc = "" qline = None if not addr_enc: dmail_address = yield from _load_default_dmail_address(dispatcher) if dmail_address: addr_enc = mbase32.encode(dmail_address.site_key) msg_list = None if qline: eparams = parse_qs(qline) msg_list = eparams.get("msg_list") if msg_list: msg_list = msg_list[0] if not msg_list: msg_list = "morphis://.dmail/msg_list/" + addr_enc + "/" + tag template = templates.dmail_page_wrapper[0] template = template.format(tag=tag, addr=addr_enc, msg_list_iframe_url=msg_list) if cacheable: dispatcher.send_content([template, req]) else: dispatcher.send_content(template) return if req == "/style.css": dispatcher.send_content(templates.dmail_css, content_type="text/css") elif req == "/logo": template = templates.dmail_logo[0] current_version = dispatcher.node.morphis_version latest_version_number = dispatcher.latest_version_number if latest_version_number and current_version != latest_version_number: version_str = '<span class="strikethrough nomargin">{}</span>]' ' [<a href="{}{}">GET {}</a>'.format( current_version, dispatcher.handler.maalstroom_url_prefix_str, "sp1nara3xhndtgswh7fznt414we4mi3y6kdwbkz4jmt8ocb6" "x4w1faqjotjkcrefta11swe3h53dt6oru3r13t667pr7" "cpe3ocxeuma/latest_version", latest_version_number, ) else: version_str = current_version connections = dispatcher.connection_count if connections == 1: connection_str = "1 Connection" else: connection_str = str(connections) + " Connections" template = template.format(version=version_str, connections=connection_str) dispatcher.send_content(template) elif req.startswith("/nav/"): params = req[5:] p0 = params.index("/") addr_enc = params[:p0] tag = params[p0 + 1 :] template = templates.dmail_nav[0] template = template.format(csrf_token=dispatcher.client_engine.csrf_token, addr=addr_enc, tag=tag) dispatcher.send_content(template) elif req.startswith("/aside/"): params = req[7:] p0 = params.index("/") addr_enc = params[:p0] tag = params[p0 + 1 :] addr = mbase32.decode(addr_enc) template = templates.dmail_aside[0] fmt = {} for top_tag in top_tags: active = top_tag == tag unread_count = yield from _count_unread_dmails(dispatcher, addr, top_tag) fmt[top_tag + "_active"] = "active-mailbox" if active else "" fmt[top_tag + "_unread_count"] = unread_count if unread_count else "" fmt[top_tag + "_unread_class"] = ("active-notify" if active else "inactive-notify") if unread_count else "" tags = yield from _load_tags(dispatcher, top_tags) tag_rows = [] unquoted_tag = unquote(tag) for tag in tags: if unquoted_tag == tag.name: active = " active_tag" else: active = "" row = ( '<li class="bullet{active}"><span class="mailbox-pad">' '<a href="morphis://.dmail/wrapper/{addr}/{tag}">{tag}</a>' "</span></li>".format(active=active, addr=addr_enc, tag=tag.name) ) tag_rows.append(row) template = template.format( csrf_token=dispatcher.client_engine.csrf_token, addr=addr_enc, tag=tag, tag_rows="".join(tag_rows), **fmt ) acharset = dispatcher.get_accept_charset() dispatcher.send_content(template) elif req.startswith("/msg_list/list/"): params = req[15:] p0 = params.index("/") addr_enc = params[:p0] tag = unquote(params[p0 + 1 :]) template = templates.dmail_msg_list_list_start[0] addr_heading = "TO" if tag in ("Outbox", "Sent", "Drafts") else "FROM" if tag == "Inbox" or tag == "": unread_check = '<meta target="self" http-equiv="refresh" content="60"/>' else: unread_check = "" template = template.format(unread_check=unread_check, addr_heading=addr_heading) acharset = dispatcher.get_accept_charset() dispatcher.send_partial_content(template, True, content_type="text/html; charset={}".format(acharset)) yield from _list_dmails_for_tag(dispatcher, addr_enc, unquote(tag)) dispatcher.send_partial_content(templates.dmail_msg_list_list_end[0]) dispatcher.end_partial_content() elif req.startswith("/msg_list/"): params = req[10:] p0 = params.index("/") addr_enc = params[:p0] tag = params[p0 + 1 :] if dispatcher.handle_cache(req): return if tag == "Trash": empty_trash_button_class = "link-button" else: empty_trash_button_class = "display_none" template = templates.dmail_msg_list[0] template = template.format( csrf_token=dispatcher.client_engine.csrf_token, tag=unquote(tag), addr=addr_enc, empty_trash_button_class=empty_trash_button_class, ) dispatcher.send_content([template, req]) elif req == "/new_mail": template = templates.dmail_new_mail[0] unread_count = yield from _count_unread_dmails(dispatcher) template = template.format(unread_count=unread_count) dispatcher.send_content(template) elif req.startswith("/images/"): dispatcher.send_content(templates.imgs[req[8:]]) elif req.startswith("/tag/view/list/"): params = req[15:] p0 = params.index("/") tag = params[:p0] addr_enc = params[p0 + 1 :] if log.isEnabledFor(logging.INFO): log.info("Viewing dmails with tag [{}] for address [{}].".format(tag, addr_enc)) start = templates.dmail_tag_view_list_start.replace(b"${TAG_NAME}", tag.encode()) # FIXME: This is getting inefficient now, maybe time for Flask or # something like it. Maybe we can use just it's template renderer. start = start.replace(b"${DMAIL_ADDRESS}", addr_enc.encode()) start = start.replace(b"${DMAIL_ADDRESS2}", "{}...".format(addr_enc[:32]).encode()) acharset = dispatcher.get_accept_charset() dispatcher.send_partial_content(start, True, content_type="text/html; charset={}".format(acharset)) yield from _list_dmails_for_tag(dispatcher, mbase32.decode(addr_enc), tag) dispatcher.send_partial_content(templates.dmail_tag_view_list_end) dispatcher.end_partial_content() elif req.startswith("/read/content/"): params = req[14:] msg_dbid = params dm = yield from _load_dmail(dispatcher, msg_dbid, fetch_parts=True) dmail_text = _format_dmail_content(dm) acharset = dispatcher.get_accept_charset() dispatcher.send_content(dmail_text.encode(acharset), content_type="text/plain; charset={}".format(acharset)) elif req.startswith("/read/subject/"): params = req[14:] msg_dbid = params dm = yield from _load_dmail(dispatcher, msg_dbid) acharset = dispatcher.get_accept_charset() dispatcher.send_content(dm.subject.encode(acharset), content_type="text/plain; charset={}".format(acharset)) elif req.startswith("/read/"): params = req[6:] p0 = params.index("/") p1 = params.index("/", p0 + 1) addr_enc = params[:p0] tag = params[p0 + 1 : p1] msg_dbid = params[p1 + 1 :] def processor(sess, dm): dm.read = True return True dm = yield from _process_dmail_message(dispatcher, msg_dbid, processor, fetch_parts=True, fetch_tags=True) if dm.hidden: trash_msg = "REMOVE FROM TRASH" else: trash_msg = "MOVE TO TRASH" safe_reply_subject = generate_safe_reply_subject(dm) if dm.sender_dmail_key: sender_addr = mbase32.encode(dm.sender_dmail_key) if dm.sender_valid: sender_class = "valid_sender" else: sender_class = "invalid_sender" else: sender_addr = "[Anonymous]" sender_class = "valid_sender" if dm.destination_dmail_key: dest_addr_enc = mbase32.encode(dm.destination_dmail_key) dest_class = "" else: dest_addr_enc = "" dest_class = " display_none" unquoted_tag = unquote(tag) existing_tag_rows = [] if len(dm.tags) > 1: remove_tag_class = "" for etag in dm.tags: if etag.name == unquoted_tag: selected = "selected " else: selected = "" row = '<option {selected}value"{tag_id}">{tag_name}</option>'.format( selected=selected, tag_id=etag.id, tag_name=etag.name ) existing_tag_rows.append(row) else: remove_tag_class = "display_none" current_tag_names = [x.name for x in dm.tags] current_tag_names.extend(top_tags) current_tag_names.remove("Inbox") tags = yield from _load_tags(dispatcher, current_tag_names) available_tag_rows = [] for atag in tags: row = '<option value"{tag_id}">{tag_name}</option>'.format(tag_id=atag.id, tag_name=atag.name) available_tag_rows.append(row) template = templates.dmail_read[0] template = template.format( csrf_token=dispatcher.client_engine.csrf_token, addr=addr_enc, tag=tag, safe_reply_subject=safe_reply_subject, trash_msg=trash_msg, msg_id=msg_dbid, sender_class=sender_class, sender=sender_addr, dest_class=dest_class, dest_addr=dest_addr_enc, date=mutil.format_human_no_ms_datetime(dm.date), remove_tag_class=remove_tag_class, existing_tags="".join(existing_tag_rows), available_tags="".join(available_tag_rows), ) dispatcher.send_content(template) elif req.startswith("/compose/"): if len(req) > 8 and req[8] == "/": params = req[9:] else: params = req[8:] p0 = params.find("?") if p0 != -1: eparams = parse_qs(params[p0 + 1 :]) subject = eparams.get("subject") if subject: subject = subject[0].replace('"', """) else: subject = "" sender_addr_enc = eparams.get("sender") if sender_addr_enc: sender_addr_enc = sender_addr_enc[0] else: sender_addr_enc = "" message_text = eparams.get("message") if message_text: message_text = message_text[0] else: message_text = "" else: subject = "" sender_addr_enc = "" message_text = "" p0 = len(params) dest_addr_enc = params[:p0] autofocus_fields = {"dest_addr_autofocus": "", "subject_autofocus": "", "message_text_autofocus": ""} if not dest_addr_enc: autofocus_fields["dest_addr_autofocus"] = " autofocus" elif not subject: autofocus_fields["subject_autofocus"] = " autofocus" elif not message_text: autofocus_fields["message_text_autofocus"] = " autofocus" addrs = yield from _list_dmail_addresses(dispatcher) if sender_addr_enc: sender_addr = mbase32.decode(sender_addr_enc) default_id = None else: sender_addr = None default_id = yield from _load_default_dmail_address_id(dispatcher) if not default_id: owner_if_anon_id = "" from_addr_options = [] for addr in addrs: if sender_addr: selected = addr.site_key.startswith(sender_addr) elif default_id: selected = addr.id == default_id else: selected = False if selected: option = '<option value="{}" selected>{}</option>' owner_if_anon_id = addr.id else: option = '<option value="{}">{}</option>' addr_enc = mbase32.encode(addr.site_key) from_addr_options.append(option.format(addr.id, addr_enc)) from_addr_options.append("<option value=" ">[Anonymous]</option>") from_addr_options = "".join(from_addr_options) template = templates.dmail_compose[0] template = template.format( csrf_token=dispatcher.client_engine.csrf_token, delete_class="display_none", owner_if_anon=owner_if_anon_id, from_addr_options=from_addr_options, dest_addr=dest_addr_enc, subject=subject, message_text=message_text, **autofocus_fields ) acharset = dispatcher.get_accept_charset() dispatcher.send_content(template, content_type="text/html; charset={}".format(acharset)) elif req == "/address_list": addrs = yield from _list_dmail_addresses(dispatcher) default_id = yield from _load_default_dmail_address_id(dispatcher) csrf_token = dispatcher.client_engine.csrf_token row_template = templates.dmail_address_list_row[0] rows = [] for addr in addrs: site_key_enc = mbase32.encode(addr.site_key) if default_id and addr.id == default_id: set_default_class = "hidden" else: set_default_class = "" if addr.scan_interval: autoscan_link_text = "disable autoscan" autoscan_interval = 0 else: autoscan_link_text = "enable autoscan" autoscan_interval = 60 resp = row_template.format( csrf_token=csrf_token, addr=site_key_enc, addr_dbid=addr.id, set_default_class=set_default_class, autoscan_link_text=autoscan_link_text, autoscan_interval=autoscan_interval, ) rows.append(resp) rows_content = "".join(rows) template = templates.dmail_address_list[0] template = template.format(address_list=rows_content) dispatcher.send_content(template) # Actions. elif req.startswith("/create_tag?"): query = req[12:] qdict = parse_qs(query, keep_blank_values=True) csrf_token = qdict["csrf_token"][0] if not dispatcher.check_csrf_token(csrf_token): return tag_name = qdict["tag_name"][0] if not tag_name: dispatcher.send_204() return r = yield from _create_tag(dispatcher, tag_name) redirect = qdict.get("redirect") if r and redirect: dispatcher.send_301(redirect[0]) else: dispatcher.send_204() elif req.startswith("/modify_message_tag?"): query = req[20:] qdict = parse_qs(query, keep_blank_values=True) csrf_token = qdict["csrf_token"][0] if not dispatcher.check_csrf_token(csrf_token): return submit = qdict["submit"][0] def processor(sess, dm): if submit == "add_tag": dmail.attach_dmail_tag(sess, dm, qdict["add_tag"][0]) return True elif submit == "move_to_tag": dm.tags.clear() dmail.attach_dmail_tag(sess, dm, qdict["add_tag"][0]) return True elif submit == "remove_tag": if len(dm.tags) <= 1: return False remove_tag = qdict["remove_tag"][0] remove_target = None for tag in dm.tags: if tag.name == remove_tag: remove_target = tag break dm.tags.remove(remove_target) return True else: return False msg_id = qdict["msg_id"][0] dm = yield from _process_dmail_message(dispatcher, msg_id, processor, fetch_tags=True) redirect = qdict.get("redirect") if redirect: dispatcher.send_301(redirect[0]) else: dispatcher.send_204() elif req.startswith("/refresh/"): params = req[9:] p0 = params.index("/") csrf_token = params[:p0] addr_enc = params[p0 + 1 :] if not dispatcher.check_csrf_token(csrf_token): return dmail_address = yield from _load_dmail_address(dispatcher, site_key=mbase32.decode(addr_enc), fetch_keys=True) dispatcher.client_engine.trigger_dmail_scan(dmail_address) dispatcher.send_204() elif req.startswith("/toggle_read/"): params = req[13:] pq = params.find("?redirect=") if pq != -1: redirect = params[pq + 10 :] else: redirect = None pq = len(params) p0 = params.index("/", 0, pq) csrf_token = params[:p0] msg_dbid = params[p0 + 1 : pq] if not dispatcher.check_csrf_token(csrf_token): return def processor(sess, dm): dm.read = not dm.read return True yield from _process_dmail_message(dispatcher, msg_dbid, processor) if redirect: dispatcher.send_301(redirect) else: dispatcher.send_204() elif req.startswith("/toggle_trashed/"): params = req[16:] pq = params.find("?redirect=") if pq != -1: redirect = params[pq + 10 :] else: redirect = None pq = len(params) p0 = params.index("/", 0, pq) csrf_token = params[:p0] msg_dbid = params[p0 + 1 : pq] if not dispatcher.check_csrf_token(csrf_token): return def processor(sess, dm): dm.hidden = not dm.hidden return True yield from _process_dmail_message(dispatcher, msg_dbid, processor) if redirect: dispatcher.send_301(redirect) else: dispatcher.send_204() elif req.startswith("/set_autoscan/"): params = req[14:] pq = params.find("?redirect=") if pq != -1: redirect = params[pq + 10 :] else: redirect = None pq = len(params) p0 = params.index("/", 0, pq) p1 = params.index("/", p0 + 1, pq) csrf_token = params[:p0] addr_id = int(params[p0 + 1 : p1]) interval = int(params[p1 + 1 : pq]) if not dispatcher.check_csrf_token(csrf_token): return def processor(sess, addr): addr.scan_interval = interval return True addr = yield from _process_dmail_address(dispatcher, processor, addr_id, fetch_keys=True) dispatcher.client_engine.update_dmail_autoscan(addr) if redirect: dispatcher.send_301(redirect) else: dispatcher.send_204() elif req.startswith("/empty_trash/"): params = req[13:] pq = params.find("?redirect=") if pq != -1: redirect = params[pq + 10 :] else: redirect = None pq = len(params) p0 = params.index("/", 0, pq) csrf_token = params[:p0] addr_enc = params[p0 + 1 : pq] if not dispatcher.check_csrf_token(csrf_token): return yield from _empty_trash(dispatcher, addr_enc) if redirect: dispatcher.send_301(redirect) else: dispatcher.send_204() elif req.startswith("/make_address_default/"): params = req[22:] pq = params.find("?redirect=") if pq != -1: redirect = params[pq + 10 :] else: redirect = None pq = len(params) p0 = params.index("/") csrf_token = params[:p0] addr_dbid = params[p0 + 1 : pq] if not dispatcher.check_csrf_token(csrf_token): return yield from _set_default_dmail_address(dispatcher, addr_dbid) if redirect: dispatcher.send_301(redirect) else: dispatcher.send_204() ##### OLD: elif req == "/create_address": if dispatcher.handle_cache(req): return template = templates.dmail_create_address[0] template = template.format(csrf_token=dispatcher.client_engine.csrf_token) dispatcher.send_content([template, req]) elif req.startswith("/address_config/"): params = req[16:] addr_enc = params dmail_address = yield from _load_dmail_address(dispatcher, site_key=mbase32.decode(addr_enc), fetch_keys=True) content = templates.dmail_address_config[0] content = content.replace("{csrf_token}", dispatcher.client_engine.csrf_token) content = content.replace("${DIFFICULTY}", str(dmail_address.keys[0].difficulty)) content = content.replace("${DMAIL_ADDRESS_SHORT}", addr_enc[:32]) content = content.replace("${DMAIL_ADDRESS}", addr_enc) content = content.replace("${PRIVATE_KEY}", base58.encode(dmail_address.site_privatekey)) content = content.replace("${X}", base58.encode(dmail_address.keys[0].x)) content = content.replace("${TARGET_KEY}", base58.encode(dmail_address.keys[0].target_key)) dispatcher.send_content([content, None]) ##### OLD ACTIONS: elif req.startswith("/create_address/make_it_so?"): query = req[27:] qdict = parse_qs(query, keep_blank_values=True) prefix = qdict["prefix"][0] difficulty = int(qdict["difficulty"][0]) csrf_token = qdict["csrf_token"][0] if not dispatcher.check_csrf_token(csrf_token): return log.info("prefix=[{}].".format(prefix)) privkey, dmail_key, dms, storing_nodes = yield from _create_dmail_address(dispatcher, prefix, difficulty) dmail_key_enc = mbase32.encode(dmail_key) dispatcher.send_partial_content(templates.dmail_frame_start, True) if storing_nodes: dispatcher.send_partial_content(b"SUCCESS<br/>") else: dispatcher.send_partial_content( "PARTIAL SUCCESS<br/>" "<p>Your Dmail site was generated successfully; however," " it failed to be stored on the network. To remedy this," " simply go to your Dmail address page and click the" ' [<a target="_self" href="morphis://.dmail/' 'address_config/{}">Address Settings</a>] link, and then' ' click the "Republish Dmail Site" button.</p>'.format(dmail_key_enc).encode() ) dispatcher.send_partial_content( '<p>New dmail address: <a href="morphis://.dmail/wrapper/' '{addr_enc}">{addr_enc}</a></p>'.format(addr_enc=dmail_key_enc).encode() ) dispatcher.send_partial_content(templates.dmail_frame_end) dispatcher.end_partial_content() elif req.startswith("/save_address_config/publish?"): query = req[29:] qdict = parse_qs(query, keep_blank_values=True) addr_enc = qdict["dmail_address"][0] difficulty = qdict["difficulty"][0] csrf_token = qdict["csrf_token"][0] if not dispatcher.check_csrf_token(csrf_token): return def processor(sess, dmail_address): if difficulty != dmail_address.keys[0].difficulty: dmail_address.keys[0].difficulty = difficulty return True else: return False dmail_address = yield from _process_dmail_address( dispatcher, processor, site_key=mbase32.decode(addr_enc), fetch_keys=True ) dh = dhgroup14.DhGroup14() dh.x = sshtype.parseMpint(dmail_address.keys[0].x)[1] dh.generate_e() dms = dmail.DmailSite() root = dms.root root["ssm"] = "mdh-v1" root["sse"] = base58.encode(sshtype.encodeMpint(dh.e)) root["target"] = mbase32.encode(dmail_address.keys[0].target_key) root["difficulty"] = int(difficulty) private_key = rsakey.RsaKey(privdata=dmail_address.site_privatekey) de = dmail.DmailEngine(dispatcher.node.chord_engine.tasks, dispatcher.node.db) storing_nodes = yield from de.publish_dmail_site(private_key, dms) if storing_nodes: dispatcher.send_content( templates.dmail_addr_settings_edit_success_content[0].format(addr_enc, addr_enc[:32]).encode() ) else: dispatcher.send_content( templates.dmail_addr_settings_edit_fail_content[0].format(addr_enc, addr_enc[:32]).encode() ) else: dispatcher.send_error(errcode=400)
def __serve_get(handler, rpath, done_event): if len(rpath) == len(s_dmail): handler._send_content(pages.dmail_page_content) else: req = rpath[len(s_dmail):] log.info("req=[{}].".format(req)) if req == "/css": handler._send_content(\ pages.dmail_css_content, content_type="text/css") elif req == "/address_list": handler._send_partial_content( pages.dmail_page_content__f1_start, True) site_keys = yield from _list_dmail_addresses(handler) for dbid, site_key in site_keys: site_key_enc = mbase32.encode(site_key) resp = """<span class="nowrap">[<a href="addr/{}">view</a>]"""\ """ {}</span><br/>"""\ .format(site_key_enc, site_key_enc) handler._send_partial_content(resp) handler._send_partial_content(pages.dmail_page_content__f1_end) handler._end_partial_content() elif req.startswith("/compose/form"): dest_addr_enc = req[14:] if len(req) > 14 else "" handler._send_partial_content(\ pages.dmail_compose_dmail_form_start, True) site_keys = yield from _list_dmail_addresses(handler) for dbid, site_key in site_keys: site_key_enc = mbase32.encode(site_key) sender_element = """<option value="{}">{}</option>"""\ .format(dbid, site_key_enc) handler._send_partial_content(sender_element) handler._send_partial_content(\ "<option value="">[Anonymous]</option>") handler._send_partial_content(\ pages.dmail_compose_dmail_form_end.replace(\ b"${DEST_ADDR}", dest_addr_enc.encode())) handler._end_partial_content() elif req.startswith("/compose"): from_addr = req[9:] if len(req) > 9 else "" if from_addr: iframe_src = "../compose/form/{}".format(from_addr).encode() else: iframe_src = "compose/form".encode() content = pages.dmail_compose_dmail_content[0].replace(\ b"${IFRAME_SRC}", iframe_src) handler._send_content([content, None]) elif req.startswith("/addr/view/"): addr_enc = req[11:] start = pages.dmail_addr_view_start.replace(\ b"${DMAIL_ADDRESS}", addr_enc.encode()) start = start.replace(\ b"${DMAIL_ADDRESS_SHORT}", addr_enc[:32].encode()) handler._send_partial_content(start, True) handler._send_partial_content(pages.dmail_addr_view_end) handler._end_partial_content() elif req.startswith("/addr/settings/edit/publish?"): query = req[28:] qdict = urllib.parse.parse_qs(query, keep_blank_values=True) addr_enc = qdict["dmail_address"][0] difficulty = qdict["difficulty"][0] def processor(dmail_address): if difficulty != dmail_address.keys[0].difficulty: dmail_address.keys[0].difficulty = difficulty return True else: return False dmail_address = yield from\ _process_dmail_address(\ handler, mbase32.decode(addr_enc), processor) dh = dhgroup14.DhGroup14() dh.x = sshtype.parseMpint(dmail_address.keys[0].x)[1] dh.generate_e() dms = dmail.DmailSite() root = dms.root root["target"] =\ mbase32.encode(dmail_address.keys[0].target_key) root["difficulty"] = int(difficulty) root["ssm"] = "mdh-v1" root["sse"] = base58.encode(sshtype.encodeMpint(dh.e)) private_key = rsakey.RsaKey(privdata=dmail_address.site_privatekey) r = yield from\ handler.node.chord_engine.tasks.send_store_updateable_key(\ dms.export(), private_key,\ version=int(time.time()*1000), store_key=True) handler._send_content(\ pages.dmail_addr_settings_edit_success_content[0]\ .format(addr_enc, addr_enc[:32]).encode()) elif req.startswith("/addr/settings/edit/"): addr_enc = req[20:] dmail_address = yield from\ _load_dmail_address(handler, mbase32.decode(addr_enc)) content = pages.dmail_addr_settings_edit_content[0].replace(\ b"${DIFFICULTY}",\ str(dmail_address.keys[0].difficulty).encode()) content = content.replace(\ b"${DMAIL_ADDRESS_SHORT}", addr_enc[:32].encode()) content = content.replace(\ b"${DMAIL_ADDRESS}", addr_enc.encode()) content = content.replace(\ b"${PRIVATE_KEY}",\ base58.encode(dmail_address.site_privatekey).encode()) content = content.replace(\ b"${X}", base58.encode(dmail_address.keys[0].x).encode()) content = content.replace(\ b"${TARGET_KEY}",\ base58.encode(dmail_address.keys[0].target_key).encode()) handler._send_content([content, None]) elif req.startswith("/addr/settings/"): addr_enc = req[15:] content = pages.dmail_addr_settings_content[0].replace(\ b"${IFRAME_SRC}",\ "edit/{}".format(addr_enc).encode()) handler._send_content([content, None]) elif req.startswith("/addr/"): addr_enc = req[6:] if log.isEnabledFor(logging.INFO): log.info("Viewing dmail address [{}].".format(addr_enc)) content = pages.dmail_address_page_content[0].replace(\ b"${IFRAME_SRC}", "view/{}".format(addr_enc).encode()) handler._send_content([content, None]) elif req.startswith("/tag/view/list/"): params = req[15:] p0 = params.index('/') tag = params[:p0] addr_enc = params[p0+1:] if log.isEnabledFor(logging.INFO): log.info("Viewing dmails with tag [{}] for address [{}]."\ .format(tag, addr_enc)) start = pages.dmail_tag_view_list_start.replace(\ b"${TAG_NAME}", tag.encode()) #FIXME: This is getting inefficient now, maybe time for Flask or # something like it. Maybe we can use just it's template renderer. start = start.replace(b"${DMAIL_ADDRESS}", addr_enc.encode()) start = start.replace(\ b"${DMAIL_ADDRESS2}",\ "{}...".format(addr_enc[:32]).encode()) handler._send_partial_content(start, True) yield from\ _list_dmails_for_tag(handler, mbase32.decode(addr_enc), tag) handler._send_partial_content(pages.dmail_tag_view_list_end) handler._end_partial_content() elif req.startswith("/tag/view/"): params = req[10:] content = pages.dmail_tag_view_content[0].replace(\ b"${IFRAME_SRC}", "../list/{}".format(params).encode()) handler._send_content(content) elif req.startswith("/scan/list/"): addr_enc = req[11:] if log.isEnabledFor(logging.INFO): log.info("Viewing inbox for dmail address [{}]."\ .format(addr_enc)) start = pages.dmail_inbox_start.replace(\ b"${DMAIL_ADDRESS}", addr_enc.encode()) start = start.replace(\ b"${DMAIL_ADDRESS2}", "{}...".format(addr_enc[:32]).encode()) handler._send_partial_content(start, True) addr, significant_bits = mutil.decode_key(addr_enc) yield from _scan_new_dmails(handler, addr, significant_bits) handler._send_partial_content(pages.dmail_inbox_end) handler._end_partial_content() elif req.startswith("/scan/"): addr_enc = req[6:] content = pages.dmail_address_page_content[0].replace(\ b"${IFRAME_SRC}", "list/{}".format(addr_enc).encode()) handler._send_content([content, None]) elif req.startswith("/fetch/view/"): keys = req[12:] p0 = keys.index('/') dmail_addr_enc = keys[:p0] dmail_key_enc = keys[p0+1:] dmail_addr = mbase32.decode(dmail_addr_enc) dmail_key = mbase32.decode(dmail_key_enc) dm = yield from _load_dmail(handler, dmail_key) if dm: valid_sig = dm.sender_valid else: dm, valid_sig =\ yield from _fetch_dmail(handler, dmail_addr, dmail_key) dmail_text = _format_dmail(dm, valid_sig) handler._send_content(\ dmail_text.encode(), content_type="text/plain") elif req.startswith("/fetch/panel/mark_as_read/"): req_data = req[26:] p0 = req_data.index('/') dmail_key_enc = req_data[p0+1:] dmail_key = mbase32.decode(dmail_key_enc) def processor(dmail): dmail.read = not dmail.read return True yield from _process_dmail_message(handler, dmail_key, processor) handler._send_204() elif req.startswith("/fetch/panel/trash/"): req_data = req[20:] p0 = req_data.index('/') dmail_key_enc = req_data[p0+1:] dmail_key = mbase32.decode(dmail_key_enc) def processor(dmail): dmail.hidden = not dmail.hidden return True yield from _process_dmail_message(handler, dmail_key, processor) handler._send_204() elif req.startswith("/fetch/panel/"): req_data = req[13:] content = pages.dmail_fetch_panel_content[0].replace(\ b"${DMAIL_IDS}", req_data.encode()) handler._send_content([content, None]) elif req.startswith("/fetch/wrapper/"): req_data = req[15:] content = pages.dmail_fetch_wrapper[0].replace(\ b"${IFRAME_SRC}",\ "../../view/{}"\ .format(req_data).encode()) #FIXME: This is getting inefficient now, maybe time for Flask or # something like it. Maybe we can use just it's template renderer. content = content.replace(\ b"${IFRAME2_SRC}",\ "../../panel/{}"\ .format(req_data).encode()) handler._send_content([content, None]) elif req.startswith("/fetch/"): req_data = req[7:] content = pages.dmail_address_page_content[0].replace(\ b"${IFRAME_SRC}", "../wrapper/{}".format(req_data).encode()) handler._send_content([content, None]) elif req == "/create_address": handler._send_content(pages.dmail_create_address_content) elif req == "/create_address/form": handler._send_content(pages.dmail_create_address_form_content) elif req.startswith("/create_address/make_it_so?"): query = req[27:] qdict = urllib.parse.parse_qs(query, keep_blank_values=True) prefix = qdict["prefix"][0] difficulty = int(qdict["difficulty"][0]) log.info("prefix=[{}].".format(prefix)) privkey, dmail_key, dms =\ yield from _create_dmail_address(handler, prefix, difficulty) dmail_key_enc = mbase32.encode(dmail_key) handler._send_partial_content(pages.dmail_frame_start, True) handler._send_partial_content(b"SUCCESS<br/>") handler._send_partial_content(\ """<p>New dmail address: <a href="../addr/{}">{}</a></p>"""\ .format(dmail_key_enc, dmail_key_enc).encode()) handler._send_partial_content(pages.dmail_frame_end) handler._end_partial_content() else: handler._handle_error()