feat: explain "Failed to send" when the homeserver wants its terms accepted
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
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
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
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
103c6f4624
commit
c96c47dd0d
@@ -0,0 +1,45 @@
|
||||
import { describe, it } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { EventStatus, MatrixError, MatrixEvent } from 'matrix-js-sdk';
|
||||
import { CONSENT_ERRCODE, failedForConsent, safeConsentUri } from './consent';
|
||||
|
||||
describe('safeConsentUri', () => {
|
||||
it('keeps http(s) links from any homeserver', () => {
|
||||
assert.equal(
|
||||
safeConsentUri('https://matrix.example.org/_matrix/consent?u=a&h=b'),
|
||||
'https://matrix.example.org/_matrix/consent?u=a&h=b',
|
||||
);
|
||||
assert.equal(
|
||||
safeConsentUri('http://localhost:8008/_matrix/consent'),
|
||||
'http://localhost:8008/_matrix/consent',
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects other schemes and junk', () => {
|
||||
// eslint-disable-next-line no-script-url
|
||||
assert.equal(safeConsentUri('javascript:alert(1)'), undefined);
|
||||
assert.equal(safeConsentUri('file:///etc/passwd'), undefined);
|
||||
assert.equal(safeConsentUri('not a url'), undefined);
|
||||
assert.equal(safeConsentUri(undefined), undefined);
|
||||
assert.equal(safeConsentUri(42), undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('failedForConsent', () => {
|
||||
const echo = (status: EventStatus, errcode?: string) => {
|
||||
const ev = new MatrixEvent({ type: 'm.room.message', content: { body: 'hi' } });
|
||||
ev.setStatus(status);
|
||||
if (errcode) ev.error = new MatrixError({ errcode, error: 'x' }, 403);
|
||||
return ev;
|
||||
};
|
||||
|
||||
it('matches a send that failed for consent', () => {
|
||||
assert.equal(failedForConsent(echo(EventStatus.NOT_SENT, CONSENT_ERRCODE)), true);
|
||||
});
|
||||
|
||||
it('ignores other failures and non-failed echoes', () => {
|
||||
assert.equal(failedForConsent(echo(EventStatus.NOT_SENT, 'M_FORBIDDEN')), false);
|
||||
assert.equal(failedForConsent(echo(EventStatus.NOT_SENT)), false);
|
||||
assert.equal(failedForConsent(echo(EventStatus.SENDING, CONSENT_ERRCODE)), false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user