From ed54ec27703fa983d3710527bbd0cdddfa170cdd Mon Sep 17 00:00:00 2001 From: MeaTLoTioN Date: Wed, 15 Mar 2023 18:31:19 +0000 Subject: [PATCH] Add full encryption/decryption to mrc_client --- mrc_client_encryption.pyc | Bin 0 -> 2036 bytes mrc_client_v3.py | 497 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 497 insertions(+) create mode 100644 mrc_client_encryption.pyc create mode 100755 mrc_client_v3.py diff --git a/mrc_client_encryption.pyc b/mrc_client_encryption.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9df0e855dd193b5e3211acceb6f2b0e211edd9b1 GIT binary patch literal 2036 zcmb7F+in|G6x}nvUy?x51{+E+MM8e6h^dNHMHR-KG#2*Qni)5!FP7soiR}2s%n7LK z7$F6z5BwGndJ}UH${=OZPjH%~5&{w&=2nwP8U2ZmJv0FGxDvP;xWeDDL_}k$cr7K$$i7Ta z@Y~-vlIxA7L6Nb}TbdN1uSw-)LQo1QNg5&8Ns>y_wMokq=>(0F6r~8wxNC;NG9CNV zQiENY4Of=R?8;Jv;u*R$DfopVm}r@zqgkF*E;ew>;}jd5k)v6fZv!C8;Zg9t+c*@_ z4U#R*sJb1a_7znCBsT8vc1X5Xk{R$)~kSdbe zBDGCwhtxZy-X*n5YLC=CQuj&ilX{OUT$Bg|R;8HYWoCnHl_HoI5t?8dSsi4w!$JX$pR2z(EIb5ahv>gcd+${0u_NJCz|EmJE&q!7%y= z2uVN{po}1Nhafb{ql(B0Bwv|XAwM3-$09b6KQHnt!~q2fC^E^%D2#{pPy)6n!Vi5O z(2*+BSX!}=wkg`CCDFHUjhRdgxB3ZQj4eECw(G6tOG{W}Tc=*9+ib`N45!m+3ol!p z7oFo{QPt^5r(+B1L3^&`F={nkPx2Zkb=$UDvH|QtTdruN(Sg4Kk!jY5#4~7jyyub# z9lK4`X6K33>Pi#Wt9!1XX7{W5>d4)m&6tVLt=m1%(mWm5=-FcO9=AZ8E4RRfdag98 z_q7-=f^J!<=<+kqj4yRe3W@c%$O*sbq|dLg#Z%*a9!v+?ktxH=&6dOGud-$wmawQ?&DWZgx*Dp!5H!0*)5&P&%cD3C z=F{8p!N%Fy&B)Sob~`eAc$~z6taq7Et6?EFp92Hq&ivSjIF!M#4&khta}Q}%T>o{j zAZc^3>?1S$hV#vY@qfNKvu1pX(X)@SQ(O%s3?*|1cvr4G)}kr@NadBtlXvc;mGcbC c`p|;@eI)WLJ(|wd)x>|sv 5: + mline = fl.split("~") + fromuser = mline[0] + frombbs = mline[1] + touser = mline[3] + message = mline[6] + + if message == "VERSION": + deliver_mrc("CLIENT~~~%s~%s~~|07- %s~" % (fromuser, frombbs, client_version)) + send_server(fl) + + elif touser == "CLIENT" and message == "LATENCY": + deliver_mrc("SERVER~~~CLIENT~%s~~LATENCY:%s~" % (frombbs, latency)) + + elif touser == "CLIENT" and message == "STATS": + deliver_mrc("SERVER~~~CLIENT~%s~~STATS:%s~" % (frombbs, mrcstats)) + + else: + # Encrypt message + new_fl = mrc_client_encryption.encrypt_message(fl) + send_server(new_fl) + + if debugflag: + logger("OUT: %s" % fl) + os.remove(mrcfile) + else: + if debugflag: + logger("File %s contains invalid packet" % mrcfile) + + except IOError: + if debugflag: + logger("MRC file still busy") + pass + except: + if debugflag: + logger("Error:" + traceback.print_exc()) + else: + os.remove(mrcfile) + +# Write time serialized file for display in MRC +def deliver_mrc( server_data ): + global registry + global latency + global mrcstats + global timebase + + curtime = int(time.time()*1000) + if server_data.strip() in registry.keys(): + pkttime = int(registry[server_data.strip()]) + roundtrip = curtime - pkttime + if roundtrip > 1: + latency = roundtrip + if debugflag: + logger("LATENCY: Current: %s - Packet: %s = RoundTrip: %s" % (curtime, pkttime, roundtrip)) + registry.clear() + + # Make up a serialized filename based on time + fileserial = int((time.time()-timebase) * 1000) + + # Wrap the file serial if longer than 8 chars + if fileserial > 99999999: + timebase = int(time.time()) + fileserial = int((time.time()-timebase) * 1000) + # Zeropad the filename + filename = "%08d.mrc" % fileserial + + try: + packet = server_data.split("~") + fromuser = packet[0] + fromsite = packet[1] + fromroom = packet[2] + touser = packet[3] + tosite = packet[4] + toroom = packet[5] + message = packet[6] + except: + logger("Bad packet: %s" % server_data) + return + + if debugflag: logger("IN: %s" % server_data) + + # Manage server PINGs + if fromuser == "SERVER" and message.lower() == "ping": + send_im_alive() + + # Manage update available notifications + elif fromuser == "SERVER" and message.startswith("NEWUPDATE:"): + logger("Upgrade is available, consider upgrading at your earliest convenience") + logger("You are using version %s" % version) + logger("Latest version is %s" % message.split(":")[1]) + + # Manage old clients + elif fromuser == "SERVER" and message.startswith("OLDVERSION:"): + logger("Your client is too old and can no longer be used.") + logger("You are using version %s" % version) + logger("Latest version is %s" % message.split(":")[1]) + raise KeyboardInterrupt + + #elif fromuser == "SERVER" and message.startswith("ROOMTOPIC:"): + # ltime=time.asctime(time.localtime(time.time())) + # MM = message.split(":") + # room = MM[1] + # topic = MM[2] + # clogfile = "%s%smrcchat.log" % (mrcdir, os.sep) + # clog = open(clogfile, "a") + # clog.write("%s %s %s\n" % (ltime, "NEWTOPIC{" + room + "}", topic)) + # clog.close() + + else: + + # Manage server stats + if fromuser == "SERVER" and message.startswith("STATS:"): + statsfile = "%s%smrcstats.dat" % (mrcdir, os.sep) + try: + f = open(statsfile, "w") + f.write(message.split(":")[1]) + f.close() + mrcstats = message.split(":")[1] + except: + logger("Cannot write server stats to %s" % statsfile) + + chatlog(server_data) + + if fromuser != 'SERVER': + # Decrypt messages + server_data = mrc_client_encryption.decrypt_message(server_data) + + for f in glob.iglob(chatdats): + if not 'chatroom' in f: + chatfile="%s%schat" % (datadir,os.sep) + xy = f.replace(chatfile,tempdir) + xy = xy[:-4] + inusefile = "%s%stchat.inuse" % (xy,os.sep) + if os.path.isfile(inusefile): + mrcfile = "%s%s%s" % (xy,os.sep,filename) + openfile = open(mrcfile,"a") + openfile.write(server_data) + openfile.close() + msleep(5) + +# Respond to server PING +def send_im_alive(): + data = "CLIENT~%s~~SERVER~~~IMALIVE:%s~\n" % (bbsname,bbsname) + send_server(data) + +# Send graceful shutdown request to server when exited +def send_shutdown(): + data = "CLIENT~%s~~SERVER~~~SHUTDOWN~\n" % bbsname + send_server(data) + +# Request server stats for applet +def request_stats(): + data = "CLIENT~%s~~SERVER~~~STATS~\n" % bbsname + send_server(data) + +# Send BBS additional info for INFO command +def send_bbsinfo(): + prefix = "CLIENT~%s~~SERVER~ALL~~" % bbsname + packet = prefix + "INFOWEB:%s~\n" % info_web + packet += prefix + "INFOTEL:%s~\n" % info_telnet + packet += prefix + "INFOSSH:%s~\n" % info_ssh + packet += prefix + "INFOSYS:%s~\n" % info_sysop + packet += prefix + "INFODSC:%s~\n" % info_desc + send_server(packet) + +# Handle different line separator scenarios +def check_separator(data): + if data.count("\r\n"): return("\r\n") + elif data.count("\n\r"): return("\n\r") + elif data.count("\r"): return("\r") + else: return("\n") + +# Main process loop +def mainproc(): + global delay + global mrcserver + global latency + + mrcserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + mrcserver.settimeout(5) + + restart = 0 + readbuffer = '' + tdat = '' + latency = 0 + + # Non-blocking socket loop to improve speed + try: + mrcserver.connect((host, port)) + mrcserver.setblocking(0) + mrcserver.send("%s~%s" % (bbsname, version_string)) + logger("Connected to Multi Relay Chat host %s port %d" % (host, port)) + delay = 0 + except: + logger("Unable to connect to %s:%d" % (host,port)) + return + + send_bbsinfo() + send_im_alive() + + loop = 1800 + while True: + msleep(10) + send_mrc() + + loop += 1 + try: + readbuffer = mrcserver.recv(8192) + except socket.error, e: + err = e.args[0] + if err == errno.EAGAIN or err == errno.EWOULDBLOCK: + # Request stats every 20 seconds + if loop > 2000: + request_stats() + loop = 0 + continue + else: + restart = 1 + else: + if readbuffer: + sep = check_separator(readbuffer) + tdat = readbuffer.split(sep) + for data in tdat: + if data: + deliver_mrc(data) + else: + restart = 1 + + # Handle socket restarts with socket shutdowns + if restart: + logger("Lost connection to server\n") + try: + mrcserver.shutdown(2) + finally: + mrcserver.close() + return + +# Some validation of config to ensure smoother operation +def check_startup(): + failed = 0 + + if not os.path.exists(mrcdir): + os.makedirs(mrcdir) + + if len(stripmci(bbsname)) < 5: + print "Config: 'bbsname' should be set to something sensible" + failed = 1 + + if len(stripmci(bbsname)) > 40: + print "Config: 'bbsname' cannot be longer than 40 characters after PIPE codes evaluation" + failed = 1 + + for param in ['info_web' 'info_telnet', 'info_ssh', 'info_sysop', 'info_desc']: + if len(stripmci(param)) > 64: + print "Config: '%s' cannot be longer than 64 characters after PIPE codes evaluation" % param + failed = 1 + + for param in ['info_web' 'info_telnet', 'info_ssh', 'info_sysop', 'info_desc']: + if len(param) > 128: + print "Config: '%s' cannot be longer than 128 characters including PIPE codes" % param + failed = 1 + + if failed: + print "This must be fixed in mrc_config.py" + sys.exit() + +# Main loop +if __name__ == "__main__": + logger(client_version) + check_startup() + delay = 0 + while True: + try: + mainproc() + + # Incremental auto-restart built-in + logger("Reconnecting in %d seconds" % intv[delay]) + time.sleep(intv[delay]) + delay += 1 + if delay > 9: delay = 0 + + except KeyboardInterrupt: + logger("Shutting down") + try: + send_shutdown() + try: + mrcserver.shutdown(2) + except: + pass + finally: + mrcserver.close() + sys.exit() + except: + continue +