From 80e2542ed3e4823c01c64376fd02b50306b72fed Mon Sep 17 00:00:00 2001 From: Saniddhya Dubey Date: Fri, 22 May 2026 14:29:36 -0400 Subject: [PATCH 1/2] docs(changeset): new user-facing config field --- .changeset/lemon-views-know.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/lemon-views-know.md diff --git a/.changeset/lemon-views-know.md b/.changeset/lemon-views-know.md new file mode 100644 index 00000000..bf4e8fc4 --- /dev/null +++ b/.changeset/lemon-views-know.md @@ -0,0 +1,5 @@ +--- +"nostream": minor +--- + +new user-facing config field From d4e91cebbd3c909cc96768d6130ecf2107175e90 Mon Sep 17 00:00:00 2001 From: Saniddhya Dubey Date: Fri, 22 May 2026 14:31:21 -0400 Subject: [PATCH 2/2] feat: config schema for wot --- resources/default-settings.yaml | 11 ++++++++++ src/@types/settings.ts | 20 +++++++++++++++++ test/unit/utils/settings.spec.ts | 37 ++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/resources/default-settings.yaml b/resources/default-settings.yaml index e49ad366..1f8948a5 100755 --- a/resources/default-settings.yaml +++ b/resources/default-settings.yaml @@ -62,6 +62,17 @@ nip05: domainBlacklist: [] nip45: enabled: true +wot: + # Web of Trust filtering. When enabled, only events from pubkeys within + # the relay owner's 2-hop follow graph are accepted. + enabled: false + # The relay owner's pubkey in hex. This is the root of the trust graph. + # Required when enabled is true. + seedPubkey: "" + # A pubkey must be followed by at least this many 1-hop accounts to be trusted. + minimumFollowers: 1 + # Hours between full trust graph rebuilds. + refreshIntervalHours: 24 network: maxPayloadSize: 524288 # Uncomment only when using a trusted reverse proxy and configuring trustedProxies. diff --git a/src/@types/settings.ts b/src/@types/settings.ts index d4463dc9..348efdae 100644 --- a/src/@types/settings.ts +++ b/src/@types/settings.ts @@ -266,6 +266,25 @@ export interface Nip05Settings { domainBlacklist?: string[] } +export interface WoTSettings { + enabled: boolean + /** + * The relay owner's pubkey (hex). The trust graph is rooted here. + * Required when enabled is true. + */ + seedPubkey: Pubkey + /** + * Minimum number of 1-hop follows a pubkey must have to enter the trust filter. + * Defaults to 1. + */ + minimumFollowers: number + /** + * How many hours between full trust graph rebuilds. + * Defaults to 24. + */ + refreshIntervalHours: number +} + export interface Settings { info: Info payments?: Payments @@ -276,4 +295,5 @@ export interface Settings { mirroring?: Mirroring nip05?: Nip05Settings nip45?: Nip45Settings + wot?: WoTSettings } diff --git a/test/unit/utils/settings.spec.ts b/test/unit/utils/settings.spec.ts index ca428bdf..349943a0 100644 --- a/test/unit/utils/settings.spec.ts +++ b/test/unit/utils/settings.spec.ts @@ -2,6 +2,8 @@ import { expect } from 'chai' import fs from 'fs' import { join } from 'path' import Sinon from 'sinon' +import { mergeDeepRight } from 'ramda' +import { Settings } from '../../../src/@types/settings' import { SettingsFileTypes, SettingsStatic } from '../../../src/utils/settings' @@ -258,4 +260,39 @@ describe('SettingsStatic', () => { ) }) }) + + describe('WoT settings defaults', () => { + it('default-settings.yaml contains a wot block with enabled: false', () => { + const defaults = SettingsStatic.loadAndParseYamlFile( + SettingsStatic.getDefaultSettingsFilePath() + ) + expect(defaults).to.have.nested.property('wot.enabled', false) + expect(defaults).to.have.nested.property('wot.seedPubkey', '') + expect(defaults).to.have.nested.property('wot.minimumFollowers', 1) + expect(defaults).to.have.nested.property('wot.refreshIntervalHours', 24) + }) + + it('merging an empty user config preserves wot defaults', () => { + const defaults = SettingsStatic.loadAndParseYamlFile( + SettingsStatic.getDefaultSettingsFilePath() + ) + const merged = mergeDeepRight(defaults, {}) as Settings + expect(merged.wot?.enabled).to.equal(false) + expect(merged.wot?.minimumFollowers).to.equal(1) + expect(merged.wot?.refreshIntervalHours).to.equal(24) + }) + + it('user config wot block overrides defaults', () => { + const defaults = SettingsStatic.loadAndParseYamlFile( + SettingsStatic.getDefaultSettingsFilePath() + ) + const userConfig = { wot: { enabled: true, seedPubkey: 'abc123', minimumFollowers: 3 } } + const merged = mergeDeepRight(defaults, userConfig) as Settings + expect(merged.wot?.enabled).to.equal(true) + expect(merged.wot?.seedPubkey).to.equal('abc123') + expect(merged.wot?.minimumFollowers).to.equal(3) + // non-overridden fields stay as defaults + expect(merged.wot?.refreshIntervalHours).to.equal(24) + }) + }) })