Compare commits

..

95 Commits

Author SHA1 Message Date
61c65010e4 iteration 2023-10-09 07:22:18 -04:00
dde9993e07 iteration 2023-10-09 07:15:05 -04:00
c3d3fefd08 iteration 2023-10-09 07:14:14 -04:00
7aad0ba0e1 iteration 2023-10-09 07:06:30 -04:00
254a44ee82 iteration 2023-10-09 07:05:13 -04:00
de8efb1b5d iteration 2023-10-09 07:01:31 -04:00
bb0d27b755 iteration 2023-10-09 06:54:35 -04:00
e6ed55bcc7 iteration 2023-10-08 05:44:23 -04:00
cba8b4089c iteration 2023-10-08 05:43:24 -04:00
8c3feb5233 iteration 2023-10-08 05:39:17 -04:00
6aeedb89a6 iteration 2023-10-08 05:36:08 -04:00
310af0a489 iteration 2023-10-08 05:34:38 -04:00
93f9e3e0c7 iteration 2023-10-08 05:33:00 -04:00
44a98f1741 iteration 2023-10-08 05:29:02 -04:00
fbc308d265 iteration 2023-10-08 05:26:14 -04:00
30dd8e8070 iteration 2023-10-08 05:25:17 -04:00
3035d7563f iteration 2023-10-08 05:22:41 -04:00
1fe688e287 iteration 2023-10-08 05:19:07 -04:00
2114e16af9 iteration 2023-10-08 05:15:17 -04:00
729a6a211d iteration 2023-10-08 05:12:55 -04:00
f17190bbc9 iteration 2023-10-08 05:11:52 -04:00
f9ae7618c9 iteration 2023-10-08 05:07:48 -04:00
b4d9af64d0 iteration 2023-10-08 05:03:40 -04:00
9ce61897d4 iteration 2023-10-08 05:02:19 -04:00
75a45e18e3 iteration 2023-10-08 05:01:36 -04:00
0f748992a8 iteration 2023-10-08 04:59:38 -04:00
7a79961839 iteration 2023-10-08 04:57:53 -04:00
c06a8f2265 iteration 2023-10-08 04:56:10 -04:00
4199e6e793 iteration 2023-10-08 04:54:18 -04:00
20a8b68314 iteration 2023-10-08 04:52:13 -04:00
6eca8bd3a5 iteration 2023-10-08 04:51:13 -04:00
c305bcd995 iteration 2023-10-08 04:49:28 -04:00
7585850fa3 iteration 2023-10-08 04:47:35 -04:00
70c05cf42c iteration 2023-10-08 04:46:22 -04:00
9ed504bb5f iteration 2023-10-08 04:44:58 -04:00
282f209217 iteration 2023-10-08 04:23:25 -04:00
510bc2b2a9 iteration 2023-10-08 04:19:52 -04:00
654c5394cd iteration 2023-10-08 04:18:31 -04:00
f3c4004500 iteration 2023-10-08 04:17:33 -04:00
23839bfcbe iteration 2023-10-08 04:14:52 -04:00
7c580e25ea iteration 2023-10-08 04:12:29 -04:00
1f24cd18b1 iteration 2023-10-08 04:11:02 -04:00
b52af66471 iteration 2023-10-08 04:10:24 -04:00
745de810e4 iteration 2023-10-08 04:07:33 -04:00
8eeaad61d5 iteration 2023-10-08 04:06:34 -04:00
8623e9cdd9 iteration 2023-10-08 04:05:18 -04:00
f0233a640d iteration 2023-10-08 04:04:21 -04:00
c9e6e5d229 iteration 2023-10-08 03:24:17 -04:00
d147fe682c iteration 2023-10-08 03:21:02 -04:00
41c7bc33a0 iteration 2023-10-08 03:14:12 -04:00
ad59627743 iteration 2023-10-08 03:13:18 -04:00
1a143b8995 iteration 2023-10-08 03:12:29 -04:00
0aa280381e iteration 2023-10-08 03:12:06 -04:00
0fefa83215 iteration 2023-10-08 03:09:41 -04:00
697906c953 iteration 2023-10-08 03:01:39 -04:00
2128066f14 iteration 2023-10-08 03:00:16 -04:00
a7761faf62 iteration 2023-10-08 02:57:56 -04:00
0510472f3c iteration 2023-10-08 02:56:33 -04:00
ca1af05b1e iteration 2023-10-08 02:55:56 -04:00
97f0f5529a iteration 2023-10-08 02:54:58 -04:00
908b5c6906 iteration 2023-10-08 02:53:18 -04:00
a2473fccdb iteration 2023-10-08 02:51:25 -04:00
0acd6acb11 iteration 2023-10-08 02:50:17 -04:00
f02d18674a iteration 2023-10-08 02:48:03 -04:00
a58ca7b94c iteration 2023-10-08 02:44:20 -04:00
22743c248c iteration 2023-10-08 02:36:02 -04:00
1f180d0627 iteration 2023-10-08 02:31:20 -04:00
60afced577 iteration 2023-10-08 02:28:59 -04:00
974c395331 iteration 2023-10-08 02:26:08 -04:00
c296d2612e iteration 2023-10-08 02:25:17 -04:00
c918c2da39 iteration 2023-10-08 02:18:41 -04:00
eb55a5d783 iteration 2023-10-08 01:59:14 -04:00
f63ab77fc1 iteration 2023-10-08 01:56:24 -04:00
d0ea038cdb iteration 2023-10-08 01:52:14 -04:00
583bca0a38 iteration 2023-10-08 01:47:22 -04:00
8a27a2ad06 iteration 2023-10-08 01:41:16 -04:00
b576c57f18 iteration 2023-10-08 01:39:10 -04:00
00cb10d9f5 iteration 2023-10-08 01:26:35 -04:00
14b8fc2cb6 iteration 2023-10-08 01:15:07 -04:00
0f2a13c4e3 iteration 2023-10-08 01:14:20 -04:00
f0615dfdc2 iteration 2023-10-08 01:12:05 -04:00
8068b1dcd0 iteration 2023-10-08 01:10:29 -04:00
4767b0ea01 iteration 2023-10-08 01:09:44 -04:00
8d2d7e2455 iteration 2023-10-08 00:43:56 -04:00
c8868c6732 iteration 2023-10-08 00:41:44 -04:00
ea5b2af9e8 iteration 2023-10-08 00:39:56 -04:00
975a70f69f iteration 2023-10-08 00:36:13 -04:00
d8f6c626ef iteration 2023-10-08 00:35:08 -04:00
f5c104b3de iteration 2023-10-08 00:33:38 -04:00
c85af16b55 iteration 2023-10-08 00:32:26 -04:00
d06c9c24c9 iteration 2023-10-08 00:30:50 -04:00
627dc1ac68 iteration 2023-10-08 00:19:55 -04:00
7fcae7b276 iteration 2023-10-07 23:52:54 -04:00
268e92d12a iteration 2023-10-07 23:49:51 -04:00
f6d3aef757 iteration 2023-10-07 23:48:43 -04:00
18 changed files with 1378 additions and 112 deletions

3
ReadMe.md Normal file
View File

@ -0,0 +1,3 @@
# ComputerCraft Programs & APIs
ComputerCraft Lua programs and APIs

45
install.lua Normal file
View File

@ -0,0 +1,45 @@
local args = { ... }
local target_branch = "main"
local bin_path = "/bin/"
local lib_path = "/lib/"
local startup_path = "/startup/"
function download(remote_path, local_path)
io.write("Downloading " .. remote_path .. " to " .. local_path .. "\n")
response = http.get("https://gitea.layla.gg/layla/computercraft/raw/branch/" .. target_branch .. "/" .. remote_path, nil)
if response.getResponseCode() == 200 then
file = fs.open(local_path, "w")
file.write(response.readAll())
file.close()
else
io.write("Failed to update " .. remote_path .. "\n")
io.write(response)
end
end
-- Startup
download("utils/lsh.lua", startup_path .. "lsh.lua")
-- Lib
download("lib/auth.lua", lib_path .. "auth.lua")
download("lib/lns.lua", lib_path .. "lns.lua")
download("lib/lum.lua", lib_path .. "lum.lua")
-- Bin
download("lum.lua", bin_path .. "lum.lua")
-- Run lsh
ok = shell.run(startup_path .. "lsh.lua")
if not ok then
io.write("Failed to run lsh!\n")
return
end
-- Packages
lum.install("dig")
lum.install("auth")
io.write("Done!\n")

202
lib/auth.lua Normal file
View File

@ -0,0 +1,202 @@
-- Desc: Authentication library
-- Auth: Layla Manley
-- Link: https://gitea.layla.gg/layla/computercraft
settings.define("auth.token", {
description = "Authentication token",
type = "number",
default = -1
})
settings.define("auth.server", {
description = "Authentication server",
type = "string",
default = "auth.box"
})
function login(username, password)
local data = {
["action"] = "login",
["username"] = username,
["password"] = password
}
local auth_server_id = lns.lookup(settings.get("auth.server"))
rednet.send(auth_server_id, data, "auth")
local token = nil
while true do
id, msg = rednet.receive("auth")
if id == auth_server_id then
if msg == "invalid request" then
io.write("Invalid request\n")
return false
elseif msg == "user not found" then
io.write("User not found\n")
return false
elseif msg == "invalid password" then
io.write("Invalid password\n")
return false
else
token = msg
break
end
end
end
settings.set("auth.username", username)
settings.set("auth.token", token)
settings.save()
return true
end
function register(username, password)
local data = {
["action"] = "register",
["username"] = username,
["password"] = password
}
local auth_server_id = lns.lookup(settings.get("auth.server"))
rednet.send(auth_server_id, data, "auth")
while true do
id, msg = rednet.receive("auth")
if id == auth_server_id then
if msg == "invalid request" then
io.write("Invalid request\n")
return false
elseif msg == "user already exists" then
io.write("User already exists\n")
return false
else
io.write("Registered user " .. username .. "\n")
return true
end
end
end
end
function logout()
settings.set("auth.token", -1)
settings.save()
io.write("Logged out\n")
end
function get_token()
return settings.get("auth.token")
end
function check_user_in_group(username, group)
local data = {
["action"] = "check_group",
["username"] = username,
["group"] = group
}
local auth_server_id = lns.lookup(settings.get("auth.server"))
rednet.send(auth_server_id, data, "auth")
while true do
id, msg = rednet.receive("auth")
if id == auth_server_id then
if msg == "invalid request" then
io.write("Invalid request\n")
return false
elseif msg == true then
return true
else
return false
end
end
end
end
function trueKeysToString(tbl)
local result = ""
local first = true
for key, value in pairs(tbl) do
if value == true then
if not first then
result = result .. ", "
else
first = false
end
result = result .. key
end
end
return result
end
function list_to_string(list)
local str = ""
for i, v in ipairs(list) do
str = str .. v .. ", "
end
return str:sub(1, -3)
end
function list_user_groups(username)
local data = {
["action"] = "list_groups",
["username"] = username
}
local auth_server_id = lns.lookup(settings.get("auth.server"))
rednet.send(auth_server_id, data, "auth")
while true do
id, msg = rednet.receive("auth")
if id == auth_server_id then
if msg == "invalid request" then
io.write("Invalid request\n")
return
elseif msg == "user not found" then
io.write("User not found\n")
return
elseif msg == "invalid token" then
io.write("Invalid token\n")
return
else
return msg
end
end
end
end
function add_user_to_group(username, group)
local data = {
["action"] = "add_group",
["username"] = username,
["group"] = group,
["token"] = get_token()
}
local auth_server_id = lns.lookup(settings.get("auth.server"))
rednet.send(auth_server_id, data, "auth")
while true do
id, msg = rednet.receive("auth")
if id == auth_server_id then
if msg == "invalid request" then
io.write("Invalid request\n")
return false
elseif msg == "user not found" then
io.write("User not found\n")
return false
elseif msg == "invalid token" then
io.write("Invalid token\n")
return false
elseif msg == "invalid privileges" then
io.write("Invalid privileges\n")
return false
elseif msg == "ok" then
return true
else
return false
end
end
end
end

22
lib/ccttp.lua Normal file
View File

@ -0,0 +1,22 @@
-- Desc: CCTTP Networking Library
-- Auth: Layla Manley
-- Link: https://gitea.layla.gg/layla/computercraft
Response = {
status = 0,
body = "",
headers = {}
}
function Response:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function get(url, headers)
headers = headers or {}
return true
end

212
lib/json.lua Normal file
View File

@ -0,0 +1,212 @@
-- Desc: JSON encoder/decoder
-- Auth: ElvishJerricco
-- Link: http://www.computercraft.info/forums2/index.php?/topic/5854-json-api-v201-for-computercraft/
------------------------------------------------------------------ utils
local controls = {["\n"]="\\n", ["\r"]="\\r", ["\t"]="\\t", ["\b"]="\\b", ["\f"]="\\f", ["\""]="\\\"", ["\\"]="\\\\"}
local function isArray(t)
local max = 0
for k,v in pairs(t) do
if type(k) ~= "number" then
return false
elseif k > max then
max = k
end
end
return max == #t
end
local whites = {['\n']=true; ['\r']=true; ['\t']=true; [' ']=true; [',']=true; [':']=true}
function removeWhite(str)
while whites[str:sub(1, 1)] do
str = str:sub(2)
end
return str
end
------------------------------------------------------------------ encoding
local function encodeCommon(val, pretty, tabLevel, tTracking)
local str = ""
-- Tabbing util
local function tab(s)
str = str .. ("\t"):rep(tabLevel) .. s
end
local function arrEncoding(val, bracket, closeBracket, iterator, loopFunc)
str = str .. bracket
if pretty then
str = str .. "\n"
tabLevel = tabLevel + 1
end
for k,v in iterator(val) do
tab("")
loopFunc(k,v)
str = str .. ","
if pretty then str = str .. "\n" end
end
if pretty then
tabLevel = tabLevel - 1
end
if str:sub(-2) == ",\n" then
str = str:sub(1, -3) .. "\n"
elseif str:sub(-1) == "," then
str = str:sub(1, -2)
end
tab(closeBracket)
end
-- Table encoding
if type(val) == "table" then
assert(not tTracking[val], "Cannot encode a table holding itself recursively")
tTracking[val] = true
if isArray(val) then
arrEncoding(val, "[", "]", ipairs, function(k,v)
str = str .. encodeCommon(v, pretty, tabLevel, tTracking)
end)
else
arrEncoding(val, "{", "}", pairs, function(k,v)
assert(type(k) == "string", "JSON object keys must be strings", 2)
str = str .. encodeCommon(k, pretty, tabLevel, tTracking)
str = str .. (pretty and ": " or ":") .. encodeCommon(v, pretty, tabLevel, tTracking)
end)
end
-- String encoding
elseif type(val) == "string" then
str = '"' .. val:gsub("[%c\"\\]", controls) .. '"'
-- Number encoding
elseif type(val) == "number" or type(val) == "boolean" then
str = tostring(val)
else
error("JSON only supports arrays, objects, numbers, booleans, and strings", 2)
end
return str
end
function encode(val)
return encodeCommon(val, false, 0, {})
end
function encodePretty(val)
return encodeCommon(val, true, 0, {})
end
------------------------------------------------------------------ decoding
local decodeControls = {}
for k,v in pairs(controls) do
decodeControls[v] = k
end
function parseBoolean(str)
if str:sub(1, 4) == "true" then
return true, removeWhite(str:sub(5))
else
return false, removeWhite(str:sub(6))
end
end
function parseNull(str)
return nil, removeWhite(str:sub(5))
end
local numChars = {['e']=true; ['E']=true; ['+']=true; ['-']=true; ['.']=true}
function parseNumber(str)
local i = 1
while numChars[str:sub(i, i)] or tonumber(str:sub(i, i)) do
i = i + 1
end
local val = tonumber(str:sub(1, i - 1))
str = removeWhite(str:sub(i))
return val, str
end
function parseString(str)
str = str:sub(2)
local s = ""
while str:sub(1,1) ~= "\"" do
local next = str:sub(1,1)
str = str:sub(2)
assert(next ~= "\n", "Unclosed string")
if next == "\\" then
local escape = str:sub(1,1)
str = str:sub(2)
next = assert(decodeControls[next..escape], "Invalid escape character")
end
s = s .. next
end
return s, removeWhite(str:sub(2))
end
function parseArray(str)
str = removeWhite(str:sub(2))
local val = {}
local i = 1
while str:sub(1, 1) ~= "]" do
local v = nil
v, str = parseValue(str)
val[i] = v
i = i + 1
str = removeWhite(str)
end
str = removeWhite(str:sub(2))
return val, str
end
function parseObject(str)
str = removeWhite(str:sub(2))
local val = {}
while str:sub(1, 1) ~= "}" do
local k, v = nil, nil
k, v, str = parseMember(str)
val[k] = v
str = removeWhite(str)
end
str = removeWhite(str:sub(2))
return val, str
end
function parseMember(str)
local k = nil
k, str = parseValue(str)
local val = nil
val, str = parseValue(str)
return k, val, str
end
function parseValue(str)
local fchar = str:sub(1, 1)
if fchar == "{" then
return parseObject(str)
elseif fchar == "[" then
return parseArray(str)
elseif tonumber(fchar) ~= nil or numChars[fchar] then
return parseNumber(str)
elseif str:sub(1, 4) == "true" or str:sub(1, 5) == "false" then
return parseBoolean(str)
elseif fchar == "\"" then
return parseString(str)
elseif str:sub(1, 4) == "null" then
return parseNull(str)
end
return nil
end
function decode(str)
str = removeWhite(str)
t = parseValue(str)
return t
end
function decodeFromFile(path)
local file = assert(fs.open(path, "r"))
local decoded = decode(file.readAll())
file.close()
return decoded
end

84
lib/lns.lua Normal file
View File

@ -0,0 +1,84 @@
-- Desc: LNS Client
-- Auth: Layla Manley
-- Link: https://gitea.layla.gg/layla/computercraft
local cache = {}
local cache_file = "/var/cache/lns_cache.db"
settings.define("lns_client.allow_dynamic_lns_hosts", {
description = "Allow dynamic LNS hosts",
type = "boolean",
default = false
})
settings.define("lns_client.lns_server", {
description = "LNS Server Rednet ID",
type = "number",
default = 8
})
function _load_cache()
if fs.exists(cache_file) then
db = fs.open(cache_file, "r")
db_contents = db.readAll()
db.close()
cache = textutils.unserialize(db_contents)
end
end
function _save_cache()
db = fs.open(cache_file, "w")
db.write(textutils.serialize(cache))
db.close()
end
function server()
local lns_server_id = settings.get("lns_client.lns_server")
local allow_dynamic_lns_hosts = settings.get("lns_client.allow_dynamic_lns_hosts")
if allow_dynamic_lns_hosts then
lns_server_id = rednet.lookup("lns", lns_server)
if lns_server_id == nil then
io.write("LNS Server not found!\n")
return nil
end
end
return lns_server_id
end
function lookup(remote_hostname)
_load_cache()
if cache[remote_hostname] ~= nil then
return cache[remote_hostname]
end
local data = {
["action"] = "lookup",
["hostname"] = remote_hostname
}
local lns_server_id = server()
rednet.send(lns_server_id, data, "lns")
while true do
id, msg = rednet.receive("lns")
if id == lns_server_id then
if msg == nil then
return nil
else
cache[remote_hostname] = msg
_save_cache()
return msg
end
end
end
end
function clear_cache()
cache = {}
_save_cache()
print("Cleared cache!")
end

66
lib/lum.lua Normal file
View File

@ -0,0 +1,66 @@
-- Desc: Lum Package Manager
-- Auth: Layla Manley
-- Link: https://gitea.layla.gg/layla/computercraft
local target_branch = "main"
local bin_path = "/bin/"
local lib_path = "/lib/"
local startup_path = "/startup/"
settings.define("lum.target_branch", {
description = "Target branch for updates",
type = "string",
default = "main"
})
settings.define("lum.log_level", {
description = "Log Level",
type = "string",
default = "debug"
})
function download_lua(remote_path, local_path)
local url = "https://gitea.layla.gg/layla/computercraft/raw/branch/" .. settings.get("lum.target_branch") .. "/" .. remote_path
if settings.get("lum.log_level") == "debug" then
io.write("Downloading " .. url .. " to " .. local_path .. "\n")
end
local response = http.get(url, nil)
if response.getResponseCode() == 200 then
file = fs.open(local_path, "w")
file.write(response.readAll())
file.close()
else
io.write("Failed to download " .. remote_path .. ".lua\n")
io.write(response)
end
end
function install(package)
io.write("Installing " .. package .. "\n")
local dir = bin_path
local package_dir = "packages/"
--if package starts with lib then remove lib
if string.sub(package, 1, 3) == "lib" then
package = string.sub(package, 4)
dir = lib_path
package_dir = "lib/"
end
download_lua(package_dir .. package .. ".lua", dir .. package .. ".lua")
if dir == lib_path then
os.loadAPI(lib_path .. package .. ".lua")
end
end
function remove(package)
io.write("Removing " .. package .. "\n")
local dir = bin_path
--if package starts with lib then remove lib
if string.sub(package, 1, 3) == "lib" then
package = string.sub(package, 5)
dir = lib_path
end
fs.delete(dir .. package .. ".lua")
end

195
lib/sha256.lua Normal file
View File

@ -0,0 +1,195 @@
-- Desc: SHA-256 hashing algorithm
-- Auth: GravityScore
-- Link: http://www.computercraft.info/forums2/index.php?/topic/8169-sha-256-in-pure-lua/
-------------------------------------------------------------------
--
-- Adaptation of the Secure Hashing Algorithm (SHA-244/256)
-- Found Here: http://lua-users.org/wiki/SecureHashAlgorithm
--
-- Using an adapted version of the bit library
-- Found Here: https://bitbucket.org/Boolsheet/bslf/src/1ee664885805/bit.lua
--
local MOD = 2^32
local MODM = MOD-1
local function memoize(f)
local mt = {}
local t = setmetatable({}, mt)
function mt:__index(k)
local v = f(k)
t[k] = v
return v
end
return t
end
local function make_bitop_uncached(t, m)
local function bitop(a, b)
local res,p = 0,1
while a ~= 0 and b ~= 0 do
local am, bm = a % m, b % m
res = res + t[am][bm] * p
a = (a - am) / m
b = (b - bm) / m
p = p*m
end
res = res + (a + b) * p
return res
end
return bitop
end
local function make_bitop(t)
local op1 = make_bitop_uncached(t,2^1)
local op2 = memoize(function(a) return memoize(function(b) return op1(a, b) end) end)
return make_bitop_uncached(op2, 2 ^ (t.n or 1))
end
local bxor1 = make_bitop({[0] = {[0] = 0,[1] = 1}, [1] = {[0] = 1, [1] = 0}, n = 4})
local function bxor(a, b, c, ...)
local z = nil
if b then
a = a % MOD
b = b % MOD
z = bxor1(a, b)
if c then z = bxor(z, c, ...) end
return z
elseif a then return a % MOD
else return 0 end
end
local function band(a, b, c, ...)
local z
if b then
a = a % MOD
b = b % MOD
z = ((a + b) - bxor1(a,b)) / 2
if c then z = bit32_band(z, c, ...) end
return z
elseif a then return a % MOD
else return MODM end
end
local function bnot(x) return (-1 - x) % MOD end
local function rshift1(a, disp)
if disp < 0 then return lshift(a,-disp) end
return math.floor(a % 2 ^ 32 / 2 ^ disp)
end
local function rshift(x, disp)
if disp > 31 or disp < -31 then return 0 end
return rshift1(x % MOD, disp)
end
local function lshift(a, disp)
if disp < 0 then return rshift(a,-disp) end
return (a * 2 ^ disp) % 2 ^ 32
end
local function rrotate(x, disp)
x = x % MOD
disp = disp % 32
local low = band(x, 2 ^ disp - 1)
return rshift(x, disp) + lshift(low, 32 - disp)
end
local k = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
}
local function str2hexa(s)
return (string.gsub(s, ".", function(c) return string.format("%02x", string.byte(c)) end))
end
local function num2s(l, n)
local s = ""
for i = 1, n do
local rem = l % 256
s = string.char(rem) .. s
l = (l - rem) / 256
end
return s
end
local function s232num(s, i)
local n = 0
for i = i, i + 3 do n = n*256 + string.byte(s, i) end
return n
end
local function preproc(msg, len)
local extra = 64 - ((len + 9) % 64)
len = num2s(8 * len, 8)
msg = msg .. "\128" .. string.rep("\0", extra) .. len
assert(#msg % 64 == 0)
return msg
end
local function initH256(H)
H[1] = 0x6a09e667
H[2] = 0xbb67ae85
H[3] = 0x3c6ef372
H[4] = 0xa54ff53a
H[5] = 0x510e527f
H[6] = 0x9b05688c
H[7] = 0x1f83d9ab
H[8] = 0x5be0cd19
return H
end
local function digestblock(msg, i, H)
local w = {}
for j = 1, 16 do w[j] = s232num(msg, i + (j - 1)*4) end
for j = 17, 64 do
local v = w[j - 15]
local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3))
v = w[j - 2]
w[j] = w[j - 16] + s0 + w[j - 7] + bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10))
end
local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]
for i = 1, 64 do
local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22))
local maj = bxor(band(a, b), band(a, c), band(b, c))
local t2 = s0 + maj
local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25))
local ch = bxor (band(e, f), band(bnot(e), g))
local t1 = h + s1 + ch + k[i] + w[i]
h, g, f, e, d, c, b, a = g, f, e, d + t1, c, b, a, t1 + t2
end
H[1] = band(H[1] + a)
H[2] = band(H[2] + b)
H[3] = band(H[3] + c)
H[4] = band(H[4] + d)
H[5] = band(H[5] + e)
H[6] = band(H[6] + f)
H[7] = band(H[7] + g)
H[8] = band(H[8] + h)
end
local function sha256(msg)
msg = preproc(msg, #msg)
local H = initH256({})
for i = 1, #msg, 64 do digestblock(msg, i, H) end
return str2hexa(num2s(H[1], 4) .. num2s(H[2], 4) .. num2s(H[3], 4) .. num2s(H[4], 4) ..
num2s(H[5], 4) .. num2s(H[6], 4) .. num2s(H[7], 4) .. num2s(H[8], 4))
end

View File

@ -1,67 +0,0 @@
modem_location = "right"
rednet.host("lns", "default")
rednet.open(modem_location)
local data = {}
function save_data()
db = fs.open("lns.db", "w")
db.write(textutils.serialize(data))
db.close()
end
function load_data()
if fs.exists("lns.db") then
db = fs.open("lns.db", "r")
db_contents = db.readAll()
db.close()
data = textutils.unserialize(db_contents)
end
end
function split (inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
load_data()
while true do
client_id, msg = rednet.receive()
request = msg
if request.action == nil or request.hostname == nil then
rednet.send(client_id, "invalid request")
end
if request.action == "lookup" then
-- check if hostname in data
if request.hostname == nil then
rednet.send(client_id, "not found")
else
rednet.send(client_id, data[request.hostname])
end
end
if request.action == "reload" then
load_data()
rednet.send(client_id, "ok")
end
if request.action == "register" then
data[request.hostname] = client_id
save_data()
rednet.send(client_id, "ok")
end
end

28
lum.lua Normal file
View File

@ -0,0 +1,28 @@
local args = { ... }
local action = args[1]
if action == "install" then
package = args[2]
if package == nil then
print("Usage: lum install <package>")
return
end
lum.install(package)
io.write("Done!\n")
elseif action == "remove" then
package = args[2]
if package == nil then
print("Usage: lum remove <package>")
return
end
lum.remove(package)
io.write("Done!\n")
elseif action == "version" then
print("0.1.0")
else
io.write("Usage: lum <install:remove:version>\n")
end

View File

@ -1,33 +0,0 @@
local args = { ... }
local target_branch = "main"
local bin_path = "/bin/"
local program_name = args[1]
if program_name == nil then
print("Usage: lupdate <program_name>")
return
end
response = http.get("https://gitea.layla.gg/layla/computercraft/raw/branch/" .. target_branch .. "/" .. program_name .. ".lua", nil)
io.write("Updating " .. program_name .. ".lua\n")
if response.getResponseCode() == 200 then
file = fs.open(bin_path .. program_name .. ".lua", "w")
file.write(response.readAll())
file.close()
-- check if program is in path
if not shell.resolveProgram(program_name) then
io.write("Program not in path, adding to path\n")
shell.setPath(shell.path() .. ":" .. bin_path)
end
io.write("Updated " .. program_name .. ".lua\n")
else
io.write("Failed to update " .. program_name .. ".lua\n")
io.write(response)
end

75
packages/auth.lua Normal file
View File

@ -0,0 +1,75 @@
args = { ... }
if args[1] == nil then
io.write("Usage: auth <action>\n")
return
end
local action = args[1]
if action == "login" then
io.write("Username: ")
local username = io.read()
io.write("Password: ")
local password = read("*")
if login(username, password) then
io.write("Logged in as " .. username .. "\n")
end
elseif action == "logout" then
auth.logout()
return
elseif action == "register" then
io.write("Username: ")
local username = io.read()
io.write("Password: ")
local password = read("*")
io.write("Confirm Password: ")
local confirm_password = read("*")
if password ~= confirm_password then
io.write("Passwords do not match\n")
return
end
auth.register(username, password)
elseif action == "group" then
local subaction = args[2]
if subaction == nil then
io.write("Usage: auth group <list:check:add>\n")
return
end
if subaction == "list" then
local result = auth.list_user_groups(settings.get("auth.username"))
io.write("Groups: " .. auth.trueKeysToString(result) .. "\n")
elseif subaction == "add" then
local target_user = args[3]
local group = args[4]
if target_user == nil or group == nil then
io.write("Usage: auth group add <user> <group>\n")
return
end
local result = auth.add_user_to_group(target_user, group)
elseif subaction == "check" then
local target_user = args[3]
local group = args[4]
if target_user == nil or group == nil then
io.write("Usage: auth group check <user> <group>\n")
return
end
local result = auth.check_user_in_group(target_user, group)
if result then
io.write("User " .. target_user .. " is in group " .. group .. "\n")
else
io.write("User " .. target_user .. " is not in group " .. group .. "\n")
end
else
io.write("Usage: auth group <list:check:add>\n")
return
end
end

233
packages/auth_server.lua Normal file
View File

@ -0,0 +1,233 @@
settings.define("auth_server.salt", {
description = "Salt for hashing passwords",
type = "string",
default = "3m&LmNm7"
})
local data = {
users = {}
}
-- Schema:
-- data = {
-- users = {
-- ["username"] = {
-- token = "token",
-- password = "hashed password",
-- groups = {
-- ["group"] = true
-- },
-- },
-- }
function save_data()
db = fs.open("auth.db", "w")
db.write(textutils.serialize(data))
db.close()
end
function load_data()
if fs.exists("auth.db") then
db = fs.open("auth.db", "r")
db_contents = db.readAll()
db.close()
data = textutils.unserialize(db_contents)
end
end
function generate_token(user)
local token = sha256.sha256(user .. os.time() .. math.random())
data.users[user].token = token
return token
end
function convert_password(password)
local salt = settings.get("auth_server.salt")
return sha256.sha256(password .. salt)
end
function log(str)
io.write("[" .. os.time() .. "] " .. str .. "\n")
end
function countElements(table)
local count = 0
for key, value in pairs(table) do
count = count + 1
end
return count
end
load_data()
math.randomseed(os.time())
while true do
client_id, msg = rednet.receive("auth")
request = msg
if request.action == nil then
rednet.send(client_id, "invalid request", "auth")
end
if request.action == "register" then
if request.username == nil or request.password == nil then
rednet.send(client_id, "invalid request", "auth")
end
if data.users[request.username] ~= nil then
rednet.send(client_id, "user already exists", "auth")
end
data.users[request.username] = {
password = convert_password(request.password)
}
local user_count = countElements(data.users)
if user_count == 1 then
log("Promoting " .. request.username .. " to admin")
data.users[request.username].groups = {
["admin"] = true
}
end
save_data()
rednet.send(client_id, "ok", "auth")
log(request.username .. " registered")
end
if request.action == "login" then
if request.username == nil or request.password == nil then
rednet.send(client_id, "invalid request", "auth")
elseif data.users[request.username] == nil then
rednet.send(client_id, "user not found", "auth")
log(request.username .. " failed log in attempt")
elseif convert_password(request.password) == data.users[request.username].password then
local token = generate_token(request.username)
rednet.send(client_id, token, "auth")
log(request.username .. " logged in")
else
rednet.send(client_id, "invalid password", "auth")
end
end
if request.action == "token" then
if request.token == nil or request.token == "" or request.token == -1 then
rednet.send(client_id, "invalid request", "auth")
else
local found = false
for user, userdata in pairs(data.users) do
if userdata.token == request.token then
rednet.send(client_id, user, "auth")
found = true
end
end
if not found then
rednet.send(client_id, "invalid token", "auth")
end
end
end
if request.action == "profile" then
if request.username == nil then
rednet.send(client_id, "invalid request", "auth")
end
local profile = {}
if data.users[request.username].profile_data ~= nil then
profile = data.users[request.username].profile_data
else
profile.display_name = request.username
end
profile.username = request.username
rednet.send(client_id, data.users[request.username], "auth")
end
if request.action == "update_profile" then
if request.username == nil or request.token == nil then
rednet.send(client_id, "invalid request", "auth")
end
if data.users[request.username].token == request.token then
if request.profile_data ~= nil then
data.users[request.username].profile_data = request.profile_data
end
save_data()
rednet.send(client_id, "ok")
log(request.username .. " updated their profile", "auth")
else
rednet.send(client_id, "invalid token", "auth")
end
end
if request.action == "check_group" then
if request.username == nil or request.group == nil then
rednet.send(client_id, "invalid request", "auth")
end
if data.users[request.username].groups == nil or data.users[request.username].groups[request.group] == nil or data.users[request.username].groups[request.group] == false then
rednet.send(client_id, false, "auth")
else
rednet.send(client_id, true, "auth")
end
end
if request.action == "list_groups" then
if request.username == nil then
rednet.send(client_id, "invalid request", "auth")
end
if data.users[request.username].groups == nil then
rednet.send(client_id, {}, "auth")
else
rednet.send(client_id, data.users[request.username].groups, "auth")
end
end
-- Only if in group admin
if request.action == "add_group" then
if request.username == nil or request.group == nil or request.token == nil then
rednet.send(client_id, "invalid request", "auth")
else
local found = false
local acting_user = nil
for user, userdata in pairs(data.users) do
if userdata.token == request.token then
acting_user = user
found = true
end
end
if not found then
rednet.send(client_id, "invalid token", "auth")
elseif data.users[acting_user]["groups"] == nil or data.users[acting_user].groups["admin"] == nil then
rednet.send(client_id, "invalid privileges", "auth")
else
if data.users[request.username].groups == nil then
data.users[request.username].groups = {}
end
data.users[request.username].groups[request.group] = true
save_data()
rednet.send(client_id, "ok", "auth")
log(request.username .. " added to group " .. request.group, "auth")
end
end
end
end

13
packages/dig.lua Normal file
View File

@ -0,0 +1,13 @@
local args = { ... }
if args[1] == nil then
print("Usage: dig <hostname>")
return
end
result = lns.lookup(args[1])
if result == nil then
io.write("Not found!\n")
else
io.write(result .. "\n")
end

184
packages/lns_server.lua Normal file
View File

@ -0,0 +1,184 @@
settings.define("lns_server.modem_location", {
description = "Modem location",
type = "string",
default = "right"
})
modem_location = settings.get("lns_server.modem_location")
settings.define("lns_server.rednet_hostname", {
description = "Rednet hostname",
type = "string",
default = "test"
})
settings.define("lns_server.require_auth", {
description = "Require authentication",
type = "boolean",
default = false
})
require_auth = settings.get("lns_server.require_auth")
settings.define("lns_server.auth_group", {
description = "Authentication group",
type = "string",
default = "admin"
})
local auth_group = settings.get("lns_server.auth_group")
settings.define("lns_server.auth_server", {
description = "Authentication server",
type = "string",
default = "auth.box"
})
auth_server = settings.get("lns_server.auth_server")
settings.define("lns_server.log_level", {
description = "Log Level",
type = "string",
default = "info"
})
log_level = settings.get("lns_server.log_level")
rednet.host("lns", settings.get("lns_server.rednet_hostname"))
rednet.open(modem_location)
local data = {}
function log(str)
io.write("[" .. os.time() .. "] " .. str .. "\n")
end
function log_debug(str)
if log_level == "debug" then
log(str)
end
end
function save_data()
db = fs.open("lns.db", "w")
db.write(textutils.serialize(data))
db.close()
end
function load_data()
if fs.exists("lns.db") then
db = fs.open("lns.db", "r")
db_contents = db.readAll()
db.close()
data = textutils.unserialize(db_contents)
end
end
function split (inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
function check_user_in_group(username, group)
local package = {
["action"] = "check_group",
["username"] = username,
["group"] = group
}
local authID = data[auth_server]
rednet.send(authID, package, "auth")
while true do
id, msg = rednet.receive("auth")
if id == authID then
if msg == "invalid request" then
io.write("Invalid request\n")
return false
elseif msg == true then
return true
else
return false
end
end
end
end
load_data()
while true do
client_id, msg = rednet.receive("lns")
request = msg
if request.action == nil or request.hostname == nil then
rednet.send(client_id, "invalid request", "lns")
end
if request.action == "lookup" then
-- check if hostname in data
if request.hostname == nil then
rednet.send(client_id, nil, "lns")
log("Sent nil to " .. client_id)
else
rednet.send(client_id, data[request.hostname], "lns")
log("Sent " .. request.hostname .. " to " .. client_id)
end
end
if request.action == "reload" then
load_data()
rednet.send(client_id, "ok", "lns")
log("Reloaded data")
end
if request.action == "register" then
local auth_passed = false
if require_auth then
local authID = data[auth_server]
if request.token == nil then
rednet.send(client_id, "invalid auth", "lns")
elseif authID ~= nil then
rednet.send(authID, {
["action"] = "token",
["token"] = request.token
}, "auth")
local responseServerID = nil
while responseServerID ~= authID do
responseServerID, auth_response = rednet.receive("auth")
end
local errorPos, errorEnd = string.find(auth_response, "invalid")
if errorPos then
log("Error: " .. auth_response)
else
if check_user_in_group(auth_response, auth_group) then
auth_passed = true
else
rednet.send(client_id, "invalid auth", "lns")
end
end
else
log("Error: Auth server not found to " .. client_id)
end
else
auth_passed = true
end
if auth_passed then
data[request.hostname] = client_id
log("Registered " .. request.hostname .. " as " .. client_id)
save_data()
rednet.send(client_id, "ok", "lns")
else
rednet.send(client_id, "auth required", "lns")
end
end
end

View File

@ -5,15 +5,6 @@ hostname = io.read()
io.write("Enter the modem location: ") io.write("Enter the modem location: ")
modem_location = io.read() modem_location = io.read()
io.write("Use default LNS Server? (y/n): ")
use_default = io.read()
lns_server = "default"
if use_default == "n" then
io.write("Enter the LNS Server Rednet Hostname: ")
lns_server = io.read()
end
rednet.open(modem_location) rednet.open(modem_location)
receiverID = rednet.lookup("lns", lns_server) receiverID = rednet.lookup("lns", lns_server)
current_time = os.time() current_time = os.time()
@ -21,13 +12,14 @@ current_time = os.time()
data = { data = {
["action"] = "register", ["action"] = "register",
["hostname"] = hostname ["hostname"] = hostname,
["token"] = settings.get("auth.token", nil)
} }
rednet.send(receiverID, data) rednet.send(receiverID, data, "lns")
while true do while true do
id, msg = rednet.receive() id, msg = rednet.receive("lns")
if id == receiverID then if id == receiverID then
if msg == "ok" then if msg == "ok" then
print("Registered with LNS Server Successfully!") print("Registered with LNS Server Successfully!")

12
utils/lsh.lua Normal file
View File

@ -0,0 +1,12 @@
local bin_path = "/bin/"
local lib_path = "/lib/"
shell.setPath(shell.path() .. ":" .. bin_path)
-- Load libraries
for _, file in ipairs(fs.list(lib_path)) do
if not fs.isDir(lib_path .. file) then
os.loadAPI(lib_path .. file)
end
end