Compare commits
8 Commits
develop-1.
...
39caa32908
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39caa32908 | ||
|
|
9103c44658 | ||
|
|
882894685c | ||
|
|
ba49f7ca7d | ||
|
|
f3c35afe07 | ||
|
|
8a6896e276 | ||
|
|
a18a8b7140 | ||
|
|
6d6b43daf7 |
@@ -51,7 +51,7 @@ local config = {
|
|||||||
}
|
}
|
||||||
Config.load('Overview', config)
|
Config.load('Overview', config)
|
||||||
|
|
||||||
local extSupport = Util.supportsExtChars()
|
local extSupport = Util.getVersion() >= 1.76
|
||||||
|
|
||||||
local applications = { }
|
local applications = { }
|
||||||
local buttons = { }
|
local buttons = { }
|
||||||
|
|||||||
@@ -1,22 +1,14 @@
|
|||||||
local SHA = require("opus.crypto.sha2")
|
local SHA = require("opus.crypto.sha2")
|
||||||
|
|
||||||
local acceptableCharacters = {}
|
local acceptableCharacters = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}
|
||||||
for c = 0, 127 do
|
|
||||||
local char = string.char(c)
|
|
||||||
-- exclude potentially ambiguous characters
|
|
||||||
if char:match("[1-9a-zA-Z]") and char:match("[^OIl]") then
|
|
||||||
table.insert(acceptableCharacters, char)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local acceptableCharactersLen = #acceptableCharacters
|
local acceptableCharactersLen = #acceptableCharacters
|
||||||
|
|
||||||
local password = ""
|
local password = ""
|
||||||
|
|
||||||
for i = 1, 10 do
|
for _i = 1, 8 do
|
||||||
password = password .. acceptableCharacters[math.random(acceptableCharactersLen)]
|
password = password .. acceptableCharacters[math.random(acceptableCharactersLen)]
|
||||||
end
|
end
|
||||||
|
|
||||||
os.queueEvent("set_otp", SHA.compute(password))
|
os.queueEvent("set_otp", SHA.compute(password))
|
||||||
|
|
||||||
print("This allows one other device to permanently gain access to this device.")
|
print("Your one-time password is: " .. password)
|
||||||
print("Use the trust settings in System to revert this.")
|
|
||||||
print("Your one-time password is: " .. password)
|
|
||||||
200
sys/apps/memprofile.lua
Normal file
200
sys/apps/memprofile.lua
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
-- Memory Profiler for CC:Tweaked / Opus OS
|
||||||
|
-- Usage: memprofile [--watch] [--interval <seconds>]
|
||||||
|
--
|
||||||
|
-- Shows current Lua memory usage with breakdown estimates.
|
||||||
|
-- Use --watch to continuously monitor.
|
||||||
|
-- Useful for detecting memory leaks and understanding overhead.
|
||||||
|
|
||||||
|
local args = { ... }
|
||||||
|
local watch = false
|
||||||
|
local interval = 3
|
||||||
|
|
||||||
|
for i, arg in ipairs(args) do
|
||||||
|
if arg == '--watch' or arg == '-w' then
|
||||||
|
watch = true
|
||||||
|
elseif arg == '--interval' or arg == '-i' then
|
||||||
|
interval = tonumber(args[i + 1]) or 3
|
||||||
|
elseif arg == '--help' or arg == '-h' then
|
||||||
|
print('Usage: memprofile [--watch] [--interval <secs>]')
|
||||||
|
print('')
|
||||||
|
print('Options:')
|
||||||
|
print(' --watch, -w Continuously monitor memory')
|
||||||
|
print(' --interval, -i N Update interval in seconds (default: 3)')
|
||||||
|
print(' --help, -h Show this help')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local term = _G.term
|
||||||
|
local os = _G.os
|
||||||
|
|
||||||
|
local function formatBytes(bytes)
|
||||||
|
if bytes < 1024 then
|
||||||
|
return string.format('%d B', bytes)
|
||||||
|
elseif bytes < 1024 * 1024 then
|
||||||
|
return string.format('%.1f KB', bytes / 1024)
|
||||||
|
else
|
||||||
|
return string.format('%.2f MB', bytes / (1024 * 1024))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function countTable(t, seen)
|
||||||
|
if type(t) ~= 'table' or seen[t] then return 0, 0 end
|
||||||
|
seen[t] = true
|
||||||
|
local entries = 0
|
||||||
|
local nested = 0
|
||||||
|
for k, v in pairs(t) do
|
||||||
|
entries = entries + 1
|
||||||
|
if type(v) == 'table' then
|
||||||
|
local e, n = countTable(v, seen)
|
||||||
|
nested = nested + 1 + e
|
||||||
|
entries = entries + n
|
||||||
|
end
|
||||||
|
if type(k) == 'table' then
|
||||||
|
local e, n = countTable(k, seen)
|
||||||
|
nested = nested + 1 + e
|
||||||
|
entries = entries + n
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return entries, nested
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getSnapshot()
|
||||||
|
-- Force a full GC cycle to get accurate usage
|
||||||
|
collectgarbage('collect')
|
||||||
|
collectgarbage('collect')
|
||||||
|
local memKB = collectgarbage('count') -- returns KB as float
|
||||||
|
|
||||||
|
local snapshot = {
|
||||||
|
totalKB = memKB,
|
||||||
|
totalBytes = math.floor(memKB * 1024),
|
||||||
|
timestamp = os.clock(),
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Count entries in major global tables
|
||||||
|
local seen = {}
|
||||||
|
local globals = {}
|
||||||
|
|
||||||
|
local interesting = {
|
||||||
|
{ name = '_G (globals)', tbl = _G },
|
||||||
|
{ name = 'kernel', tbl = _G.kernel },
|
||||||
|
{ name = 'network', tbl = _G.network },
|
||||||
|
{ name = 'device', tbl = _G.device },
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item in ipairs(interesting) do
|
||||||
|
if type(item.tbl) == 'table' then
|
||||||
|
local entries, nested = countTable(item.tbl, seen)
|
||||||
|
table.insert(globals, {
|
||||||
|
name = item.name,
|
||||||
|
entries = entries,
|
||||||
|
nested = nested,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
snapshot.globals = globals
|
||||||
|
|
||||||
|
-- Count routines if kernel is available
|
||||||
|
if _G.kernel and _G.kernel.routines then
|
||||||
|
snapshot.routines = #_G.kernel.routines
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Count loaded modules
|
||||||
|
if package and package.loaded then
|
||||||
|
local count = 0
|
||||||
|
for _ in pairs(package.loaded) do
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
snapshot.loadedModules = count
|
||||||
|
end
|
||||||
|
|
||||||
|
return snapshot
|
||||||
|
end
|
||||||
|
|
||||||
|
local function printSnapshot(snap, prev)
|
||||||
|
term.clear()
|
||||||
|
term.setCursorPos(1, 1)
|
||||||
|
|
||||||
|
local w = term.getSize()
|
||||||
|
local sep = string.rep('-', w)
|
||||||
|
|
||||||
|
term.setTextColor(colors.yellow)
|
||||||
|
print('=== Memory Profile ===')
|
||||||
|
term.setTextColor(colors.white)
|
||||||
|
print('')
|
||||||
|
|
||||||
|
-- Total memory
|
||||||
|
local memStr = formatBytes(snap.totalBytes)
|
||||||
|
local deltaStr = ''
|
||||||
|
if prev then
|
||||||
|
local delta = snap.totalBytes - prev.totalBytes
|
||||||
|
if delta > 0 then
|
||||||
|
deltaStr = string.format(' (+%s)', formatBytes(delta))
|
||||||
|
term.setTextColor(colors.red)
|
||||||
|
elseif delta < 0 then
|
||||||
|
deltaStr = string.format(' (-%s)', formatBytes(-delta))
|
||||||
|
term.setTextColor(colors.green)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
term.setTextColor(colors.white)
|
||||||
|
print(string.format('Total Memory: %s%s', memStr, deltaStr))
|
||||||
|
print(string.format('Uptime: %.1fs', snap.timestamp))
|
||||||
|
print('')
|
||||||
|
|
||||||
|
-- Table sizes
|
||||||
|
term.setTextColor(colors.lightBlue)
|
||||||
|
print('Global Tables:')
|
||||||
|
term.setTextColor(colors.white)
|
||||||
|
print(sep)
|
||||||
|
print(string.format(' %-20s %8s %8s', 'Name', 'Entries', 'Nested'))
|
||||||
|
print(sep)
|
||||||
|
for _, g in ipairs(snap.globals) do
|
||||||
|
print(string.format(' %-20s %8d %8d', g.name, g.entries, g.nested))
|
||||||
|
end
|
||||||
|
print(sep)
|
||||||
|
print('')
|
||||||
|
|
||||||
|
-- Kernel info
|
||||||
|
if snap.routines then
|
||||||
|
term.setTextColor(colors.lightBlue)
|
||||||
|
print('Kernel:')
|
||||||
|
term.setTextColor(colors.white)
|
||||||
|
print(string.format(' Active routines: %d', snap.routines))
|
||||||
|
end
|
||||||
|
|
||||||
|
if snap.loadedModules then
|
||||||
|
print(string.format(' Loaded modules: %d', snap.loadedModules))
|
||||||
|
end
|
||||||
|
|
||||||
|
print('')
|
||||||
|
|
||||||
|
-- CC:Tweaked limits
|
||||||
|
term.setTextColor(colors.gray)
|
||||||
|
print('Note: CC:Tweaked default memory limit is ~128MB per computer.')
|
||||||
|
print('High memory usage may cause slowdowns or crashes.')
|
||||||
|
|
||||||
|
if watch then
|
||||||
|
print('')
|
||||||
|
term.setTextColor(colors.yellow)
|
||||||
|
print(string.format('Refreshing every %ds... (Ctrl+T to stop)', interval))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function run()
|
||||||
|
local prev = nil
|
||||||
|
|
||||||
|
if watch then
|
||||||
|
while true do
|
||||||
|
local snap = getSnapshot()
|
||||||
|
printSnapshot(snap, prev)
|
||||||
|
prev = snap
|
||||||
|
os.sleep(interval)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local snap = getSnapshot()
|
||||||
|
printSnapshot(snap, nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
run()
|
||||||
@@ -59,10 +59,6 @@ local function sambaConnection(socket)
|
|||||||
print('samba: Connection closed')
|
print('samba: Connection closed')
|
||||||
end
|
end
|
||||||
|
|
||||||
local function sanitizeLabel(computer)
|
|
||||||
return (computer.id.."_"..computer.label:gsub("[%c%.\"'/%*]", "")):sub(1, 40)
|
|
||||||
end
|
|
||||||
|
|
||||||
Event.addRoutine(function()
|
Event.addRoutine(function()
|
||||||
print('samba: listening on port 139')
|
print('samba: listening on port 139')
|
||||||
|
|
||||||
@@ -83,10 +79,10 @@ Event.addRoutine(function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
Event.on('network_attach', function(_, computer)
|
Event.on('network_attach', function(_, computer)
|
||||||
fs.mount(fs.combine('network', sanitizeLabel(computer)), 'netfs', computer.id)
|
fs.mount(fs.combine('network', computer.label), 'netfs', computer.id)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
Event.on('network_detach', function(_, computer)
|
Event.on('network_detach', function(_, computer)
|
||||||
print('samba: detaching ' .. sanitizeLabel(computer))
|
print('samba: detaching ' .. computer.label)
|
||||||
fs.unmount(fs.combine('network', sanitizeLabel(computer)))
|
fs.unmount(fs.combine('network', computer.label))
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ local function getSlots()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function sendInfo()
|
local function sendInfo()
|
||||||
if os.clock() - infoTimer >= 5 then -- don't flood
|
if os.clock() - infoTimer >= 1 then -- don't flood
|
||||||
infoTimer = os.clock()
|
infoTimer = os.clock()
|
||||||
info.label = os.getComputerLabel()
|
info.label = os.getComputerLabel()
|
||||||
info.uptime = math.floor(os.clock())
|
info.uptime = math.floor(os.clock())
|
||||||
@@ -194,25 +194,16 @@ local function sendInfo()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function cleanNetwork()
|
-- every 10 seconds, send out this computer's info
|
||||||
|
Event.onInterval(10, function()
|
||||||
|
sendInfo()
|
||||||
for _,c in pairs(_G.network) do
|
for _,c in pairs(_G.network) do
|
||||||
local elapsed = os.clock()-c.timestamp
|
local elapsed = os.clock()-c.timestamp
|
||||||
if c.active and elapsed > 50 then
|
if c.active and elapsed > 15 then
|
||||||
c.active = false
|
c.active = false
|
||||||
os.queueEvent('network_detach', c)
|
os.queueEvent('network_detach', c)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- every 30 seconds, send out this computer's info
|
|
||||||
-- send with offset so that messages are evenly distributed and do not all come at once
|
|
||||||
Event.onTimeout(math.random() * 30, function()
|
|
||||||
sendInfo()
|
|
||||||
cleanNetwork()
|
|
||||||
Event.onInterval(30, function()
|
|
||||||
sendInfo()
|
|
||||||
cleanNetwork()
|
|
||||||
end)
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
Event.on('turtle_response', function()
|
Event.on('turtle_response', function()
|
||||||
@@ -222,5 +213,4 @@ Event.on('turtle_response', function()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- send info early so that computers show soon after booting
|
Event.onTimeout(1, sendInfo)
|
||||||
Event.onTimeout(math.random() * 2 + 1, sendInfo)
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
local Security = require('opus.security')
|
local Security = require('opus.security')
|
||||||
local SHA = require('opus.crypto.sha2')
|
|
||||||
local Terminal = require('opus.terminal')
|
local Terminal = require('opus.terminal')
|
||||||
|
|
||||||
local password = Terminal.readPassword('Enter new password: ')
|
local password = Terminal.readPassword('Enter new password: ')
|
||||||
|
|
||||||
if password then
|
if password then
|
||||||
Security.updatePassword(SHA.compute(password))
|
Security.updatePassword(password)
|
||||||
print('Password updated')
|
print('Password updated')
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -26,12 +26,12 @@ return UI.Tab {
|
|||||||
x = 2, y = 5, ex = -2, ey = -2,
|
x = 2, y = 5, ex = -2, ey = -2,
|
||||||
values = {
|
values = {
|
||||||
{ name = '', value = '' },
|
{ name = '', value = '' },
|
||||||
{ name = 'CC version', value = ("%d.%d"):format(Util.getVersion()) },
|
{ name = 'CC version', value = Util.getVersion() },
|
||||||
{ name = 'Lua version', value = _VERSION },
|
{ name = 'Lua version', value = _VERSION },
|
||||||
{ name = 'MC version', value = Util.getMinecraftVersion() },
|
{ name = 'MC version', value = Util.getMinecraftVersion() },
|
||||||
{ name = 'Disk free', value = Util.toBytes(fs.getFreeSpace('/')) },
|
{ name = 'Disk free', value = Util.toBytes(fs.getFreeSpace('/')) },
|
||||||
{ name = 'Computer ID', value = tostring(os.getComputerID()) },
|
{ name = 'Computer ID', value = tostring(os.getComputerID()) },
|
||||||
{ name = 'Day', value = tostring(os.day()) },
|
{ name = 'Day', value = tostring(os.day()) },
|
||||||
},
|
},
|
||||||
disableHeader = true,
|
disableHeader = true,
|
||||||
inactive = true,
|
inactive = true,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
sys/apps/pain.lua urlfs https://github.com/LDDestroier/CC/raw/master/pain.lua
|
sys/apps/pain.lua urlfs https://github.com/LDDestroier/CC/raw/master/pain.lua
|
||||||
sys/apps/update.lua urlfs http://pastebin.com/raw/UzGHLbNC
|
sys/apps/update.lua urlfs https://pastebin.com/raw/UzGHLbNC
|
||||||
sys/apps/Enchat.lua urlfs https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua
|
sys/apps/Enchat.lua urlfs https://raw.githubusercontent.com/LDDestroier/enchat/master/enchat3.lua
|
||||||
sys/apps/cloud.lua urlfs https://cloud-catcher.squiddev.cc/cloud.lua
|
sys/apps/cloud.lua urlfs https://cloud-catcher.squiddev.cc/cloud.lua
|
||||||
rom/modules/main/opus linkfs sys/modules/opus
|
rom/modules/main/opus linkfs sys/modules/opus
|
||||||
@@ -14,7 +14,7 @@ local parentTerm = _G.device.terminal
|
|||||||
local w,h = parentTerm.getSize()
|
local w,h = parentTerm.getSize()
|
||||||
local overviewId
|
local overviewId
|
||||||
local tabsDirty = false
|
local tabsDirty = false
|
||||||
local closeInd = Util.supportsExtChars() and '\215' or '*'
|
local closeInd = Util.getVersion() >= 1.76 and '\215' or '*'
|
||||||
local multishell = { }
|
local multishell = { }
|
||||||
|
|
||||||
_ENV.multishell = multishell
|
_ENV.multishell = multishell
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ local cbor = require('opus.cbor')
|
|||||||
local sha2 = require('opus.crypto.sha2')
|
local sha2 = require('opus.crypto.sha2')
|
||||||
local Util = require('opus.util')
|
local Util = require('opus.util')
|
||||||
|
|
||||||
local ROUNDS = 8 -- Adjust this for speed tradeoff
|
local ROUNDS = 20 -- Standard ChaCha20 (was 8, upgraded for security)
|
||||||
|
|
||||||
local bxor = bit32.bxor
|
local bxor = bit32.bxor
|
||||||
local band = bit32.band
|
local band = bit32.band
|
||||||
|
|||||||
@@ -15,7 +15,11 @@ for _,m in pairs(methods) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
function linkfs.resolve(node, dir)
|
function linkfs.resolve(node, dir)
|
||||||
return dir:gsub(node.mountPoint, node.source, 1)
|
local mp = node.mountPoint
|
||||||
|
if dir:sub(1, #mp) == mp then
|
||||||
|
return node.source .. dir:sub(#mp + 1)
|
||||||
|
end
|
||||||
|
return dir
|
||||||
end
|
end
|
||||||
|
|
||||||
function linkfs.mount(path, source)
|
function linkfs.mount(path, source)
|
||||||
@@ -41,8 +45,8 @@ function linkfs.mount(path, source)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function linkfs.copy(node, s, t)
|
function linkfs.copy(node, s, t)
|
||||||
s = s:gsub(node.mountPoint, node.source, 1)
|
s = linkfs.resolve(node, s)
|
||||||
t = t:gsub(node.mountPoint, node.source, 1)
|
t = linkfs.resolve(node, t)
|
||||||
return fs.copy(s, t)
|
return fs.copy(s, t)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -50,25 +54,29 @@ function linkfs.delete(node, dir)
|
|||||||
if dir == node.mountPoint then
|
if dir == node.mountPoint then
|
||||||
fs.unmount(node.mountPoint)
|
fs.unmount(node.mountPoint)
|
||||||
else
|
else
|
||||||
dir = dir:gsub(node.mountPoint, node.source, 1)
|
dir = linkfs.resolve(node, dir)
|
||||||
return fs.delete(dir)
|
return fs.delete(dir)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function linkfs.find(node, spec)
|
function linkfs.find(node, spec)
|
||||||
spec = spec:gsub(node.mountPoint, node.source, 1)
|
spec = linkfs.resolve(node, spec)
|
||||||
|
|
||||||
local list = fs.find(spec)
|
local list = fs.find(spec)
|
||||||
|
local src = node.source
|
||||||
|
local mp = node.mountPoint
|
||||||
for k,f in ipairs(list) do
|
for k,f in ipairs(list) do
|
||||||
list[k] = f:gsub(node.source, node.mountPoint, 1)
|
if f:sub(1, #src) == src then
|
||||||
|
list[k] = mp .. f:sub(#src + 1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return list
|
return list
|
||||||
end
|
end
|
||||||
|
|
||||||
function linkfs.move(node, s, t)
|
function linkfs.move(node, s, t)
|
||||||
s = s:gsub(node.mountPoint, node.source, 1)
|
s = linkfs.resolve(node, s)
|
||||||
t = t:gsub(node.mountPoint, node.source, 1)
|
t = linkfs.resolve(node, t)
|
||||||
return fs.move(s, t)
|
return fs.move(s, t)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,10 @@ end
|
|||||||
local methods = { 'delete', 'exists', 'getFreeSpace', 'makeDir', 'list', 'listEx', 'attributes' }
|
local methods = { 'delete', 'exists', 'getFreeSpace', 'makeDir', 'list', 'listEx', 'attributes' }
|
||||||
|
|
||||||
local function resolve(node, dir)
|
local function resolve(node, dir)
|
||||||
-- TODO: Wrong ! (does not support names with dashes)
|
local mp = node.mountPoint
|
||||||
dir = dir:gsub(node.mountPoint, '', 1)
|
if dir:sub(1, #mp) == mp then
|
||||||
|
dir = dir:sub(#mp + 1)
|
||||||
|
end
|
||||||
return fs.combine(node.source, dir)
|
return fs.combine(node.source, dir)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -53,7 +55,7 @@ end
|
|||||||
|
|
||||||
function netfs.mount(_, id, source)
|
function netfs.mount(_, id, source)
|
||||||
if not id or not tonumber(id) then
|
if not id or not tonumber(id) then
|
||||||
error('ramfs syntax: computerId [directory]')
|
error('netfs syntax: computerId [directory]')
|
||||||
end
|
end
|
||||||
return {
|
return {
|
||||||
id = tonumber(id),
|
id = tonumber(id),
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ function git.list(repository)
|
|||||||
|
|
||||||
local user = table.remove(t, 1)
|
local user = table.remove(t, 1)
|
||||||
local repo = table.remove(t, 1)
|
local repo = table.remove(t, 1)
|
||||||
local branch = table.remove(t, 1) or 'master'
|
local branch = table.remove(t, 1) or 'main'
|
||||||
local path
|
local path
|
||||||
|
|
||||||
if not Util.empty(t) then
|
if not Util.empty(t) then
|
||||||
|
|||||||
@@ -39,8 +39,7 @@ if register_global_module_table then
|
|||||||
_G[global_module_name] = json
|
_G[global_module_name] = json
|
||||||
end
|
end
|
||||||
|
|
||||||
-- this was incompatible because we use fs later
|
local _ENV = nil -- blocking globals in Lua 5.2
|
||||||
--local _ENV = nil -- blocking globals in Lua 5.2
|
|
||||||
|
|
||||||
pcall (function()
|
pcall (function()
|
||||||
-- Enable access to blocked metatables.
|
-- Enable access to blocked metatables.
|
||||||
|
|||||||
@@ -1,10 +1,38 @@
|
|||||||
local Config = require('opus.config')
|
local Config = require('opus.config')
|
||||||
|
local SHA = require('opus.crypto.sha2')
|
||||||
|
local Util = require('opus.util')
|
||||||
|
|
||||||
|
local PBKDF2_ITERATIONS = 100
|
||||||
|
|
||||||
local Security = { }
|
local Security = { }
|
||||||
|
|
||||||
|
local function generateSalt()
|
||||||
|
local salt = { }
|
||||||
|
for _ = 1, 16 do
|
||||||
|
salt[#salt + 1] = math.random(0, 0xFF)
|
||||||
|
end
|
||||||
|
return setmetatable(salt, Util.byteArrayMT):toHex()
|
||||||
|
end
|
||||||
|
|
||||||
function Security.verifyPassword(password)
|
function Security.verifyPassword(password)
|
||||||
local current = Security.getPassword()
|
local stored = Security.getPassword()
|
||||||
return current and password == current
|
if not stored then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- New format: { hash = hex, salt = hex, iter = N }
|
||||||
|
if type(stored) == 'table' and stored.hash and stored.salt then
|
||||||
|
local iter = stored.iter or PBKDF2_ITERATIONS
|
||||||
|
local derived = SHA.pbkdf2(password, Util.hexToByteArray(stored.salt), iter)
|
||||||
|
return derived:toHex() == stored.hash
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Legacy format: plain SHA-256 hex string
|
||||||
|
if type(stored) == 'string' then
|
||||||
|
return SHA.compute(password) == stored
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function Security.hasPassword()
|
function Security.hasPassword()
|
||||||
@@ -28,8 +56,15 @@ function Security.getIdentifier()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Security.updatePassword(password)
|
function Security.updatePassword(password)
|
||||||
|
local salt = generateSalt()
|
||||||
|
local derived = SHA.pbkdf2(password, Util.hexToByteArray(salt), PBKDF2_ITERATIONS)
|
||||||
|
|
||||||
local config = Config.load('os')
|
local config = Config.load('os')
|
||||||
config.password = password
|
config.password = {
|
||||||
|
hash = derived:toHex(),
|
||||||
|
salt = salt,
|
||||||
|
iter = PBKDF2_ITERATIONS,
|
||||||
|
}
|
||||||
Config.update('os', config)
|
Config.update('os', config)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ function UI:init()
|
|||||||
tertiary = colors.gray,
|
tertiary = colors.gray,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.extChars = Util.supportsExtChars()
|
self.extChars = Util.getVersion() >= 1.76
|
||||||
|
|
||||||
local function keyFunction(event, code, held)
|
local function keyFunction(event, code, held)
|
||||||
local ie = Input:translate(event, code, held)
|
local ie = Input:translate(event, code, held)
|
||||||
@@ -115,12 +115,16 @@ function UI:init()
|
|||||||
local ie = Input:translate('mouse_up', button, x, y)
|
local ie = Input:translate('mouse_up', button, x, y)
|
||||||
local currentPage = self:getActivePage()
|
local currentPage = self:getActivePage()
|
||||||
|
|
||||||
if ie.code == 'control-shift-mouse_click' then -- hack
|
if ie.code == 'control-shift-mouse_click' then -- debug inspector
|
||||||
local event = currentPage:pointToChild(x, y)
|
local Config = require('opus.config')
|
||||||
_ENV.multishell.openTab(_ENV, {
|
local debugCfg = Config.load('os', { debug_inspector = false })
|
||||||
path = 'sys/apps/Lua.lua',
|
if debugCfg.debug_inspector then
|
||||||
args = { event.element, self, _ENV },
|
local event = currentPage:pointToChild(x, y)
|
||||||
focused = true })
|
_ENV.multishell.openTab(_ENV, {
|
||||||
|
path = 'sys/apps/Lua.lua',
|
||||||
|
args = { event.element, self, _ENV },
|
||||||
|
focused = true })
|
||||||
|
end
|
||||||
|
|
||||||
elseif ie and currentPage and currentPage.parent.device.side == side then
|
elseif ie and currentPage and currentPage.parent.device.side == side then
|
||||||
self:click(currentPage, ie)
|
self:click(currentPage, ie)
|
||||||
|
|||||||
@@ -170,19 +170,16 @@ function Util.print(pattern, ...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Util.getVersion()
|
function Util.getVersion()
|
||||||
local versionString = _G._HOST or _G._CC_VERSION
|
local version
|
||||||
local versionMajor, versionMinor = versionString:match("(%d+)%.(%d+)")
|
|
||||||
-- ex.: 1.89 would return 1, 89
|
|
||||||
return tonumber(versionMajor), tonumber(versionMinor)
|
|
||||||
end
|
|
||||||
|
|
||||||
function Util.compareVersion(major, minor)
|
if _G._CC_VERSION then
|
||||||
local currentMajor, currentMinor = Util.getVersion()
|
version = tonumber(_G._CC_VERSION:match('[%d]+%.?[%d][%d]'))
|
||||||
return currentMajor > major or currentMajor == major and currentMinor >= minor
|
end
|
||||||
end
|
if not version and _G._HOST then
|
||||||
|
version = tonumber(_G._HOST:match('[%d]+%.?[%d][%d]'))
|
||||||
|
end
|
||||||
|
|
||||||
function Util.supportsExtChars()
|
return version or 1.7
|
||||||
return Util.compareVersion(1, 76)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Util.getMinecraftVersion()
|
function Util.getMinecraftVersion()
|
||||||
|
|||||||
Reference in New Issue
Block a user