Set Accept-Language at the connection level for chat connections

This commit is contained in:
Jordan Rose 2025-07-09 10:57:01 -07:00 committed by GitHub
parent 3063262730
commit b440aec88c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 41 additions and 54 deletions

View file

@ -120,7 +120,7 @@
"@react-aria/utils": "3.25.3",
"@react-spring/web": "9.7.5",
"@react-types/shared": "3.27.0",
"@signalapp/libsignal-client": "0.76.0",
"@signalapp/libsignal-client": "0.76.3",
"@signalapp/quill-cjs": "2.1.2",
"@signalapp/ringrtc": "2.54.1",
"@signalapp/sqlcipher": "2.1.0",

10
pnpm-lock.yaml generated
View file

@ -129,8 +129,8 @@ importers:
specifier: 3.27.0
version: 3.27.0(react@18.3.1)
'@signalapp/libsignal-client':
specifier: 0.76.0
version: 0.76.0
specifier: 0.76.3
version: 0.76.3
'@signalapp/quill-cjs':
specifier: 2.1.2
version: 2.1.2
@ -2767,8 +2767,8 @@ packages:
'@signalapp/libsignal-client@0.60.2':
resolution: {integrity: sha512-tU4kNP/yCwkFntb2ahXOSQJtzdy+YifAB2yv5hw0qyKSidRHLn6bYiz4Zo2tjxLDRoBLAUxCRsQramStiqNZdA==}
'@signalapp/libsignal-client@0.76.0':
resolution: {integrity: sha512-wQZFC79GAUeee8pf+aDK5Gii0HbQoCAv/oTn1Ht7d5mFq2pw/L0jRcv3j9DgVYodzCOlnanfto3apfA6eN/Whw==}
'@signalapp/libsignal-client@0.76.3':
resolution: {integrity: sha512-Ht8XtdsSvgiCb8ftUYE9DaLcWy0vltrj9cQ2sfy+DGUayE1k2njicNhB2RKOfQV2Wb/1Cl0WxVZP/NlXRo2+jA==}
'@signalapp/mock-server@13.1.0':
resolution: {integrity: sha512-CuDNLNEBMzwIs5jr7Lx9F4YFoRD62s7WgPGtm3qpaggixSQtabjMC7AKSR0xvaHcZpYZtBU5jcGK8Roguo9nuw==}
@ -12460,7 +12460,7 @@ snapshots:
type-fest: 4.26.1
uuid: 8.3.2
'@signalapp/libsignal-client@0.76.0':
'@signalapp/libsignal-client@0.76.3':
dependencies:
node-gyp-build: 4.8.4
type-fest: 4.26.1

View file

@ -48,7 +48,6 @@ import { isValidTapToView } from '../util/isValidTapToView';
import { getNotificationTextForMessage } from '../util/getNotificationTextForMessage';
import { getMessageAuthorText } from '../util/getMessageAuthorText';
import { GiftBadgeStates } from '../components/conversation/Message';
import { getUserLanguages } from '../util/userLanguages';
import { parseBoostBadgeListFromServer } from '../badges/parseBadgesFromServer';
import { SignalService as Proto } from '../protobuf';
import {
@ -761,16 +760,11 @@ export async function handleDataMessage(
typeof updatesUrl === 'string',
'getProfile: expected updatesUrl to be a defined string'
);
const userLanguages = getUserLanguages(
window.SignalContext.getPreferredSystemLocales(),
window.SignalContext.getResolvedMessagesLocale()
);
const { messaging } = window.textsecure;
if (!messaging) {
throw new Error(`${idLog}: messaging is not available`);
}
const response =
await messaging.server.getSubscriptionConfiguration(userLanguages);
const response = await messaging.server.getSubscriptionConfiguration();
const boostBadgesByLevel = parseBoostBadgeListFromServer(
response,
updatesUrl

View file

@ -27,7 +27,6 @@ import {
handleProfileKeyCredential,
} from '../util/zkgroup';
import { isMe } from '../util/whatTypeOfConversation';
import { getUserLanguages } from '../util/userLanguages';
import { parseBadgesFromServer } from '../badges/parseBadgesFromServer';
import { strictAssert } from '../util/assert';
import { drop } from '../util/drop';
@ -236,11 +235,6 @@ export const profileService = new ProfileService();
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace ProfileFetchOptions {
type Base = ReadonlyDeep<{
request: {
userLanguages: ReadonlyArray<string>;
};
}>;
type WithVersioned = ReadonlyDeep<{
profileKey: string;
profileCredentialRequestContext: ProfileKeyCredentialRequestContext | null;
@ -275,16 +269,16 @@ namespace ProfileFetchOptions {
export type Unauth =
// versioned (unauth)
| (Base & WithVersioned & WithUnauthAccessKey)
| (WithVersioned & WithUnauthAccessKey)
// unversioned (unauth)
| (Base & WithUnversioned & WithUnauthAccessKey)
| (Base & WithUnversioned & WithUnauthGroupSendToken);
| (WithUnversioned & WithUnauthAccessKey)
| (WithUnversioned & WithUnauthGroupSendToken);
export type Auth =
// unversioned (auth) -- Using lastProfile
| (Base & WithVersioned & WithAuth)
| (WithVersioned & WithAuth)
// unversioned (auth)
| (Base & WithUnversioned & WithAuth);
| (WithUnversioned & WithAuth);
}
export type ProfileFetchUnauthRequestOptions =
@ -308,11 +302,6 @@ async function buildProfileFetchOptions({
}): Promise<ProfileFetchOptions.Auth | ProfileFetchOptions.Unauth> {
const logId = `buildGetProfileOptions(${conversation.idForLogging()})`;
const userLanguages = getUserLanguages(
window.SignalContext.getPreferredSystemLocales(),
window.SignalContext.getResolvedMessagesLocale()
);
const profileKey = conversation.get('profileKey');
const profileKeyVersion = conversation.deriveProfileKeyVersion();
const accessKey = conversation.get('accessKey');
@ -330,7 +319,6 @@ async function buildProfileFetchOptions({
profileKey,
profileCredentialRequestContext: null,
request: {
userLanguages,
accessKey,
groupSendToken: null,
profileKeyVersion,
@ -350,7 +338,6 @@ async function buildProfileFetchOptions({
profileKey,
profileCredentialRequestContext: result.context,
request: {
userLanguages,
accessKey,
groupSendToken: null,
profileKeyVersion,
@ -374,7 +361,6 @@ async function buildProfileFetchOptions({
profileKey: lastProfile.profileKey,
profileCredentialRequestContext: null,
request: {
userLanguages,
accessKey: null,
groupSendToken: null,
profileKeyVersion: lastProfile.profileKeyVersion,
@ -403,7 +389,6 @@ async function buildProfileFetchOptions({
profileKey: null,
profileCredentialRequestContext: null,
request: {
userLanguages,
accessKey: null,
groupSendToken,
profileKeyVersion: null,
@ -418,7 +403,6 @@ async function buildProfileFetchOptions({
profileKey: null,
profileCredentialRequestContext: null,
request: {
userLanguages,
accessKey: null,
groupSendToken: null,
profileKeyVersion: null,

View file

@ -55,6 +55,10 @@ import {
parseServerAlertsFromHeader,
type ServerAlert,
} from '../util/handleServerAlerts';
import {
formatAcceptLanguageHeader,
getUserLanguages,
} from '../util/userLanguages';
const log = createLogger('SocketManager');
@ -216,6 +220,11 @@ export class SocketManager extends EventListener {
'desktop.experimentalTransport.enableAuth'
) && this.#transportOption() === TransportOption.Libsignal;
const userLanguages = getUserLanguages(
window.SignalContext.getPreferredSystemLocales(),
window.SignalContext.getResolvedMessagesLocale()
);
const process = useLibsignalTransport
? connectAuthenticatedLibsignal({
libsignalNet: this.libsignalNet,
@ -228,6 +237,7 @@ export class SocketManager extends EventListener {
this.emit('serverAlerts', alerts);
},
receiveStories: !this.#hasStoriesDisabled,
userLanguages,
keepalive: { path: '/v1/keepalive' },
})
: this.#connectResource({
@ -243,6 +253,7 @@ export class SocketManager extends EventListener {
extraHeaders: {
Authorization: getBasicAuth({ username, password }),
'X-Signal-Receive-Stories': String(!this.#hasStoriesDisabled),
'Accept-Language': formatAcceptLanguageHeader(userLanguages),
},
onUpgradeResponse: (response: IncomingMessage) => {
this.#handleAuthenticatedUpgradeResponseHeaders(response.headers);
@ -722,12 +733,18 @@ export class SocketManager extends EventListener {
status: SocketStatus.CONNECTING,
});
const userLanguages = getUserLanguages(
window.SignalContext.getPreferredSystemLocales(),
window.SignalContext.getResolvedMessagesLocale()
);
let process: AbortableProcess<IWebSocketResource>;
if (transportOption === TransportOption.Libsignal) {
process = connectUnauthenticatedLibsignal({
libsignalNet: this.libsignalNet,
name: UNAUTHENTICATED_CHANNEL_NAME,
userLanguages,
keepalive: { path: '/v1/keepalive' },
});
} else {
@ -740,6 +757,9 @@ export class SocketManager extends EventListener {
keepalive: { path: '/v1/keepalive' },
transportOption,
},
extraHeaders: {
'Accept-Language': formatAcceptLanguageHeader(userLanguages),
},
});
}

View file

@ -29,7 +29,6 @@ import type { ExplodePromiseResultType } from '../util/explodePromise';
import { explodePromise } from '../util/explodePromise';
import { getUserAgent } from '../util/getUserAgent';
import { getTimeoutStream } from '../util/getStreamWithTimeout';
import { formatAcceptLanguageHeader } from '../util/userLanguages';
import { toWebSafeBase64, fromWebSafeBase64 } from '../util/webSafeBase64';
import { getBasicAuth } from '../util/getBasicAuth';
import { createHTTPSAgent } from '../util/createHTTPSAgent';
@ -1630,9 +1629,7 @@ export type WebAPIType = {
options: ProfileFetchUnauthRequestOptions
) => Promise<ProfileType>;
getBadgeImageFile: (imageUrl: string) => Promise<Uint8Array>;
getSubscriptionConfiguration: (
userLanguages: ReadonlyArray<string>
) => Promise<unknown>;
getSubscriptionConfiguration: () => Promise<unknown>;
getSubscription: (
subscriberId: Uint8Array
) => Promise<SubscriptionResponseType>;
@ -2743,17 +2740,13 @@ export function initialize({
serviceId: ServiceIdString,
options: ProfileFetchAuthRequestOptions
) {
const { profileKeyVersion, profileKeyCredentialRequest, userLanguages } =
options;
const { profileKeyVersion, profileKeyCredentialRequest } = options;
return (await _ajax({
host: 'chatService',
call: 'profile',
httpType: 'GET',
urlParameters: getProfileUrl(serviceId, options),
headers: {
'Accept-Language': formatAcceptLanguageHeader(userLanguages),
},
responseType: 'json',
redactUrl: _createRedactor(
serviceId,
@ -2855,7 +2848,6 @@ export function initialize({
groupSendToken,
profileKeyVersion,
profileKeyCredentialRequest,
userLanguages,
} = options;
if (profileKeyVersion != null || profileKeyCredentialRequest != null) {
@ -2872,9 +2864,6 @@ export function initialize({
call: 'profile',
httpType: 'GET',
urlParameters: getProfileUrl(serviceId, options),
headers: {
'Accept-Language': formatAcceptLanguageHeader(userLanguages),
},
responseType: 'json',
unauthenticated: true,
accessKey: accessKey ?? undefined,
@ -2939,16 +2928,11 @@ export function initialize({
);
}
async function getSubscriptionConfiguration(
userLanguages: ReadonlyArray<string>
): Promise<unknown> {
async function getSubscriptionConfiguration(): Promise<unknown> {
return _ajax({
host: 'chatService',
call: 'subscriptionConfiguration',
httpType: 'GET',
headers: {
'Accept-Language': formatAcceptLanguageHeader(userLanguages),
},
responseType: 'json',
// TODO DESKTOP-8719
zodSchema: z.unknown(),

View file

@ -315,10 +315,12 @@ const UNEXPECTED_DISCONNECT_CODE = 3001;
export function connectUnauthenticatedLibsignal({
libsignalNet,
name,
userLanguages,
keepalive,
}: {
libsignalNet: Net.Net;
name: string;
userLanguages: ReadonlyArray<string>;
keepalive: KeepAliveOptionsType;
}): AbortableProcess<LibsignalWebSocketResource> {
const logId = `LibsignalWebSocketResource(${name})`;
@ -338,6 +340,7 @@ export function connectUnauthenticatedLibsignal({
abortSignal =>
libsignalNet.connectUnauthenticatedChat(listener, {
abortSignal,
languages: [...userLanguages],
}),
listener,
logId,
@ -351,6 +354,7 @@ export function connectAuthenticatedLibsignal({
credentials,
handler,
receiveStories,
userLanguages,
keepalive,
onReceivedAlerts,
}: {
@ -360,6 +364,7 @@ export function connectAuthenticatedLibsignal({
handler: (request: IncomingWebSocketRequest) => void;
onReceivedAlerts: (alerts: Array<ServerAlert>) => void;
receiveStories: boolean;
userLanguages: ReadonlyArray<string>;
keepalive: KeepAliveOptionsType;
}): AbortableProcess<LibsignalWebSocketResource> {
const logId = `LibsignalWebSocketResource(${name})`;
@ -411,7 +416,7 @@ export function connectAuthenticatedLibsignal({
credentials.password,
receiveStories,
listener,
{ abortSignal }
{ abortSignal, languages: [...userLanguages] }
),
listener,
logId,