Browse Source

fix blocking social kinds

imwald
Silberengel 1 week ago
parent
commit
a5aa0c5788
  1. 6
      src/constants.ts
  2. 4
      src/features/feed/relay-policy.ts
  3. 34
      src/lib/social-kind-blocked-relays.test.ts
  4. 47
      src/lib/social-kind-blocked-relays.ts
  5. 20
      src/services/client.service.ts

6
src/constants.ts

@ -804,11 +804,15 @@ export const NOTE_STATS_OP_REFERENCE_KINDS_WITHOUT_HIGHLIGHT: readonly number[]
/** /**
* When a filter touches these kinds (or omits `kinds`), omit {@link SOCIAL_KIND_BLOCKED_RELAY_URLS} from the relay * When a filter touches these kinds (or omits `kinds`), omit {@link SOCIAL_KIND_BLOCKED_RELAY_URLS} from the relay
* stack those relays do not carry this note/comment surface (kinds **1** / **1111** / **11** per relay policy). * stack those relays do not carry this note/comment/reaction surface (kinds **1** / **7** / **11** / **1111** / **17**).
* @see {@link relayFilterIncludesSocialKindBlockedKind} * @see {@link relayFilterIncludesSocialKindBlockedKind}
*/ */
const SOCIAL_KIND_BLOCKED_KINDS: readonly number[] = [ const SOCIAL_KIND_BLOCKED_KINDS: readonly number[] = [
kinds.ShortTextNote, kinds.ShortTextNote,
kinds.Reaction,
kinds.Repost,
ExtendedKind.GENERIC_REPOST,
ExtendedKind.EXTERNAL_REACTION,
ExtendedKind.DISCUSSION, ExtendedKind.DISCUSSION,
ExtendedKind.COMMENT ExtendedKind.COMMENT
] ]

4
src/features/feed/relay-policy.ts

@ -1,6 +1,5 @@
import { import {
READ_ONLY_RELAY_URLS, READ_ONLY_RELAY_URLS,
SOCIAL_KIND_BLOCKED_RELAY_URLS,
relayFilterIncludesSocialKindBlockedKind relayFilterIncludesSocialKindBlockedKind
} from '@/constants' } from '@/constants'
import { relayAllowsPublishKind } from '@/lib/relay-publish-filter' import { relayAllowsPublishKind } from '@/lib/relay-publish-filter'
@ -11,6 +10,7 @@ import {
relayUrlsStripExtendedTagReqBlocked relayUrlsStripExtendedTagReqBlocked
} from '@/lib/relay-extended-tag-req-blocks' } from '@/lib/relay-extended-tag-req-blocks'
import { isRelayBlockedByUser } from '@/lib/relay-blocked' import { isRelayBlockedByUser } from '@/lib/relay-blocked'
import { isSocialKindBlockedRelayUrl } from '@/lib/social-kind-blocked-relays'
import { isLocalNetworkUrl, normalizeHttpRelayUrl, normalizeRelayUrlByScheme } from '@/lib/url' import { isLocalNetworkUrl, normalizeHttpRelayUrl, normalizeRelayUrlByScheme } from '@/lib/url'
import type { TSubRequestFilter } from '@/types' import type { TSubRequestFilter } from '@/types'
@ -134,7 +134,7 @@ function isReadOnlyRelay(norm: string): boolean {
} }
function isSocialKindBlockedRelay(norm: string): boolean { function isSocialKindBlockedRelay(norm: string): boolean {
return normalizedSet(SOCIAL_KIND_BLOCKED_RELAY_URLS).has(norm) return isSocialKindBlockedRelayUrl(norm)
} }
function isExtendedTagBlockedRelay(norm: string): boolean { function isExtendedTagBlockedRelay(norm: string): boolean {

34
src/lib/social-kind-blocked-relays.test.ts

@ -0,0 +1,34 @@
import { kinds } from 'nostr-tools'
import { ExtendedKind } from '@/constants'
import {
filterPublishingRelayUrls,
filterRelayUrlsForSocialKindPublish,
isSocialKindBlockedRelayUrl
} from '@/lib/social-kind-blocked-relays'
import { describe, expect, it } from 'vitest'
describe('social-kind-blocked-relays', () => {
it('matches essayist by hostname even with a path suffix', () => {
expect(isSocialKindBlockedRelayUrl('wss://essayist.decentnewsroom.com/')).toBe(true)
expect(isSocialKindBlockedRelayUrl('wss://essayist.decentnewsroom.com/npub1abc')).toBe(true)
})
it('strips essayist for kind 1 and reactions but not long-form', () => {
const urls = ['wss://relay.damus.io/', 'wss://essayist.decentnewsroom.com/']
expect(filterRelayUrlsForSocialKindPublish(urls, kinds.ShortTextNote)).toEqual([
'wss://relay.damus.io/'
])
expect(filterRelayUrlsForSocialKindPublish(urls, kinds.Reaction)).toEqual([
'wss://relay.damus.io/'
])
expect(filterRelayUrlsForSocialKindPublish(urls, kinds.LongFormArticle)).toEqual(urls)
})
it('filterPublishingRelayUrls applies read-only and social filters', () => {
const out = filterPublishingRelayUrls(
['wss://nostr.land/', 'wss://essayist.decentnewsroom.com/', 'wss://relay.damus.io/'],
ExtendedKind.COMMENT
)
expect(out).toEqual(['wss://relay.damus.io/'])
})
})

47
src/lib/social-kind-blocked-relays.ts

@ -0,0 +1,47 @@
import { SOCIAL_KIND_BLOCKED_RELAY_URLS, isSocialKindBlockedKind } from '@/constants'
import { filterRelaysForEventPublish } from '@/lib/relay-publish-filter'
import { dedupeNormalizeRelayUrlsOrdered } from '@/lib/relay-url-priority'
import { normalizeRelayUrlByScheme } from '@/lib/url'
function relayHostname(url: string): string | null {
const normalized = normalizeRelayUrlByScheme(url) || url.trim()
if (!normalized) return null
try {
return new URL(normalized).hostname.toLowerCase()
} catch {
return null
}
}
const blockedExactKeys = new Set(
SOCIAL_KIND_BLOCKED_RELAY_URLS.map((u) => (normalizeRelayUrlByScheme(u) || u).toLowerCase()).filter(Boolean)
)
const blockedHostnames = new Set(
SOCIAL_KIND_BLOCKED_RELAY_URLS.map((u) => relayHostname(u)).filter((h): h is string => !!h)
)
/** True when `url` is (or is hosted on) a relay in {@link SOCIAL_KIND_BLOCKED_RELAY_URLS}. */
export function isSocialKindBlockedRelayUrl(url: string): boolean {
const key = (normalizeRelayUrlByScheme(url) || url.trim()).toLowerCase()
if (!key) return false
if (blockedExactKeys.has(key)) return true
const host = relayHostname(url)
return host != null && blockedHostnames.has(host)
}
/** Strip social-kind-blocked relays for kinds in {@link isSocialKindBlockedKind}. */
export function filterRelayUrlsForSocialKindPublish(
urls: readonly string[],
eventKind: number
): string[] {
if (!isSocialKindBlockedKind(eventKind)) return [...urls]
return urls.filter((url) => !isSocialKindBlockedRelayUrl(url))
}
/** Read-only / profile-index filter + social-kind-blocked strip + dedupe (publish stack). */
export function filterPublishingRelayUrls(urls: readonly string[], eventKind: number): string[] {
return dedupeNormalizeRelayUrlsOrdered(
filterRelayUrlsForSocialKindPublish(filterRelaysForEventPublish(urls, eventKind), eventKind)
)
}

20
src/services/client.service.ts

@ -168,13 +168,14 @@ import { hexPubkeysEqual, isValidPubkey, pubkeyToNpub, userIdToPubkey } from '@/
import { collectNip05ValuesFromKind0, profileKind0MatchesSearchQuery } from '@/lib/profile-metadata-search' import { collectNip05ValuesFromKind0, profileKind0MatchesSearchQuery } from '@/lib/profile-metadata-search'
import { decodeProfileSearchQueryToPubkeyHex } from '@/lib/profile-search-query' import { decodeProfileSearchQueryToPubkeyHex } from '@/lib/profile-search-query'
import { getPubkeysFromPTags, tagNameEquals } from '@/lib/tag' import { getPubkeysFromPTags, tagNameEquals } from '@/lib/tag'
import { filterRelaysForEventPublish, isReadOnlyRelayUrl } from '@/lib/relay-publish-filter' import { isReadOnlyRelayUrl } from '@/lib/relay-publish-filter'
import { getPaymentAttestationTargetId } from '@/lib/superchat' import { getPaymentAttestationTargetId } from '@/lib/superchat'
import { import {
buildPublicMessagePublishRelayUrls, buildPublicMessagePublishRelayUrls,
collectRecipientInboxUrls collectRecipientInboxUrls
} from '@/lib/public-message-publish-relays' } from '@/lib/public-message-publish-relays'
import { buildPrioritizedWriteRelayUrls, dedupeNormalizeRelayUrlsOrdered } from '@/lib/relay-url-priority' import { buildPrioritizedWriteRelayUrls, dedupeNormalizeRelayUrlsOrdered } from '@/lib/relay-url-priority'
import { filterPublishingRelayUrls } from '@/lib/social-kind-blocked-relays'
import { import {
IndexRelayTransportError, IndexRelayTransportError,
isIndexRelayTransportFailure, isIndexRelayTransportFailure,
@ -961,14 +962,7 @@ class ClientService extends EventTarget {
* Normalize, dedupe, then cap at {@link MAX_PUBLISH_RELAYS}. * Normalize, dedupe, then cap at {@link MAX_PUBLISH_RELAYS}.
*/ */
private filterPublishingRelays(relays: string[], event: NEvent): string[] { private filterPublishingRelays(relays: string[], event: NEvent): string[] {
const socialKindBlockedSet = new Set(SOCIAL_KIND_BLOCKED_RELAY_URLS.map((u) => normalizeUrl(u) || u)) return filterPublishingRelayUrls(relays, event.kind)
return dedupeNormalizeRelayUrlsOrdered(
filterRelaysForEventPublish(relays, event.kind).filter((url) => {
const n = normalizeRelayUrlByScheme(url) || url
if (isSocialKindBlockedKind(event.kind) && socialKindBlockedSet.has(n)) return false
return true
})
)
} }
/** Kind 31987: always attempt the reviewed relay (`d` tag) first in the publish stack. */ /** Kind 31987: always attempt the reviewed relay (`d` tag) first in the publish stack. */
@ -1760,13 +1754,7 @@ class ClientService extends EventTarget {
: relayUrls : relayUrls
} }
const socialKindBlockedSet = new Set(SOCIAL_KIND_BLOCKED_RELAY_URLS.map((u) => normalizeUrl(u) || u)) let filtered = filterPublishingRelayUrls(mergedRelayUrls, event.kind)
let filtered = filterRelaysForEventPublish(mergedRelayUrls, event.kind).filter((url) => {
const n = normalizeRelayUrlByScheme(url) || url
if (isSocialKindBlockedKind(event.kind) && socialKindBlockedSet.has(n)) return false
return true
})
filtered = Array.from(new Set(filtered))
filtered = Array.from(new Set(filtered)) filtered = Array.from(new Set(filtered))
const countAfterFiltersBeforeCap = filtered.length const countAfterFiltersBeforeCap = filtered.length
filtered = await this.capPublishRelayUrlsForPublish( filtered = await this.capPublishRelayUrlsForPublish(

Loading…
Cancel
Save