名称: nostr-logging-system 描述: 通过Nostr发布操作日志,公开事件用于非敏感日志,私有管理员消息用于敏感日志。
Nostr 日志系统
使用Nostr作为分布式日志传输:发布非敏感日志公开,并通过Nostr私信将敏感日志私密发送给管理员。
何时使用
- 您希望有防篡改、中继分布式的公共操作日志。
- 您希望敏感日志(包含秘密的错误、内部跟踪)私密地发送给管理员。
- 您需要一个轻量级的日志通道,无需集中式日志基础设施。
所需工具 / API
- Node.js 18+
nostr-sdk库
安装:
npm install nostr-sdk
环境变量:
# 必需:管理员Nostr公钥(npub或十六进制公钥)
export ADMIN_NOSTR_PUBKEY="npub1..."
# 必需:日志器身份(如果缺失,请创建;见下文设置)
export NOSTR_NSEC="nsec1..."
# 可选
export NOSTR_RELAYS="wss://relay.damus.io,wss://nos.lol,wss://relay.snort.social"
设置流程(必须首先执行)
- 向管理员索要他们的Nostr地址(
npub/ 公钥)。 - 检查是否已有
NOSTR_NSEC保存。 - 如果缺失,生成新的密钥对,并保存
nsec以备将来运行。
如果缺失,生成并持久化nsec(Node.js)
// setup-nostr-identity.js
const fs = require('fs');
const path = require('path');
const { generateRandomNsec, nsecToPublic } = require('nostr-sdk');
function ensureNostrIdentity() {
const envPath = path.resolve(process.cwd(), '.env');
const envText = fs.existsSync(envPath) ? fs.readFileSync(envPath, 'utf8') : '';
const fromProcess = process.env.NOSTR_NSEC;
const fromEnvFile = envText.match(/^NOSTR_NSEC=(.+)$/m)?.[1];
const currentNsec = fromProcess || fromEnvFile;
if (currentNsec && currentNsec.startsWith('nsec1')) {
console.log('NOSTR_NSEC already exists. Reusing saved key.');
return currentNsec;
}
const nsec = generateRandomNsec();
const pub = nsecToPublic(nsec);
const line = `NOSTR_NSEC=${nsec}`;
const nextEnv = envText.includes('NOSTR_NSEC=')
? envText.replace(/^NOSTR_NSEC=.*$/m, line)
: `${envText}${envText.endsWith('
') || envText.length === 0 ? '' : '
'}${line}
`;
fs.writeFileSync(envPath, nextEnv, 'utf8');
console.log('Generated new Nostr identity. Saved NOSTR_NSEC to .env');
console.log('Your npub:', pub.npub);
return nsec;
}
ensureNostrIdentity();
运行:
node setup-nostr-identity.js
技能
1. 公共日志事件(非敏感)
const { posttoNostr } = require('nostr-sdk');
async function logPublic(message, level = 'info') {
const tags = [
['t', 'logs'],
['t', 'public'],
['t', level]
];
return posttoNostr(`[PUBLIC_LOG] ${message}`, {
nsec: process.env.NOSTR_NSEC,
tags,
relays: null,
powDifficulty: 4
});
}
// 示例:
// await logPublic('Worker started successfully', 'info');
2. 敏感日志发给管理员私信
const { sendMessageNIP17 } = require('nostr-sdk');
async function logSensitiveToAdmin(message) {
const admin = process.env.ADMIN_NOSTR_PUBKEY;
if (!admin) throw new Error('Missing ADMIN_NOSTR_PUBKEY');
return sendMessageNIP17(admin, `[SENSITIVE_LOG] ${message}`, {
nsec: process.env.NOSTR_NSEC
});
}
// 示例:
// await logSensitiveToAdmin('DB auth retry failed for tenant=alpha');
3. 按敏感性路由日志(单一日志器)
const { posttoNostr, sendMessageNIP17 } = require('nostr-sdk');
async function logNostrEvent({ level = 'info', message, sensitive = false, context = {} }) {
if (!process.env.NOSTR_NSEC) throw new Error('Missing NOSTR_NSEC');
if (!process.env.ADMIN_NOSTR_PUBKEY) throw new Error('Missing ADMIN_NOSTR_PUBKEY');
const payload = JSON.stringify({
ts: new Date().toISOString(),
level,
message,
context
});
if (sensitive) {
return sendMessageNIP17(process.env.ADMIN_NOSTR_PUBKEY, `[SENSITIVE_LOG] ${payload}`, {
nsec: process.env.NOSTR_NSEC
});
}
return posttoNostr(`[PUBLIC_LOG] ${payload}`, {
nsec: process.env.NOSTR_NSEC,
tags: [['t', 'logs'], ['t', 'public'], ['t', level]],
relays: null,
powDifficulty: 4
});
}
// 示例:
// await logNostrEvent({ level: 'info', message: 'Cron completed', sensitive: false });
// await logNostrEvent({ level: 'error', message: 'JWT parse failed', sensitive: true, context: { userId: 42 } });
代理提示
使用Nostr日志系统技能。
规则:
1) 首先索要管理员Nostr地址(npub/公钥)并存储为ADMIN_NOSTR_PUBKEY。
2) 检查环境/.env中是否已存在NOSTR_NSEC。
3) 如果缺失,生成新身份并持久化NOSTR_NSEC以备将来运行。
4) 路由日志:
- 非敏感 -> 公共Nostr笔记,带有标签logs/public/<level>
- 敏感 -> 私有私信给ADMIN_NOSTR_PUBKEY,使用NIP-17
5) 切勿在公共笔记中发布秘密。
最佳实践
- 在记录前编辑秘密(令牌、私钥、密码)。
- 默认将任何用户识别信息视为敏感。
- 添加稳定的标签(
logs、service-name、env)以便过滤。 - 使用多个中继以提高交付和弹性。
- 如果泄露,轮换日志器身份密钥。
故障排除
Missing ADMIN_NOSTR_PUBKEY:向管理员索要npub/公钥并导出。Missing NOSTR_NSEC:运行设置脚本生成并持久化身份。- 发布成功率低:添加更多中继或降低POW难度重试。
- 私信未收到:确认管理员密钥正确,且中继支持私信。