diff --git a/e2e/local-homeserver.spec.ts b/e2e/local-homeserver.spec.ts index 62e41769e..0df5c0d1a 100644 --- a/e2e/local-homeserver.spec.ts +++ b/e2e/local-homeserver.spec.ts @@ -257,12 +257,21 @@ test.describe('local homeserver regression', () => { await page.clock.install({ time: Date.now() + 14 * 60 * 1000 }); await loginUI(page, alice); await openRoom(page, room); - for (let i = 0; i < 4; i += 1) { - // eslint-disable-next-line no-await-in-loop - await sendText(bob, room, `tick ${i}`); - // eslint-disable-next-line no-await-in-loop - await page.waitForTimeout(500); - } + const ticks = async (from: number, n: number) => { + for (let i = from; i < from + n; i += 1) { + // eslint-disable-next-line no-await-in-loop + await sendText(bob, room, `tick ${i}`); + // eslint-disable-next-line no-await-in-loop + await page.waitForTimeout(500); + } + }; + await ticks(0, 4); + // "Ahead" could be a late delivery (a stalled server), so it is only + // reported once it has held for a minute of fresh samples. + await page.waitForTimeout(2000); + await expect(page.getByText(/clock is .*ahead of the server/)).toHaveCount(0); + await page.clock.fastForward('01:05'); + await ticks(4, 2); await expect(page.getByText(/clock is .*14 minutes ahead of the server/)).toBeVisible(); await page.getByRole('button', { name: 'Dismiss for 24 h' }).click(); await expect(page.getByText(/clock is .*ahead of the server/)).toHaveCount(0); diff --git a/src/app/features/call-status/CallStatus.tsx b/src/app/features/call-status/CallStatus.tsx index 37bd9cfb4..4b4be1543 100644 --- a/src/app/features/call-status/CallStatus.tsx +++ b/src/app/features/call-status/CallStatus.tsx @@ -72,9 +72,9 @@ export function CallStatus({ callEmbed }: CallStatusProps) { size="T200" truncate style={{ color: color.Warning.Main }} - title="Fix your computer's clock — calls and encryption depend on it" + title="This device's clock is off. Calls and encryption depend on it: turn on automatic time in your system settings." > - Clock {describeSkewVsServer(clockSkew.skewMs)} — calls will fail + Device clock {describeSkewVsServer(clockSkew.skewMs)}: calls may fail )} diff --git a/src/app/pages/client/ClientNonUIFeatures.tsx b/src/app/pages/client/ClientNonUIFeatures.tsx index ec09b460f..b0c1b6d0c 100644 --- a/src/app/pages/client/ClientNonUIFeatures.tsx +++ b/src/app/pages/client/ClientNonUIFeatures.tsx @@ -1072,6 +1072,10 @@ function ClockSkewFeature() { data, ) => { if (!data.liveEvent) return; + // Only events our homeserver stamped: a federated event's + // origin_server_ts is the other server's clock. + const senderServer = mEvent.getSender()?.split(':').slice(1).join(':'); + if (senderServer !== mx.getDomain()) return; monitor.sample(mEvent.getTs(), mEvent.getAge(), mEvent.localTimestamp); }; mx.on(RoomEvent.Timeline, onTimeline); diff --git a/src/app/pages/client/ClockSkewBanner.tsx b/src/app/pages/client/ClockSkewBanner.tsx index 0c39d3f7d..ae86ea8c0 100644 --- a/src/app/pages/client/ClockSkewBanner.tsx +++ b/src/app/pages/client/ClockSkewBanner.tsx @@ -19,7 +19,7 @@ const readDismissedUntil = (): number => { }; /** - * [Gitea #158] "Your computer's clock is 14 minutes ahead of the server." + * [Gitea #158] "This device's clock is 14 minutes ahead of the server." * Same slot and style as the sync banners. Shown while the skew monitor is * over its threshold; the direction matters, so it is said. Dismissable for * 24 h; never auto-corrects anything. @@ -53,8 +53,8 @@ export function ClockSkewBanner() { > - Your computer's clock is {describeSkewVsServer(skewMs)}. Encrypted messages - and voice calls will fail until it is fixed. + This device's clock is {describeSkewVsServer(skewMs)}. Voice calls and + encrypted messages can fail until it's corrected.