- 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
248 lines
12 KiB
JavaScript
248 lines
12 KiB
JavaScript
#!/usr/bin/env node
|
|
// Git SSH signing needs files: `user.signingkey` takes a path, and
|
|
// `gpg.ssh.allowedSignersFile` has no inline form at all. So the panel
|
|
// projects the companion's validated public identities to disk. These tests
|
|
// run the real export script against real directories, because every rule
|
|
// that matters here is a filesystem rule -- modes, symlinks, collisions,
|
|
// hostile names, and what survives a lock versus a logout.
|
|
//
|
|
// node tests/ssh-agent-export.test.js
|
|
|
|
const fs = require("fs")
|
|
const os = require("os")
|
|
const path = require("path")
|
|
const { spawnSync } = require("child_process")
|
|
|
|
const repoRoot = path.join(__dirname, "..")
|
|
const Model = {}
|
|
new Function("exports", fs.readFileSync(path.join(repoRoot, "BitwardenModel.js"), "utf8")
|
|
.replace(/^\.pragma library\s*$/m, "") + `
|
|
exports.parseAgentEvent = parseAgentEvent
|
|
exports.sshExportDisplayDir = sshExportDisplayDir
|
|
exports.sshExportFileName = sshExportFileName
|
|
exports.sshExportPayload = sshExportPayload
|
|
exports.sshExportCommand = sshExportCommand
|
|
exports.sshExportClearCommand = sshExportClearCommand
|
|
exports.parseSshExportResult = parseSshExportResult
|
|
exports.sshExportIdentities = sshExportIdentities
|
|
`)(Model)
|
|
|
|
let pass = 0
|
|
const failures = []
|
|
const check = (label, ok, detail) => ok ? pass++ : failures.push(`${label}\n ${detail}`)
|
|
const eq = (label, actual, expected) =>
|
|
check(label, actual === expected, `expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`)
|
|
|
|
// Disposable fixture keys, generated for this test and belonging to nobody.
|
|
// Never use a real key here: it is public material, but a personal key in a
|
|
// public repository's fixtures is noise at best and identifying at worst.
|
|
const ED = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDgSTquIEW1Ui0iRAQcZZAjS1OIA/D6Q+Arq/JfoVLkh"
|
|
const RSA = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCR+MdcObOYaHGNBySG8ZLOzK3If5fptENOIuBlpqXOosoXu7lSL5V0dDkXcckbDeZ7bn3UnnWKu8RqSJu9jDT/VQvarjRMgnppAI7QEWZyPlGl8OfvnZ0q3mPHRRbhhpXz4/UblfteEpuBDkrfrFhaeiwmXyoJ5bgiZslDk+WEM2y+3P1MHVXXkgJ7H+uKXU8/p/fmj/DcwpoDf1Y2UWCwFk8Ckobt9dhaDkzwRqyYFn00YbiYaHOyfWCSJGSq1dr1aDMOUk22L4QuA/7nyNZb3ip/9Z+zlC+K7PzETOtVGE4nh8z9L1FUM3ygMRZ6M0gWBfyiwejpgYB8nGN3+rJ"
|
|
|
|
// -------------------------------------------------------------------------
|
|
// The companion reports its validated public set, one message per key
|
|
// -------------------------------------------------------------------------
|
|
|
|
// A single message carrying every key would blow the 64 KiB control-line cap
|
|
// at the documented 128-key limit, so each identity arrives on its own line.
|
|
const line = Model.parseAgentEvent(JSON.stringify({
|
|
v: 1, type: "public_key", epoch: 4, itemId: "item-1",
|
|
name: "personal ed25519", fingerprint: "SHA256:x", publicKey: ED
|
|
}))
|
|
eq("a public_key message parses", line.ok, true)
|
|
eq("it keeps its epoch", line.ok && line.message.epoch, 4)
|
|
eq("it carries the OpenSSH form", line.ok && line.message.publicKey, ED)
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Filenames from vault names
|
|
// -------------------------------------------------------------------------
|
|
|
|
check("the export directory is under XDG_DATA_HOME, not ~/.ssh",
|
|
/qs-bitwarden-cli\/ssh$/.test(Model.sshExportDisplayDir())
|
|
&& Model.sshExportDisplayDir().indexOf(".ssh/") < 0,
|
|
Model.sshExportDisplayDir())
|
|
|
|
const taken = {}
|
|
eq("an ordinary name becomes an obvious file",
|
|
Model.sshExportFileName("personal ed25519", "item-1", taken), "personal ed25519.pub")
|
|
|
|
// An item name is decrypted vault content about to become a path, and the
|
|
// collection it came from may be writable by somebody else.
|
|
const hostile = {}
|
|
for (const [raw, why] of [
|
|
["../../.bashrc", "traversal"],
|
|
["a/b", "separator"],
|
|
["with |