-- setup_admin.lua — one-shot script to set the admin password. -- -- Run with: ./blog.com -i setup_admin.lua -- (Redbean executes the script in the same Lua environment as the app, -- so require "db" and the argon2 module are available.) -- -- Uses argon2id with OWASP Password Storage Cheat Sheet parameters: -- m_cost = 65536 (64 MiB memory) -- t_cost = 3 (3 passes) -- parallelism = 4 -- hash_len = 32 local db = require "db" db.init() -- Toggle terminal echo so the password is not shown while typing. -- Returns true when echo state was actually changed (i.e. stdin is a -- tty and stty exists); on Windows or piped stdin it fails silently -- and input is read as-is. local function set_echo(enabled) local ok = os.execute("stty " .. (enabled and "echo" or "-echo") .. " 2>/dev/null") return ok == true or ok == 0 end local function read_password(prompt) io.write(prompt) io.flush() local hidden = set_echo(false) local pw = io.read("*l") if hidden then set_echo(true) io.write("\n") -- the user's Enter was not echoed io.flush() end return pw end local password = read_password("Enter new admin password: ") if not password or password:match("^%s*$") then io.stderr:write("Error: password cannot be empty.\n") os.exit(1) end local confirm = read_password("Confirm admin password: ") if password ~= confirm then io.stderr:write("Error: passwords do not match.\n") os.exit(1) end -- Generate a 16-byte random salt. local salt local ok_r, bytes = pcall(unix.getrandom, 16) if ok_r and bytes and #bytes == 16 then salt = bytes else local f = io.open("/dev/urandom", "rb") if f then salt = f:read(16) f:close() end end if not salt or #salt < 16 then io.stderr:write("Error: could not generate a random salt.\n") os.exit(1) end -- Hash with argon2id using OWASP-recommended parameters. local ok_h, hash = pcall(argon2.hash_encoded, password, salt, { variant = argon2.variants.argon2_id, m_cost = 65536, -- 64 MiB t_cost = 3, parallelism = 4, hash_len = 32, }) if not ok_h or not hash then io.stderr:write("Error: argon2 hashing failed: " .. tostring(hash) .. "\n") os.exit(1) end db.set_setting("admin_password_hash", hash) io.write("Admin password set successfully.\n")