From 6429f82829eec9401871c2f079affb6a597a1e93 Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Tue, 4 Nov 2025 15:36:20 -0800 Subject: [PATCH] Improve claim/access detection --- src/app/core/commands.ts | 13 +++++++------ src/app/core/state.ts | 19 +++++++++---------- src/app/core/sync.ts | 3 ++- src/app/util/policies.ts | 40 +++++++++++++++++++++++++++++----------- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/app/core/commands.ts b/src/app/core/commands.ts index 81eb2d7f..128f27d1 100644 --- a/src/app/core/commands.ts +++ b/src/app/core/commands.ts @@ -107,6 +107,7 @@ import { getSetting, userInboxRelays, userGroupSelections, + shouldIgnoreError, } from "@app/core/state" import {loadAlertStatuses} from "@app/core/requests" import {platform, platformName, getPushInfo} from "@app/util/push" @@ -288,14 +289,14 @@ export const attemptRelayAccess = async (url: string, claim = "") => { const thunk = publishJoinRequest({url, claim}) const error = await waitForThunkError(thunk) - // Ignore messages about the relay ignoring our messages - if (error?.startsWith("mute: ")) return + if (shouldIgnoreError(error)) return - // If it's a strict NIP 29 relay don't worry about requesting access - // TODO: remove this if relay29 ever gets less strict - if (error?.includes("missing group (`h`) tag")) return + if (claim) { + const ignoreClaimError = + error.includes("invalid invite code size") || error.includes("failed to validate invite code") - return claim ? error?.replace(/^\w+: /, "") : "" + if (!ignoreClaimError) return error?.replace(/^\w+: /, "") + } } // Deletions diff --git a/src/app/core/state.ts b/src/app/core/state.ts index 5636613f..f5f961f5 100644 --- a/src/app/core/state.ts +++ b/src/app/core/state.ts @@ -961,6 +961,14 @@ export const deriveTimeout = (timeout: number) => { return derived(store, identity) } +export const shouldIgnoreError = (error: string) => { + const isIgnored = error.startsWith("mute: ") + const isAborted = error.includes("Signing was aborted") + const isStrictNip29Relay = error.includes("missing group (`h`) tag") + + return isIgnored || isAborted || isStrictNip29Relay +} + export const deriveRelayAuthError = (url: string, claim = "") => { const stripPrefix = (m: string) => m.replace(/^\w+: /, "") @@ -987,18 +995,9 @@ export const deriveRelayAuthError = (url: string, claim = "") => { const error = getThunkError(thunk) if (error) { - const isIgnored = error.startsWith("mute: ") - const isAborted = error.includes("Signing was aborted") const isEmptyInvite = !claim && error.includes("invite code") - const isStrictNip29Relay = error.includes("missing group (`h`) tag") - if ( - !isStrictNip29Relay && - !isIgnored && - !isAborted && - !isEmptyInvite && - !isStrictNip29Relay - ) { + if (!shouldIgnoreError(error) && !isEmptyInvite) { return stripPrefix(error) || "join request rejected" } } diff --git a/src/app/core/sync.ts b/src/app/core/sync.ts index 9af61436..4189f7d7 100644 --- a/src/app/core/sync.ts +++ b/src/app/core/sync.ts @@ -18,6 +18,7 @@ import { RELAY_ADD_MEMBER, RELAY_REMOVE_MEMBER, isSignedEvent, + unionFilters, } from "@welshman/util" import type {Filter, TrustedEvent} from "@welshman/util" import {request, load, pull} from "@welshman/net" @@ -96,7 +97,7 @@ const pullAndListen = ({relays, filters, signal}: PullOpts) => { request({ relays, signal, - filters: filters.map(assoc("limit", 0)), + filters: unionFilters(filters).map(assoc("limit", 0)), }) } diff --git a/src/app/util/policies.ts b/src/app/util/policies.ts index ecb194f1..9097f92a 100644 --- a/src/app/util/policies.ts +++ b/src/app/util/policies.ts @@ -6,9 +6,12 @@ import { isRelayEvent, isRelayOk, isRelayClosed, + isRelayNegErr, isClientReq, isClientEvent, isClientClose, + isClientNegOpen, + isClientNegClose, } from "@welshman/net" import {sign} from "@welshman/app" import { @@ -59,10 +62,11 @@ export const mostlyRestrictedPolicy = (socket: Socket) => { const pending = new Set() - const updateStatus = () => + const updateStatus = () => { relaysMostlyRestricted.update( restricted > total / 2 ? assoc(socket.url, error) : dissoc(socket.url), ) + } const unsubscribers = [ on(socket, SocketEvent.Receive, (message: RelayMessage) => { @@ -72,20 +76,32 @@ export const mostlyRestrictedPolicy = (socket: Socket) => { if (pending.has(id)) { pending.delete(id) - if (!ok && details.startsWith("restricted: ")) { - restricted++ - error = details - updateStatus() + if (!ok) { + if (details.startsWith("auth-required: ")) { + total-- + updateStatus() + } + + if (details.startsWith("restricted: ")) { + restricted++ + error = details + updateStatus() + } } } } - if (isRelayClosed(message)) { + if (isRelayClosed(message) || isRelayNegErr(message)) { const [_, id, details = ""] = message if (pending.has(id)) { pending.delete(id) + if (details.startsWith("auth-required: ")) { + total-- + updateStatus() + } + if (details.startsWith("restricted: ")) { restricted++ error = details @@ -95,10 +111,12 @@ export const mostlyRestrictedPolicy = (socket: Socket) => { } }), on(socket, SocketEvent.Send, (message: ClientMessage) => { - if (isClientReq(message)) { - total++ - pending.add(message[1]) - updateStatus() + if (isClientReq(message) || isClientNegOpen(message)) { + if (!pending.has(message[1])) { + total++ + pending.add(message[1]) + updateStatus() + } } if (isClientEvent(message)) { @@ -107,7 +125,7 @@ export const mostlyRestrictedPolicy = (socket: Socket) => { updateStatus() } - if (isClientClose(message)) { + if (isClientClose(message) || isClientNegClose(message)) { pending.delete(message[1]) } }),