Resolve fallback dns addrs during build
This commit is contained in:
parent
f5787ba1bc
commit
e3dbcc1e0f
10 changed files with 151 additions and 34 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,6 +3,7 @@ node_modules_bkp
|
||||||
.sass-cache
|
.sass-cache
|
||||||
coverage/*
|
coverage/*
|
||||||
build/curve25519_compiled.js
|
build/curve25519_compiled.js
|
||||||
|
build/dns-fallback.json
|
||||||
stylesheets/*.css.map
|
stylesheets/*.css.map
|
||||||
/dist
|
/dist
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
33
app/dns-fallback.ts
Normal file
33
app/dns-fallback.ts
Normal 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;
|
||||||
|
}
|
13
app/main.ts
13
app/main.ts
|
@ -36,6 +36,7 @@ import packageJson from '../package.json';
|
||||||
import * as GlobalErrors from './global_errors';
|
import * as GlobalErrors from './global_errors';
|
||||||
import { setup as setupCrashReports } from './crashReports';
|
import { setup as setupCrashReports } from './crashReports';
|
||||||
import { setup as setupSpellChecker } from './spell_check';
|
import { setup as setupSpellChecker } from './spell_check';
|
||||||
|
import { getDNSFallback } from './dns-fallback';
|
||||||
import { redactAll, addSensitivePath } from '../ts/util/privacy';
|
import { redactAll, addSensitivePath } from '../ts/util/privacy';
|
||||||
import { createSupportUrl } from '../ts/util/createSupportUrl';
|
import { createSupportUrl } from '../ts/util/createSupportUrl';
|
||||||
import { missingCaseError } from '../ts/util/missingCaseError';
|
import { missingCaseError } from '../ts/util/missingCaseError';
|
||||||
|
@ -52,7 +53,6 @@ import { explodePromise } from '../ts/util/explodePromise';
|
||||||
|
|
||||||
import './startup_config';
|
import './startup_config';
|
||||||
|
|
||||||
import type { ConfigType } from './config';
|
|
||||||
import type { RendererConfigType } from '../ts/types/RendererConfig';
|
import type { RendererConfigType } from '../ts/types/RendererConfig';
|
||||||
import {
|
import {
|
||||||
directoryConfigSchema,
|
directoryConfigSchema,
|
||||||
|
@ -112,6 +112,7 @@ import { HourCyclePreference } from '../ts/types/I18N';
|
||||||
import { DBVersionFromFutureError } from '../ts/sql/migrations';
|
import { DBVersionFromFutureError } from '../ts/sql/migrations';
|
||||||
import type { ParsedSignalRoute } from '../ts/util/signalRoutes';
|
import type { ParsedSignalRoute } from '../ts/util/signalRoutes';
|
||||||
import { parseSignalRoute } from '../ts/util/signalRoutes';
|
import { parseSignalRoute } from '../ts/util/signalRoutes';
|
||||||
|
import * as dns from '../ts/util/dns';
|
||||||
import { ZoomFactorService } from '../ts/services/ZoomFactorService';
|
import { ZoomFactorService } from '../ts/services/ZoomFactorService';
|
||||||
|
|
||||||
const STICKER_CREATOR_PARTITION = 'sticker-creator';
|
const STICKER_CREATOR_PARTITION = 'sticker-creator';
|
||||||
|
@ -1734,6 +1735,8 @@ if (DISABLE_GPU) {
|
||||||
// Some APIs can only be used after this event occurs.
|
// Some APIs can only be used after this event occurs.
|
||||||
let ready = false;
|
let ready = false;
|
||||||
app.on('ready', async () => {
|
app.on('ready', async () => {
|
||||||
|
dns.setFallback(await getDNSFallback());
|
||||||
|
|
||||||
const [userDataPath, crashDumpsPath, installPath] = await Promise.all([
|
const [userDataPath, crashDumpsPath, installPath] = await Promise.all([
|
||||||
realpath(app.getPath('userData')),
|
realpath(app.getPath('userData')),
|
||||||
realpath(app.getPath('crashDumps')),
|
realpath(app.getPath('crashDumps')),
|
||||||
|
@ -2449,15 +2452,17 @@ ipc.on('get-config', async event => {
|
||||||
updatesUrl: config.get<string>('updatesUrl'),
|
updatesUrl: config.get<string>('updatesUrl'),
|
||||||
resourcesUrl: config.get<string>('resourcesUrl'),
|
resourcesUrl: config.get<string>('resourcesUrl'),
|
||||||
artCreatorUrl: config.get<string>('artCreatorUrl'),
|
artCreatorUrl: config.get<string>('artCreatorUrl'),
|
||||||
cdnUrl0: config.get<ConfigType>('cdn').get<string>('0'),
|
cdnUrl0: config.get<string>('cdn.0'),
|
||||||
cdnUrl2: config.get<ConfigType>('cdn').get<string>('2'),
|
cdnUrl2: config.get<string>('cdn.2'),
|
||||||
cdnUrl3: config.get<ConfigType>('cdn').get<string>('3'),
|
cdnUrl3: config.get<string>('cdn.3'),
|
||||||
certificateAuthority: config.get<string>('certificateAuthority'),
|
certificateAuthority: config.get<string>('certificateAuthority'),
|
||||||
environment:
|
environment:
|
||||||
!isTestEnvironment(getEnvironment()) && ciMode
|
!isTestEnvironment(getEnvironment()) && ciMode
|
||||||
? Environment.Production
|
? Environment.Production
|
||||||
: getEnvironment(),
|
: getEnvironment(),
|
||||||
ciMode,
|
ciMode,
|
||||||
|
// Should be already computed and cached at this point
|
||||||
|
dnsFallback: await getDNSFallback(),
|
||||||
nodeVersion: process.versions.node,
|
nodeVersion: process.versions.node,
|
||||||
hostname: os.hostname(),
|
hostname: os.hostname(),
|
||||||
osRelease: os.release(),
|
osRelease: os.release(),
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
"postinstall": "yarn build:acknowledgments && patch-package && yarn electron:install-app-deps",
|
"postinstall": "yarn build:acknowledgments && patch-package && yarn electron:install-app-deps",
|
||||||
"postuninstall": "yarn build:acknowledgments",
|
"postuninstall": "yarn build:acknowledgments",
|
||||||
"start": "electron .",
|
"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",
|
"build-release": "yarn run build",
|
||||||
"sign-release": "node ts/updater/generateSignature.js",
|
"sign-release": "node ts/updater/generateSignature.js",
|
||||||
"notarize": "echo 'No longer necessary'",
|
"notarize": "echo 'No longer necessary'",
|
||||||
|
@ -75,6 +75,7 @@
|
||||||
"build": "run-s --print-label generate build:esbuild:prod build:release",
|
"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-linux": "yarn generate && yarn build:esbuild:prod && yarn build:release -- --publish=never",
|
||||||
"build:acknowledgments": "node scripts/generate-acknowledgments.js",
|
"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:dev": "run-s --print-label generate build:esbuild:prod",
|
||||||
"build:esbuild": "node scripts/esbuild.js",
|
"build:esbuild": "node scripts/esbuild.js",
|
||||||
"build:esbuild:prod": "node scripts/esbuild.js --prod",
|
"build:esbuild:prod": "node scripts/esbuild.js --prod",
|
||||||
|
@ -501,6 +502,7 @@
|
||||||
"build/available-locales.json",
|
"build/available-locales.json",
|
||||||
"build/locale-display-names.json",
|
"build/locale-display-names.json",
|
||||||
"build/country-display-names.json",
|
"build/country-display-names.json",
|
||||||
|
"build/dns-fallback.json",
|
||||||
"node_modules/**",
|
"node_modules/**",
|
||||||
"!node_modules/underscore/**",
|
"!node_modules/underscore/**",
|
||||||
"!node_modules/emoji-datasource/emoji_pretty.json",
|
"!node_modules/emoji-datasource/emoji_pretty.json",
|
||||||
|
|
71
ts/scripts/generate-dns-fallback.ts
Normal file
71
ts/scripts/generate-dns-fallback.ts
Normal 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
18
ts/types/DNSFallback.ts
Normal 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>;
|
|
@ -6,6 +6,7 @@ import { z } from 'zod';
|
||||||
import { Environment } from '../environment';
|
import { Environment } from '../environment';
|
||||||
import { themeSettingSchema } from './StorageUIKeys';
|
import { themeSettingSchema } from './StorageUIKeys';
|
||||||
import { HourCyclePreferenceSchema } from './I18N';
|
import { HourCyclePreferenceSchema } from './I18N';
|
||||||
|
import { DNSFallbackSchema } from './DNSFallback';
|
||||||
|
|
||||||
const environmentSchema = z.nativeEnum(Environment);
|
const environmentSchema = z.nativeEnum(Environment);
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@ export const rendererConfigSchema = z.object({
|
||||||
contentProxyUrl: configRequiredStringSchema,
|
contentProxyUrl: configRequiredStringSchema,
|
||||||
crashDumpsPath: configRequiredStringSchema,
|
crashDumpsPath: configRequiredStringSchema,
|
||||||
ciMode: z.enum(['full', 'benchmark']).or(z.literal(false)),
|
ciMode: z.enum(['full', 'benchmark']).or(z.literal(false)),
|
||||||
|
dnsFallback: DNSFallbackSchema,
|
||||||
environment: environmentSchema,
|
environment: environmentSchema,
|
||||||
homePath: configRequiredStringSchema,
|
homePath: configRequiredStringSchema,
|
||||||
hostname: configRequiredStringSchema,
|
hostname: configRequiredStringSchema,
|
||||||
|
|
|
@ -40,6 +40,7 @@ const HOST_LOG_ALLOWLIST = new Set([
|
||||||
'cdsi.signal.org',
|
'cdsi.signal.org',
|
||||||
'cdn.signal.org',
|
'cdn.signal.org',
|
||||||
'cdn2.signal.org',
|
'cdn2.signal.org',
|
||||||
|
'cdn3.signal.org',
|
||||||
'create.signal.art',
|
'create.signal.art',
|
||||||
|
|
||||||
// Staging
|
// Staging
|
||||||
|
|
|
@ -12,35 +12,16 @@ import type { ResolvedHost, ResolvedEndpoint } from 'electron';
|
||||||
|
|
||||||
import { strictAssert } from './assert';
|
import { strictAssert } from './assert';
|
||||||
import { drop } from './drop';
|
import { drop } from './drop';
|
||||||
|
import type { DNSFallbackType } from '../types/DNSFallback';
|
||||||
|
|
||||||
const FALLBACK_ADDRS: ReadonlyMap<
|
const fallbackAddrs = new Map<string, ReadonlyArray<ResolvedEndpoint>>();
|
||||||
string,
|
|
||||||
ReadonlyArray<ResolvedEndpoint>
|
export function setFallback(dnsFallback: DNSFallbackType): void {
|
||||||
> = new Map([
|
fallbackAddrs.clear();
|
||||||
[
|
for (const { domain, endpoints } of dnsFallback) {
|
||||||
'cdsi.signal.org',
|
fallbackAddrs.set(domain, endpoints);
|
||||||
[
|
}
|
||||||
{ 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::' },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
function lookupAll(
|
function lookupAll(
|
||||||
hostname: string,
|
hostname: string,
|
||||||
|
@ -80,7 +61,7 @@ function lookupAll(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const fallback = FALLBACK_ADDRS.get(hostname);
|
const fallback = fallbackAddrs.get(hostname);
|
||||||
if (fallback) {
|
if (fallback) {
|
||||||
result = { endpoints: fallback.slice() };
|
result = { endpoints: fallback.slice() };
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { textsecure } from '../../textsecure';
|
||||||
import * as Attachments from '../attachments';
|
import * as Attachments from '../attachments';
|
||||||
import { setup } from '../../signal';
|
import { setup } from '../../signal';
|
||||||
import { addSensitivePath } from '../../util/privacy';
|
import { addSensitivePath } from '../../util/privacy';
|
||||||
|
import * as dns from '../../util/dns';
|
||||||
import * as log from '../../logging/log';
|
import * as log from '../../logging/log';
|
||||||
import { SignalContext } from '../context';
|
import { SignalContext } from '../context';
|
||||||
|
|
||||||
|
@ -72,6 +73,8 @@ if (config.crashDumpsPath) {
|
||||||
addSensitivePath(config.crashDumpsPath);
|
addSensitivePath(config.crashDumpsPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dns.setFallback(SignalContext.config.dnsFallback);
|
||||||
|
|
||||||
window.Signal = setup({
|
window.Signal = setup({
|
||||||
Attachments,
|
Attachments,
|
||||||
getRegionCode: () => window.storage.get('regionCode'),
|
getRegionCode: () => window.storage.get('regionCode'),
|
||||||
|
|
Loading…
Add table
Reference in a new issue