Files
flying-jib/lib/secrets.js
T
2026-07-31 00:46:06 -04:00

73 lines
1.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict'
/**
* Secret redaction helpers (agent/SECURITY.md S4).
* Invites, caps, seeds must never appear unredacted in progress logs.
*/
// z32 alphabet includes 1 and 8 (not only 27)
const Z32_CHARS = 'a-z0-9'
const INVITE_RE = new RegExp(`\\bfj1\\.[${Z32_CHARS}]+`, 'gi')
// Long z32 blobs (keys/caps) — avoid short words
const Z32_LONG_RE = new RegExp(`\\b[${Z32_CHARS}]{40,}\\b`, 'gi')
/**
* Redact a full fj1. invite string for logs.
* @param {string} invite
* @returns {string}
*/
function redactInvite(invite) {
const s = String(invite || '')
if (!s.startsWith('fj1.') || s.length < 12) return s ? '[redacted-invite]' : ''
const body = s.slice(4)
if (body.length <= 12) return 'fj1.' + '*'.repeat(Math.min(8, body.length))
return `fj1.${body.slice(0, 6)}${body.slice(-4)} (len=${s.length})`
}
/**
* Redact a z32 key/cap for logs.
* @param {string} key
* @returns {string}
*/
function redactKey(key) {
const s = String(key || '')
if (s.length < 8) return s ? '[redacted-key]' : ''
return `${s.slice(0, 4)}${s.slice(-4)} (len=${s.length})`
}
/**
* Redact any fj1. tokens (and long z32 blobs) inside a free-form message.
* @param {string} text
* @returns {string}
*/
function redactSecretsInText(text) {
let s = String(text || '')
s = s.replace(INVITE_RE, (m) => redactInvite(m))
// Avoid mangling short words; only long z32-looking tokens
s = s.replace(Z32_LONG_RE, (m) => {
if (m.startsWith('fj1')) return m
return redactKey(m)
})
return s
}
/**
* True if string looks like an invite or long secret.
* @param {string} s
* @returns {boolean}
*/
function looksLikeSecret(s) {
const t = String(s || '')
if (t.startsWith('fj1.')) return true
if (/^[a-z2-7]{40,}$/i.test(t)) return true
if (/seed|private.?key|cap=/i.test(t) && t.length > 20) return true
return false
}
module.exports = {
redactInvite,
redactKey,
redactSecretsInText,
looksLikeSecret
}