Handle server alerts received on libsignal auth socket

Co-authored-by: trevor-signal <trevor@signal.org>
This commit is contained in:
Alex Bakon
2025-03-07 15:30:49 -05:00
committed by GitHub
parent 2aef75dede
commit 5b130ae780
9 changed files with 105 additions and 38 deletions
+8 -7
View File
@@ -51,7 +51,8 @@ import { isNightly, isBeta, isStaging } from '../util/version';
import { getBasicAuth } from '../util/getBasicAuth';
import { isTestOrMockEnvironment } from '../environment';
import type { ConfigKeyType } from '../RemoteConfig';
import { ServerAlert } from '../state/ducks/server';
import type { ServerAlert } from '../state/ducks/server';
import { parseServerAlertFromHeader } from '../state/ducks/server';
const FIVE_MINUTES = 5 * durations.MINUTE;
@@ -205,6 +206,9 @@ export class SocketManager extends EventListener {
handler: (req: IncomingWebSocketRequest): void => {
this.#queueOrHandleRequest(req);
},
onReceivedAlerts: (alerts: Array<ServerAlert>) => {
this.emit('serverAlerts', alerts);
},
receiveStories: !this.#hasStoriesDisabled,
keepalive: { path: '/v1/keepalive' },
})
@@ -972,12 +976,9 @@ export class SocketManager extends EventListener {
}
}
const serverAlerts: Array<ServerAlert> = [];
alerts.forEach(alert => {
if (alert.toLowerCase() === 'critical-idle-primary-device') {
serverAlerts.push(ServerAlert.CRITICAL_IDLE_PRIMARY_DEVICE);
}
});
const serverAlerts: Array<ServerAlert> = alerts
.map(parseServerAlertFromHeader)
.filter(v => v !== undefined);
this.emit('serverAlerts', serverAlerts);
}
+13 -1
View File
@@ -82,6 +82,7 @@ import { getMockServerPort } from '../util/getMockServerPort';
import { pemToDer } from '../util/pemToDer';
import { ToastType } from '../types/Toast';
import { isProduction } from '../util/version';
import type { ServerAlert } from '../state/ducks/server';
// Note: this will break some code that expects to be able to use err.response when a
// web request fails, because it will force it to text. But it is very useful for
@@ -1606,6 +1607,7 @@ export type WebAPIType = {
getConfig: () => Promise<RemoteConfigResponseType>;
authenticate: (credentials: WebAPICredentials) => Promise<void>;
logout: () => Promise<void>;
getServerAlerts: () => Array<ServerAlert>;
getSocketStatus: () => SocketStatuses;
registerRequestHandler: (handler: IRequestHandler) => void;
unregisterRequestHandler: (handler: IRequestHandler) => void;
@@ -1761,6 +1763,10 @@ export function initialize({
}
}
// We store server alerts (returned on the WS upgrade response headers) so that the app
// can query them later, which is necessary if they arrive before app state is ready
let serverAlerts: Array<ServerAlert> = [];
// Thanks to function-hoisting, we can put this return statement before all of the
// below function definitions.
return {
@@ -1813,7 +1819,8 @@ export function initialize({
});
socketManager.on('serverAlerts', alerts => {
window.Whisper.events.trigger('serverAlerts', alerts);
log.info(`onServerAlerts: number of alerts received: ${alerts.length}`);
serverAlerts = alerts;
});
if (useWebSocket) {
@@ -1939,6 +1946,7 @@ export function initialize({
getReleaseNoteImageAttachment,
getTransferArchive,
getSenderCertificate,
getServerAlerts,
getSocketStatus,
getSticker,
getStickerPackManifest,
@@ -2143,6 +2151,10 @@ export function initialize({
return socketManager.getStatus();
}
function getServerAlerts(): Array<ServerAlert> {
return serverAlerts;
}
function checkSockets(): void {
// Intentionally not awaiting
void socketManager.check();
+9
View File
@@ -58,6 +58,8 @@ import { AbortableProcess } from '../util/AbortableProcess';
import type { WebAPICredentials } from './Types';
import { NORMAL_DISCONNECT_CODE } from './SocketManager';
import { parseUnknown } from '../util/schemas';
import type { ServerAlert } from '../state/ducks/server';
import { parseServerAlertFromHeader } from '../state/ducks/server';
const THIRTY_SECONDS = 30 * durations.SECOND;
@@ -345,11 +347,13 @@ export function connectAuthenticatedLibsignal({
handler,
receiveStories,
keepalive,
onReceivedAlerts,
}: {
libsignalNet: Net.Net;
name: string;
credentials: WebAPICredentials;
handler: (request: IncomingWebSocketRequest) => void;
onReceivedAlerts: (alerts: Array<ServerAlert>) => void;
receiveStories: boolean;
keepalive: KeepAliveOptionsType;
}): AbortableProcess<LibsignalWebSocketResource> {
@@ -391,6 +395,11 @@ export function connectAuthenticatedLibsignal({
this.resource.onConnectionInterrupted(cause);
this.resource = undefined;
},
onReceivedAlerts(alerts: Array<string>): void {
onReceivedAlerts(
alerts.map(parseServerAlertFromHeader).filter(v => v !== undefined)
);
},
};
return connectLibsignal(
(abortSignal: AbortSignal) =>