Files
c-relay/tests/config_query_test.js
2025-10-05 14:35:09 -04:00

135 lines
5.1 KiB
JavaScript

#!/usr/bin/env node
// Spec-compliant test to send config_query command with proper NIP-44 encryption
// Uses nostr-tools for encryption and event creation
import { nip44, finalizeEvent, getPublicKey } from 'nostr-tools';
import WebSocket from 'ws';
// Test keys from make_and_restart_relay.sh -t
const ADMIN_PRIVATE_KEY = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const ADMIN_PUBLIC_KEY = "6a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3";
const RELAY_PUBLIC_KEY = "4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa";
const RELAY_URL = "ws://localhost:8888";
async function main() {
console.log("=== Testing Admin API Config Query (Spec Compliant) ===");
console.log("Sending config_query command using nostr-tools...");
// Command array as per README.md spec
const commandArray = ["config_query", "all"];
const commandJson = JSON.stringify(commandArray);
console.log(`Command: ${commandJson}`);
return new Promise((resolve, reject) => {
const ws = new WebSocket(RELAY_URL);
let queryResponseReceived = false;
ws.on('open', () => {
console.log("WebSocket connected");
try {
const adminPubkey = getPublicKey(Buffer.from(ADMIN_PRIVATE_KEY, 'hex'));
console.log(`Admin pubkey: ${adminPubkey}`);
// Send subscription for response events
const subId = "admin_response";
const subMessage = JSON.stringify(["REQ", subId, { kinds: [23457], "#p": [ADMIN_PUBLIC_KEY] }]);
ws.send(subMessage);
console.log(`Subscription sent: ${subMessage}`);
// Send the first command
sendCommand(ws, commandArray);
} catch (error) {
console.error("Failed to prepare/send command:", error.message);
ws.close();
reject(error);
}
});
ws.on('message', (data) => {
const message = data.toString();
console.log(`Relay response: ${message}`);
try {
const parsed = JSON.parse(message);
if (parsed[0] === "EVENT" && parsed[1] === "admin_response") {
const event = parsed[2];
if (event.kind === 23457) {
// Decrypt the response content
const conversationKey = nip44.getConversationKey(Buffer.from(ADMIN_PRIVATE_KEY, 'hex'), RELAY_PUBLIC_KEY);
const decrypted = nip44.decrypt(event.content, conversationKey);
console.log(`Decrypted response: ${decrypted}`);
if (!queryResponseReceived) {
queryResponseReceived = true;
console.log("\n=== Testing Admin API Config Update ===");
console.log("Sending config_update command to change relay_description...");
// Send the second command
const updateCommandArray = ["config_update", [{"key": "relay_description", "value": "Bozo the clown", "data_type": "string", "category": "relay"}]];
sendCommand(ws, updateCommandArray);
}
}
}
} catch (error) {
// Ignore parsing errors
}
});
ws.on('error', (error) => {
console.error("WebSocket error:", error.message);
reject(error);
});
ws.on('close', () => {
console.log("WebSocket closed");
resolve();
});
// Timeout after 20 seconds
setTimeout(() => {
ws.close();
}, 20000);
});
}
function sendCommand(ws, commandArray) {
try {
const commandJson = JSON.stringify(commandArray);
console.log(`Command: ${commandJson}`);
// Derive conversation key for NIP-44 encryption
const conversationKey = nip44.getConversationKey(Buffer.from(ADMIN_PRIVATE_KEY, 'hex'), RELAY_PUBLIC_KEY);
// Encrypt the command JSON with NIP-44
const encryptedContent = nip44.encrypt(commandJson, conversationKey);
console.log(`Encrypted content: ${encryptedContent.substring(0, 50)}...`);
// Create the event template
const eventTemplate = {
kind: 23456,
created_at: Math.floor(Date.now() / 1000),
tags: [['p', RELAY_PUBLIC_KEY]],
content: encryptedContent
};
// Sign the event
const event = finalizeEvent(eventTemplate, Buffer.from(ADMIN_PRIVATE_KEY, 'hex'));
console.log(`Event sent: ${JSON.stringify(event, null, 2)}`);
// Send the event
const eventMessage = JSON.stringify(["EVENT", event]);
ws.send(eventMessage);
console.log("Command sent successfully!");
console.log("Listening for responses...");
} catch (error) {
console.error("Failed to send command:", error.message);
ws.close();
}
}
main().catch(console.error);