Compare commits

..

3 Commits

Author SHA1 Message Date
17e3a3b5a8 Second attempt to fix sha256 2025-03-25 15:51:28 +01:00
d575f3c98c Fix typo 2025-03-25 15:39:40 +01:00
f8ef3b0210 Try using different implementation of sha256 2025-03-25 15:38:42 +01:00
15 changed files with 41 additions and 439 deletions

View File

@@ -1 +0,0 @@
use flake

View File

@@ -1,2 +0,0 @@
.direnv
node_modules

View File

@@ -1,47 +0,0 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "dev-server",
"dependencies": {
"@elysiajs/static": "^1.2.0",
"elysia": "^1.2.25",
},
"devDependencies": {
"@types/bun": "latest",
},
"peerDependencies": {
"typescript": "^5",
},
},
},
"packages": {
"@elysiajs/static": ["@elysiajs/static@1.2.0", "", { "dependencies": { "node-cache": "^5.1.2" }, "peerDependencies": { "elysia": ">= 1.2.0" } }, "sha512-oLpAi8c+maPpA0XhhK3BELaIjIG+nXg/K9p8cFfW4q5ayRD59a3MOMOOGgpiXZkHJzLPWcouhhyyLAYtaANW4g=="],
"@sinclair/typebox": ["@sinclair/typebox@0.34.31", "", {}, "sha512-qQ71T9DsITbX3dVCrcBERbs11YuSMg3wZPnT472JhqhWGPdiLgyvihJXU8m+ADJtJvRdjATIiACJD22dEknBrQ=="],
"@types/bun": ["@types/bun@1.2.8", "", { "dependencies": { "bun-types": "1.2.7" } }, "sha512-t8L1RvJVUghW5V+M/fL3Thbxcs0HwNsXsnTEBEfEVqGteiJToOlZ/fyOEaR1kZsNqnu+3XA4RI/qmnX4w6+S+w=="],
"@types/node": ["@types/node@22.13.14", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w=="],
"@types/ws": ["@types/ws@8.18.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-8svvI3hMyvN0kKCJMvTJP/x6Y/EoQbepff882wL+Sn5QsXb3etnamgrJq4isrBxSJj5L2AuXcI0+bgkoAXGUJw=="],
"bun-types": ["bun-types@1.2.7", "", { "dependencies": { "@types/node": "*", "@types/ws": "*" } }, "sha512-P4hHhk7kjF99acXqKvltyuMQ2kf/rzIw3ylEDpCxDS9Xa0X0Yp/gJu/vDCucmWpiur5qJ0lwB2bWzOXa2GlHqA=="],
"clone": ["clone@2.1.2", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="],
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
"elysia": ["elysia@1.2.25", "", { "dependencies": { "@sinclair/typebox": "^0.34.27", "cookie": "^1.0.2", "memoirist": "^0.3.0", "openapi-types": "^12.1.3" }, "peerDependencies": { "typescript": ">= 5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-WsdQpORJvb4uszzeqYT0lg97knw1iBW1NTzJ1Jm57tiHg+DfAotlWXYbjmvQ039ssV0fYELDHinLLoUazZkEHg=="],
"memoirist": ["memoirist@0.3.0", "", {}, "sha512-wR+4chMgVPq+T6OOsk40u9Wlpw1Pjx66NMNiYxCQQ4EUJ7jDs3D9kTCeKdBOkvAiqXlHLVJlvYL01PvIJ1MPNg=="],
"node-cache": ["node-cache@5.1.2", "", { "dependencies": { "clone": "2.x" } }, "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg=="],
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
"typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
"undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
}
}

61
dev-server/flake.lock generated
View File

@@ -1,61 +0,0 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1742923925,
"narHash": "sha256-biPjLws6FiBVUUDHEMFq5pUQL84Wf7PntPYdo3oKkFw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "25d1b84f5c90632a623c48d83a2faf156451e6b1",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"utils": "utils"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View File

@@ -1,17 +0,0 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, utils }:
utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
in {
devShell = with pkgs; mkShell {
buildInputs = with pkgs; [ bun ];
};
}
);
}

View File

@@ -1,35 +0,0 @@
import { Elysia } from 'elysia'
import { staticPlugin } from "@elysiajs/static"
import { stat, readdir, readFile } from "node:fs/promises"
import { createHash } from "node:crypto";
type IndexEntry = { src: string, dest: string, hash: string };
async function scanDir(scanIn: string, base: string, outputBase: string): Promise<IndexEntry[]> {
let files = await readdir(scanIn + "/" + base);
let results: IndexEntry[] = [];
for (let file of files) {
if (await stat(scanIn + "/" + base + "/" + file).then(r => r.isDirectory())) {
results = [...results, ...(await scanDir(scanIn, base + "/" + file, outputBase + file + "/"))]
} else {
results.push({
src: base + "/" + file,
dest: outputBase + file,
hash: createHash('sha256').update(await readFile(scanIn + "/" + base + "/" + file)).digest('hex')
});
}
}
return results;
}
new Elysia()
.get("/index.json", async () => scanDir("..", "src", "/"))
.get("/sha256.lua", async () => Bun.file("../sha256.lua"))
.use(staticPlugin({
assets: "../src",
prefix: "/src"
}))
.get("/install.lua", async () => Bun.file("../install.lua"))
.listen(parseInt(process.env.PORT || "3000"))

View File

@@ -1,16 +0,0 @@
{
"name": "dev-server",
"module": "index.ts",
"type": "module",
"private": true,
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5"
},
"dependencies": {
"@elysiajs/static": "^1.2.0",
"elysia": "^1.2.25"
}
}

View File

@@ -1,28 +0,0 @@
{
"compilerOptions": {
// Environment setup & latest features
"lib": ["esnext"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}

View File

@@ -2,11 +2,6 @@
{
"src": "src/startup.lua",
"dest": "/startup.lua",
"hash": "38b4f27b677716688ce5c27f416a3e4605e03d1a07f76df7b5ef1cedf4f355ea"
},
{
"src": "src/kernel/entry.lua",
"dest": "/kernel/entry.lua",
"hash": "5d17a09860a3d14346105e363c0b3333bf720c75c4670add778fd20a736dafb7"
"hash": "07219cd9561b41ce1f39209958076c471b17855679c968b42767b0122423c782"
}
]

View File

@@ -1,5 +1,4 @@
local defaultRoot = "https://git.colon-three.com/kodi/snowier/raw/branch/main/"
local repoRoot = settings.get("snowier.repo_base") or defaultRoot
local repoRoot = "https://git.colon-three.com/kodi/snowier/raw/branch/main/"
local URLs = {
fileIndex = repoRoot .. "index.json",
@@ -13,11 +12,6 @@ function log.info(value)
print("[I] " .. value)
end
--- @param value string
function log.debug(value)
print("[D] " .. value)
end
--- @param value string
function log.error(value)
printError("[E] " .. value)
@@ -34,12 +28,11 @@ local function main()
shafile.close()
sharequest.close()
end
package.path = package.path .. ";/?;/?.lua" -- hack to solve 'wget run'
local hash = require("sha256")
log.info("Downloading index file")
local indexrequest = http.get(URLs.fileIndex)
local index = textutils.unserializeJSON(indexrequest.readAll())
local index = textutils.unserializeJson(request.readAll())
indexrequest.close()
if (index == nil) then
@@ -59,45 +52,38 @@ local function main()
local destfile = fs.open(v.dest, "r")
local filehash = hash.sha256(destfile.readAll())
destfile.close()
if filehash ~= v.hash then
if filehash ~= v.sha256 then
toDownload[#toDownload+1] = v
end
end
end
if #toDownload > 0 then
log.info(#toDownload .. " files to download")
for k, v in ipairs(toDownload) do
if not fs.exists("/tmp") then
fs.makeDir("/tmp")
end
log.info("Downloading '" .. v.dest .. "'")
local filerequest = http.get(repoRoot .. v.src)
local tempfile = fs.open("/tmp/" .. v.hash .. ".lua", "w")
tempfile.write(filerequest.readAll())
filerequest.close()
tempfile.close()
-- Check the validity of the hash, this acts both as a checksum
-- and a way to raise an error if the index is incorrect
tempfile = fs.open("/tmp/" .. v.hash .. ".lua", "r")
local filehash = hash.sha256(tempfile.readAll())
tempfile.close()
if filehash ~= v.hash then
log.error("File " .. v.dest .. " (from " .. v.src .. ") has a mismatched hash.")
log.error("Installation aborted. Remember to clean /tmp manually.")
return
end
log.info(#toDownload .. " files to download")
for k, v in ipairs(toDownload) do
if not fs.exists("/tmp") then
fs.makeDir("/tmp")
end
log.info("Installing")
for k, v in ipairs(toDownload) do
fs.delete(v.dest)
fs.copy("/tmp/" .. v.hash .. ".lua", v.dest)
log.info("Downloading '" .. v.dest .. "'")
local filerequest = http.get(repoRoot .. v.src)
local tempfile = fs.open("/tmp/" .. v.hash .. ".lua", "w")
tempfile.write(filerequest.readAll())
filerequest.close()
tempfile.close()
-- Check the validity of the hash, this acts both as a checksum
-- and a way to raise an error if the index is incorrect
tempfile = fs.open("/tmp/" .. v.hash .. ".lua", "r")
local filehash = hash.sha256(tempfile.readAll())
tempfile.close()
if filehash ~= v.hash then
log.error("File " .. v.dest .. " (from " .. v.src .. ") has a mismatched hash.")
log.error("Installation aborted.")
return
end
end
fs.delete("/tmp/")
else
log.info("Nothing to do")
log.info("Installing")
for k, v in ipairs(toDownload) do
fs.move("/tmp/" .. v.hash .. ".lua", v.dest)
end
log.info("Installation complete!")

View File

@@ -193,9 +193,6 @@ if print_debug_messages then
print(" "..method)
end
-- For computercraft, use emulated mode for the sake of compatibility
branch = "EMUL"
--------------------------------------------------------------------------------
-- BASIC 32-BIT BITWISE FUNCTIONS
@@ -211,6 +208,8 @@ if branch == "FFI" or branch == "LJ" or branch == "LIB32" then
-- Your system has 32-bit bitwise library (either "bit" or "bit32")
-- ADJUSTED FOR COMPUTERCRAFT
AND = b.band -- 2 arguments
OR = b.bor -- 2 arguments
XOR = b.bxor -- 2..5 arguments
@@ -220,17 +219,17 @@ if branch == "FFI" or branch == "LJ" or branch == "LIB32" then
SHR = b.brshift
-- ROL = b.rol or b.lrotate -- second argument is integer 0..31
-- ROR = b.ror or b.rrotate -- second argument is integer 0..31
--function ROL(x, n)
-- x = x % 2^32 * 2^n
-- local r = x % 2^32
-- return r + (x - r) / 2^32
--end
function ROL(x, n)
x = x % 2^32 * 2^n
local r = x % 2^32
return r + (x - r) / 2^32
end
--function ROR(x, n)
-- x = x % 2^32 / 2^n
-- local r = x % 1
-- return r * 2^32 + (x - r)
--end
function ROR(x, n)
x = x % 2^32 / 2^n
local r = x % 1
return r * 2^32 + (x - r)
end
NOT = b.bnot -- only for LuaJIT
NORM = b.tobit -- only for LuaJIT

View File

@@ -1,7 +0,0 @@
-- kernel entrypoint
-- this is responsible for initializing core kernel services
-- required to advance to the next step of the OS
require 'kernel.system'
os.run({}, "/rom/programs/advanced/multishell.lua") -- placeholder

View File

@@ -1,117 +0,0 @@
--[[
The Erica Actor System ([Er]lang + A[kka])
Each actor has:
- Coroutine
- Mailbox
- Address
- Extra Addresses
- State
- Child IDs
The Actor System utilizes coroutine yielding for all invocations of the system. No global APIs are exposed by the system.
The following calls are available to actors:
- spawn function:handler table?:options
The options table exposes the following:
- addressBase | default: seedocs | If not provided, the address will take this form: "$currentAddress/$childId" and childId gets incremented
| in local state.
| If provided, the global address base counter gets updated and the provided address base is used.
| Actors created without an address base are considered child actors of the current actor,
| and their status updates (death) will emit status update events to the next immediate parent.
| The death of an actor will kill all of it's children recursively.
- localNamespace| default: nil | If set, adds the localNamespace into the address of the newly spawned actor.
- extraAddresses| default: {} | Logic for global base addresses, that are used to add receive-only extra addresses to this actor.
The returned value is: bStatus, tAddress?
- bStatus: True if successful, false if failed
- tAddress: Address of newly spawned actor
- tell addressPredicate:string ...content
Any instances of `?` in addressPredicate are replaced with a random valid instance.
Adds a message of "content" to the mailbox of the target actor
The returned value is: bStatus, sData?
- bStatus: True if successful, false if failed
- sData: The error string if status is false, for example no valid instances.
If status is true, actor address that received this tell.
- announce addressPredicate:string ...content
Any instances of `?` in addressPredicate are replaced with all valid instances.
Adds a message of "content" to the mailbox of the target actor
The returned value is: bStatus, data?
- bStatus: True if successful, false if failed
- data: The error string if status is false, for example no valid instances.
If status is true, amount of actors that received this announcement.
- ask addressPredicate:string timeout:number ...content
Suspends this actor until the responseHandle is used with the "reply" or "fail" syscall,
or until the timeout elapses. The timeout elapsing invalidates the handle and makes calls to "reply" or "fail" fail silently.
The return value is:
- bStatus: If the ask was successful
- ...data: If the status is false, this contains the reason for the error.
If the status is true, the first value is the actor asked, and subsequent data contains the response from the actor asked.
- reply askHandle:string ...data
Replies to an ask. Returns nil.
- fail askHandle:string ...reason
Fails an ask. Returns nil.
- idle timeout:number receiveUnfiltered?:bool
Notifies the actor system that this actor is ready to process events. Values returned by this call are described below, in the signals section.
If receiveUnfiltered is set, the actor will receive "hostEvent" signals without any filtering.
Signals:
- timeout
When the idle call times out. No extra params
- message sourceAddress:string {content}
When a message is received from another actor.
- ask replyHandle:string sourceAddress:string {content}
When an ask is received from another actor. Good idea to immediately fail any asks that the current actor doesn't recognize.
- childStatus address:string {newStatus}
When a child's status updates (coroutine.status() call)
- hostEvent {data}
ComputerCraft event from the top level coroutine.yield() call. Use with caution, generally this should only be used by actors
that propagate events to announcement channels.
Addresses
There are 3 types of address:
- Fully Qualified Address
- Local Address
- Relative Address
Fully Qualified addresses take on the following format:
systemId .. ":/" .. localAddressWithinSystem
The purpose of fully qualified addresses is to be provided by the system to actors to have unambigous resolution of actors.
User-written code generally shouldn't need to use fully qualified addresses, because their primary use case is future compatibility
with a version of this system that allows multi-node operation (and setting wildcards on systemId)
Local Addresses are full addresses within a single system.
The "child:" prefix is reserved in address parts only for automatically-generated addresses, and manual usage of it in addresses
is considered undefined behavior.
Here is an example address of the first actor spawned within the "com/colon-three/someApp" namespace:
"com/colon-three/someApp/1" (subsequent actors are 2, 3, 4, etc. Monotonically increasing, but not guaranteed. Do not rely on this.)
If that actor then makes a child, that child's address is:
"com/colon-three/someApp/1/child:1"
And if that child makes another child, that child's address is:
"com/colon-three/someApp/1/child:1/child:1"
If that actor makes a child with the local namespace of "someNs", the address will be:
"com/colon-three/someApp/1/someNs/child:2" (because child:1 for this actor already exists, and namespaces are for filtering only.)
Every address of an actual actor ends with either a plain number, or the "child:number" template.
Relative Addresses:
Used only in calls, and taking the following format:
".." - refer to the parent actor. IGNORES NAMESPACES!!!
"../someNs" - refer to parent actor's "someNs". Ignores the current actor's namespace.
"./someNs" - refer to the current actor's someNs namespace.
Allows asking the parent something, or the parent broadcasting something to all of it's children, or children in a specific namespace.
This is generally only useful with `?` in asks or broadcasts, because a child's ID shouldn't be considered predictable.
]]
local tActors = {}
local tAddressBases = {}

View File

@@ -1,48 +1 @@
-- Bootloader
-- This script is only responsible for killing rednet and jumping to the kernel
-- based on some code rph wrote and gave me
if settings.get("snowier.auto_update") then
local defaultRoot = "https://git.colon-three.com/kodi/snowier/raw/branch/main/"
local repoRoot = settings.get("snowier.repo_base") or defaultRoot
shell.run("wget run " .. repoRoot .. "install.lua")
end
local function main()
if not _G["rednet"] then
return
end
local o = os.pullEventRaw
os.pullEventRaw = function()
local a = table.pack(o())
if a[1] == "modem_message" then
if string.match(debug.traceback(), "/rom/apis/rednet.lua") then
print("[D] Rednet called os.pullEventRaw, crashing")
error("nya")
end
end
return table.unpack(a)
end
local p = _G.printError
_G.printError = function()
print("[D] Got printError call, cleaning and jumping to kernel")
_G.printError = p
_G.os.pullEventRaw = o
_G["rednet"] = nil
os.run({
-- This is an odd hack. We should look into not doing this to run the kernel.
["require"]=require
}, "/kernel/entry.lua")
end
print("[D] Queueing bogus modem message")
os.queueEvent("modem_message")
end
main()
print("Hello, World!")

View File

@@ -4,7 +4,7 @@
open index.json
| each {|entry|
{src: $entry.src, dest: $entry.dest,
hash: (open $entry.src | hash sha256)}
hash: (cat $entry.src | hash sha256)}
}
| collect
| save -f index.json