Skip to content

Feat: addition of nip-05 verification (issue #261)#463

Merged
cameri merged 13 commits intocameri:mainfrom
archief2910:feature/261-NIP-05-verification
Apr 18, 2026
Merged

Feat: addition of nip-05 verification (issue #261)#463
cameri merged 13 commits intocameri:mainfrom
archief2910:feature/261-NIP-05-verification

Conversation

@archief2910
Copy link
Copy Markdown
Contributor

@archief2910 archief2910 commented Apr 11, 2026

Description

This PR implements NIP-05 verification as a spam reduction mechanism for nostream, as described in the nostr-rs-relay reference configuration.

Changes included:

NIP-05 Verification Core:

  • Added Nip05Verification and DBNip05Verification types for application and database layers.
  • Added Nip05Settings interface with three operational modes: enabled (require NIP-05 for publishing), passive (validate without blocking), and disabled (no-op).
  • Implemented parseNip05Identifier, extractNip05FromEvent, verifyNip05Identifier, and isDomainAllowed utility functions conforming to the NIP-05 protocol (https://<domain>/.well-known/nostr.json?name=<local>).
  • Created Nip05VerificationRepository following the existing repository pattern with Ramda applySpec DB-to-app mapping.
  • Added Knex migration for the nip05_verifications table with indexes on domain, is_verified, and last_checked_at.

Event Handler Integration:

  • Integrated checkNip05Verification into EventMessageHandler pipeline — blocks unverified authors when mode is enabled, always allows kind-0 (SET_METADATA) events through so users can set their NIP-05 identifier.
  • Implemented processNip05Metadata as fire-and-forget async verification triggered on successful kind-0 event persistence. Deletes verification records when a user removes their NIP-05 from metadata.

Background Re-verification:

  • Added processNip05Reverifications to MaintenanceWorker — periodically re-checks stale verifications respecting verifyUpdateFrequency and maxConsecutiveFailures settings with jittered delays between requests.

Configuration:

  • Added nip05 section to default-settings.yaml with defaults matching nostr-rs-relay: 1 week expiration, 24-hour update frequency, 20 max consecutive failures.
  • Updated CONFIGURATION.md with documentation for all six settings.

Factory Wiring:

  • Threaded Nip05VerificationRepository through workerFactorywebSocketAdapterFactorymessageHandlerFactoryEventMessageHandler and maintenanceWorkerFactoryMaintenanceWorker as a required dependency.

Cleanup:

  • Consolidated duplicate import from '../constants/base' lines in event-message-handler.ts.
  • Removed dead sinonChai import from NIP-05 utility test file.

Related Issue

Closes #261

Motivation and Context

Spam is a persistent problem for public Nostr relays. NIP-05 verification provides a DNS-based identity layer that ties pubkeys to domain names, allowing relay operators to require that event authors have a verifiable internet identity. This is the same approach implemented by nostr-rs-relay and requested in issue #261. The three-mode system (enabled/passive/disabled) gives operators full control over enforcement level without requiring code changes.

How Has This Been Tested?

  • 57 NIP-05 specific unit tests covering:
    • parseNip05Identifier: 12 tests — valid identifiers, subdomains, case normalization, edge cases (null, empty, missing @, no TLD).
    • extractNip05FromEvent: 6 tests — valid kind-0, wrong kind, missing field, bad JSON, empty string, non-string value.
    • isDomainAllowed: 8 tests — whitelist, blacklist, empty lists, case-insensitivity, blacklist-over-whitelist precedence.
    • checkNip05Verification: 12 tests — all three modes, relay pubkey bypass, kind-0 passthrough, missing/expired/unverified records, domain whitelist/blacklist filtering.
    • processNip05Metadata: 10 tests — disabled/passive modes, non-kind-0, delete on missing NIP-05, unparseable identifier, blocked domain, successful/failed verification with upsert assertions, error handling, passive mode verification.
    • processNip05Reverifications: 9 tests — disabled mode, no pending records, success/failure state updates, failure count increment, error resilience across batch, custom config values, undefined fallback defaults, passive mode operation.
  • Updated existing factory tests (message-handler-factory.spec.ts, websocket-adapter-factory.spec.ts) for the new required repository parameter.
  • Full test suite passes: 544 passing (2 pre-existing Windows path-separator failures ).
  • ESLint: 0 errors across all modified files.
  • TypeScript: compiles cleanly with --noEmit.

Screenshots (if appropriate):

N/A

Types of changes

  • Non-functional change (docs, style, minor refactor)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my code changes.
  • All new and existing tests passed.

@archief2910 archief2910 changed the title Feature/261-nip-05-verification Feat: addition of nip-05 verification (#261) Apr 11, 2026
@archief2910 archief2910 changed the title Feat: addition of nip-05 verification (#261) Feat: addition of nip-05 verification (issue #261) Apr 11, 2026
@archief2910
Copy link
Copy Markdown
Contributor Author

@phoenix-server @cameri This pr is ready for review and checks
Local checks including lint, unit passed.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds NIP-05 verification support to nostream to reduce spam by optionally requiring authors to have a verifiable NIP-05 identity, with persistence and periodic re-checking.

Changes:

  • Introduces NIP-05 parsing/extraction/verification utilities plus a DB-backed nip05_verifications repository and migration.
  • Integrates NIP-05 enforcement/metadata-triggered verification into EventMessageHandler and adds periodic re-verification to MaintenanceWorker.
  • Wires the new repository through factories, and documents/configures new nip05.* settings (with unit tests added/updated).

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
test/unit/utils/nip05.spec.ts Adds unit coverage for NIP-05 parsing/extraction/domain filtering utilities.
test/unit/handlers/event-message-handler.spec.ts Adds unit coverage for handler enforcement + metadata-triggered verification behavior.
test/unit/factories/websocket-adapter-factory.spec.ts Updates factory tests for the new repository dependency.
test/unit/factories/message-handler-factory.spec.ts Updates factory tests for the new repository dependency.
test/unit/app/maintenance-worker.spec.ts Adds unit coverage for periodic NIP-05 re-verification behavior.
src/utils/nip05.ts Implements NIP-05 identifier parsing, metadata extraction, domain allow/deny logic, and HTTP verification.
src/repositories/nip05-verification-repository.ts Adds repository for storing and querying NIP-05 verification state.
src/handlers/event-message-handler.ts Enforces NIP-05 (mode-dependent) and triggers async verification on kind-0 metadata events.
src/factories/worker-factory.ts Instantiates and injects the NIP-05 verification repository into websocket adapter wiring.
src/factories/websocket-adapter-factory.ts Threads NIP-05 repository into message handler construction.
src/factories/message-handler-factory.ts Adds NIP-05 repository dependency to EventMessageHandler creation.
src/factories/maintenance-worker-factory.ts Instantiates and injects NIP-05 repository into MaintenanceWorker.
src/app/maintenance-worker.ts Adds periodic batch re-verification of stale NIP-05 records.
src/@types/settings.ts Introduces Nip05Settings and nip05 config field in Settings.
src/@types/repositories.ts Adds INip05VerificationRepository interface.
src/@types/nip05.ts Adds app and DB-layer types for NIP-05 verification records.
resources/default-settings.yaml Adds default nip05 configuration section.
migrations/20260409_120000_create_nip05_verifications_table.js Creates nip05_verifications table + indexes.
CONFIGURATION.md Documents new nip05.* settings.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 35 to +43
public run(): void {
this.interval = setInterval(() => this.onSchedule(), UPDATE_INVOICE_INTERVAL)
}

private async onSchedule(): Promise<void> {
const currentSettings = this.settings()

await this.processNip05Reverifications(currentSettings)

Comment thread src/@types/settings.ts Outdated
Comment on lines +220 to +222
verifyExpiration: number
verifyUpdateFrequency: number
maxConsecutiveFailures: number
Comment thread src/handlers/event-message-handler.ts Outdated
Comment on lines +363 to +374
if (!verification || !verification.isVerified) {
return 'blocked: NIP-05 verification required'
}

const expirationMs = nip05Settings.verifyExpiration ?? 604800000
if (verification.lastVerifiedAt) {
const elapsed = Date.now() - verification.lastVerifiedAt.getTime()
if (elapsed > expirationMs) {
return 'blocked: NIP-05 verification expired'
}
}

Comment thread src/handlers/event-message-handler.ts Outdated
Comment on lines +367 to +372
const expirationMs = nip05Settings.verifyExpiration ?? 604800000
if (verification.lastVerifiedAt) {
const elapsed = Date.now() - verification.lastVerifiedAt.getTime()
if (elapsed > expirationMs) {
return 'blocked: NIP-05 verification expired'
}
Comment thread src/handlers/event-message-handler.ts Outdated
Comment on lines +408 to +423
verifyNip05Identifier(nip05Identifier, event.pubkey)
.then((verified) => {
const now = new Date()
const verification: Nip05Verification = {
pubkey: event.pubkey,
nip05: nip05Identifier,
domain: parsed.domain,
isVerified: verified,
lastVerifiedAt: verified ? now : null,
lastCheckedAt: now,
failureCount: verified ? 0 : 1,
createdAt: now,
updatedAt: now,
}
return this.nip05VerificationRepository.upsert(verification)
})
Comment thread src/utils/nip05.ts
Comment on lines +72 to +76
const response = await axios.get(url, {
timeout: VERIFICATION_TIMEOUT_MS,
headers: { 'Accept': 'application/json' },
validateStatus: (status) => status === 200,
})
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@archief2910 good point here, let's set max redirects to 1 (not zero), and limit body and content length. This verification feature can be used to perform DoS attacks or consume the relay's bandwidth for malicious purposes.

Comment thread src/utils/nip05.ts Outdated
} catch (error: unknown) {
const message = error instanceof Error ? error.message : String(error)
debug('verification request failed for %s: %s', nip05, message)
return false
Comment thread src/app/maintenance-worker.ts Outdated
Comment on lines +123 to +130
const updated: Nip05Verification = {
...verification,
isVerified: verified,
lastVerifiedAt: verified ? now : verification.lastVerifiedAt,
lastCheckedAt: now,
failureCount: verified ? 0 : verification.failureCount + 1,
updatedAt: now,
}
@cameri
Copy link
Copy Markdown
Owner

cameri commented Apr 18, 2026

@copilot resolve the merge conflicts in this pull request

@socket-security
Copy link
Copy Markdown

socket-security Bot commented Apr 18, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedcross-env@​10.1.010010010082100

View full report

@archief2910
Copy link
Copy Markdown
Contributor Author

hey @cameri , i have resolved the conflicts you can check once or should i address the copilot comments too .

Comment thread src/utils/nip05.ts Outdated
validateStatus: (status) => status === 200,
})

const { data } = response
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's validate the response using zod

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but the joi to zod validation issue is not yet merged . so im using it with joi . will it work.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but can you create an issue to migrate this to zod too?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok sure

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@archief2910 zod PR has been merged just FYI

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok then i will update the pr accr ot new commits and migrate it to zod.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @cameri , resolved the zod migration you can check once .

@archief2910
Copy link
Copy Markdown
Contributor Author

hey @cameri , made an issue for migration and resolved the review comments . can you check once .

@cameri cameri merged commit f7869b0 into cameri:main Apr 18, 2026
9 checks passed
@archief2910 archief2910 deleted the feature/261-NIP-05-verification branch April 18, 2026 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NIP-05 verification as a way to reduce spam

3 participants