mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
fix(nostr): accept uppercase Bech32 keys in setup and DM targeting (#109878)
* fix(nostr): accept uppercase NSEC and NPUB inputs * test(nostr): satisfy target resolver type check
This commit is contained in:
@@ -158,6 +158,10 @@ describe("nostr outbound cfg threading", () => {
|
||||
await cleanup.stop();
|
||||
});
|
||||
|
||||
it("recognizes uppercase npub targets", () => {
|
||||
expect(nostrPlugin.messaging?.targetResolver?.looksLikeId?.("NPUB1XYZ123")).toBe(true);
|
||||
});
|
||||
|
||||
it("backs declared message adapter capabilities with outbound sends", async () => {
|
||||
installOutboundRuntime();
|
||||
const { cleanup, sendDm } = await startOutboundAccount();
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Nostr tests cover the lightweight setup plugin behavior.
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { nostrSetupPlugin } from "./channel.setup.js";
|
||||
import { TEST_HEX_PRIVATE_KEY } from "./test-fixtures.js";
|
||||
|
||||
describe("nostr setup plugin", () => {
|
||||
it("accepts uppercase bech32 private keys", () => {
|
||||
const nsec = nip19.nsecEncode(Buffer.from(TEST_HEX_PRIVATE_KEY, "hex")).toUpperCase();
|
||||
|
||||
expect(
|
||||
nostrSetupPlugin.setup?.validateInput?.({
|
||||
cfg: {},
|
||||
accountId: "default",
|
||||
input: { privateKey: nsec },
|
||||
} as never),
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -91,7 +91,11 @@ function resolveSetupNostrAccount(params: {
|
||||
}
|
||||
|
||||
function looksLikeNostrPrivateKey(privateKey: string): boolean {
|
||||
return privateKey.startsWith("nsec1") || /^[0-9a-fA-F]{64}$/.test(privateKey);
|
||||
return (
|
||||
privateKey.startsWith("nsec1") ||
|
||||
privateKey.startsWith("NSEC1") ||
|
||||
/^[0-9a-fA-F]{64}$/.test(privateKey)
|
||||
);
|
||||
}
|
||||
|
||||
const nostrSetupAdapter = createNostrSetupAdapter({
|
||||
|
||||
@@ -137,7 +137,11 @@ export const nostrPlugin: ChannelPlugin<ResolvedNostrAccount> = createChatChanne
|
||||
targetResolver: {
|
||||
looksLikeId: (input) => {
|
||||
const trimmed = input.trim();
|
||||
return trimmed.startsWith("npub1") || /^[0-9a-fA-F]{64}$/.test(trimmed);
|
||||
return (
|
||||
trimmed.startsWith("npub1") ||
|
||||
trimmed.startsWith("NPUB1") ||
|
||||
/^[0-9a-fA-F]{64}$/.test(trimmed)
|
||||
);
|
||||
},
|
||||
hint: "<npub|hex pubkey|nostr:npub...>",
|
||||
},
|
||||
|
||||
@@ -62,6 +62,18 @@ describe("validatePrivateKey", () => {
|
||||
});
|
||||
|
||||
describe("nsec format", () => {
|
||||
it("accepts uppercase bech32 private keys", () => {
|
||||
const nsec = nip19.nsecEncode(Buffer.from(TEST_HEX_PRIVATE_KEY, "hex"));
|
||||
|
||||
expect(validatePrivateKey(nsec.toUpperCase())).toEqual(validatePrivateKey(nsec));
|
||||
});
|
||||
|
||||
it("rejects mixed-case bech32 private keys", () => {
|
||||
const nsec = nip19.nsecEncode(Buffer.from(TEST_HEX_PRIVATE_KEY, "hex"));
|
||||
|
||||
expectThrowsError(() => validatePrivateKey(`N${nsec.slice(1)}`));
|
||||
});
|
||||
|
||||
it("rejects invalid nsec (wrong checksum)", () => {
|
||||
const badNsec = "nsec1invalidinvalidinvalidinvalidinvalidinvalidinvalidinvalid";
|
||||
expectThrowsError(() => validatePrivateKey(badNsec));
|
||||
@@ -113,6 +125,14 @@ describe("normalizePubkey", () => {
|
||||
it("trims surrounding whitespace before decoding", () => {
|
||||
expect(normalizePubkey(` ${NPUB} `)).toBe(HEX);
|
||||
});
|
||||
|
||||
it("decodes uppercase bech32 public keys", () => {
|
||||
expect(normalizePubkey(NPUB.toUpperCase())).toBe(HEX);
|
||||
});
|
||||
|
||||
it("rejects mixed-case bech32 public keys", () => {
|
||||
expectThrowsError(() => normalizePubkey(`N${NPUB.slice(1)}`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ export function validatePrivateKey(key: string): Uint8Array {
|
||||
const trimmed = key.trim();
|
||||
|
||||
// Handle nsec (bech32) format
|
||||
if (trimmed.startsWith("nsec1")) {
|
||||
if (trimmed.startsWith("nsec1") || trimmed.startsWith("NSEC1")) {
|
||||
const decoded = nip19.decode(trimmed);
|
||||
if (decoded.type !== "nsec") {
|
||||
throw new Error("Invalid nsec key: wrong type");
|
||||
@@ -44,7 +44,7 @@ export function normalizePubkey(input: string): string {
|
||||
const trimmed = input.trim();
|
||||
|
||||
// npub format - decode to hex
|
||||
if (trimmed.startsWith("npub1")) {
|
||||
if (trimmed.startsWith("npub1") || trimmed.startsWith("NPUB1")) {
|
||||
const decoded = nip19.decode(trimmed);
|
||||
if (decoded.type !== "npub" || typeof decoded.data !== "string") {
|
||||
throw new Error("Invalid npub key");
|
||||
|
||||
Reference in New Issue
Block a user