def _decode_key(self, data): """ # private key file contains: # RSAPrivateKey = { version = 0, n, e, d, p, q, d mod p-1, d mod q-1, q**-1 mod p } try: keylist = BER(data).decode() except BERException: raise SshException('Unable to parse key file') if (type(keylist) is not list) or (len(keylist) < 4) or (keylist[0] != 0): raise SshException('Not a valid RSA private key file (bad ber encoding)') self.n = keylist[1] self.e = keylist[2] self.d = keylist[3] # not really needed self.p = keylist[4] self.q = keylist[5] self.size = util.bit_length(self.n) """ ver = struct.unpack("B", data[:1])[0] if ver != 1: raise SshException("Unsupported mnk version [{}].".format(ver)) i = 1 l, self.e = sshtype.parseMpint(data[i:]) i += l l, self.n = sshtype.parseMpint(data[i:]) i += l l, self.d = sshtype.parseMpint(data[i:]) i += l l, self.p = sshtype.parseMpint(data[i:]) i += l l, self.q = sshtype.parseMpint(data[i:])
def __init__(self, data=None, privdata=None, filename=None, password=None, vals=None, file_obj=None): self.n = None self.e = None self.d = None self.p = None self.q = None self.__public_key = None self.__public_key_bytes = None self.__private_key = None self.__rsassa_pss_signer = None self.__rsassa_pss_verifier = None if file_obj is not None: self._from_private_key(file_obj, password) return if filename is not None: self._from_private_key_file(filename, password) return if vals is not None: self.e, self.n = vals else: if data is None: if privdata is None: raise SshException('Key object may not be empty') else: self._decode_key(privdata) else: i, v = sshtype.parseString(data) if v != 'ssh-rsa': raise SshException('Invalid key') l, self.e = sshtype.parseMpint(data[i:]) i += l l, self.n = sshtype.parseMpint(data[i:]) self.size = util.bit_length(self.n)
def __init__(self, data=None, privdata=None, filename=None, password=None, vals=None, file_obj=None): self.n = None self.e = None self.d = None self.p = None self.q = None self.__public_key = None self.__private_key = None self.__rsassa_pss_signer = None self.__rsassa_pss_verifier = None if file_obj is not None: self._from_private_key(file_obj, password) return if filename is not None: self._from_private_key_file(filename, password) return if vals is not None: self.e, self.n = vals else: if data is None: if privdata is None: raise SshException("Key object may not be empty") else: self._decode_key(privdata) else: i, v = sshtype.parseString(data) if v != "ssh-rsa": raise SshException("Invalid key") l, self.e = sshtype.parseMpint(data[i:]) i += l l, self.n = sshtype.parseMpint(data[i:]) self.size = util.bit_length(self.n)
def _fetch_dmail(handler, dmail_addr, dmail_key): de =\ dmail.DmailEngine(handler.node.chord_engine.tasks, handler.node.db) if log.isEnabledFor(logging.INFO): dmail_key_enc = mbase32.encode(dmail_key) dmail_addr_enc = mbase32.encode(dmail_addr) log.info("Fetching dmail (key=[{}]) for address=[{}]."\ .format(dmail_key_enc, dmail_addr_enc)) dmail_address = yield from _load_dmail_address(handler, dmail_addr) dmail_key_obj = dmail_address.keys[0] target_key = dmail_key_obj.target_key x_bin = dmail_key_obj.x l, x = sshtype.parseMpint(x_bin) dm, valid_sig =\ yield from de.fetch_dmail(bytes(dmail_key), x, target_key) if not dm: handler._send_partial_content(\ "Dmail for key [{}] was not found."\ .format(dmail_key_enc)) return None, None return dm, valid_sig
def _dmail_auto_publish(self, dmail_address): data_rw = yield from self.engine.tasks.send_get_data(\ dmail_address.site_key, retry_factor=100) if data_rw.data: if log.isEnabledFor(logging.DEBUG): log.debug("Succeeded in fetching dmail site [{}]; won't"\ " auto-publish."\ .format(mbase32.encode(dmail_address.site_key))) return if log.isEnabledFor(logging.INFO): log.info("Failed to fetch dmail site [{}]; republishing."\ .format(mbase32.encode(dmail_address.site_key))) private_key = rsakey.RsaKey(privdata=dmail_address.site_privatekey) 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(dmail_address.keys[0].difficulty) storing_nodes =\ yield from self._dmail_engine.publish_dmail_site(private_key, dms) if log.isEnabledFor(logging.INFO): log.info("Republished Dmail site with [{}] storing nodes."\ .format(storing_nodes))
def parse(self): super().parse() i = 1 l, self.host_key = sshtype.parseBinary(self.buf[i:]) i += l l, self.f = sshtype.parseMpint(self.buf[i:]) i += l l, self.signature = sshtype.parseBinary(self.buf[i:])
def parse(self): super().parse() i = 1 l, self.data = sshtype.parseBinary(self.buf[i:]) i += l self.targeted = struct.unpack_from("?", self.buf, i)[0] i += 1 if i == len(self.buf): return l, self.pubkey = sshtype.parseBinary(self.buf[i:]) i += l l, self.path_hash = sshtype.parseBinary(self.buf[i:]) i += l l, self.version = sshtype.parseMpint(self.buf[i:]) i += l l, self.signature = sshtype.parseBinary(self.buf[i:])
def parse(self): super().parse() i = 1 l, self.data = sshtype.parseBinary(self.buf[i:]) i += l self.original_size = struct.unpack(">L", self.buf[i:i + 4])[0] i += 4 if i == len(self.buf): return l, self.version = sshtype.parseMpint(self.buf[i:]) i += l l, self.signature = sshtype.parseBinary(self.buf[i:]) i += l if i == len(self.buf): return l, self.epubkey = sshtype.parseBinary(self.buf[i:]) i += l self.pubkeylen = struct.unpack(">L", self.buf[i:i + 4])[0]
def parse(self): super().parse() i = 1 l, self.data = sshtype.parseBinary(self.buf[i:]) i += l self.original_size = struct.unpack(">L", self.buf[i : i + 4])[0] i += 4 if i == len(self.buf): return l, self.version = sshtype.parseMpint(self.buf[i:]) i += l l, self.signature = sshtype.parseBinary(self.buf[i:]) i += l if i == len(self.buf): return l, self.epubkey = sshtype.parseBinary(self.buf[i:]) i += l self.pubkeylen = struct.unpack(">L", self.buf[i : i + 4])[0]
def parse(self): super().parse() self.e = sshtype.parseMpint(self.buf[1:])[1]
def _fetch_and_save_dmail(self, dmail_message_key, dmail_address,\ address_key): key_type = type(dmail_message_key) if key_type is not bytes: assert key_type is bytearray dmail_message_key = bytes(dmail_message_key) # Fetch the Dmail data from the network. l, x_mpint = sshtype.parseMpint(address_key.x) dmobj, valid_sig =\ yield from self.fetch_dmail(\ dmail_message_key, x_mpint, address_key.target_key) if not dmobj: if log.isEnabledFor(logging.INFO): log.info("Dmail was not found on the network.") return False def dbcall(): with self.db.open_session() as sess: self.db.lock_table(sess, db.DmailMessage) q = sess.query(func.count("*")).select_from(db.DmailMessage)\ .filter(db.DmailMessage.data_key == dmail_message_key) if q.scalar(): return False msg = db.DmailMessage() msg.dmail_address_id = dmail_address.id msg.dmail_key_id = address_key.id msg.data_key = dmail_message_key msg.sender_dmail_key =\ enc.generate_ID(dmobj.sender_pubkey)\ if dmobj.sender_pubkey else None msg.sender_valid = valid_sig msg.subject = dmobj.subject msg.date = mutil.parse_iso_datetime(dmobj.date) msg.hidden = False msg.read = False msg.deleted = False attach_dmail_tag(sess, msg, "Inbox") msg.parts = [] for part in dmobj.parts: dbpart = db.DmailPart() dbpart.mime_type = part.mime_type dbpart.data = part.data msg.parts.append(dbpart) sess.add(msg) sess.commit() yield from self.loop.run_in_executor(None, dbcall) if log.isEnabledFor(logging.INFO): log.info("Dmail saved!") return True
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 _fetch_and_save_dmail(self, dmail_message_key, dmail_address,\ address_key): key_type = type(dmail_message_key) if key_type is not bytes: assert key_type is bytearray dmail_message_key = bytes(dmail_message_key) # Fetch the Dmail data from the network. l, x_mpint = sshtype.parseMpint(address_key.x) dmobj, valid_sig =\ yield from self.fetch_dmail(\ dmail_message_key, x_mpint, address_key.target_key) if not dmobj: if log.isEnabledFor(logging.INFO): log.info("Dmail was not found on the network.") return False if dmobj.version > 1: if dmobj.destination_addr != dmail_address.site_key: log.warning(\ "Dmail was addressed to [{}], yet passed address was"\ " [{}]."\ .format(mbase32.encode(dmobj.destination_addr),\ mbase32.encode(dmail_address.site_key))) sig_valid = False # Save the Dmail to our local database. def dbcall(): with self.db.open_session() as sess: self.db.lock_table(sess, db.DmailMessage) q = sess.query(func.count("*")).select_from(db.DmailMessage)\ .filter(db.DmailMessage.data_key == dmail_message_key) if q.scalar(): return False msg = db.DmailMessage() msg.dmail_address_id = dmail_address.id msg.dmail_key_id = address_key.id msg.data_key = dmail_message_key msg.sender_dmail_key =\ enc.generate_ID(dmobj.sender_pubkey)\ if dmobj.sender_pubkey else None msg.sender_valid = valid_sig msg.subject = dmobj.subject msg.date = mutil.parse_iso_datetime(dmobj.date) msg.hidden = False msg.read = False msg.deleted = False attach_dmail_tag(sess, msg, "Inbox") msg.parts = [] for part in dmobj.parts: dbpart = db.DmailPart() dbpart.mime_type = part.mime_type dbpart.data = part.data msg.parts.append(dbpart) sess.add(msg) sess.commit() yield from self.loop.run_in_executor(None, dbcall) if log.isEnabledFor(logging.INFO): log.info("Dmail saved!") return True
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 __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()
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()