Skip to content

Instantly share code, notes, and snippets.

@n8henrie
Created February 17, 2025 23:37
Show Gist options
  • Save n8henrie/8a3d22dc25e47aeff23aa6665e73b095 to your computer and use it in GitHub Desktop.
Save n8henrie/8a3d22dc25e47aeff23aa6665e73b095 to your computer and use it in GitHub Desktop.
JXA script to export SSH passphrases saved in macOS's Keychain Access
#!/usr/bin/osascript -l JavaScript
// 1. Open Keychain Access.app
// 2. Filter by `SSH:`
// 3. Set pw and outfile in this script
// 4. Run
// 5. Transfer the file to the new device
// 5. Use the sloppy script below to then read that file and add to Keychain Access on the new device
/*
#!/usr/bin/env bash
set -Eeuf -o pipefail
main() {
jq -r '.[] | "\(.keyfile)::::\(.passphrase)"' ssh-passphrases.json |
while read -r line; do
path=${line%%::::*}
pass=${line##*::::}
if [[ -f "${path}" && -n "${pass}" ]]; then
{
sleep 0.1
printf '%s' "${pass}"
} | script -q /dev/null ssh-add --apple-use-keychain "${path}"
fi
done
}
main "$@"
*/
'use strict'
const pw = "macosPasswordHere"
const outfile = "/Users/n8henrie/ssh-passphrases.json"
// Increase here if your computer needs a little more time in between UI clicks
const delayFactor = 1
const sys = Application("System Events")
const app = Application.currentApplication()
function getPassphrase(outline, idx) {
app.setTheClipboardTo("")
let row = outline.rows[idx]
let keyfile = row.textFields()[0].value().split("SSH: ").slice(-1)[0].trim()
row.uiElements()[0].actions["AXShowMenu"].perform()
delay(0.1 * delayFactor)
outline.menus.at(0).menuItems.byName("Copy Password to Clipboard").click()
delay(0.5 * delayFactor)
sys.keystroke(pw)
sys.keyCode(36)
delay(0.1 * delayFactor)
var passphrase = app.theClipboard()
app.setTheClipboardTo("")
return {keyfile: keyfile, passphrase: passphrase}
}
function run(argv) {
app.includeStandardAdditions = true
let kc = sys.processes["Keychain Access"].windows.byName("Keychain Access")
let outline = kc.groups.at(0).splitterGroups.at(0).groups.at(1).scrollAreas.at(0).outlines.at(0)
let results = []
for (var idx in outline.rows) {
results.push(getPassphrase(outline, idx))
}
const fileID = app.openForAccess(Path(outfile), {writePermission: true})
app.write(JSON.stringify(results), {to: fileID, as: "text"})
app.closeAccess(fileID)
return
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment