Files
cinny/src/app/utils/consent.ts
T
Lotus CIandClaude Opus 5.5 c96c47dd0d
CI / Build & Quality Checks (push) Successful in 1m45s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 14s
CI / Trigger Desktop Build (push) Successful in 14s
CI / Playwright smoke (e2e) (push) Successful in 6m58s
feat: explain "Failed to send" when the homeserver wants its terms accepted
A homeserver with a consent requirement (Synapse user_consent) rejects sends
with 403 M_CONSENT_NOT_GIVEN until the user accepts its current terms. The
message just showed "Failed to send" with no reason.

Listen for the SDK's HttpApiEvent.NoConsent and show a dialog naming the
user's own homeserver (the client works with any server, so no Lotus-specific
wording), with "Review and accept" opening the server's consent_uri (http(s)
only; anything else is dropped) and "I've accepted — retry sending" resending
every event that failed for this reason. "Later" snoozes it for 10 s so
background retries don't re-open it immediately.

Verified in Chromium against a local Synapse with the send endpoint answering
M_CONSENT_NOT_GIVEN: dialog shows, link opens, retry delivers the message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
2026-09-24 21:08:15 -04:00

22 lines
784 B
TypeScript

import { EventStatus, MatrixEvent } from 'matrix-js-sdk';
export const CONSENT_ERRCODE = 'M_CONSENT_NOT_GIVEN';
/**
* The consent page comes from whichever homeserver the user is on (this client
* works with any of them), so only ever open a plain web link.
*/
export const safeConsentUri = (uri: unknown): string | undefined => {
if (typeof uri !== 'string') return undefined;
try {
const url = new URL(uri);
return url.protocol === 'https:' || url.protocol === 'http:' ? url.href : undefined;
} catch {
return undefined;
}
};
/** True when a local echo failed because the server wants the ToS accepted. */
export const failedForConsent = (event: MatrixEvent): boolean =>
event.status === EventStatus.NOT_SENT && event.error?.errcode === CONSENT_ERRCODE;