- hypr/apps.lua - hypr/autostart.lua - hypr/envs.lua - hypr/hyprland.lua - hypr/hyprsunset.conf - hypr/input.lua - hypr/looknfeel.lua - hypr/omasettings.lua - hypr/xdph.conf - omarchy/branding/about.txt - omarchy/branding/screensaver.txt - omarchy/extensions/omarchy-menu.jsonc - omarchy/hooks/battery-low.d/play-warning-sound.sample - omarchy/hooks/font-set.d/show-font-notification.sample - omarchy/hooks/post-boot.d/weather.sample - omarchy/hooks/post-update.d/install-voxtype.hook - omarchy/hooks/post-update.d/setup-agent.hook - omarchy/hooks/post-update.d/setup-fingerprint.hook - omarchy/hooks/post-update.d/show-update-notification.sample - omarchy/hooks/pre-refresh-pacman.d/add-custom-repo.sample - omarchy/hooks/theme-set.d/show-theme-notification.sample - omarchy/shell.json - omarchy/shell.toml - omarchy/theme.name - omarchy/themes/azure-glow/README.md - omarchy/themes/azure-glow/alacritty.toml - omarchy/themes/azure-glow/btop.theme - omarchy/themes/azure-glow/hyprland.conf - omarchy/themes/azure-glow/hyprlock.conf - omarchy/themes/azure-glow/icons.theme - … 269 more
120 lines
5.1 KiB
JavaScript
120 lines
5.1 KiB
JavaScript
#!/usr/bin/env node
|
|
// The remembered session must not survive the machine it was minted on.
|
|
//
|
|
// These run the real shell scripts the panel executes, against a stand-in
|
|
// secret-tool, so what is checked is the behaviour and not a string.
|
|
//
|
|
// node tests/session-boot.test.js
|
|
|
|
const fs = require("fs")
|
|
const os = require("os")
|
|
const path = require("path")
|
|
const { execFileSync } = require("child_process")
|
|
|
|
const Model = {}
|
|
new Function("exports", fs.readFileSync(path.join(__dirname, "..", "BitwardenModel.js"), "utf8")
|
|
.replace(/^\.pragma library\s*$/m, "") + `
|
|
exports.keyringStoreCommand = keyringStoreCommand
|
|
exports.keyringLookupCommand = keyringLookupCommand
|
|
exports.keyringClearCommand = keyringClearCommand
|
|
exports.keyringSecretEnvVar = keyringSecretEnvVar
|
|
exports.bootIdPath = bootIdPath
|
|
`)(Model)
|
|
|
|
let pass = 0
|
|
const failures = []
|
|
const check = (l, ok, d) => ok ? pass++ : failures.push(`${l}\n ${d}`)
|
|
|
|
// A stand-in for libsecret. Keeps the stored blob in a file, records every
|
|
// call, and can be told to refuse the session collection the way a secret
|
|
// service without one would.
|
|
const stub = fs.mkdtempSync(path.join(os.tmpdir(), "qsbw-keyring-"))
|
|
fs.writeFileSync(path.join(stub, "secret-tool"), `#!/usr/bin/env bash
|
|
set -uo pipefail
|
|
echo "$*" >> "$STUB/calls"
|
|
cmd="\${1:-}"; shift || true
|
|
collection=""
|
|
for a in "$@"; do case "$a" in --collection=*) collection="\${a#--collection=}" ;; esac; done
|
|
case "$cmd" in
|
|
store)
|
|
if [ "\${STUB_NO_SESSION_COLLECTION:-}" = "1" ] && [ "$collection" = "session" ]; then
|
|
cat >/dev/null; exit 1
|
|
fi
|
|
cat > "$STUB/value"; printf '%s' "$collection" > "$STUB/collection"; exit 0 ;;
|
|
lookup) [ -s "$STUB/value" ] || exit 1; cat "$STUB/value"; exit 0 ;;
|
|
clear) rm -f "$STUB/value"; exit 0 ;;
|
|
esac
|
|
exit 1
|
|
`)
|
|
fs.chmodSync(path.join(stub, "secret-tool"), 0o755)
|
|
|
|
const TOKEN = "not-a-real-session-token"
|
|
const bootId = fs.readFileSync(Model.bootIdPath(), "utf8").trim()
|
|
|
|
const reset = () => {
|
|
for (const f of ["value", "collection", "calls"]) fs.rmSync(path.join(stub, f), { force: true })
|
|
}
|
|
const run = (command, extraEnv) => {
|
|
const env = Object.assign({}, process.env, { PATH: `${stub}:${process.env.PATH}`, STUB: stub }, extraEnv || {})
|
|
return execFileSync(command[0], command.slice(1), { env, encoding: "utf8" })
|
|
}
|
|
const stored = () => fs.existsSync(path.join(stub, "value"))
|
|
? fs.readFileSync(path.join(stub, "value"), "utf8") : null
|
|
const calls = () => fs.existsSync(path.join(stub, "calls"))
|
|
? fs.readFileSync(path.join(stub, "calls"), "utf8") : ""
|
|
|
|
const secretEnv = { [Model.keyringSecretEnvVar()]: TOKEN }
|
|
|
|
// --- storing ---
|
|
reset()
|
|
run(Model.keyringStoreCommand(), secretEnv)
|
|
check("the session is stored in the memory-only session collection",
|
|
fs.readFileSync(path.join(stub, "collection"), "utf8") === "session",
|
|
fs.readFileSync(path.join(stub, "collection"), "utf8"))
|
|
check("the stored blob carries the boot id that minted the session",
|
|
stored() === `${bootId} ${TOKEN}`, JSON.stringify(stored()))
|
|
check("the token still never reaches a command line",
|
|
!Model.keyringStoreCommand().join(" ").includes(TOKEN) && !calls().includes(TOKEN),
|
|
Model.keyringStoreCommand().join(" ") + " || " + calls())
|
|
|
|
// A secret service with no session collection must not cost the user the
|
|
// setting entirely -- the boot id is what enforces the lock either way.
|
|
reset()
|
|
run(Model.keyringStoreCommand(), Object.assign({ STUB_NO_SESSION_COLLECTION: "1" }, secretEnv))
|
|
check("a service without a session collection falls back to the default one",
|
|
fs.readFileSync(path.join(stub, "collection"), "utf8") === "" && stored() === `${bootId} ${TOKEN}`,
|
|
JSON.stringify(stored()))
|
|
|
|
// --- looking up on the same boot ---
|
|
reset()
|
|
run(Model.keyringStoreCommand(), secretEnv)
|
|
check("a session from this boot is handed back, boot id stripped",
|
|
run(Model.keyringLookupCommand()) === TOKEN, JSON.stringify(run(Model.keyringLookupCommand())))
|
|
check("a usable session is left in the keyring",
|
|
stored() !== null, "expected the entry to survive a lookup")
|
|
|
|
// --- looking up after a reboot ---
|
|
reset()
|
|
fs.writeFileSync(path.join(stub, "value"), `11111111-2222-3333-4444-555555555555 ${TOKEN}`)
|
|
check("a session from another boot is not handed back",
|
|
run(Model.keyringLookupCommand()) === "", JSON.stringify(run(Model.keyringLookupCommand())))
|
|
check("a session from another boot is cleared out of the keyring",
|
|
stored() === null, JSON.stringify(stored()))
|
|
|
|
// An entry written before the boot id existed has no provenance at all, so it
|
|
// gets the same treatment rather than the benefit of the doubt.
|
|
reset()
|
|
fs.writeFileSync(path.join(stub, "value"), TOKEN)
|
|
check("a bare pre-boot-id entry is refused and cleared",
|
|
run(Model.keyringLookupCommand()) === "" && stored() === null, JSON.stringify(stored()))
|
|
|
|
// --- nothing to find ---
|
|
reset()
|
|
check("an empty keyring is not an error, so the panel falls through to bw status",
|
|
run(Model.keyringLookupCommand()) === "", "expected empty output and exit 0")
|
|
|
|
fs.rmSync(stub, { recursive: true, force: true })
|
|
|
|
console.log(`${pass} passed, ${failures.length} failed`)
|
|
if (failures.length) { console.error("\nFAILURES:\n " + failures.join("\n ")); process.exit(1) }
|