Advertisement
turtle5204

Ringchat Client

Jun 19th, 2018
581
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 13.14 KB | None | 0 0
  1. --@version 1.2
  2.  
  3. local version = 1.2
  4. local ht_up = http.get("https://pastebin.com/raw/p94WHguU")
  5. local up_A = ht_up.readLine()
  6. local up_B = ht_up.readAll()
  7. local up = up_A .. up_B
  8. ht_up.close()
  9. local their_version = tonumber(up_A:sub(12))
  10. if (their_version > version) then
  11.     local fi_up = fs.open(shell.getRunningProgram(), "w")
  12.     fi_up.write(up)
  13.     fi_up.close()
  14.     shell.run(shell.getRunningProgram())
  15.     return
  16. end
  17.  
  18. --stack trace builder by apemanzilla
  19. local function buildStackTrace(rootErr)
  20.     local trace = {}
  21.     local i, hitEnd, _, e = 4, false
  22.     repeat
  23.         _, e =
  24.             pcall(
  25.             function()
  26.                 error("<tracemarker>", i)
  27.             end
  28.         )
  29.         i = i + 1
  30.         if e == "xpcall: <tracemarker>" or e == "pcall: <tracemarker>" then
  31.             hitEnd = true
  32.             break
  33.         end
  34.         table.insert(trace, e)
  35.     until i > 10
  36.     table.remove(trace)
  37.     table.remove(trace, 1)
  38.     if rootErr:match("^" .. trace[1]:match("^(.-:%d+)")) then
  39.         table.remove(trace, 1)
  40.     end
  41.     local out = {}
  42.     table.insert(out, rootErr)
  43.     for i, v in ipairs(trace) do
  44.         table.insert(out, "  at " .. v:match("^(.-:%d+)"))
  45.     end
  46.     if not hitEnd then
  47.         table.insert(out, "  ...")
  48.     end
  49.     return table.concat(out, "\n")
  50. end
  51.  
  52. local ok, err =
  53.     xpcall(
  54.     function()
  55.         ---------------------------------
  56.         -- BLITWRAP BY ELDIDIDESTROYER --
  57.         ---------------------------------
  58.  
  59.         local explode = function(div, str, replstr, includeDiv)
  60.             if (div == "") then
  61.                 return false
  62.             end
  63.             local pos, arr = 0, {}
  64.             for st, sp in function()
  65.                 return string.find(str, div, pos, false)
  66.             end do
  67.                 table.insert(arr, string.sub(replstr or str, pos, st - 1 + (includeDiv and #div or 0)))
  68.                 pos = sp + 1
  69.             end
  70.             table.insert(arr, string.sub(replstr or str, pos))
  71.             return arr
  72.         end
  73.  
  74.         local blitwrap = function(char, text, back, noWrite)
  75.             local cWords = explode(" ", char, nil, true)
  76.             local tWords = explode(" ", char, text, true)
  77.             local bWords = explode(" ", char, back, true)
  78.             local ox, oy = term.getCursorPos()
  79.             local cx, cy, ty = ox, oy, 1
  80.             local scr_x, scr_y = term.getSize()
  81.             local output = {}
  82.             for a = 1, #cWords do
  83.                 if ((cx + #cWords[a]) > scr_x) then
  84.                     cx = 1
  85.                     if (cy == scr_y) then
  86.                         term.scroll(1)
  87.                     end
  88.                     cy = math.min(cy + 1, scr_y)
  89.                     ty = ty + 1
  90.                 end
  91.                 if not noWrite then
  92.                     term.setCursorPos(cx, cy)
  93.                     term.blit(cWords[a], tWords[a], bWords[a])
  94.                 end
  95.                 cx = cx + #cWords[a]
  96.                 output[ty] = output[ty] or {"", "", ""}
  97.                 output[ty][1] = output[ty][1] .. cWords[a]
  98.                 output[ty][2] = output[ty][2] .. tWords[a]
  99.                 output[ty][3] = output[ty][3] .. bWords[a]
  100.             end
  101.             return output
  102.         end
  103.  
  104.         ------------------
  105.         -- BLITWRAP END --
  106.         ------------------
  107.  
  108.         local pingdata_channel = 895
  109.         local connect_channel = 885
  110.  
  111.         local d = false
  112.         local mod = nil
  113.         local our_rids = {}
  114.         for k, v in pairs(peripheral.getNames()) do
  115.             if peripheral.getType(v) == "modem" then
  116.                 rednet.open(v)
  117.                 mod = peripheral.wrap(v)
  118.                 d = true
  119.             end
  120.         end
  121.         if not d or not mod then
  122.             error("A modem is required!")
  123.         end
  124.  
  125.         local dump_log = {}
  126.  
  127.         local function download_file(url, target)
  128.             local ht = http.get(url)
  129.             local data = ht.readAll()
  130.             ht.close()
  131.             local file = fs.open(target, "w")
  132.             file.write(data)
  133.             file.close()
  134.         end
  135.  
  136.         local function read_file(target)
  137.             local file = fs.open(target, "r")
  138.             local data = file.readAll()
  139.             file.close()
  140.             return data
  141.         end
  142.  
  143.         local function isOurRid(id)
  144.             for k, v in pairs(our_rids) do
  145.                 if v == id then
  146.                     return true
  147.                 end
  148.             end
  149.             return false
  150.         end
  151.  
  152.         local servers = {}
  153.         local serber = nil
  154.         local truelog = {}
  155.         --------------
  156.         -- UI stuff --
  157.         --------------
  158.         local s_offset = 0
  159.         local current_server = 1
  160.         local chat_win = nil
  161.         local type_win = nil
  162.  
  163.         local chat_w, chat_h
  164.  
  165.         local function cwrite(t, str, y)
  166.             local w, h = t.getSize()
  167.             t.setCursorPos(math.floor((w / 2) - (str:len() / 2)), y or (h / 2))
  168.             t.write(str)
  169.         end
  170.  
  171.         local function setup_win()
  172.             local tn = term.native()
  173.             local w, h = tn.getSize()
  174.             chat_win = window.create(tn, 1, 1, w, h - 1, true)
  175.             chat_win.setCursorBlink(false)
  176.             chat_win.setBackgroundColor(colors.black)
  177.             chat_win.setTextColor(colors.white)
  178.             chat_win.clear()
  179.             chat_w, chat_h = chat_win.getSize()
  180.             type_win = window.create(tn, 1, h, w, 1, true)
  181.             type_win.setBackgroundColor(colors.black)
  182.             type_win.setTextColor(colors.lightGray)
  183.             type_win.clear()
  184.             term.redirect(type_win)
  185.         end
  186.  
  187.         local function kill(terminated)
  188.             if (type(term.native) == "function") then
  189.                 term = m
  190.                 term.redirect(term.native())
  191.                 term = term.native()
  192.             else
  193.                 term.redirect(term)
  194.             end
  195.             term.setBackgroundColor(colors.black)
  196.             term.setTextColor(colors.white)
  197.             term.clear()
  198.             chat_win = nil
  199.             type_win = nil
  200.  
  201.             if (serber and serber.cid) then
  202.                 ringnet.sendData(
  203.                     serber.cid,
  204.                     textutils.serialize(
  205.                         {
  206.                             type = "CHAT_LOGOUT"
  207.                         }
  208.                     )
  209.                 )
  210.             end
  211.         end
  212.  
  213.         local function writeRight(text, y)
  214.             local w, h = term.getSize()
  215.             term.setCursorPos(w - #text, y)
  216.             term.write(text)
  217.         end
  218.  
  219.         local function draw_list()
  220.             if #servers < 1 then
  221.                 error("No servers found.", 0)
  222.             end
  223.             term.setBackgroundColor(colors.black)
  224.             term.clear()
  225.             for i = 1, #servers do
  226.                 local serv = servers[i]
  227.                 if i == current_server then
  228.                     term.setBackgroundColor(colors.white)
  229.                     term.setTextColor(colors.black)
  230.                 else
  231.                     term.setBackgroundColor(colors.black)
  232.                     term.setTextColor(colors.white)
  233.                 end
  234.                 term.setCursorPos(1, i)
  235.                 term.clearLine()
  236.                 term.write(serv.name)
  237.                 writeRight(tostring(serv.fingerprint):sub(1, 8), i)
  238.             end
  239.             local _w, _h = term.getSize()
  240.             term.setBackgroundColor(colors.black)
  241.             term.setTextColor(colors.white)
  242.             cwrite(term, "Press Enter to join a server.", _h)
  243.         end
  244.  
  245.         local function draw_chat()
  246.             chat_win.setBackgroundColor(colors.black)
  247.             chat_win.setTextColor(colors.white)
  248.             chat_win.clear()
  249.             for y = 1, chat_h do
  250.                 local o = truelog[(#truelog + s_offset - chat_h) + y]
  251.                 if (type(o) == "table") then
  252.                     chat_win.setCursorPos(1, y)
  253.                     chat_win.blit(o[1], o[2], o[3])
  254.                 end
  255.                 y = y + 1
  256.             end
  257.         end
  258.  
  259.         --------------
  260.         --  UI End  --
  261.         --------------
  262.  
  263.         -- API Loading
  264.         local function getAPI(name, url)
  265.             local apiloc = "/" .. name
  266.             if (not fs.exists(apiloc)) then
  267.                 local newapiloc = shell and shell.resolveProgram(name) or nil
  268.                 if type(newapiloc) ~= "string" then
  269.                     download_file(url, apiloc)
  270.                 else
  271.                     apiloc = newapiloc
  272.                 end
  273.             end
  274.             return apiloc
  275.         end
  276.  
  277.         local ringnet = require(getAPI("ringnet", "https://pastebin.com/raw/tUe94t9J"))
  278.         getAPI("aeslua", "https://git.io/aeslua")
  279.         os.loadAPI("aeslua")
  280.         ringnet.openChannel(pingdata_channel)
  281.         ringnet.openChannel(connect_channel)
  282.  
  283.         local tid = nil
  284.  
  285.         term.setBackgroundColor(colors.black)
  286.         term.setTextColor(colors.white)
  287.         term.clear()
  288.         cwrite(term, "Scanning for servers...")
  289.  
  290.         local rid = math.random(100000, 999999)
  291.         table.insert(our_rids, rid)
  292.         mod.transmit(
  293.             pingdata_channel,
  294.             pingdata_channel,
  295.             textutils.serialize(
  296.                 {
  297.                     type = "SERVER_DATA",
  298.                     rid = rid
  299.                 }
  300.             )
  301.         )
  302.  
  303.         parallel.waitForAll(
  304.             ringnet.connectionHandler,
  305.             function()
  306.                 sleep(1.75)
  307.                 os.queueEvent("timer_chat")
  308.                 return
  309.             end,
  310.             function()
  311.                 local mode = 1
  312.                 local timer_tripped = false
  313.                 while true do
  314.                     local ev = {os.pullEvent()}
  315.                     table.insert(dump_log, {mode, ev[1]})
  316.                     if (ev[1] == "modem_message" and not timer_tripped) then
  317.                         local mes = ev[5]
  318.                         if (type(mes) == "string") then
  319.                             mes = textutils.unserialize(mes)
  320.                         end
  321.                         if
  322.                             (mes.type == "SERVER_RETURNDATA" and isOurRid(mes.to) and type(mes.hid) == "string" and string.len(mes.hid) == 8)
  323.                          then
  324.                             --print("Server! Name: " .. tostring(mes.name) .. " | Fingerprint: " .. tostring(mes.fingerprint):sub(1, 12))
  325.                             table.insert(
  326.                                 servers,
  327.                                 {
  328.                                     name = mes.name,
  329.                                     fingerprint = mes.fingerprint,
  330.                                     hid = mes.hid,
  331.                                     locked = mes.locked or false
  332.                                 }
  333.                             )
  334.                         end
  335.                     elseif (mode == 1 and ev[1] == "timer_chat") then
  336.                         mode = 2
  337.                         timer_tripped = true
  338.                         draw_list()
  339.                     elseif (mode == 2 and ev[1] == "key") then
  340.                         if (ev[2] == 208 or ev[2] == 205) then
  341.                             current_server = current_server + 1
  342.                             if (current_server > #servers) then
  343.                                 current_server = 1
  344.                             end
  345.                         elseif (ev[2] == 200 or ev[2] == 203) then
  346.                             current_server = current_server - 1
  347.                             if (current_server < 1) then
  348.                                 current_server = #servers
  349.                             end
  350.                         elseif (ev[2] == 28) then
  351.                             mode = 3
  352.                             serber = servers[current_server]
  353.                             print(serber.hid)
  354.                         end
  355.                         if (ev[2] ~= 28) then
  356.                             draw_list()
  357.                         end
  358.                     elseif (mode == 3) then
  359.                         ringnet.openTunnel(serber.hid, connect_channel)
  360.                         mode = 4
  361.                     elseif (mode == 4 and ev[1] == "tunnel_finish" and ev[3] == serber.hid) then
  362.                         --elseif (mode == 5 and ev[1] == "mouse_scroll") then
  363.                         --  s_offset = (s_offset) + ev[2]
  364.                         --  s_offset = math.min(math.max(s_offset, 0), #truelog)
  365.                         --  draw_chat()
  366.                         serber.cid = ev[2]
  367.                         setup_win()
  368.                         mode = 5
  369.                     elseif (mode == 5 and ev[1] == "secure_receive" and ev[2] == serber.cid) then
  370.                         local cid = ev[2]
  371.                         local data = ev[3]
  372.                         if (serber.password) then
  373.                             data = aeslua.decrypt(serber.password, data, aeslua.AES128, aeslua.CFBMODE)
  374.                         end
  375.                         if (type(data) == "string") then
  376.                             data = textutils.unserialize(data)
  377.                         end
  378.                         if (type(data) == "table") then
  379.                             table.insert(dump_log, textutils.serialize(data))
  380.                             if (data.type == "CHAT_LOG" and type(data.log) == "table") then
  381.                                 truelog = {}
  382.                                 for i = 1, #data.log do
  383.                                     local a = data.log[i]
  384.                                     if ((type(a.name) == "string" or a.raw == true) and type(a.mes) == "string") then
  385.                                         if not a.raw then
  386.                                             local prefix = (a.name .. ": ")
  387.                                             local dje = (a.mes)
  388.                                             local combined = (prefix .. dje)
  389.                                             local output =
  390.                                                 blitwrap(combined, (string.rep("0", #prefix) .. string.rep("8", #dje)), string.rep("f", #combined), true)
  391.                                             for k, v in pairs(output) do
  392.                                                 table.insert(truelog, v)
  393.                                             end
  394.                                         else
  395.                                             local output = blitwrap(a.mes, string.rep("8", #a.mes), string.rep("f", #a.mes), true)
  396.                                             for k, v in pairs(output) do
  397.                                                 table.insert(truelog, v)
  398.                                             end
  399.                                         end
  400.                                     end
  401.                                 end
  402.                                 local k = fs.open("/.TESTDUMP", "w")
  403.                                 k.write(textutils.serialize(truelog))
  404.                                 k.close()
  405.                                 draw_chat()
  406.                             end
  407.                         end
  408.                     end
  409.                 end
  410.             end,
  411.             function()
  412.                 local named = false
  413.                 local still_locked = true
  414.                 while true do
  415.                     if (type_win ~= nil) then
  416.                         if not (serber.locked) then
  417.                             still_locked = false
  418.                         end
  419.                         type_win.setBackgroundColor(colors.black)
  420.                         type_win.setTextColor(colors.lightGray)
  421.                         type_win.clear()
  422.                         term.redirect(type_win)
  423.                         if (serber.locked and still_locked and not named) then
  424.                             cwrite(chat_win, "Please enter this server's password")
  425.                         elseif (not still_locked and not named) then
  426.                             cwrite(chat_win, "Please type the name you want below")
  427.                         end
  428.                         local a = tostring(read())
  429.                         if a == "_EXIT" then
  430.                             kill()
  431.                             error("Exited.", 0)
  432.                         elseif (serber.locked and still_locked) then
  433.                             if (aeslua.decrypt(a, serber.locked, aeslua.AES128, aeslua.CFBMODE) == "_A_COMMON_ENCRYPTION_STRING") then
  434.                                 still_locked = false
  435.                                 serber.password = a
  436.                             end
  437.                         elseif (not still_locked) then
  438.                             if named then
  439.                                 if a:lower() == "/exit" or a:lower() == "/logout" then
  440.                                     ringnet.sendData(
  441.                                         serber.cid,
  442.                                         textutils.serialize(
  443.                                             {
  444.                                                 type = "CHAT_LOGOUT"
  445.                                             }
  446.                                         )
  447.                                     )
  448.                                     sleep(1.5)
  449.                                     kill()
  450.                                     error()
  451.                                 elseif a:lower() == "/forceupdate" or a:lower() == "/update" then
  452.                                     ringnet.sendData(
  453.                                         serber.cid,
  454.                                         textutils.serialize(
  455.                                             {
  456.                                                 type = "CHAT_FORCEUPDATE"
  457.                                             }
  458.                                         )
  459.                                     )
  460.                                 else
  461.                                     ringnet.sendData(
  462.                                         serber.cid,
  463.                                         textutils.serialize(
  464.                                             {
  465.                                                 type = "CHAT_CHAT",
  466.                                                 message = a
  467.                                             }
  468.                                         )
  469.                                     )
  470.                                 end
  471.                             else
  472.                                 ringnet.sendData(
  473.                                     serber.cid,
  474.                                     textutils.serialize(
  475.                                         {
  476.                                             type = "CHAT_LOGIN",
  477.                                             name = a
  478.                                         }
  479.                                     )
  480.                                 )
  481.                                 chat_win.setBackgroundColor(colors.black)
  482.                                 chat_win.setTextColor(colors.white)
  483.                                 chat_win.clear()
  484.                                 named = true
  485.                             end
  486.                         end
  487.                     end
  488.                     sleep(0.1)
  489.                 end
  490.             end
  491.         )
  492.     end,
  493.     function(err)
  494.         term.redirect(term.native and term.native() or term.current())
  495.         local stack = buildStackTrace(err)
  496.         printError("\nRingchat has crashed! Stack trace:")
  497.         printError(stack)
  498.         local file = fs.open("/chat.err", "w")
  499.         file.write(tostring(stack))
  500.         file.close()
  501.     end
  502. )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement