Ringchat 1.2 - Encrypted chat via Ring LWE!
Description
@version 1.2
Installation
Copy one of these commands into your ComputerCraft terminal:
Pastebin:
pastebin get p94WHguU ringchat_1.2_-_encrypted_chat_via_ring_lwe!wget:
wget https://pastebin.com/raw/p94WHguU ringchat_1.2_-_encrypted_chat_via_ring_lwe!Archive:
wget https://cc.shobie.xyz/cc/get/pb-p94WHguU ringchat_1.2_-_encrypted_chat_via_ring_lwe!
Quick Install:
wget https://cc.shobie.xyz/cc/get/pb-p94WHguU Ringchat 1.2 - Encrypted chat via Ring LWE!
Usage
Run the program after downloading
Tags
Source
View Original SourceCode Preview
--@version 1.2
local version = 1.2
local ht_up = http.get("https://pastebin.com/raw/p94WHguU")
local up_A = ht_up.readLine()
local up_B = ht_up.readAll()
local up = up_A .. up_B
ht_up.close()
local their_version = tonumber(up_A:sub(12))
if (their_version > version) then
local fi_up = fs.open(shell.getRunningProgram(), "w")
fi_up.write(up)
fi_up.close()
shell.run(shell.getRunningProgram())
return
end
--stack trace builder by apemanzilla
local function buildStackTrace(rootErr)
local trace = {}
local i, hitEnd, _, e = 4, false
repeat
_, e =
pcall(
function()
error("<tracemarker>", i)
end
)
i = i + 1
if e == "xpcall: <tracemarker>" or e == "pcall: <tracemarker>" then
hitEnd = true
break
end
table.insert(trace, e)
until i > 10
table.remove(trace)
table.remove(trace, 1)
if rootErr:match("^" .. trace[1]:match("^(.-:%d+)")) then
table.remove(trace, 1)
end
local out = {}
table.insert(out, rootErr)
for i, v in ipairs(trace) do
table.insert(out, " at " .. v:match("^(.-:%d+)"))
end
if not hitEnd then
table.insert(out, " ...")
end
return table.concat(out, "\n")
end
local ok, err =
xpcall(
function()
---------------------------------
-- BLITWRAP BY ELDIDIDESTROYER --
---------------------------------
local explode = function(div, str, replstr, includeDiv)
if (div == "") then
return false
end
local pos, arr = 0, {}
for st, sp in function()
return string.find(str, div, pos, false)
end do
table.insert(arr, string.sub(replstr or str, pos, st - 1 + (includeDiv and #div or 0)))
pos = sp + 1
end
table.insert(arr, string.sub(replstr or str, pos))
return arr
end
local blitwrap = function(char, text, back, noWrite)
local cWords = explode(" ", char, nil, true)
local tWords = explode(" ", char, text, true)
local bWords = explode(" ", char, back, true)
local ox, oy = term.getCursorPos()
local cx, cy, ty = ox, oy, 1
local scr_x, scr_y = term.getSize()
local output = {}
for a = 1, #cWords do
if ((cx + #cWords[a]) > scr_x) then
cx = 1
if (cy == scr_y) then
term.scroll(1)
end
cy = math.min(cy + 1, scr_y)
ty = ty + 1
end
if not noWrite then
term.setCursorPos(cx, cy)
term.blit(cWords[a], tWords[a], bWords[a])
end
cx = cx + #cWords[a]
output[ty] = output[ty] or {"", "", ""}
output[ty][1] = output[ty][1] .. cWords[a]
output[ty][2] = output[ty][2] .. tWords[a]
output[ty][3] = output[ty][3] .. bWords[a]
end
return output
end
------------------
-- BLITWRAP END --
------------------
local pingdata_channel = 895
local connect_channel = 885
local d = false
local mod = nil
local our_rids = {}
for k, v in pairs(peripheral.getNames()) do
if peripheral.getType(v) == "modem" then
rednet.open(v)
mod = peripheral.wrap(v)
d = true
end
end
if not d or not mod then
error("A modem is required!")
end
local dump_log = {}
local function download_file(url, target)
local ht = http.get(url)
local data = ht.readAll()
ht.close()
local file = fs.open(target, "w")
file.write(data)
file.close()
end
local function read_file(target)
local file = fs.open(target, "r")
local data = file.readAll()
file.close()
return data
end
local function isOurRid(id)
for k, v in pairs(our_rids) do
if v == id then
return true
end
end
return false
end
local servers = {}
local serber = nil
local truelog = {}
--------------
-- UI stuff --
--------------
local s_offset = 0
local current_server = 1
local chat_win = nil
local type_win = nil
local chat_w, chat_h
local function cwrite(t, str, y)
local w, h = t.getSize()
t.setCursorPos(math.floor((w / 2) - (str:len() / 2)), y or (h / 2))
t.write(str)
end
local function setup_win()
local tn = term.native()
local w, h = tn.getSize()
chat_win = window.create(tn, 1, 1, w, h - 1, true)
chat_win.setCursorBlink(false)
chat_win.setBackgroundColor(colors.black)
chat_win.setTextColor(colors.white)
chat_win.clear()
chat_w, chat_h = chat_win.getSize()
type_win = window.create(tn, 1, h, w, 1, true)
type_win.setBackgroundColor(colors.black)
type_win.setTextColor(colors.lightGray)
type_win.clear()
term.redirect(type_win)
end
local function kill(terminated)
if (type(term.native) == "function") then
term = m
term.redirect(term.native())
term = term.native()
else
term.redirect(term)
end
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
term.clear()
chat_win = nil
type_win = nil
if (serber and serber.cid) then
ringnet.sendData(
serber.cid,
textutils.serialize(
{
type = "CHAT_LOGOUT"
}
)
)
end
end
local function writeRight(text, y)
local w, h = term.getSize()
term.setCursorPos(w - #text, y)
term.write(text)
end
local function draw_list()
if #servers < 1 then
error("No servers found.", 0)
end
term.setBackgroundColor(colors.black)
term.clear()
for i = 1, #servers do
local serv = servers[i]
if i == current_server then
term.setBackgroundColor(colors.white)
term.setTextColor(colors.black)
else
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
end
term.setCursorPos(1, i)
term.clearLine()
term.write(serv.name)
writeRight(tostring(serv.fingerprint):sub(1, 8), i)
end
local _w, _h = term.getSize()
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
cwrite(term, "Press Enter to join a server.", _h)
end
local function draw_chat()
chat_win.setBackgroundColor(colors.black)
chat_win.setTextColor(colors.white)
chat_win.clear()
for y = 1, chat_h do
local o = truelog[(#truelog + s_offset - chat_h) + y]
if (type(o) == "table") then
chat_win.setCursorPos(1, y)
chat_win.blit(o[1], o[2], o[3])
end
y = y + 1
end
end
--------------
-- UI End --
--------------
-- API Loading
local function getAPI(name, url)
local apiloc = "/" .. name
if (not fs.exists(apiloc)) then
local newapiloc = shell and shell.resolveProgram(name) or nil
if type(newapiloc) ~= "string" then
download_file(url, apiloc)
else
apiloc = newapiloc
end
end
return apiloc
end
local ringnet = require(getAPI("ringnet", "https://pastebin.com/raw/tUe94t9J"))
getAPI("aeslua", "https://git.io/aeslua")
os.loadAPI("aeslua")
ringnet.openChannel(pingdata_channel)
ringnet.openChannel(connect_channel)
local tid = nil
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
term.clear()
cwrite(term, "Scanning for servers...")
local rid = math.random(100000, 999999)
table.insert(our_rids, rid)
mod.transmit(
pingdata_channel,
pingdata_channel,
textutils.serialize(
{
type = "SERVER_DATA",
rid = rid
}
)
)
parallel.waitForAll(
ringnet.connectionHandler,
function()
sleep(1.75)
os.queueEvent("timer_chat")
return
end,
function()
local mode = 1
local timer_tripped = false
while true do
local ev = {os.pullEvent()}
table.insert(dump_log, {mode, ev[1]})
if (ev[1] == "modem_message" and not timer_tripped) then
local mes = ev[5]
if (type(mes) == "string") then
mes = textutils.unserialize(mes)
end
if
(mes.type == "SERVER_RETURNDATA" and isOurRid(mes.to) and type(mes.hid) == "string" and string.len(mes.hid) == 8)
then
--print("Server! Name: " .. tostring(mes.name) .. " | Fingerprint: " .. tostring(mes.fingerprint):sub(1, 12))
table.insert(
servers,
{
name = mes.name,
fingerprint = mes.fingerprint,
hid = mes.hid,
locked = mes.locked or false
}
)
end
elseif (mode == 1 and ev[1] == "timer_chat") then
mode = 2
timer_tripped = true
draw_list()
elseif (mode == 2 and ev[1] == "key") then
if (ev[2] == 208 or ev[2] == 205) then
current_server = current_server + 1
if (current_server > #servers) then
current_server = 1
end
elseif (ev[2] == 200 or ev[2] == 203) then
current_server = current_server - 1
if (current_server < 1) then
current_server = #servers
end
elseif (ev[2] == 28) then
mode = 3
serber = servers[current_server]
print(serber.hid)
end
if (ev[2] ~= 28) then
draw_list()
end
elseif (mode == 3) then
ringnet.openTunnel(serber.hid, connect_channel)
mode = 4
elseif (mode == 4 and ev[1] == "tunnel_finish" and ev[3] == serber.hid) then
--elseif (mode == 5 and ev[1] == "mouse_scroll") then
-- s_offset = (s_offset) + ev[2]
-- s_offset = math.min(math.max(s_offset, 0), #truelog)
-- draw_chat()
serber.cid = ev[2]
setup_win()
mode = 5
elseif (mode == 5 and ev[1] == "secure_receive" and ev[2] == serber.cid) then
local cid = ev[2]
local data = ev[3]
if (serber.password) then
data = aeslua.decrypt(serber.password, data, aeslua.AES128, aeslua.CFBMODE)
end
if (type(data) == "string") then
data = textutils.unserialize(data)
end
if (type(data) == "table") then
table.insert(dump_log, textutils.serialize(data))
if (data.type == "CHAT_LOG" and type(data.log) == "table") then
truelog = {}
for i = 1, #data.log do
local a = data.log[i]
if ((type(a.name) == "string" or a.raw == true) and type(a.mes) == "string") then
if not a.raw then
local prefix = (a.name .. ": ")
local dje = (a.mes)
local combined = (prefix .. dje)
local output =
blitwrap(combined, (string.rep("0", #prefix) .. string.rep("8", #dje)), string.rep("f", #combined), true)
for k, v in pairs(output) do
table.insert(truelog, v)
end
else
local output = blitwrap(a.mes, string.rep("8", #a.mes), string.rep("f", #a.mes), true)
for k, v in pairs(output) do
table.insert(truelog, v)
end
end
end
end
local k = fs.open("/.TESTDUMP", "w")
k.write(textutils.serialize(truelog))
k.close()
draw_chat()
end
end
end
end
end,
function()
local named = false
local still_locked = true
while true do
if (type_win ~= nil) then
if not (serber.locked) then
still_locked = false
end
type_win.setBackgroundColor(colors.black)
type_win.setTextColor(colors.lightGray)
type_win.clear()
term.redirect(type_win)
if (serber.locked and still_locked and not named) then
cwrite(chat_win, "Please enter this server's password")
elseif (not still_locked and not named) then
cwrite(chat_win, "Please type the name you want below")
end
local a = tostring(read())
if a == "_EXIT" then
kill()
error("Exited.", 0)
elseif (serber.locked and still_locked) then
if (aeslua.decrypt(a, serber.locked, aeslua.AES128, aeslua.CFBMODE) == "_A_COMMON_ENCRYPTION_STRING") then
still_locked = false
serber.password = a
end
elseif (not still_locked) then
if named then
if a:lower() == "/exit" or a:lower() == "/logout" then
ringnet.sendData(
serber.cid,
textutils.serialize(
{
type = "CHAT_LOGOUT"
}
)
)
sleep(1.5)
kill()
error()
elseif a:lower() == "/forceupdate" or a:lower() == "/update" then
ringnet.sendData(
serber.cid,
textutils.serialize(
{
type = "CHAT_FORCEUPDATE"
}
)
)
else
ringnet.sendData(
serber.cid,
textutils.serialize(
{
type = "CHAT_CHAT",
message = a
}
)
)
end
else
ringnet.sendData(
serber.cid,
textutils.serialize(
{
type = "CHAT_LOGIN",
name = a
}
)
)
chat_win.setBackgroundColor(colors.black)
chat_win.setTextColor(colors.white)
chat_win.clear()
named = true
end
end
end
sleep(0.1)
end
end
)
end,
function(err)
term.redirect(term.native and term.native() or term.current())
local stack = buildStackTrace(err)
printError("\nRingchat has crashed! Stack trace:")
printError(stack)
local file = fs.open("/chat.err", "w")
file.write(tostring(stack))
file.close()
end
)