diff --git a/README.md b/README.md index 26a9fb2..c46c15e 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,21 @@ x-signature-timestamp: 1707776632 } ``` +## Generate Ed25519 public & private key pair + +```bash +$ bunx substreams-sink-webhook keypair +{ + "publicKey": "36a89085d54d866c60ecccc2bf332d1c0dd5f1a810af175b1cfb7ff9e64b67d6", + "privateKey": "67603675f8160b4e4ca67770eaf7df797f3a9617665a84ec3e9baf92c403fb4f" +} +``` +or using `curl` + +```bash +$ curl http://localhost:9102/keypair +``` + ## Validate Ed25519 signature ```typescript diff --git a/bin/cli.ts b/bin/cli.ts index e2df6af..1714adc 100755 --- a/bin/cli.ts +++ b/bin/cli.ts @@ -34,8 +34,7 @@ program .description("Generate random Ed25519 private & public keys") .action(() => { const { publicKey, privateKey } = keyPair(); - console.log(`PUBLIC_KEY=${publicKey}`); - console.log(`PRIVATE_KEY=${privateKey}`); + process.stdout.write(JSON.stringify({ publicKey, privateKey }, null, 2)); }); program diff --git a/index.ts b/index.ts index 6149cb6..9cc27ac 100644 --- a/index.ts +++ b/index.ts @@ -7,7 +7,7 @@ import type { WebhookRunOptions } from "./bin/cli.js"; import { banner } from "./src/banner.js"; import { toJSON, toText } from "./src/http.js"; import { ping } from "./src/ping.js"; -import { checkKey, keyPair } from "./src/auth.js"; +import { keyPair, parsePrivateKey } from "./src/auth.js"; export async function action(options: WebhookRunOptions) { // Block Emitter @@ -17,8 +17,7 @@ export async function action(options: WebhookRunOptions) { const queue = new PQueue({ concurrency: 1 }); // all messages are sent in block order, no need to parallelize // Ping URL to check if it's valid - const privateKey = options.privateKey; - checkKey(privateKey, "private"); + const privateKey = parsePrivateKey(options.privateKey); if (options.disablePing === "false") { if (!(await ping(options.webhookUrl, privateKey))) { logger.error("exiting from invalid PING response"); diff --git a/src/auth.spec.ts b/src/auth.spec.ts index 81092a1..72427a6 100644 --- a/src/auth.spec.ts +++ b/src/auth.spec.ts @@ -83,3 +83,7 @@ describe("verify", () => { expect(auth.verify(timestamp, body, sig, publicKey)).toBeTruthy(); }); }); + +test("parsePrivateKey", () => { + expect(auth.parsePrivateKey(privateKey + publicKey)).toBe(privateKey); +}); diff --git a/src/auth.ts b/src/auth.ts index 5851604..13f5fe4 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -16,6 +16,15 @@ export function checkKey(key: Hex, type: "public" | "private") { } } +// TweetNaCl.js private key (includes public key) +// split the private key from the public key +export function parsePrivateKey(privateKey: string) { + if (typeof privateKey === "string" && privateKey.length === 128) { + return privateKey.slice(0, 64); + } + return privateKey; +} + export function checkSignature(signature: Hex) { const length = typeof signature === "string" ? 128 : 64; if (signature.length !== length) {