Resolve fallback dns addrs during build

This commit is contained in:
Fedor Indutny 2024-02-27 16:53:58 -08:00 committed by GitHub
parent f5787ba1bc
commit e3dbcc1e0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 151 additions and 34 deletions

1
.gitignore vendored
View file

@ -3,6 +3,7 @@ node_modules_bkp
.sass-cache
coverage/*
build/curve25519_compiled.js
build/dns-fallback.json
stylesheets/*.css.map
/dist
.DS_Store

33
app/dns-fallback.ts Normal file
View file

@ -0,0 +1,33 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { join } from 'path';
import { readFile } from 'fs/promises';
import { DNSFallbackSchema } from '../ts/types/DNSFallback';
import type { DNSFallbackType } from '../ts/types/DNSFallback';
let cached: DNSFallbackType | undefined;
export async function getDNSFallback(): Promise<DNSFallbackType> {
if (cached != null) {
return cached;
}
const configPath = join(__dirname, '..', 'build', 'dns-fallback.json');
let str: string;
try {
str = await readFile(configPath, 'utf8');
} catch (error) {
console.error(
'Warning: build/dns-fallback.json not build, run `yarn generate`'
);
cached = [];
return cached;
}
const json = JSON.parse(str);
const result = DNSFallbackSchema.parse(json);
cached = result;
return result;
}

View file

@ -36,6 +36,7 @@ import packageJson from '../package.json';
import * as GlobalErrors from './global_errors';
import { setup as setupCrashReports } from './crashReports';
import { setup as setupSpellChecker } from './spell_check';
import { getDNSFallback } from './dns-fallback';
import { redactAll, addSensitivePath } from '../ts/util/privacy';
import { createSupportUrl } from '../ts/util/createSupportUrl';
import { missingCaseError } from '../ts/util/missingCaseError';
@ -52,7 +53,6 @@ import { explodePromise } from '../ts/util/explodePromise';
import './startup_config';
import type { ConfigType } from './config';
import type { RendererConfigType } from '../ts/types/RendererConfig';
import {
directoryConfigSchema,
@ -112,6 +112,7 @@ import { HourCyclePreference } from '../ts/types/I18N';
import { DBVersionFromFutureError } from '../ts/sql/migrations';
import type { ParsedSignalRoute } from '../ts/util/signalRoutes';
import { parseSignalRoute } from '../ts/util/signalRoutes';
import * as dns from '../ts/util/dns';
import { ZoomFactorService } from '../ts/services/ZoomFactorService';
const STICKER_CREATOR_PARTITION = 'sticker-creator';
@ -1734,6 +1735,8 @@ if (DISABLE_GPU) {
// Some APIs can only be used after this event occurs.
let ready = false;
app.on('ready', async () => {
dns.setFallback(await getDNSFallback());
const [userDataPath, crashDumpsPath, installPath] = await Promise.all([
realpath(app.getPath('userData')),
realpath(app.getPath('crashDumps')),
@ -2449,15 +2452,17 @@ ipc.on('get-config', async event => {
updatesUrl: config.get<string>('updatesUrl'),
resourcesUrl: config.get<string>('resourcesUrl'),
artCreatorUrl: config.get<string>('artCreatorUrl'),
cdnUrl0: config.get<ConfigType>('cdn').get<string>('0'),
cdnUrl2: config.get<ConfigType>('cdn').get<string>('2'),
cdnUrl3: config.get<ConfigType>('cdn').get<string>('3'),
cdnUrl0: config.get<string>('cdn.0'),
cdnUrl2: config.get<string>('cdn.2'),
cdnUrl3: config.get<string>('cdn.3'),
certificateAuthority: config.get<string>('certificateAuthority'),
environment:
!isTestEnvironment(getEnvironment()) && ciMode
? Environment.Production
: getEnvironment(),
ciMode,
// Should be already computed and cached at this point
dnsFallback: await getDNSFallback(),
nodeVersion: process.versions.node,
hostname: os.hostname(),
osRelease: os.release(),

View file

@ -19,7 +19,7 @@
"postinstall": "yarn build:acknowledgments && patch-package && yarn electron:install-app-deps",
"postuninstall": "yarn build:acknowledgments",
"start": "electron .",
"generate": "npm-run-all build-protobuf build:esbuild sass get-expire-time copy-components",
"generate": "npm-run-all build-protobuf build:esbuild build:dns-fallback sass get-expire-time copy-components",
"build-release": "yarn run build",
"sign-release": "node ts/updater/generateSignature.js",
"notarize": "echo 'No longer necessary'",
@ -75,6 +75,7 @@
"build": "run-s --print-label generate build:esbuild:prod build:release",
"build-linux": "yarn generate && yarn build:esbuild:prod && yarn build:release -- --publish=never",
"build:acknowledgments": "node scripts/generate-acknowledgments.js",
"build:dns-fallback": "node ts/scripts/generate-dns-fallback.js",
"build:dev": "run-s --print-label generate build:esbuild:prod",
"build:esbuild": "node scripts/esbuild.js",
"build:esbuild:prod": "node scripts/esbuild.js --prod",
@ -501,6 +502,7 @@
"build/available-locales.json",
"build/locale-display-names.json",
"build/country-display-names.json",
"build/dns-fallback.json",
"node_modules/**",
"!node_modules/underscore/**",
"!node_modules/emoji-datasource/emoji_pretty.json",

View file

@ -0,0 +1,71 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { join } from 'path';
import { lookup as lookupCb } from 'dns';
import { writeFile } from 'fs/promises';
import { promisify } from 'util';
import type { ResolvedEndpoint } from 'electron';
import { isNotNil } from '../util/isNotNil';
const lookup = promisify(lookupCb);
const FALLBACK_DOMAINS = [
'chat.signal.org',
'storage.signal.org',
'cdsi.signal.org',
'cdn.signal.org',
'cdn2.signal.org',
'cdn3.signal.org',
'updates2.signal.org',
'sfu.voip.signal.org',
'create.signal.art',
];
async function main() {
const config = await Promise.all(
FALLBACK_DOMAINS.sort().map(async domain => {
const addresses = await lookup(domain, { all: true });
const endpoints = addresses
.map(({ address, family }): ResolvedEndpoint | null => {
if (family === 4) {
return { family: 'ipv4', address };
}
if (family === 6) {
return { family: 'ipv6', address };
}
return null;
})
.filter(isNotNil)
.sort((a, b) => {
if (a.family < b.family) {
return -1;
}
if (a.family > b.family) {
return 1;
}
if (a.address < b.address) {
return -1;
}
if (a.address > b.address) {
return 1;
}
return 0;
});
return { domain, endpoints };
})
);
const outPath = join(__dirname, '../../build/dns-fallback.json');
await writeFile(outPath, `${JSON.stringify(config, null, 2)}\n`);
}
main().catch(error => {
console.error(error);
process.exit(1);
});

18
ts/types/DNSFallback.ts Normal file
View file

@ -0,0 +1,18 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import z from 'zod';
export const DNSFallbackSchema = z.array(
z.object({
domain: z.string(),
endpoints: z.array(
z.object({
family: z.enum(['ipv4', 'ipv6']),
address: z.string(),
})
),
})
);
export type DNSFallbackType = z.infer<typeof DNSFallbackSchema>;

View file

@ -6,6 +6,7 @@ import { z } from 'zod';
import { Environment } from '../environment';
import { themeSettingSchema } from './StorageUIKeys';
import { HourCyclePreferenceSchema } from './I18N';
import { DNSFallbackSchema } from './DNSFallback';
const environmentSchema = z.nativeEnum(Environment);
@ -40,6 +41,7 @@ export const rendererConfigSchema = z.object({
contentProxyUrl: configRequiredStringSchema,
crashDumpsPath: configRequiredStringSchema,
ciMode: z.enum(['full', 'benchmark']).or(z.literal(false)),
dnsFallback: DNSFallbackSchema,
environment: environmentSchema,
homePath: configRequiredStringSchema,
hostname: configRequiredStringSchema,

View file

@ -40,6 +40,7 @@ const HOST_LOG_ALLOWLIST = new Set([
'cdsi.signal.org',
'cdn.signal.org',
'cdn2.signal.org',
'cdn3.signal.org',
'create.signal.art',
// Staging

View file

@ -12,35 +12,16 @@ import type { ResolvedHost, ResolvedEndpoint } from 'electron';
import { strictAssert } from './assert';
import { drop } from './drop';
import type { DNSFallbackType } from '../types/DNSFallback';
const FALLBACK_ADDRS: ReadonlyMap<
string,
ReadonlyArray<ResolvedEndpoint>
> = new Map([
[
'cdsi.signal.org',
[
{ family: 'ipv4', address: '40.122.45.194' },
{ family: 'ipv6', address: '2603:1030:7::1' },
],
],
[
'chat.signal.org',
[
{ family: 'ipv4', address: '13.248.212.111' },
{ family: 'ipv4', address: '76.223.92.165' },
{ family: 'ipv6', address: '2600:9000:a507:ab6d:4ce3:2f58:25d7:9cbf' },
{ family: 'ipv6', address: '2600:9000:a61f:527c:d5eb:a431:5239:3232' },
],
],
[
'sfu.voip.signal.org',
[
{ family: 'ipv4', address: '34.49.5.136' },
{ family: 'ipv6', address: '2600:1901:0:9c39::' },
],
],
]);
const fallbackAddrs = new Map<string, ReadonlyArray<ResolvedEndpoint>>();
export function setFallback(dnsFallback: DNSFallbackType): void {
fallbackAddrs.clear();
for (const { domain, endpoints } of dnsFallback) {
fallbackAddrs.set(domain, endpoints);
}
}
function lookupAll(
hostname: string,
@ -80,7 +61,7 @@ function lookupAll(
);
}
} catch (error) {
const fallback = FALLBACK_ADDRS.get(hostname);
const fallback = fallbackAddrs.get(hostname);
if (fallback) {
result = { endpoints: fallback.slice() };
} else {

View file

@ -12,6 +12,7 @@ import { textsecure } from '../../textsecure';
import * as Attachments from '../attachments';
import { setup } from '../../signal';
import { addSensitivePath } from '../../util/privacy';
import * as dns from '../../util/dns';
import * as log from '../../logging/log';
import { SignalContext } from '../context';
@ -72,6 +73,8 @@ if (config.crashDumpsPath) {
addSensitivePath(config.crashDumpsPath);
}
dns.setFallback(SignalContext.config.dnsFallback);
window.Signal = setup({
Attachments,
getRegionCode: () => window.storage.get('regionCode'),