Fix NIP-05 verification fetch errors#281
Fix NIP-05 verification fetch errors#281arnavkirti wants to merge 4 commits intoshopstr-eng:mainfrom
Conversation
|
@arnavkirti is attempting to deploy a commit to the shopstr-eng Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Pull request overview
This PR moves NIP-05 verification fetching from the browser to a server-side Next.js API route to avoid client-side CORS failures, while keeping the client’s boolean verification flow.
Changes:
- Added
/api/nostr/verify-nip05to fetch and validate/.well-known/nostr.jsonserver-side with a request timeout. - Updated the client verifier to call the internal API route and consume a
{ verified }response. - Added Jest tests for the new API route covering success, malformed identifiers, and external fetch failure.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| utils/nostr/nostr-helper-functions.ts | Switches client-side NIP-05 verification to call the internal API route and read verified. |
| pages/api/nostr/verify-nip05.ts | Adds a server-side verification endpoint with timeout + response parsing/matching. |
| pages/api/nostr/tests/verify-nip05.test.ts | Adds route-level tests validating core behaviors. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Please make the server-side fetch reject/ignore redirects, since NIP-05 explicitly forbids following them and it also protects the new SSRF guard. |
|
@GautamBytes Please take a look, I have done the changes. |
|
Hi @arnavkirti ! I’ve already opened a PR for this issue earlier. Sharing here in case it helps avoid duplicate work. Happy to collaborate or adjust if your approach improves something 👍 |
I am sorry, I didn't see your PR earlier. We can collaborate on this, as your PR implements the core feature, and my PR has relevant tests for the feature. Thanks! |
|
LGTM Now!! |
| const response = await fetch( | ||
| `/api/nostr/verify-nip05?nip05=${encodeURIComponent( | ||
| nip05 | ||
| )}&pubkey=${encodeURIComponent(pubkey)}` |
There was a problem hiding this comment.
- The url is still relative , a absolute url is requied in Node
- Can Remove @-split validation — server already handles this so no need to duplicate
- Can add type unknown as it would be more concrete
- no need of nested try catch all three blocks were doing the same thing , one wrapper would be fine
I have suggested the optimum code below do give a check
export async function verifyNip05Identifier(
nip05: string,
pubkey: string,
options?: { baseUrl?: string }
): Promise<boolean> {
if (!nip05 || !pubkey) return false;
try {
const params = new URLSearchParams({ nip05, pubkey });
const path = `/api/nostr/verify-nip05?${params.toString()}`;
const baseUrl =
options?.baseUrl ??
(typeof window !== "undefined" ? window.location.origin : null);
if (!baseUrl && typeof window === "undefined") {
throw new Error("verifyNip05Identifier requires baseUrl in SSR");
}
const requestUrl = baseUrl
export async function verifyNip05Identifier(
nip05: string,
pubkey: string,
options?: { baseUrl?: string }
): Promise<boolean> {
if (!nip05 || !pubkey) return false;
try {
const params = new URLSearchParams({ nip05, pubkey });
const path = `/api/nostr/verify-nip05?${params.toString()}`;
const baseUrl =
options?.baseUrl ??
(typeof window !== "undefined" ? window.location.origin : null);
if (!baseUrl && typeof window === "undefined") {
throw new Error("verifyNip05Identifier requires baseUrl in SSR");
}
const requestUrl = baseUrl
? new URL(path, baseUrl).toString()
: path;
const response = await fetch(requestUrl);
if (!response.ok) return false;
const data: unknown = await response.json();
return (
typeof data === "object" &&
data !== null &&
"verified" in data &&
(data as { verified?: boolean }).verified === true
);
} catch {
return fals
? new URL(path, baseUrl).toString()
: path;
const response = await fetch(requestUrl);
if (!response.ok) return false;
const data: unknown = await response.json();
return (
typeof data === "object" &&
data !== null &&
"verified" in data &&
(data as { verified?: boolean }).verified === true
);
} catch {
return false;
}
}
There was a problem hiding this comment.
These are few things that can be improved . I hope it helps 👍
Description
Fix NIP-05 verification so the client no longer fetches external
/.well-known/nostr.jsonendpoints directly.Root cause
Profile verification was running in the browser and fetching external NIP-05 documents from third-party domains. Many of those domains do not send
Access-Control-Allow-Origin, so browsers blocked the requests and valid verifications failed silently.Changes
Impact
NIP-05 verification now avoids client-side CORS failures for external domains while preserving the existing boolean verification flow used during profile hydration.
Resolved or fixed issue
Fixes #262
Affirmation
For more details on what to include, see:
Bug Report Template
Feature Request Template
Documentation Issue Template
Security Issue Template