mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-01 08:06:13 +00:00
docs: report the native sync with webmail 1.18.0 and Stalwart 1.0.0
This commit is contained in:
@@ -0,0 +1,187 @@
|
|||||||
|
# Native sync with webmail 1.18.0 and Stalwart 1.0.0 (2026-10-29)
|
||||||
|
|
||||||
|
Branch `feat/stalwart-1.0`: native main (f358d605) merged in, then the 1.0.0
|
||||||
|
release check, the webmail 1.10-1.18 parity fixes and the open native issues.
|
||||||
|
It is 200 commits ahead of main (181 without merges) and 0 behind. Nothing is
|
||||||
|
pushed.
|
||||||
|
|
||||||
|
At 595df26e (the last code change; only docs follow): `tsc` clean, vitest 323 files / 4911 tests pass
|
||||||
|
(113 skipped are the opt-in live suites), `i18n:check` passes. The app has no
|
||||||
|
lint script.
|
||||||
|
|
||||||
|
## What landed
|
||||||
|
|
||||||
|
Merge of main into the branch: f1db6b48 (19 conflicted files). Main's later
|
||||||
|
work won (iOS push and its notification extension, SafeAreaModal, file
|
||||||
|
preview, restyle and Tabler icons, token sign-in, notification mutes, device
|
||||||
|
sync); the branch's per-account routing, session epochs and refusal handling
|
||||||
|
were carried onto it. Notable calls: jmap-client keeps the branch's
|
||||||
|
epoch-safe credential writes plus main's shared-keychain writes and
|
||||||
|
`adoptStoredTokens`; auth-store keeps the branch's `signIn` helper and routes
|
||||||
|
main's token sign-in through it; push keeps the branch's SetError-only
|
||||||
|
narrowing plus main's device-sync types and mutes.
|
||||||
|
|
||||||
|
### Stalwart 1.0.0 (step 1)
|
||||||
|
|
||||||
|
- Sign-in: password + TOTP on 1.0 (96ef8515: one `/api/auth` body for both
|
||||||
|
versions, RFC 7591 public client registered per server, redirect
|
||||||
|
`org.bulwarkmail.mobile:/auth/callback` because 1.0 wants a dot in the
|
||||||
|
scheme); browser sign-in with the registered client and Stalwart's data
|
||||||
|
scopes (6ffd0473, a2caa4cc); refresh-token rotation (1456e15d, 28d928f6,
|
||||||
|
cfd81737); no secret follows a redirect to another host (2c05e7bd,
|
||||||
|
06d68d73, fe4f9211, 61654d7c); account security explains a limited client
|
||||||
|
(c6eb02d4).
|
||||||
|
- Files: draft-18 `@type`/`mediaType` (174c3fc8), listing past
|
||||||
|
maxObjectsInGet #1385 (7d8e0735), shared-folder writes per account
|
||||||
|
(18b8aa09, 7c495d03).
|
||||||
|
- Mail: inline images that 1.0 lists only in the body parts (d2bb479a),
|
||||||
|
quoted inline images in replies and forwards (913b3766), part names that
|
||||||
|
are paths (4d545f8f), scheduled mail of own and group accounts with equal
|
||||||
|
ids (15171637), bulk delete with partial refusals (547d9e59).
|
||||||
|
- Calendar #89: the branch's split CalendarEvent/get (28ade775) holds on the
|
||||||
|
release; plus mail-only shares (f3e11d4c), 0.16 loads at DST changes
|
||||||
|
(7c775571), account-switch races (1f190c94, e993540a, 41e8f005, 98dc13fe).
|
||||||
|
- Push: device-sync types retry only on a type refusal (20be1105), refused
|
||||||
|
non-public relay explained and rolled back (4ec2ccac, 90e250d3), Android
|
||||||
|
extends subscriptions in the background because both servers clamp expiry
|
||||||
|
to 7 days (9804b499, ce47c73f), subscription id reuse (77327ea8), renewal
|
||||||
|
for every account (d92a2ca8), logins sharing a JMAP account id
|
||||||
|
(9ccb6228, b352e470), removed-account teardown (152f3089).
|
||||||
|
|
||||||
|
### Webmail parity 1.10-1.18 (step 2)
|
||||||
|
|
||||||
|
The inventory is docs/parity/10-webmail-1.10-to-1.18.md (ec7e8e05): 112 rows,
|
||||||
|
10 P1, 40 P2. 52 are ticked with their commits (fe33dfc5); every P1 and every
|
||||||
|
P2 that doesn't need the org policy is done. Highlights:
|
||||||
|
|
||||||
|
- Security (P1): HTML sanitizer rebuilt on a tokenizer, reader CSP
|
||||||
|
`script-src 'none'`, composer script under a nonce (f5e997ba, 07679cbf,
|
||||||
|
47a1d249, 440a2e7a, 4e3da668); forged DMARC/DKIM chips (ef9561f1,
|
||||||
|
8adef1e1); mailto unsubscribe (942f4517, 918571c3); winmail.dat freeze
|
||||||
|
(855d304b).
|
||||||
|
- Wrong-account writes (P1): composer pinned to its login (9daa3441,
|
||||||
|
388f46b5, 4e57b191), undo/Send now per login (e81f0071), calendar and
|
||||||
|
contacts switch guards (see above, 6b9552fc).
|
||||||
|
- Sieve interop (P1): webmail metadata v2, address/domain rules, elsif
|
||||||
|
chains (2167a9d7, fc9c164d), plus forwarding, audience and periods
|
||||||
|
(df1a5ab4).
|
||||||
|
- P2 features: scheduled message view #84 (14d009de), group identity send
|
||||||
|
(31d8e4a4, 893f40a2), reschedule cancel-first #1308 (22f2ac5b,
|
||||||
|
fdf8eece), unconfirmed send #1019 (3eac700a), Files trash (7c914183 and
|
||||||
|
be04fcb1..946304ab), attach from and save to Files (8e07b7d8, 39e82f99),
|
||||||
|
templates in account metadata and team templates (fac318dc), shared tags
|
||||||
|
(b7b9c7e0), verification-code chip (b1550f14), unverified sender
|
||||||
|
(cc21317b), search without Spam/Trash (a412b516, 2b5257bf), calendar
|
||||||
|
search (b50270d8) and default reminders (9b87100a), feed changes reach
|
||||||
|
imported events (8a71495e, 47f29718), directory browser (0fd14a83),
|
||||||
|
rules from a message (d546d509), contact links and vCard (32f70c10,
|
||||||
|
07fd03e2, 3c156673), placeholder warning (a8e7a3f4).
|
||||||
|
|
||||||
|
### Issues (step 3)
|
||||||
|
|
||||||
|
#80 96c7c045, #81 01983a38, #82 7a1031a9, #83 6f475c0c, #84 14d009de,
|
||||||
|
#86 65f00640, #87 e47c05c5, #89 (branch 28ade775, checked on the release).
|
||||||
|
#85 needs a decision (below). No issue was commented on or closed.
|
||||||
|
|
||||||
|
Every group got a separate review agent; review findings were fixed in a
|
||||||
|
follow-up round on each branch (two HIGHs in the composer, two pre-existing
|
||||||
|
HIGHs in the HTML handling, one in calendar feed sync).
|
||||||
|
|
||||||
|
## Verified live
|
||||||
|
|
||||||
|
Opt-in suites in src/api/__tests__/live-stalwart*.test.ts, run at the tip
|
||||||
|
against Stalwart 1.0.0 (stw-rel, :8120) and 0.16.27 (:8016), each with its
|
||||||
|
own e2e account. All pass on both: base 17, mail 14, compose 10, files 16,
|
||||||
|
push 11, contacts 9, calendar 22, auth 14 (with a TOTP account). The base
|
||||||
|
suite now imports its own mail, so it runs on any account.
|
||||||
|
|
||||||
|
Android emulator (Pixel 7 API 34, release build of the tip):
|
||||||
|
|
||||||
|
- 1.0.0: browser sign-in (consent page, registered client, new redirect
|
||||||
|
scheme) as usera; reader with the new CSP (height, links open in the
|
||||||
|
browser); reply composer loads, draft saved; push enabled through the
|
||||||
|
hosted relay, a mail sent by userb arrived as a notification; calendar
|
||||||
|
loads with series (#89); Files shows the trash.
|
||||||
|
- 1.0.0 and 0.16: password + TOTP sign-in for e2e-totp-phone (the 1.0
|
||||||
|
`invalid_client` bug is gone); send from the 1.0 TOTP account.
|
||||||
|
- Unified inbox across the logins.
|
||||||
|
|
||||||
|
Not covered on the emulator: series edits, contact photos and
|
||||||
|
reschedule/undo (covered by the live suites only), and anything iOS.
|
||||||
|
|
||||||
|
## Open
|
||||||
|
|
||||||
|
- iOS, needs a CI run: reader CSP and composer nonce assume injected scripts
|
||||||
|
ignore page CSP and the editor loads as about:blank; the notification
|
||||||
|
extension's label check (b352e470, Swift); `target=_blank` link taps;
|
||||||
|
#81 keyboard. iOS push still lapses after 7 days without opening the app
|
||||||
|
(the extension can't extend it).
|
||||||
|
- Blocked on the webmail: org policy (locked settings, session length,
|
||||||
|
external sender label and recipient confirm, org signature and
|
||||||
|
disclaimer, template library). The policy route only takes the webmail
|
||||||
|
session cookie, and the app doesn't keep the paired webmail URL. Also the
|
||||||
|
hand-off still returns the password in the `bulwarkmobile://` fragment.
|
||||||
|
- Not done: the 60 P3 rows in the parity file; P3 bugs in Sieve (forward
|
||||||
|
limit, vacation length, editor losing text); device DST in other-zone
|
||||||
|
daily expansion keeps a wrong recurrenceId for that one day; a login
|
||||||
|
switch from a deep link doesn't reset the navigation stack, so a thread
|
||||||
|
left below can act through the new login.
|
||||||
|
- New strings are English-only except where the webmail already had
|
||||||
|
translations.
|
||||||
|
- The `C:\ns` junction (to the worktree, used for the emulator build) is
|
||||||
|
still there; removing it was blocked by the permission settings.
|
||||||
|
|
||||||
|
## Bugs that also live in the webmail
|
||||||
|
|
||||||
|
Not fixed there in this run:
|
||||||
|
|
||||||
|
- Inline images of drafts and sent mail on 1.0.0 come only from
|
||||||
|
`attachments` (components/email/email-viewer.tsx:2518, email-composer.tsx
|
||||||
|
:905, :1391, :2647).
|
||||||
|
- Save to Files on 0.16 stores the whole message (save-to-files-dialog.tsx
|
||||||
|
:79-84); Blob/copy without the blob capability (lib/jmap/client.ts:9985).
|
||||||
|
- Reschedule after a lost answer: cancel (client.ts:11619) and create
|
||||||
|
(:11643) can strand or double-send.
|
||||||
|
- Default alert ids `alert1…` reused across calendars and lists; 1.0
|
||||||
|
refuses them (lib/calendar-alerts.ts:206, calendar-management-settings.tsx
|
||||||
|
:200).
|
||||||
|
- Sieve parser drops `elsif`/`else` and trailing comments, which breaks the
|
||||||
|
category-tabs section (lib/sieve/parser.ts:251); generator falls back to
|
||||||
|
`header :contains` (lib/sieve/generator.ts:126).
|
||||||
|
- Vacation turned on with a failed filter re-include only logs
|
||||||
|
(stores/vacation-store.ts:210).
|
||||||
|
- Feed sync: no END:VCALENDAR check, no mass-deletion guard
|
||||||
|
(stores/calendar-store.ts:1978); invitation trust lets a failing DKIM
|
||||||
|
signature beat dmarc=pass (lib/calendar-invitation.ts:219); a HELO SPF
|
||||||
|
pass counts as aligned (lib/email-headers.ts:64).
|
||||||
|
- Files trash: purge without a fresh read (stores/file-store.ts:1947),
|
||||||
|
restore with its folder lands at the root (:1914), no `.Trash` name check.
|
||||||
|
- Push: no device client id check (lib/web-push.ts:786), cap path destroys
|
||||||
|
first (:852), refused relay URL shown raw (notification-settings.tsx:173).
|
||||||
|
- Probably: decoded CSS put back into STYLE (lib/email-sanitization.ts:733),
|
||||||
|
untested; Lite refresh follows redirects (lib/auth/lite-tokens.ts:533).
|
||||||
|
|
||||||
|
## Questions
|
||||||
|
|
||||||
|
1. #85: the notification Delete action requires unlock (#68), which is why
|
||||||
|
Android closes the shade. Drop the requirement (Delete then works from the
|
||||||
|
lock screen, it only moves to Trash) or keep it?
|
||||||
|
2. Org policy on the phone: add a webmail route that accepts a JMAP bearer
|
||||||
|
token, and keep the paired webmail URL in the app?
|
||||||
|
3. Full account security on 1.0 needs a first-party client for the app. Add
|
||||||
|
an admin-registered `bulwark-mobile` client to the OAuth setup?
|
||||||
|
4. MIG-02 on native: after a 0.16 to 1.0 migration every token account fails
|
||||||
|
to refresh and is removed with "Your session has expired". Keep it as
|
||||||
|
"sign in again" instead? A pasted OAuth access token also drops after
|
||||||
|
about an hour (no refresh token).
|
||||||
|
5. A password change from a TOTP account ends its grant on 0.16, so the app
|
||||||
|
asks to sign in again. Fine?
|
||||||
|
6. Translate the new English-only strings into the other 26 locales now?
|
||||||
|
7. Reset the navigation stack when a deep link or notification switches the
|
||||||
|
login?
|
||||||
|
8. Small ones: the feed mass-removal guard (keeps events when more than half
|
||||||
|
of 10+ would go, no override); contact re-import marks same-UID cards as
|
||||||
|
"update existing", unselected; team templates read-only; Delete
|
||||||
|
permanently and Restore on stale trash rows refresh silently.
|
||||||
|
9. The account switcher shows `10.10.10.62` for both servers (port dropped),
|
||||||
|
so two logins of the same user look identical. Show the port?
|
||||||
Reference in New Issue
Block a user