150 lines
3.4 KiB
JavaScript
150 lines
3.4 KiB
JavaScript
import {
|
|
finalizeEvent,
|
|
verifyEvent,
|
|
getPublicKey,
|
|
nip19,
|
|
getEventHash,
|
|
} from "nostr-tools";
|
|
import { useWebSocketImplementation, Relay } from "nostr-tools/relay";
|
|
import WebSocket from "ws";
|
|
useWebSocketImplementation(WebSocket);
|
|
|
|
const TWO_DAYS = 48 * 60 * 60 * 1000;
|
|
const RELAY = "TODO";
|
|
const BOT = JSON.stringify({
|
|
name: "BOT",
|
|
about: "a little exercise",
|
|
});
|
|
let intervalId;
|
|
|
|
try {
|
|
const args = [...process.argv];
|
|
args.shift();
|
|
args.shift();
|
|
|
|
if (!args.includes("-nsec")) {
|
|
console.error("BOT NEEDS NSEC.\n-nsec <nsec>");
|
|
process.exit(1);
|
|
}
|
|
|
|
const index = args.findIndex((arg) => arg === "-nsec");
|
|
const nsec = args[index + 1];
|
|
|
|
if (typeof nsec === "undefined" || nsec === "" || !nsec.startsWith("nsec")) {
|
|
console.error("BOT NSEC MISSING");
|
|
process.exit(1);
|
|
}
|
|
|
|
const sk = nip19.decode(nsec).data;
|
|
if (!sk) {
|
|
console.error("BOT NSEC BAD.");
|
|
process.exit(1);
|
|
}
|
|
|
|
const pk = getPublicKey(sk);
|
|
const profileEvent = finalizeEventWithPoW(
|
|
{
|
|
kind: 0,
|
|
content: BOT,
|
|
created_at: Math.floor(Date.now() / 1000),
|
|
tags: [],
|
|
},
|
|
sk
|
|
);
|
|
const isGood = verifyEvent(profileEvent);
|
|
if (isGood) {
|
|
(async () => {
|
|
try {
|
|
const relay = await Relay.connect(RELAY);
|
|
await relay.publish(profileEvent);
|
|
console.log("IT IS ALIVE!!");
|
|
relay.close();
|
|
} catch (error) {
|
|
exit(error);
|
|
}
|
|
})();
|
|
}
|
|
|
|
const run = () => {
|
|
const today = new Date();
|
|
const dayOfWeek = today.getUTCDay();
|
|
const message = `${dayOfWeek % 6 === 0 ? "gfy" : "GM"} fiatjaf`;
|
|
|
|
const event = finalizeEventWithPoW(
|
|
{
|
|
kind: 1,
|
|
content: message,
|
|
created_at: Math.floor(Date.now() / 1000),
|
|
tags: [],
|
|
},
|
|
sk
|
|
);
|
|
|
|
const isGood = verifyEvent(event);
|
|
if (isGood) {
|
|
(async () => {
|
|
try {
|
|
console.log("BOT IS CONNECTING..");
|
|
const relay = await Relay.connect(RELAY);
|
|
console.log("BOT CONNECTED");
|
|
await relay.publish(event);
|
|
console.log(`[${today.toISOString()}] ${message}`, event);
|
|
relay.close();
|
|
} catch (error) {
|
|
exit(error);
|
|
}
|
|
})();
|
|
}
|
|
};
|
|
|
|
console.log("BOT IS BOTTING as", nip19.npubEncode(pk));
|
|
intervalId = setInterval(run, TWO_DAYS);
|
|
} catch (error) {
|
|
exit(error);
|
|
}
|
|
|
|
function exit(error) {
|
|
console.error(`[${new Date().toISOString()}]`, "RIP BOT", error);
|
|
clearInterval(intervalId);
|
|
process.exit(1);
|
|
}
|
|
|
|
function finalizeEventWithPoW(event, sk, difficulty = 0) {
|
|
if (!difficulty) return finalizeEvent(event, sk);
|
|
|
|
const pk = getPublicKey(sk);
|
|
let nonce = 0;
|
|
let leadingZeroes = 0;
|
|
let unsignedEvent = { ...event, pubkey: pk };
|
|
while (true) {
|
|
unsignedEvent.tags = [["nonce", nonce.toString(), difficulty.toString()]];
|
|
unsignedEvent.created_at = Math.floor(Date.now() / 1000);
|
|
|
|
const hash = getEventHash(unsignedEvent);
|
|
leadingZeroes = countLeadingZeroes(hash);
|
|
|
|
if (leadingZeroes >= difficulty) {
|
|
return finalizeEvent(unsignedEvent, sk);
|
|
}
|
|
|
|
nonce++;
|
|
}
|
|
}
|
|
|
|
// hex should be a hexadecimal string (with no 0x prefix)
|
|
function countLeadingZeroes(hex) {
|
|
let count = 0;
|
|
|
|
for (let i = 0; i < hex.length; i++) {
|
|
const nibble = parseInt(hex[i], 16);
|
|
if (nibble === 0) {
|
|
count += 4;
|
|
} else {
|
|
count += Math.clz32(nibble) - 28;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|