hyay3.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. #!/usr/bin/env python3
  2. #
  3. # Internet Delay Chat client written in Python.
  4. #
  5. # Written by: Test_User <hax@andrewyu.org>
  6. #
  7. # This is free and unencumbered software released into the public
  8. # domain.
  9. #
  10. # Anyone is free to copy, modify, publish, use, compile, sell, or
  11. # distribute this software, either in source code form or as a compiled
  12. # binary, for any purpose, commercial or non-commercial, and by any
  13. # means.
  14. #
  15. # In jurisdictions that recognize copyright laws, the author or authors
  16. # of this software dedicate any and all copyright interest in the
  17. # software to the public domain. We make this dedication for the benefit
  18. # of the public at large and to the detriment of our heirs and
  19. # successors. We intend this dedication to be an overt act of
  20. # relinquishment in perpetuity of all present and future rights to this
  21. # software under copyright law.
  22. #
  23. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  26. # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  27. # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  28. # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  29. # OTHER DEALINGS IN THE SOFTWARE.
  30. #
  31. import threading
  32. import string
  33. import curses
  34. import socket
  35. import time
  36. def send(s, msg):
  37. return s.sendall(msg.encode("UTF-8", "surrogateescape")+b"\r\n")
  38. def recv(s):
  39. return s.recv(1024).decode("UTF-8", "surrogateescape")
  40. lock = threading.Lock()
  41. input_str = ""
  42. input_index = 0
  43. message_list = []
  44. message_index = 0
  45. prompt = ""
  46. prompt_len = 0
  47. def update_screen(stdscr, net_scr, user_scr):
  48. global message_list
  49. global message_index
  50. global input_str
  51. global input_index
  52. global prompt
  53. global prompt_len
  54. if len(message_list) > 0:
  55. net_scr.erase()
  56. i=0
  57. for line in message_list[message_index]["messages"][0 - (curses.LINES - 1):]:
  58. net_scr.addstr(i, 0, line)
  59. i += 1
  60. net_scr.refresh()
  61. prompt = "[to "+message_list[message_index]["username"]+"] "
  62. prompt_len = len(prompt)
  63. user_scr.erase()
  64. user_scr.addstr(0, 0, prompt+input_str)
  65. user_scr.move(0, prompt_len + input_index)
  66. user_scr.refresh()
  67. else:
  68. net_scr.erase()
  69. net_scr.refresh()
  70. prompt = "[no open buffers] "
  71. prompt_len = len(prompt)
  72. user_scr.erase()
  73. user_scr.addstr(0, 0, prompt+input_str)
  74. user_scr.move(0, prompt_len + input_index)
  75. user_scr.refresh()
  76. def listen_to_user(s, stdscr, net_scr, user_scr):
  77. global input_str
  78. global input_index
  79. global lock
  80. global message_list
  81. global message_index
  82. global prompt
  83. global prompt_len
  84. disallowed = ["\n", "\r", "\t", "\x0B", "\x0C"]
  85. lock.acquire()
  86. while True:
  87. lock.release()
  88. input = stdscr.getkey()
  89. lock.acquire()
  90. if len(input) > 1:
  91. if input == "KEY_DOWN":
  92. message_index = message_index + 1
  93. if message_index >= len(message_list) and message_index != 0:
  94. message_index = 0
  95. update_screen(stdscr, net_scr, user_scr)
  96. elif input == "KEY_UP":
  97. message_index = message_index - 1
  98. if message_index < 0:
  99. message_index = max(0, len(message_list) - 1)
  100. update_screen(stdscr, net_scr, user_scr)
  101. elif input == "KEY_LEFT":
  102. input_index = max(0, min(len(input_str), input_index - 1))
  103. user_scr.move(0, prompt_len + input_index)
  104. user_scr.refresh()
  105. elif input == "KEY_RIGHT":
  106. input_index = max(0, min(len(input_str), input_index + 1))
  107. user_scr.move(0, prompt_len + input_index)
  108. user_scr.refresh()
  109. elif input == "KEY_BACKSPACE":
  110. if input_index > 0:
  111. input_str = input_str[:input_index - 1]+input_str[input_index:]
  112. input_index -= 1
  113. user_scr.erase()
  114. user_scr.addstr(0, 0, prompt+input_str)
  115. user_scr.move(0, prompt_len + input_index)
  116. user_scr.refresh()
  117. elif input == "KEY_RESIZE":
  118. stdscr.refresh()
  119. net_scr.refresh()
  120. user_scr.refresh()
  121. elif input in string.printable and input not in disallowed:
  122. input_str = input_str[:input_index]+input+input_str[input_index:]
  123. input_index += 1
  124. user_scr.erase()
  125. user_scr.addstr(0, 0, prompt+input_str)
  126. user_scr.move(0, prompt_len + input_index)
  127. user_scr.refresh()
  128. elif input == "\n" and input_str != "":
  129. input = input_str
  130. input_str = ""
  131. input_index = 0
  132. if input.startswith("/"):
  133. command = input[1:].split(" ")[0]
  134. args = input[1:].split(" ")[1:]
  135. if command == "query":
  136. if not any(e["username"] == args[0] for e in message_list):
  137. try:
  138. message_list.append({
  139. "username": args[0],
  140. "messages": [],
  141. })
  142. except IndexError:
  143. continue
  144. message_index = len(message_list) - 1
  145. elif len(message_list) > 0:
  146. send(s, "PRIVMSG\tTARGET="+message_list[message_index]["username"]+"\tMESSAGE="+input.replace("\\", "\\\\"))
  147. update_screen(stdscr, net_scr, user_scr)
  148. def main(stdscr):
  149. global input_str
  150. global input_index
  151. global lock
  152. global message_list
  153. global message_index
  154. global prompt
  155. global prompt_len
  156. stdscr.erase()
  157. stdscr.refresh()
  158. server_scr = curses.newwin(1, curses.COLS, 0, 0)
  159. server_scr.addstr(0, 0, "Server address: ")
  160. server_scr.refresh()
  161. port_scr = curses.newwin(1, curses.COLS, 1, 0)
  162. port_scr.addstr(0, 0, "Server port: ")
  163. port_scr.refresh()
  164. name_scr = curses.newwin(1, curses.COLS, 2, 0)
  165. name_scr.addstr(0, 0, "Username: ")
  166. name_scr.refresh()
  167. pass_scr = curses.newwin(1, curses.COLS, 3, 0)
  168. pass_scr.addstr(0, 0, "Password: ")
  169. pass_scr.refresh()
  170. line = 0
  171. index = 0
  172. config = [
  173. [server_scr, "", len("Server address: "), "Server address: "],
  174. [port_scr, "", len("Server port: "), "Server port: "],
  175. [name_scr, "", len("Username: "), "Username: "],
  176. [pass_scr, "", len("Password: "), "Password: "],
  177. ]
  178. maxlines = len(config) - 1
  179. disallowed = ["\n", "\r", "\t", "\x0B", "\x0C"]
  180. err_scr = curses.newwin(1, curses.COLS, maxlines+2, 0)
  181. err_scr.erase()
  182. err_scr.refresh()
  183. config[line][0].move(0, config[line][2])
  184. config[line][0].refresh()
  185. s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  186. while True:
  187. input = stdscr.getkey()
  188. if len(input) > 1:
  189. if input == "KEY_DOWN":
  190. line = min(line+1, maxlines)
  191. index = min(index, len(config[line][1]))
  192. config[line][0].move(0, config[line][2]+index)
  193. config[line][0].refresh()
  194. elif input == "KEY_UP":
  195. line = max(line-1, 0)
  196. index = min(index, len(config[line][1]))
  197. config[line][0].move(0, config[line][2]+index)
  198. config[line][0].refresh()
  199. elif input == "KEY_LEFT":
  200. index = max(index-1, 0)
  201. config[line][0].move(0, config[line][2]+index)
  202. config[line][0].refresh()
  203. elif input == "KEY_RIGHT":
  204. index = min(index+1, len(config[line][1]))
  205. config[line][0].move(0, config[line][2]+index)
  206. config[line][0].refresh()
  207. elif input == "KEY_BACKSPACE":
  208. if index > 0:
  209. tmp_str = config[line][1]
  210. tmp_str = tmp_str[:index-1]+tmp_str[index:]
  211. config[line][1] = tmp_str
  212. index -= 1
  213. scr = config[line][0]
  214. scr.erase()
  215. scr.addstr(0, 0, config[line][3])
  216. scr.addstr(0, config[line][2], tmp_str)
  217. scr.move(0, config[line][2]+index)
  218. scr.refresh()
  219. elif input == "KEY_RESIZE":
  220. stdscr.refresh()
  221. for c in config:
  222. c[0].refresh()
  223. err_scr.refresh()
  224. config[line][0].move(0, config[line][2]+index)
  225. config[line][0].refresh()
  226. elif input in string.printable and input not in disallowed:
  227. tmp_str = config[line][1]
  228. tmp_str = tmp_str[:index]+input+tmp_str[index:]
  229. config[line][1] = tmp_str
  230. index += 1
  231. scr = config[line][0]
  232. scr.erase()
  233. scr.addstr(0, 0, config[line][3])
  234. scr.addstr(0, config[line][2], tmp_str)
  235. scr.move(0, config[line][2]+index)
  236. scr.refresh()
  237. elif input == "\n":
  238. if not all(c[1] != "" for c in config):
  239. err_scr.erase()
  240. err_scr.addstr(0, 0, "Not all required settings have been filled.")
  241. err_scr.refresh()
  242. config[line][0].move(0, config[line][2]+index)
  243. config[line][0].refresh()
  244. else:
  245. try:
  246. port = int(config[1][1])
  247. except ValueError:
  248. err_scr.erase()
  249. err_scr.addstr(0, 0, "Invalid port.")
  250. err_scr.refresh()
  251. config[line][0].move(0, config[line][2]+index)
  252. config[line][0].refresh()
  253. continue
  254. address = config[0][1]
  255. username = config[2][1]
  256. password = config[3][1]
  257. try:
  258. s.connect((address, port))
  259. except ConnectionRefusedError:
  260. err_scr.erase()
  261. err_scr.addstr(0, 0, "Connection refused.")
  262. err_scr.refresh()
  263. config[line][0].move(0, config[line][2]+index)
  264. config[line][0].refresh()
  265. continue
  266. break
  267. net_scr = curses.newwin(curses.LINES - 1, curses.COLS, 0, 0)
  268. user_scr = curses.newwin(1, curses.COLS, curses.LINES - 1, 0)
  269. net_scr.erase()
  270. net_scr.refresh()
  271. user_scr.erase()
  272. user_scr.refresh()
  273. send(s, "LOGIN\tUSERNAME="+username+"\tPASSWORD="+password)
  274. update_screen(stdscr, net_scr, user_scr)
  275. threading.Thread(target=listen_to_user, args=(s, stdscr, net_scr, user_scr), daemon=True).start()
  276. msg = ""
  277. lock.acquire()
  278. while True:
  279. lock.release()
  280. newmsg = recv(s)
  281. lock.acquire()
  282. if newmsg == "":
  283. break
  284. msg += newmsg
  285. split_msg = msg.split("\n")
  286. if len(split_msg) < 2:
  287. continue
  288. lines = split_msg[0:-1]
  289. msg = split_msg[-1]
  290. for line in lines:
  291. command = "\\".join(c.replace("\\t", "\t").replace("\\r", "\r").replace("\\n", "\n") for c in line.split("\t")[0].split("\\\\")).upper()
  292. args = {}
  293. for x in ["\\".join(c.replace("\\t", "\t").replace("\\r", "\r").replace("\\n", "\n") for c in a.split("\\\\")) for a in line.split("\t")[1:]]:
  294. try:
  295. args[x.split("=", 1)[0].upper()] = x.split("=", 1)[1]
  296. except IndexError:
  297. continue # log an error here eventually
  298. if command == "PRIVMSG":
  299. if all(args.get(x) != None for x in ["TARGET", "SOURCE", "MESSAGE"]):
  300. if args["TARGET"] == username:
  301. buffer = args["SOURCE"]
  302. else:
  303. buffer = args["TARGET"]
  304. if not any(c["username"] == buffer for c in message_list):
  305. tmp1 = "<"+args["SOURCE"]+"> "+args["MESSAGE"]
  306. tmp2 = "".join(a for a in tmp1 if a in string.printable and a not in disallowed)
  307. message_list.append({
  308. "username": buffer,
  309. "messages": [tmp2],
  310. })
  311. update_screen(stdscr, net_scr, user_scr)
  312. else:
  313. for c in message_list:
  314. if c["username"] == buffer:
  315. tmp1 = "<"+args["SOURCE"]+"> "+args["MESSAGE"]
  316. tmp2 = "".join(a for a in tmp1 if a in string.printable and a not in disallowed)
  317. c["messages"].append(tmp2)
  318. update_screen(stdscr, net_scr, user_scr)
  319. if __name__ == "__main__":
  320. curses.wrapper(main)
  321. else:
  322. raise SystemExit("Unable to install backdoor, exiting...")