chore(nostr-client): move dev scripts to dev/ folder
Move 9 development/testing .mjs scripts out of the package root into dev/ to keep the published package clean. Update relative imports and dev.sh reference. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
01bac04cdf
commit
5448a620a9
10 changed files with 3 additions and 3 deletions
221
packages/nostr-client/dev/run-debit-agent.mjs
Normal file
221
packages/nostr-client/dev/run-debit-agent.mjs
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* ATM Debit Approval Agent (TESTING ONLY)
|
||||
*
|
||||
* ⚠️ WARNING: This script auto-approves ALL debit requests without validation!
|
||||
* ⚠️ DO NOT use in production - use the integrated debit approval service instead.
|
||||
*
|
||||
* Purpose:
|
||||
* - Standalone debugging tool for testing the GetLiveDebitRequests subscription
|
||||
* - Helps diagnose relay connectivity and message decryption issues
|
||||
* - Useful when the integrated service isn't receiving events
|
||||
*
|
||||
* Usage:
|
||||
* # Set environment variables (or create .env file in apps/machine/)
|
||||
* export ATM_PRIVATE_KEY=<hex-private-key>
|
||||
* export LIGHTNING_PUB_PUBKEY=<hex-pubkey>
|
||||
* export RELAY_URL=ws://localhost:7777
|
||||
*
|
||||
* # Run the script
|
||||
* node run-debit-agent.mjs
|
||||
*
|
||||
* Production alternative:
|
||||
* The ATM app (apps/machine) includes an integrated debit approval service
|
||||
* with session-based single-use protection. See:
|
||||
* - apps/machine/src/services/lightning.ts (startDebitApprovalService)
|
||||
* - docs/ndebit-cash-in-flow.md
|
||||
*/
|
||||
|
||||
import { Relay } from 'nostr-tools/relay'
|
||||
import { finalizeEvent, getPublicKey } from 'nostr-tools'
|
||||
import * as nip44v1 from './nip44v1.mjs'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
// Load .env file from apps/machine if it exists
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const envPath = path.join(__dirname, '../../apps/machine/.env')
|
||||
if (fs.existsSync(envPath)) {
|
||||
const envContent = fs.readFileSync(envPath, 'utf-8')
|
||||
for (const line of envContent.split('\n')) {
|
||||
const trimmed = line.trim()
|
||||
if (trimmed && !trimmed.startsWith('#')) {
|
||||
const [key, ...valueParts] = trimmed.split('=')
|
||||
if (key && valueParts.length > 0) {
|
||||
// Map VITE_ prefixed vars to non-prefixed
|
||||
const envKey = key.replace(/^VITE_/, '')
|
||||
process.env[envKey] = valueParts.join('=')
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('[Config] Loaded .env from:', envPath)
|
||||
}
|
||||
|
||||
// Configuration from environment
|
||||
const ATM_PRIVATE_KEY_HEX = process.env.ATM_PRIVATE_KEY
|
||||
const LIGHTNING_PUB_PUBKEY = process.env.LIGHTNING_PUB_PUBKEY
|
||||
const RELAY_URL = process.env.RELAY_URL || 'ws://localhost:7777'
|
||||
|
||||
// Validate required config
|
||||
if (!ATM_PRIVATE_KEY_HEX) {
|
||||
console.error('ERROR: ATM_PRIVATE_KEY environment variable is required')
|
||||
console.error('Set it directly or create apps/machine/.env with VITE_ATM_PRIVATE_KEY')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (!LIGHTNING_PUB_PUBKEY) {
|
||||
console.error('ERROR: LIGHTNING_PUB_PUBKEY environment variable is required')
|
||||
console.error('Set it directly or create apps/machine/.env with VITE_LIGHTNING_PUB_PUBKEY')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const ATM_PRIVATE_KEY = Uint8Array.from(Buffer.from(ATM_PRIVATE_KEY_HEX, 'hex'))
|
||||
const ATM_PUBLIC_KEY = getPublicKey(ATM_PRIVATE_KEY)
|
||||
|
||||
console.log('')
|
||||
console.log('='.repeat(60))
|
||||
console.log(' ATM Debit Approval Agent (TESTING ONLY)')
|
||||
console.log('='.repeat(60))
|
||||
console.log('')
|
||||
console.log('⚠️ WARNING: Auto-approves ALL requests without validation!')
|
||||
console.log('⚠️ For production, use the integrated service in apps/machine')
|
||||
console.log('')
|
||||
console.log('ATM Pubkey:', ATM_PUBLIC_KEY)
|
||||
console.log('Lightning.Pub Pubkey:', LIGHTNING_PUB_PUBKEY)
|
||||
console.log('Relay URL:', RELAY_URL)
|
||||
console.log('')
|
||||
|
||||
async function main() {
|
||||
// Connect to relay
|
||||
console.log('Connecting to relay...')
|
||||
const relay = await Relay.connect(RELAY_URL)
|
||||
console.log('Connected!')
|
||||
console.log('')
|
||||
|
||||
// Create conversation key for NIP-44 v1 encryption
|
||||
const conversationKey = nip44v1.getConversationKey(ATM_PRIVATE_KEY_HEX, LIGHTNING_PUB_PUBKEY)
|
||||
|
||||
// Subscribe to GetLiveDebitRequests
|
||||
console.log('Subscribing to live debit requests...')
|
||||
|
||||
const subscribeRequest = {
|
||||
rpcName: 'GetLiveDebitRequests',
|
||||
authIdentifier: ATM_PUBLIC_KEY,
|
||||
body: {},
|
||||
}
|
||||
|
||||
const subEvent = finalizeEvent(
|
||||
{
|
||||
kind: 21000,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
tags: [['p', LIGHTNING_PUB_PUBKEY]],
|
||||
content: nip44v1.encrypt(JSON.stringify(subscribeRequest), conversationKey),
|
||||
},
|
||||
ATM_PRIVATE_KEY
|
||||
)
|
||||
|
||||
// Listen for debit requests
|
||||
console.log('Listening for debit requests...')
|
||||
console.log('(Test by scanning ndebit QR with ShockWallet)')
|
||||
console.log('')
|
||||
|
||||
const debitSub = relay.subscribe(
|
||||
[
|
||||
{
|
||||
kinds: [21000],
|
||||
authors: [LIGHTNING_PUB_PUBKEY],
|
||||
'#p': [ATM_PUBLIC_KEY],
|
||||
since: Math.floor(Date.now() / 1000) - 5,
|
||||
},
|
||||
],
|
||||
{
|
||||
async onevent(evt) {
|
||||
try {
|
||||
const decrypted = nip44v1.decrypt(evt.content, conversationKey)
|
||||
const message = JSON.parse(decrypted)
|
||||
|
||||
// Check if this is a live debit request
|
||||
if (message.requestId === 'GetLiveDebitRequests' && message.debit) {
|
||||
console.log('')
|
||||
console.log('========================================')
|
||||
console.log('DEBIT REQUEST RECEIVED!')
|
||||
console.log(' Request ID:', message.request_id)
|
||||
console.log(' From npub:', message.npub?.substring(0, 16) + '...')
|
||||
console.log(' Debit type:', message.debit.type)
|
||||
|
||||
if (message.debit.invoice) {
|
||||
console.log(' Invoice:', message.debit.invoice.substring(0, 50) + '...')
|
||||
|
||||
// Auto-approve by responding with INVOICE type
|
||||
console.log('')
|
||||
console.log('⚠️ AUTO-APPROVING debit request (NO VALIDATION)...')
|
||||
|
||||
const approveRequest = {
|
||||
rpcName: 'RespondToDebit',
|
||||
authIdentifier: ATM_PUBLIC_KEY,
|
||||
body: {
|
||||
npub: message.npub,
|
||||
request_id: message.request_id,
|
||||
response: {
|
||||
type: 'invoice',
|
||||
invoice: message.debit.invoice,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const approveEvent = finalizeEvent(
|
||||
{
|
||||
kind: 21000,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
tags: [['p', LIGHTNING_PUB_PUBKEY]],
|
||||
content: nip44v1.encrypt(JSON.stringify(approveRequest), conversationKey),
|
||||
},
|
||||
ATM_PRIVATE_KEY
|
||||
)
|
||||
|
||||
await relay.publish(approveEvent)
|
||||
console.log('APPROVED! (event id:', approveEvent.id.substring(0, 16) + '...)')
|
||||
}
|
||||
|
||||
console.log('========================================')
|
||||
console.log('')
|
||||
} else if (message.rpcName) {
|
||||
console.log('RPC response:', message.rpcName, ':', message.status || 'received')
|
||||
} else if (message.requestId) {
|
||||
console.log('Live subscription active:', message.status)
|
||||
}
|
||||
} catch (err) {
|
||||
// Ignore decryption failures for events not meant for us
|
||||
if (!err.message?.includes('Unsupported')) {
|
||||
// Uncomment for debugging:
|
||||
// console.log('Decryption error:', err.message)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
await relay.publish(subEvent)
|
||||
console.log('Subscription sent, waiting for debit requests...')
|
||||
console.log('')
|
||||
|
||||
// Keep running
|
||||
process.on('SIGINT', () => {
|
||||
console.log('\nShutting down...')
|
||||
debitSub.close()
|
||||
relay.close()
|
||||
process.exit(0)
|
||||
})
|
||||
|
||||
// Heartbeat
|
||||
while (true) {
|
||||
await new Promise((r) => setTimeout(r, 30000))
|
||||
console.log('Still listening...')
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err.message)
|
||||
process.exit(1)
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue