diff --git a/.gitignore b/.gitignore index 4388c1a0afbd..7a5b2a5caca3 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,4 @@ sticker-creator/dist/* /.idea /.vscode *.sublime* +*.map diff --git a/app/config.ts b/app/config.ts index a970ea77655c..03e45e69be36 100644 --- a/app/config.ts +++ b/app/config.ts @@ -37,8 +37,11 @@ if (getEnvironment() === Environment.Production) { } // We load config after we've made our modifications to NODE_ENV -// eslint-disable-next-line import/order, import/first -import config from 'config'; +// Note: we use `require()` because esbuild moves the imports to the top of +// the module regardless of their actual placement in the file. +// See: https://github.com/evanw/esbuild/issues/2011 +// eslint-disable-next-line @typescript-eslint/no-var-requires +const config: IConfig = require('config'); // Log resulting env vars in use by config [ diff --git a/app/main.ts b/app/main.ts index 7af5c9ffa324..3d59176c7c08 100644 --- a/app/main.ts +++ b/app/main.ts @@ -480,9 +480,9 @@ async function createWindow() { contextIsolation: false, preload: join( __dirname, - enableCI || getEnvironment() === Environment.Production - ? '../preload.bundle.js' - : '../preload.js' + isTestEnvironment(getEnvironment()) + ? '../preload.js' + : '../preload.bundle.js' ), nativeWindowOpen: true, spellcheck: await getSpellCheckSetting(), diff --git a/package.json b/package.json index 2af8e63784e4..21f7847ff1a6 100644 --- a/package.json +++ b/package.json @@ -42,14 +42,17 @@ "lint-deps": "node ts/util/lint/linter.js", "lint-license-comments": "ts-node ts/util/lint/license_comments.ts", "format": "prettier --write \"*.{html,css,js,json,md,scss,ts,tsx}\" \"./**/*.{html,css,js,json,md,scss,ts,tsx}\"", - "transpile": "tsc", + "transpile": "run-p check:types build:esbuild", + "check:types": "tsc --noEmit", "clean-transpile-once": "rimraf app/**/*.js app/*.js ts/**/*.js ts/*.js tsconfig.tsbuildinfo", "clean-transpile": "yarn run clean-transpile-once && yarn run clean-transpile-once", "open-coverage": "open coverage/lcov-report/index.html", "ready": "npm-run-all --print-label clean-transpile generate --parallel lint lint-deps test-node test-electron", "dev": "run-p --print-label dev:*", - "dev:transpile": "yarn run transpile --watch --preserveWatchOutput", - "dev:webpack": "cross-env NODE_ENV=development webpack serve --mode development", + "dev:transpile": "run-p \"check:types --watch\" dev:esbuild", + "dev:webpack": "run-p dev:esbuild dev:webpack:sticker-creator", + "dev:webpack:sticker-creator": "cross-env NODE_ENV=development webpack serve --mode development", + "dev:esbuild": "node scripts/esbuild.js --watch", "dev:typed-scss": "yarn build:typed-scss -w", "dev:storybook": "cross-env SIGNAL_ENV=storybook start-storybook -p 6006 -s ./", "dev:sass": "yarn sass --watch", @@ -58,11 +61,9 @@ "build:acknowledgments": "node scripts/generate-acknowledgments.js", "build:dev": "run-s --print-label generate build:typed-scss build:webpack", "build:typed-scss": "tsm sticker-creator", - "build:webpack": "run-p build:webpack:sticker-creator build:webpack:preload build:webpack:sql-worker build:webpack:heic-worker", + "build:webpack": "run-p build:webpack:sticker-creator \"build:esbuild --prod\"", "build:webpack:sticker-creator": "cross-env NODE_ENV=production webpack", - "build:webpack:preload": "cross-env NODE_ENV=production webpack -c webpack-preload.config.ts", - "build:webpack:sql-worker": "cross-env NODE_ENV=production webpack -c webpack-sql-worker.config.ts", - "build:webpack:heic-worker": "cross-env NODE_ENV=production webpack -c webpack-heic-worker.config.ts", + "build:esbuild": "node scripts/esbuild.js", "build:electron": "electron-builder --config.extraMetadata.environment=$SIGNAL_ENV", "build:release": "cross-env SIGNAL_ENV=production yarn build:electron -- --config.directories.output=release", "build:zip": "node ts/scripts/zip-macos-release.js", @@ -78,7 +79,7 @@ "@evanhahn/lottie-web-light": "5.8.1", "@popperjs/core": "2.9.2", "@react-spring/web": "9.4.1", - "@signalapp/signal-client": "0.11.1", + "@signalapp/signal-client": "0.12.4", "@sindresorhus/is": "0.8.0", "@types/fabric": "4.5.3", "abort-controller": "3.0.0", @@ -258,6 +259,7 @@ "electron-builder": "22.14.5", "electron-mocha": "11.0.2", "electron-notarize": "0.1.1", + "esbuild": "0.14.3", "eslint": "7.7.0", "eslint-config-airbnb-typescript-prettier": "4.2.0", "eslint-config-prettier": "6.11.0", diff --git a/patches/react-virtualized+9.21.0.patch b/patches/react-virtualized+9.21.0.patch index 09d2337d4412..b78bb72e8ba6 100644 --- a/patches/react-virtualized+9.21.0.patch +++ b/patches/react-virtualized+9.21.0.patch @@ -70,7 +70,7 @@ index 262776b..156cf0f 100644 this._cellHeightCache[key] = height; this._cellWidthCache[key] = width; diff --git a/node_modules/react-virtualized/dist/commonjs/Grid/Grid.js b/node_modules/react-virtualized/dist/commonjs/Grid/Grid.js -index e1b959a..97d6ef9 100644 +index e1b959a..09c16c5 100644 --- a/node_modules/react-virtualized/dist/commonjs/Grid/Grid.js +++ b/node_modules/react-virtualized/dist/commonjs/Grid/Grid.js @@ -132,6 +132,9 @@ var Grid = function (_React$PureComponent) { @@ -442,3 +442,13 @@ index b5ad0eb..efb2cd7 100644 }, _this._onSectionRendered = function (_ref4) { var rowOverscanStartIndex = _ref4.rowOverscanStartIndex, rowOverscanStopIndex = _ref4.rowOverscanStopIndex, +diff --git a/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js b/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js +index 6418a78..afbc3c3 100644 +--- a/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js ++++ b/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js +@@ -72,4 +72,3 @@ export function unregisterScrollListener(component, element) { + } + } + } +-import { bpfrpt_proptype_WindowScroller } from '../WindowScroller.js'; +\ No newline at end of file diff --git a/scripts/esbuild.js b/scripts/esbuild.js new file mode 100644 index 000000000000..c15aeec91821 --- /dev/null +++ b/scripts/esbuild.js @@ -0,0 +1,111 @@ +// Copyright 2022 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +const esbuild = require('esbuild'); +const path = require('path'); +const glob = require('glob'); + +const ROOT_DIR = path.join(__dirname, '..'); + +const watch = process.argv.some(argv => argv === '-w' || argv === '--watch'); +const isProd = process.argv.some(argv => argv === '-prod' || argv === '--prod'); + +const nodeDefaults = { + platform: 'node', + target: 'node16', + sourcemap: isProd ? false : 'inline', + // Otherwise React components get renamed + // See: https://github.com/evanw/esbuild/issues/1147 + keepNames: true, + logLevel: 'info', + watch, +}; + +const bundleDefaults = { + ...nodeDefaults, + bundle: true, + external: [ + '@signalapp/signal-client', + '@signalapp/signal-client/zkgroup', + 'backbone', + 'better-sqlite3', + 'fs-xattr', + 'fsevents', + 'got', + 'jquery', + 'mac-screen-capture-permissions', + 'node-fetch', + 'sass', + 'pino', + 'proxy-agent', + 'ringrtc', + 'sharp', + 'websocket', + 'electron', + + // Uses fast-glob and dynamic requires + './preload_test', + ], +}; + +// App, tests, and scripts +esbuild.build({ + ...nodeDefaults, + format: 'cjs', + mainFields: ['browser', 'main'], + entryPoints: glob + .sync('{app,ts}/**/*.{ts,tsx}', { + nodir: true, + root: ROOT_DIR, + }) + .filter(file => !file.endsWith('.d.ts')), + outdir: path.join(ROOT_DIR), +}); + +// Preload bundle +esbuild.build({ + ...bundleDefaults, + mainFields: ['browser', 'main'], + entryPoints: [path.join(ROOT_DIR, 'preload.js')], + outfile: path.join(ROOT_DIR, 'preload.bundle.js'), +}); + +// HEIC worker +esbuild.build({ + ...bundleDefaults, + entryPoints: [path.join(ROOT_DIR, 'ts', 'workers', 'heicConverterWorker.ts')], + outfile: path.join(ROOT_DIR, 'ts', 'workers', 'heicConverter.bundle.js'), +}); + +// SQL worker +const libDir = path.join('..', '..', 'node_modules', 'better-sqlite3'); +const bindingFile = path.join( + libDir, + 'build', + 'Release', + 'better_sqlite3.node' +); + +esbuild.build({ + ...nodeDefaults, + bundle: true, + + plugins: [ + { + name: 'bindings', + setup(build) { + build.onResolve({ filter: /^bindings$/ }, () => ({ + path: path.join(ROOT_DIR, 'ts', 'sql', 'mainWorkerBindings.ts'), + })); + + build.onResolve({ filter: /^better_sqlite3\.node$/ }, () => ({ + path: bindingFile, + external: true, + })); + }, + }, + ], + + entryPoints: [path.join(ROOT_DIR, 'ts', 'sql', 'mainWorker.ts')], + outfile: path.join(ROOT_DIR, 'ts', 'sql', 'mainWorker.bundle.js'), +}); diff --git a/ts/linkPreviews/linkPreviewFetch.ts b/ts/linkPreviews/linkPreviewFetch.ts index de74767771d5..574af68c2813 100644 --- a/ts/linkPreviews/linkPreviewFetch.ts +++ b/ts/linkPreviews/linkPreviewFetch.ts @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Signal Messenger, LLC +// Copyright 2020-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import type { RequestInit, Response } from 'node-fetch'; @@ -13,6 +13,7 @@ import { IMAGE_WEBP, stringToMIMEType, } from '../types/MIME'; +import type { LoggerType } from '../types/Logging'; import * as log from '../logging/log'; const USER_AGENT = 'WhatsApp/2'; @@ -76,14 +77,15 @@ type ParsedContentType = async function fetchWithRedirects( fetchFn: FetchFn, href: string, - options: RequestInit + options: RequestInit, + logger: Pick = log ): Promise { const urlsSeen = new Set(); let nextHrefToLoad = href; for (let i = 0; i < MAX_REQUEST_COUNT_WITH_REDIRECTS; i += 1) { if (urlsSeen.has(nextHrefToLoad)) { - log.warn('fetchWithRedirects: found a redirect loop'); + logger.warn('fetchWithRedirects: found a redirect loop'); throw new Error('redirect loop'); } urlsSeen.add(nextHrefToLoad); @@ -101,7 +103,7 @@ async function fetchWithRedirects( const location = response.headers.get('location'); if (!location) { - log.warn( + logger.warn( 'fetchWithRedirects: got a redirect status code but no Location header; bailing' ); throw new Error('no location with redirect'); @@ -109,7 +111,7 @@ async function fetchWithRedirects( const newUrl = maybeParseUrl(location, nextHrefToLoad); if (newUrl?.protocol !== 'https:') { - log.warn( + logger.warn( 'fetchWithRedirects: got a redirect status code and an invalid Location header' ); throw new Error('invalid location'); @@ -118,7 +120,7 @@ async function fetchWithRedirects( nextHrefToLoad = newUrl.href; } - log.warn('fetchWithRedirects: too many redirects'); + logger.warn('fetchWithRedirects: too many redirects'); throw new Error('too many redirects'); } @@ -284,7 +286,8 @@ const parseHtmlBytes = ( const getHtmlDocument = async ( body: AsyncIterable, httpCharset: string | null, - abortSignal: AbortSignal + abortSignal: AbortSignal, + logger: Pick = log ): Promise => { let result: HTMLDocument = emptyHtmlDocument(); @@ -317,7 +320,7 @@ const getHtmlDocument = async ( } } } catch (err) { - log.warn( + logger.warn( 'getHtmlDocument: error when reading body; continuing with what we got' ); } @@ -361,12 +364,13 @@ const getLinkHrefAttribute = ( const parseMetadata = ( document: HTMLDocument, - href: string + href: string, + logger: Pick = log ): LinkPreviewMetadata | null => { const title = getOpenGraphContent(document, ['og:title']) || document.title.trim(); if (!title) { - log.warn("parseMetadata: HTML document doesn't have a title; bailing"); + logger.warn("parseMetadata: HTML document doesn't have a title; bailing"); return null; } @@ -431,40 +435,46 @@ const parseMetadata = ( export async function fetchLinkPreviewMetadata( fetchFn: FetchFn, href: string, - abortSignal: AbortSignal + abortSignal: AbortSignal, + logger: Pick = log ): Promise { let response: Response; try { - response = await fetchWithRedirects(fetchFn, href, { - headers: { - Accept: 'text/html,application/xhtml+xml', - 'User-Agent': USER_AGENT, + response = await fetchWithRedirects( + fetchFn, + href, + { + headers: { + Accept: 'text/html,application/xhtml+xml', + 'User-Agent': USER_AGENT, + }, + signal: abortSignal as AbortSignalForNodeFetch, }, - signal: abortSignal as AbortSignalForNodeFetch, - }); + logger + ); } catch (err) { - log.warn( + logger.warn( 'fetchLinkPreviewMetadata: failed to fetch link preview HTML; bailing' ); return null; } if (!response.ok) { - log.warn( + logger.warn( `fetchLinkPreviewMetadata: got a ${response.status} status code; bailing` ); return null; } if (!response.body) { - log.warn('fetchLinkPreviewMetadata: no response body; bailing'); + logger.warn('fetchLinkPreviewMetadata: no response body; bailing'); return null; } if ( !isInlineContentDisposition(response.headers.get('Content-Disposition')) ) { - log.warn( + logger.warn( 'fetchLinkPreviewMetadata: Content-Disposition header is not inline; bailing' ); return null; @@ -478,20 +488,23 @@ export async function fetchLinkPreviewMetadata( response.headers.get('Content-Length') ); if (contentLength < MIN_HTML_CONTENT_LENGTH) { - log.warn('fetchLinkPreviewMetadata: Content-Length is too short; bailing'); + logger.warn( + 'fetchLinkPreviewMetadata: Content-Length is too short; bailing' + ); return null; } const contentType = parseContentType(response.headers.get('Content-Type')); if (contentType.type !== 'text/html') { - log.warn('fetchLinkPreviewMetadata: Content-Type is not HTML; bailing'); + logger.warn('fetchLinkPreviewMetadata: Content-Type is not HTML; bailing'); return null; } const document = await getHtmlDocument( response.body, contentType.charset, - abortSignal + abortSignal, + logger ); // [The Node docs about `ReadableStream.prototype[Symbol.asyncIterator]`][0] say that @@ -511,7 +524,7 @@ export async function fetchLinkPreviewMetadata( return null; } - return parseMetadata(document, response.url); + return parseMetadata(document, response.url, logger); } /** @@ -523,19 +536,25 @@ export async function fetchLinkPreviewMetadata( export async function fetchLinkPreviewImage( fetchFn: FetchFn, href: string, - abortSignal: AbortSignal + abortSignal: AbortSignal, + logger: Pick = log ): Promise { let response: Response; try { - response = await fetchWithRedirects(fetchFn, href, { - headers: { - 'User-Agent': USER_AGENT, + response = await fetchWithRedirects( + fetchFn, + href, + { + headers: { + 'User-Agent': USER_AGENT, + }, + size: MAX_IMAGE_CONTENT_LENGTH, + signal: abortSignal as AbortSignalForNodeFetch, }, - size: MAX_IMAGE_CONTENT_LENGTH, - signal: abortSignal as AbortSignalForNodeFetch, - }); + logger + ); } catch (err) { - log.warn('fetchLinkPreviewImage: failed to fetch image; bailing'); + logger.warn('fetchLinkPreviewImage: failed to fetch image; bailing'); return null; } @@ -544,7 +563,7 @@ export async function fetchLinkPreviewImage( } if (!response.ok) { - log.warn( + logger.warn( `fetchLinkPreviewImage: got a ${response.status} status code; bailing` ); return null; @@ -554,11 +573,11 @@ export async function fetchLinkPreviewImage( response.headers.get('Content-Length') ); if (contentLength < MIN_IMAGE_CONTENT_LENGTH) { - log.warn('fetchLinkPreviewImage: Content-Length is too short; bailing'); + logger.warn('fetchLinkPreviewImage: Content-Length is too short; bailing'); return null; } if (contentLength > MAX_IMAGE_CONTENT_LENGTH) { - log.warn( + logger.warn( 'fetchLinkPreviewImage: Content-Length is too large or is unset; bailing' ); return null; @@ -568,7 +587,7 @@ export async function fetchLinkPreviewImage( response.headers.get('Content-Type') ); if (!contentType || !VALID_IMAGE_MIME_TYPES.has(contentType)) { - log.warn('fetchLinkPreviewImage: Content-Type is not an image; bailing'); + logger.warn('fetchLinkPreviewImage: Content-Type is not an image; bailing'); return null; } @@ -576,7 +595,7 @@ export async function fetchLinkPreviewImage( try { data = await response.buffer(); } catch (err) { - log.warn('fetchLinkPreviewImage: failed to read body; bailing'); + logger.warn('fetchLinkPreviewImage: failed to read body; bailing'); return null; } diff --git a/ts/routineProfileRefresh.ts b/ts/routineProfileRefresh.ts index 0f454a2a1005..9ec9e8f716cb 100644 --- a/ts/routineProfileRefresh.ts +++ b/ts/routineProfileRefresh.ts @@ -1,4 +1,4 @@ -// Copyright 2021 Signal Messenger, LLC +// Copyright 2021-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { isNil, sortBy } from 'lodash'; @@ -12,8 +12,7 @@ import { take } from './util/iterables'; import { isOlderThan } from './util/timestamp'; import type { ConversationModel } from './models/conversations'; import type { StorageInterface } from './types/Storage.d'; -// Imported this way so that sinon.sandbox can stub this properly -import * as profileGetter from './util/getProfile'; +import { getProfile } from './util/getProfile'; const STORAGE_KEY = 'lastAttemptedToRefreshProfilesAt'; const MAX_AGE_TO_BE_CONSIDERED_ACTIVE = 30 * 24 * 60 * 60 * 1000; @@ -25,10 +24,14 @@ export async function routineProfileRefresh({ allConversations, ourConversationId, storage, + + // Only for tests + getProfileFn = getProfile, }: { allConversations: Array; ourConversationId: string; storage: Pick; + getProfileFn?: typeof getProfile; }): Promise { log.info('routineProfileRefresh: starting'); @@ -59,10 +62,7 @@ export async function routineProfileRefresh({ totalCount += 1; try { - await profileGetter.getProfile( - conversation.get('uuid'), - conversation.get('e164') - ); + await getProfileFn(conversation.get('uuid'), conversation.get('e164')); log.info( `routineProfileRefresh: refreshed profile for ${conversation.idForLogging()}` ); diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index 0ec6e183ce83..73b54eb14d1c 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -1439,7 +1439,9 @@ function conversationUnloaded(id: string): ConversationUnloadedActionType { }; } -function createGroup(): ThunkAction< +function createGroup( + createGroupV2 = groups.createGroupV2 +): ThunkAction< void, RootStateType, unknown, @@ -1461,7 +1463,7 @@ function createGroup(): ThunkAction< dispatch({ type: 'CREATE_GROUP_PENDING' }); try { - const conversation = await groups.createGroupV2({ + const conversation = await createGroupV2({ name: composer.groupName.trim(), avatar: composer.groupAvatar, avatars: composer.userAvatarData.map(avatarData => diff --git a/ts/test-both/conversations/isConversationTooBigToRing_test.ts b/ts/test-both/conversations/isConversationTooBigToRing_test.ts index 709f65559f17..c86389429bfd 100644 --- a/ts/test-both/conversations/isConversationTooBigToRing_test.ts +++ b/ts/test-both/conversations/isConversationTooBigToRing_test.ts @@ -1,34 +1,19 @@ -// Copyright 2021 Signal Messenger, LLC +// Copyright 2021-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import * as sinon from 'sinon'; import { times } from 'lodash'; -import * as remoteConfig from '../../RemoteConfig'; +import { updateRemoteConfig } from '../helpers/RemoteConfigStub'; import { UUID } from '../../types/UUID'; import { isConversationTooBigToRing } from '../../conversations/isConversationTooBigToRing'; +const CONFIG_KEY = 'global.calling.maxGroupCallRingSize'; + describe('isConversationTooBigToRing', () => { - let sinonSandbox: sinon.SinonSandbox; - let getMaxGroupCallRingSizeStub: sinon.SinonStub; - - beforeEach(() => { - sinonSandbox = sinon.createSandbox(); - - const getValueStub = sinonSandbox.stub(remoteConfig, 'getValue'); - getMaxGroupCallRingSizeStub = getValueStub.withArgs( - 'global.calling.maxGroupCallRingSize' - ); - }); - const fakeMemberships = (count: number) => times(count, () => ({ uuid: UUID.generate().toString(), isAdmin: false })); - afterEach(() => { - sinonSandbox.restore(); - }); - it('returns false if there are no memberships (i.e., for a direct conversation)', () => { assert.isFalse(isConversationTooBigToRing({})); assert.isFalse(isConversationTooBigToRing({ memberships: [] })); @@ -45,17 +30,20 @@ describe('isConversationTooBigToRing', () => { } }; - it('returns whether there are 16 or more people in the group, if there is nothing in remote config', () => { + it('returns whether there are 16 or more people in the group, if there is nothing in remote config', async () => { + await updateRemoteConfig([]); textMaximum(16); }); - it('returns whether there are 16 or more people in the group, if the remote config value is bogus', () => { - getMaxGroupCallRingSizeStub.returns('uh oh'); + it('returns whether there are 16 or more people in the group, if the remote config value is bogus', async () => { + await updateRemoteConfig([ + { name: CONFIG_KEY, value: 'uh oh', enabled: true }, + ]); textMaximum(16); }); - it('returns whether there are 9 or more people in the group, if the remote config value is 9', () => { - getMaxGroupCallRingSizeStub.returns('9'); + it('returns whether there are 9 or more people in the group, if the remote config value is 9', async () => { + await updateRemoteConfig([{ name: CONFIG_KEY, value: '9', enabled: true }]); textMaximum(9); }); }); diff --git a/ts/test-both/groups/limits_test.ts b/ts/test-both/groups/limits_test.ts index 77a79e7049b0..4f763c52ea88 100644 --- a/ts/test-both/groups/limits_test.ts +++ b/ts/test-both/groups/limits_test.ts @@ -1,66 +1,56 @@ -// Copyright 2021 Signal Messenger, LLC +// Copyright 2021-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import * as sinon from 'sinon'; -import * as remoteConfig from '../../RemoteConfig'; +import { updateRemoteConfig } from '../helpers/RemoteConfigStub'; import { getGroupSizeRecommendedLimit, getGroupSizeHardLimit, } from '../../groups/limits'; +const RECOMMENDED_SIZE_KEY = 'global.groupsv2.maxGroupSize'; +const HARD_LIMIT_KEY = 'global.groupsv2.groupSizeHardLimit'; + describe('group limit utilities', () => { - let sinonSandbox: sinon.SinonSandbox; - let getRecommendedLimitStub: sinon.SinonStub; - let getHardLimitStub: sinon.SinonStub; - - beforeEach(() => { - sinonSandbox = sinon.createSandbox(); - - const getValueStub = sinonSandbox.stub(remoteConfig, 'getValue'); - getRecommendedLimitStub = getValueStub.withArgs( - 'global.groupsv2.maxGroupSize' - ); - getHardLimitStub = getValueStub.withArgs( - 'global.groupsv2.groupSizeHardLimit' - ); - }); - - afterEach(() => { - sinonSandbox.restore(); - }); - describe('getGroupSizeRecommendedLimit', () => { - it('throws if the value in remote config is not defined', () => { - getRecommendedLimitStub.returns(undefined); + it('throws if the value in remote config is not defined', async () => { + await updateRemoteConfig([]); assert.throws(getGroupSizeRecommendedLimit); }); - it('throws if the value in remote config is not a parseable integer', () => { - getRecommendedLimitStub.returns('uh oh'); + it('throws if the value in remote config is not a parseable integer', async () => { + await updateRemoteConfig([ + { name: RECOMMENDED_SIZE_KEY, value: 'uh oh', enabled: true }, + ]); assert.throws(getGroupSizeRecommendedLimit); }); - it('returns the value in remote config, parsed as an integer', () => { - getRecommendedLimitStub.returns('123'); + it('returns the value in remote config, parsed as an integer', async () => { + await updateRemoteConfig([ + { name: RECOMMENDED_SIZE_KEY, value: '123', enabled: true }, + ]); assert.strictEqual(getGroupSizeRecommendedLimit(), 123); }); }); describe('getGroupSizeHardLimit', () => { - it('throws if the value in remote config is not defined', () => { - getHardLimitStub.returns(undefined); + it('throws if the value in remote config is not defined', async () => { + await updateRemoteConfig([]); assert.throws(getGroupSizeHardLimit); }); - it('throws if the value in remote config is not a parseable integer', () => { - getHardLimitStub.returns('uh oh'); + it('throws if the value in remote config is not a parseable integer', async () => { + await updateRemoteConfig([ + { name: HARD_LIMIT_KEY, value: 'uh oh', enabled: true }, + ]); assert.throws(getGroupSizeHardLimit); }); - it('returns the value in remote config, parsed as an integer', () => { - getHardLimitStub.returns('123'); + it('returns the value in remote config, parsed as an integer', async () => { + await updateRemoteConfig([ + { name: HARD_LIMIT_KEY, value: '123', enabled: true }, + ]); assert.strictEqual(getGroupSizeHardLimit(), 123); }); }); diff --git a/ts/test-both/helpers/RemoteConfigStub.ts b/ts/test-both/helpers/RemoteConfigStub.ts new file mode 100644 index 000000000000..e8d88c1b64dc --- /dev/null +++ b/ts/test-both/helpers/RemoteConfigStub.ts @@ -0,0 +1,18 @@ +// Copyright 2022 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { refreshRemoteConfig } from '../../RemoteConfig'; +import type { WebAPIType } from '../../textsecure/WebAPI'; +import type { UnwrapPromise } from '../../types/Util'; + +export async function updateRemoteConfig( + newConfig: UnwrapPromise> +): Promise { + const fakeServer = { + async getConfig() { + return newConfig; + }, + } as Partial as unknown as WebAPIType; + + await refreshRemoteConfig(fakeServer); +} diff --git a/ts/test-electron/linkPreviews/linkPreviewFetch_test.ts b/ts/test-electron/linkPreviews/linkPreviewFetch_test.ts index 716780992ef5..563e9418bb03 100644 --- a/ts/test-electron/linkPreviews/linkPreviewFetch_test.ts +++ b/ts/test-electron/linkPreviews/linkPreviewFetch_test.ts @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Signal Messenger, LLC +// Copyright 2020-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; @@ -8,7 +8,7 @@ import * as fs from 'fs'; import * as path from 'path'; import AbortController from 'abort-controller'; import { IMAGE_JPEG, stringToMIMEType } from '../../types/MIME'; -import * as log from '../../logging/log'; +import type { LoggerType } from '../../types/Logging'; import { fetchLinkPreviewImage, @@ -24,16 +24,12 @@ describe('link preview fetching', () => { return sinon.stub(); } - let sandbox: sinon.SinonSandbox; let warn: sinon.SinonStub; + let logger: Pick; beforeEach(() => { - sandbox = sinon.createSandbox(); - warn = sandbox.stub(log, 'warn'); - }); - - afterEach(() => { - sandbox.restore(); + warn = sinon.stub(); + logger = { warn }; }); describe('fetchLinkPreviewMetadata', () => { @@ -196,7 +192,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewMetadata( fakeFetch, 'https://example.com', - new AbortController().signal + new AbortController().signal, + logger ); sinon.assert.notCalled(warn); @@ -229,7 +226,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewMetadata( fakeFetch, 'https://example.com', - new AbortController().signal + new AbortController().signal, + logger ) ); @@ -249,7 +247,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewMetadata( fakeFetch, 'https://example.com', - new AbortController().signal + new AbortController().signal, + logger ) ); @@ -434,7 +433,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewMetadata( fakeFetch, 'https://example.com', - new AbortController().signal + new AbortController().signal, + logger ) ); @@ -451,7 +451,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewMetadata( fakeFetch, 'https://example.com', - new AbortController().signal + new AbortController().signal, + logger ) ); @@ -473,7 +474,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewMetadata( fakeFetch, 'https://example.com', - new AbortController().signal + new AbortController().signal, + logger ) ); @@ -517,7 +519,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewMetadata( fakeFetch, 'https://example.com', - new AbortController().signal + new AbortController().signal, + logger ) ); @@ -798,7 +801,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewMetadata( fakeFetch, 'https://example.com', - new AbortController().signal + new AbortController().signal, + logger ), 'title', 'foo bar' @@ -893,7 +897,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewMetadata( fakeFetch, 'https://example.com', - new AbortController().signal + new AbortController().signal, + logger ) ); @@ -1166,7 +1171,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewImage( fakeFetch, 'https://example.com/img', - new AbortController().signal + new AbortController().signal, + logger ) ); @@ -1196,7 +1202,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewImage( fakeFetch, 'https://example.com/img', - new AbortController().signal + new AbortController().signal, + logger ) ); @@ -1264,7 +1271,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewImage( fakeFetch, 'https://example.com/img', - new AbortController().signal + new AbortController().signal, + logger ) ); @@ -1289,7 +1297,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewImage( fakeFetch, 'https://example.com/img', - new AbortController().signal + new AbortController().signal, + logger ) ); @@ -1319,7 +1328,8 @@ describe('link preview fetching', () => { await fetchLinkPreviewImage( fakeFetch, 'https://example.com/img', - new AbortController().signal + new AbortController().signal, + logger ) ); diff --git a/ts/test-electron/models/messages_test.ts b/ts/test-electron/models/messages_test.ts index f0b3db8ad82a..51d3c70b2bfb 100644 --- a/ts/test-electron/models/messages_test.ts +++ b/ts/test-electron/models/messages_test.ts @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Signal Messenger, LLC +// Copyright 2020-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; @@ -580,7 +580,12 @@ describe('Message', () => { }); it("shows a notification's emoji on non-Linux", function test() { - this.sandbox.stub(window.Signal.OS, 'isLinux').returns(false); + this.sandbox.replace(window.Signal, 'OS', { + ...window.Signal.OS, + isLinux() { + return false; + }, + }); assert.strictEqual( createMessage({ @@ -597,7 +602,12 @@ describe('Message', () => { }); it('hides emoji on Linux', function test() { - this.sandbox.stub(window.Signal.OS, 'isLinux').returns(true); + this.sandbox.replace(window.Signal, 'OS', { + ...window.Signal.OS, + isLinux() { + return true; + }, + }); assert.strictEqual( createMessage({ diff --git a/ts/test-electron/routineProfileRefresh_test.ts b/ts/test-electron/routineProfileRefresh_test.ts index efe1334fb853..1ecb8cf9e14b 100644 --- a/ts/test-electron/routineProfileRefresh_test.ts +++ b/ts/test-electron/routineProfileRefresh_test.ts @@ -1,4 +1,4 @@ -// Copyright 2021 Signal Messenger, LLC +// Copyright 2021-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import * as sinon from 'sinon'; @@ -8,14 +8,14 @@ import type { ConversationAttributesType } from '../model-types.d'; import { UUID } from '../types/UUID'; import { routineProfileRefresh } from '../routineProfileRefresh'; -import * as getProfileStub from '../util/getProfile'; describe('routineProfileRefresh', () => { let sinonSandbox: sinon.SinonSandbox; + let getProfileFn: sinon.SinonStub; beforeEach(() => { sinonSandbox = sinon.createSandbox(); - sinonSandbox.stub(getProfileStub, 'getProfile').resolves(undefined); + getProfileFn = sinon.stub(); }); afterEach(() => { @@ -87,9 +87,10 @@ describe('routineProfileRefresh', () => { allConversations: [conversation1, conversation2], ourConversationId: UUID.generate().toString(), storage, + getProfileFn, }); - sinon.assert.notCalled(getProfileStub.getProfile as sinon.SinonStub); + sinon.assert.notCalled(getProfileFn); sinon.assert.notCalled(storage.put); }); @@ -101,15 +102,16 @@ describe('routineProfileRefresh', () => { allConversations: [conversation1, conversation2], ourConversationId: UUID.generate().toString(), storage: makeStorage(), + getProfileFn, }); sinon.assert.calledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, conversation1.get('uuid'), conversation1.get('e164') ); sinon.assert.calledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, conversation2.get('uuid'), conversation2.get('e164') ); @@ -126,21 +128,22 @@ describe('routineProfileRefresh', () => { allConversations: [recentlyActive, inactive, neverActive], ourConversationId: UUID.generate().toString(), storage: makeStorage(), + getProfileFn, }); - sinon.assert.calledOnce(getProfileStub.getProfile as sinon.SinonStub); + sinon.assert.calledOnce(getProfileFn); sinon.assert.calledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, recentlyActive.get('uuid'), recentlyActive.get('e164') ); sinon.assert.neverCalledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, inactive.get('uuid'), inactive.get('e164') ); sinon.assert.neverCalledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, neverActive.get('uuid'), neverActive.get('e164') ); @@ -154,18 +157,11 @@ describe('routineProfileRefresh', () => { allConversations: [notMe, me], ourConversationId: me.id, storage: makeStorage(), + getProfileFn, }); - sinon.assert.calledWith( - getProfileStub.getProfile as sinon.SinonStub, - notMe.get('uuid'), - notMe.get('e164') - ); - sinon.assert.neverCalledWith( - getProfileStub.getProfile as sinon.SinonStub, - me.get('uuid'), - me.get('e164') - ); + sinon.assert.calledWith(getProfileFn, notMe.get('uuid'), notMe.get('e164')); + sinon.assert.neverCalledWith(getProfileFn, me.get('uuid'), me.get('e164')); }); it('skips conversations that were refreshed in the last hour', async () => { @@ -178,16 +174,17 @@ describe('routineProfileRefresh', () => { allConversations: [neverRefreshed, recentlyFetched], ourConversationId: UUID.generate().toString(), storage: makeStorage(), + getProfileFn, }); - sinon.assert.calledOnce(getProfileStub.getProfile as sinon.SinonStub); + sinon.assert.calledOnce(getProfileFn); sinon.assert.calledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, neverRefreshed.get('uuid'), neverRefreshed.get('e164') ); sinon.assert.neverCalledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, recentlyFetched.get('uuid'), recentlyFetched.get('e164') ); @@ -220,30 +217,31 @@ describe('routineProfileRefresh', () => { ], ourConversationId: UUID.generate().toString(), storage: makeStorage(), + getProfileFn, }); sinon.assert.calledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, privateConversation.get('uuid'), privateConversation.get('e164') ); sinon.assert.calledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, recentlyActiveGroupMember.get('uuid'), recentlyActiveGroupMember.get('e164') ); sinon.assert.calledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, inactiveGroupMember.get('uuid'), inactiveGroupMember.get('e164') ); sinon.assert.neverCalledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, memberWhoHasRecentlyRefreshed.get('uuid'), memberWhoHasRecentlyRefreshed.get('e164') ); sinon.assert.neverCalledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, groupConversation.get('uuid'), groupConversation.get('e164') ); @@ -288,11 +286,12 @@ describe('routineProfileRefresh', () => { ], ourConversationId: me.id, storage: makeStorage(), + getProfileFn, }); [...activeConversations, ...inactiveGroupMembers].forEach(conversation => { sinon.assert.calledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, conversation.get('uuid'), conversation.get('e164') ); @@ -300,7 +299,7 @@ describe('routineProfileRefresh', () => { [me, ...shouldNotBeIncluded].forEach(conversation => { sinon.assert.neverCalledWith( - getProfileStub.getProfile as sinon.SinonStub, + getProfileFn, conversation.get('uuid'), conversation.get('e164') ); diff --git a/ts/test-electron/state/ducks/conversations_test.ts b/ts/test-electron/state/ducks/conversations_test.ts index 0a65ff48b07a..75797639bce3 100644 --- a/ts/test-electron/state/ducks/conversations_test.ts +++ b/ts/test-electron/state/ducks/conversations_test.ts @@ -1,4 +1,4 @@ -// Copyright 2020-2021 Signal Messenger, LLC +// Copyright 2020-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; @@ -31,7 +31,6 @@ import { ReadStatus } from '../../../messages/MessageReadStatus'; import { ContactSpoofingType } from '../../../util/contactSpoofing'; import { CallMode } from '../../../types/Calling'; import { UUID } from '../../../types/UUID'; -import * as groups from '../../../groups'; import { getDefaultConversation, getDefaultConversationWithUuid, @@ -42,6 +41,7 @@ import { defaultChooseGroupMembersComposerState, defaultSetGroupMetadataComposerState, } from '../../../test-both/helpers/defaultComposerStates'; +import { updateRemoteConfig } from '../../../test-both/helpers/RemoteConfigStub'; const { cantAddContactToGroup, @@ -83,7 +83,7 @@ describe('both/state/ducks/conversations', () => { sinonSandbox.stub(window.Whisper.events, 'trigger'); - createGroupStub = sinonSandbox.stub(groups, 'createGroupV2'); + createGroupStub = sinon.stub(); }); afterEach(() => { @@ -686,7 +686,7 @@ describe('both/state/ducks/conversations', () => { }); it('calls groups.createGroupV2', async () => { - await createGroup()( + await createGroup(createGroupStub)( sinon.spy(), () => ({ ...getEmptyRootState(), @@ -706,7 +706,7 @@ describe('both/state/ducks/conversations', () => { }); it("trims the group's title before calling groups.createGroupV2", async () => { - await createGroup()( + await createGroup(createGroupStub)( sinon.spy(), () => ({ ...getEmptyRootState(), @@ -732,7 +732,7 @@ describe('both/state/ducks/conversations', () => { const dispatch = sinon.spy(); - const createGroupPromise = createGroup()( + const createGroupPromise = createGroup(createGroupStub)( dispatch, () => ({ ...getEmptyRootState(), @@ -764,7 +764,7 @@ describe('both/state/ducks/conversations', () => { const dispatch = sinon.spy(); - const createGroupPromise = createGroup()( + const createGroupPromise = createGroup(createGroupStub)( dispatch, () => ({ ...getEmptyRootState(), @@ -796,7 +796,7 @@ describe('both/state/ducks/conversations', () => { const dispatch = sinon.spy(); - await createGroup()( + await createGroup(createGroupStub)( dispatch, () => ({ ...getEmptyRootState(), @@ -1572,15 +1572,15 @@ describe('both/state/ducks/conversations', () => { return dispatch.getCall(0).args[0]; } - let remoteConfigGetValueStub: sinon.SinonStub; - - beforeEach(() => { - remoteConfigGetValueStub = sinonSandbox - .stub(window.Signal.RemoteConfig, 'getValue') - .withArgs('global.groupsv2.maxGroupSize') - .returns('22') - .withArgs('global.groupsv2.groupSizeHardLimit') - .returns('33'); + beforeEach(async () => { + await updateRemoteConfig([ + { name: 'global.groupsv2.maxGroupSize', value: '22', enabled: true }, + { + name: 'global.groupsv2.groupSizeHardLimit', + value: '33', + enabled: true, + }, + ]); }); it('adds conversation IDs to the list', () => { @@ -1657,11 +1657,21 @@ describe('both/state/ducks/conversations', () => { }); }); - it('defaults the maximum recommended size to 151', () => { - [undefined, 'xyz'].forEach(value => { - remoteConfigGetValueStub - .withArgs('global.groupsv2.maxGroupSize') - .returns(value); + it('defaults the maximum recommended size to 151', async () => { + for (const value of [null, 'xyz']) { + // eslint-disable-next-line no-await-in-loop + await updateRemoteConfig([ + { + name: 'global.groupsv2.maxGroupSize', + value, + enabled: true, + }, + { + name: 'global.groupsv2.groupSizeHardLimit', + value: '33', + enabled: true, + }, + ]); const state = { ...getEmptyState(), @@ -1670,7 +1680,7 @@ describe('both/state/ducks/conversations', () => { const action = getAction(uuid(), state); assert.strictEqual(action.payload.maxRecommendedGroupSize, 151); - }); + } }); it('shows the maximum group size modal when first reaching the maximum group size', () => { @@ -1735,13 +1745,17 @@ describe('both/state/ducks/conversations', () => { assert.deepEqual(result, state); }); - it('defaults the maximum group size to 1001 if the recommended maximum is smaller', () => { - [undefined, 'xyz'].forEach(value => { - remoteConfigGetValueStub - .withArgs('global.groupsv2.maxGroupSize') - .returns('2') - .withArgs('global.groupsv2.groupSizeHardLimit') - .returns(value); + it('defaults the maximum group size to 1001 if the recommended maximum is smaller', async () => { + for (const value of [null, 'xyz']) { + // eslint-disable-next-line no-await-in-loop + await updateRemoteConfig([ + { name: 'global.groupsv2.maxGroupSize', value: '2', enabled: true }, + { + name: 'global.groupsv2.groupSizeHardLimit', + value, + enabled: true, + }, + ]); const state = { ...getEmptyState(), @@ -1750,15 +1764,22 @@ describe('both/state/ducks/conversations', () => { const action = getAction(uuid(), state); assert.strictEqual(action.payload.maxGroupSize, 1001); - }); + } }); - it('defaults the maximum group size to (recommended maximum + 1) if the recommended maximum is more than 1001', () => { - remoteConfigGetValueStub - .withArgs('global.groupsv2.maxGroupSize') - .returns('1234') - .withArgs('global.groupsv2.groupSizeHardLimit') - .returns('2'); + it('defaults the maximum group size to (recommended maximum + 1) if the recommended maximum is more than 1001', async () => { + await updateRemoteConfig([ + { + name: 'global.groupsv2.maxGroupSize', + value: '1234', + enabled: true, + }, + { + name: 'global.groupsv2.groupSizeHardLimit', + value: '2', + enabled: true, + }, + ]); const state = { ...getEmptyState(), diff --git a/ts/test-node/components/leftPane/LeftPaneChooseGroupMembersHelper_test.ts b/ts/test-node/components/leftPane/LeftPaneChooseGroupMembersHelper_test.ts index e56249b97fb5..31687af48009 100644 --- a/ts/test-node/components/leftPane/LeftPaneChooseGroupMembersHelper_test.ts +++ b/ts/test-node/components/leftPane/LeftPaneChooseGroupMembersHelper_test.ts @@ -1,15 +1,15 @@ -// Copyright 2021 Signal Messenger, LLC +// Copyright 2021-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; import * as sinon from 'sinon'; import { times } from 'lodash'; import { RowType } from '../../../components/ConversationList'; -import * as remoteConfig from '../../../RemoteConfig'; import { ContactCheckboxDisabledReason } from '../../../components/conversationList/ContactCheckbox'; import { getDefaultConversation } from '../../../test-both/helpers/getDefaultConversation'; import { LeftPaneChooseGroupMembersHelper } from '../../../components/leftPane/LeftPaneChooseGroupMembersHelper'; +import { updateRemoteConfig } from '../../../test-both/helpers/RemoteConfigStub'; describe('LeftPaneChooseGroupMembersHelper', () => { const defaults = { @@ -21,21 +21,15 @@ describe('LeftPaneChooseGroupMembersHelper', () => { selectedContacts: [], }; - let sinonSandbox: sinon.SinonSandbox; - - beforeEach(() => { - sinonSandbox = sinon.createSandbox(); - - sinonSandbox - .stub(remoteConfig, 'getValue') - .withArgs('global.groupsv2.maxGroupSize') - .returns('22') - .withArgs('global.groupsv2.groupSizeHardLimit') - .returns('33'); - }); - - afterEach(() => { - sinonSandbox.restore(); + beforeEach(async () => { + await updateRemoteConfig([ + { name: 'global.groupsv2.maxGroupSize', value: '22', enabled: true }, + { + name: 'global.groupsv2.groupSizeHardLimit', + value: '33', + enabled: true, + }, + ]); }); describe('getBackAction', () => { diff --git a/ts/types/Attachment.ts b/ts/types/Attachment.ts index 02e15156591c..db8e6d90bb87 100644 --- a/ts/types/Attachment.ts +++ b/ts/types/Attachment.ts @@ -1,4 +1,4 @@ -// Copyright 2018-2021 Signal Messenger, LLC +// Copyright 2018-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import is from '@sindresorhus/is'; @@ -323,7 +323,7 @@ export function removeSchemaVersion({ attachment: AttachmentType; logger: LoggerType; }): AttachmentType { - if (!exports.isValid(attachment)) { + if (!isValid(attachment)) { logger.error( 'Attachment.removeSchemaVersion: Invalid input attachment:', attachment diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index 880f16431a53..138e8ed2cf9b 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -6945,22 +6945,6 @@ "reasonCategory": "falseMatch", "updated": "2020-07-21T18:34:59.251Z" }, - { - "rule": "DOM-innerHTML", - "path": "ts/backbone/views/Lightbox.js", - "line": " container.innerHTML = '';", - "reasonCategory": "usageTrusted", - "updated": "2018-09-17T20:50:40.689Z", - "reasonDetail": "Hard-coded value" - }, - { - "rule": "DOM-innerHTML", - "path": "ts/backbone/views/Lightbox.js", - "line": " container.innerHTML = '';", - "reasonCategory": "usageTrusted", - "updated": "2018-09-17T20:50:40.689Z", - "reasonDetail": "Hard-coded value" - }, { "rule": "DOM-innerHTML", "path": "ts/backbone/views/Lightbox.ts", @@ -6977,14 +6961,6 @@ "updated": "2018-09-17T20:50:40.689Z", "reasonDetail": "Hard-coded value" }, - { - "rule": "jQuery-html(", - "path": "ts/backbone/views/whisper_view.js", - "line": " this.$el.html(window.Mustache.render(template, attrs));", - "reasonCategory": "usageTrusted", - "updated": "2021-02-26T18:44:56.450Z", - "reasonDetail": "Rendering provided template" - }, { "rule": "jQuery-html(", "path": "ts/backbone/views/whisper_view.ts", @@ -7001,20 +6977,6 @@ "updated": "2021-12-10T23:24:03.829Z", "reasonDetail": "Doesn't touch the DOM." }, - { - "rule": "jQuery-load(", - "path": "ts/challenge.js", - "line": " async load() {", - "reasonCategory": "falseMatch", - "updated": "2021-05-05T23:11:22.692Z" - }, - { - "rule": "jQuery-load(", - "path": "ts/challenge.js", - "line": " // 1. `.load()` when the `window.storage` is ready", - "reasonCategory": "falseMatch", - "updated": "2021-05-05T23:11:22.692Z" - }, { "rule": "jQuery-load(", "path": "ts/challenge.ts", @@ -7100,14 +7062,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-12-01T01:31:12.757Z" }, - { - "rule": "React-useRef", - "path": "ts/components/CallingLobby.js", - "line": " const localVideoRef = react_1.default.useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2020-10-26T19:12:24.410Z", - "reasonDetail": "Used to get the local video element for rendering." - }, { "rule": "React-useRef", "path": "ts/components/CallingLobby.tsx", @@ -7115,22 +7069,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-07-30T16:57:33.618Z" }, - { - "rule": "React-useRef", - "path": "ts/components/CallingPip.js", - "line": " const videoContainerRef = react_1.default.useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2020-10-26T19:12:24.410Z", - "reasonDetail": "Element is measured. Its HTML is not used." - }, - { - "rule": "React-useRef", - "path": "ts/components/CallingPip.js", - "line": " const localVideoRef = react_1.default.useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2020-10-26T19:12:24.410Z", - "reasonDetail": "Used to get the local video element for rendering." - }, { "rule": "React-useRef", "path": "ts/components/CallingPip.tsx", @@ -7181,61 +7119,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-09-23T00:07:11.885Z" }, - { - "rule": "React-useRef", - "path": "ts/components/CompositionInput.js", - "line": " const emojiCompletionRef = React.useRef();", - "reasonCategory": "falseMatch", - "updated": "2020-10-26T19:12:24.410Z", - "reasonDetail": "Doesn't refer to a DOM element." - }, - { - "rule": "React-useRef", - "path": "ts/components/CompositionInput.js", - "line": " const quillRef = React.useRef();", - "reasonCategory": "falseMatch", - "updated": "2020-10-26T19:12:24.410Z", - "reasonDetail": "Doesn't refer to a DOM element." - }, - { - "rule": "React-useRef", - "path": "ts/components/CompositionInput.js", - "line": " const propsRef = React.useRef(props);", - "reasonCategory": "falseMatch", - "updated": "2020-10-26T19:12:24.410Z", - "reasonDetail": "Doesn't refer to a DOM element." - }, - { - "rule": "React-useRef", - "path": "ts/components/CompositionInput.js", - "line": " const mentionCompletionRef = React.useRef();", - "reasonCategory": "falseMatch", - "updated": "2020-10-26T23:54:34.273Z", - "reasonDetail": "Doesn't refer to a DOM element." - }, - { - "rule": "React-useRef", - "path": "ts/components/CompositionInput.js", - "line": " const memberRepositoryRef = React.useRef(new memberRepository_1.MemberRepository());", - "reasonCategory": "falseMatch", - "updated": "2020-10-26T23:56:13.482Z", - "reasonDetail": "Doesn't refer to a DOM element." - }, - { - "rule": "React-useRef", - "path": "ts/components/CompositionInput.js", - "line": " const scrollerRef = React.useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2020-10-26T19:12:24.410Z", - "reasonDetail": "Used with Quill for scrolling." - }, - { - "rule": "React-useRef", - "path": "ts/components/CompositionInput.js", - "line": " const callbacksRef = React.useRef(unstaleCallbacks);", - "reasonCategory": "usageTrusted", - "updated": "2021-04-21T21:35:38.757Z" - }, { "rule": "React-useRef", "path": "ts/components/CompositionInput.tsx", @@ -7306,13 +7189,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-07-30T16:57:33.618Z" }, - { - "rule": "React-useRef", - "path": "ts/components/ForwardMessageModal.js", - "line": " const inputApiRef = react_1.default.useRef();", - "reasonCategory": "usageTrusted", - "updated": "2021-04-19T18:13:21.664Z" - }, { "rule": "React-useRef", "path": "ts/components/ForwardMessageModal.tsx", @@ -7414,13 +7290,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-07-30T16:57:33.618Z" }, - { - "rule": "jQuery-$(", - "path": "ts/components/Intl.js", - "line": " const FIND_REPLACEMENTS = /\\$([^$]+)\\$/g;", - "reasonCategory": "falseMatch", - "updated": "2020-07-21T18:34:59.251Z" - }, { "rule": "jQuery-$(", "path": "ts/components/Intl.tsx", @@ -7515,14 +7384,6 @@ "updated": "2022-01-04T21:43:17.517Z", "reasonDetail": "Used to change the style in non-production builds." }, - { - "rule": "React-createRef", - "path": "ts/components/SafetyNumberChangeDialog.js", - "line": " const cancelButtonRef = React.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2020-06-23T06:48:06.829Z", - "reasonDetail": "Used to focus cancel button when dialog opens" - }, { "rule": "React-useRef", "path": "ts/components/Slider.tsx", @@ -7558,14 +7419,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-11-30T10:15:33.662Z" }, - { - "rule": "React-useRef", - "path": "ts/components/Tooltip.js", - "line": " const wrapperRef = react_1.default.useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2020-12-04T00:11:08.128Z", - "reasonDetail": "Used to add (and remove) event listeners." - }, { "rule": "React-useRef", "path": "ts/components/Tooltip.tsx", @@ -7573,22 +7426,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-07-30T16:57:33.618Z" }, - { - "rule": "React-createRef", - "path": "ts/components/conversation/ConversationHeader.js", - "line": " this.menuTriggerRef = react_1.default.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2020-08-28T16:12:19.904Z", - "reasonDetail": "Used to reference popup menu" - }, - { - "rule": "React-createRef", - "path": "ts/components/conversation/ConversationHeader.js", - "line": " this.headerRef = react_1.default.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2021-01-18T22:24:05.937Z", - "reasonDetail": "Used to reference popup menu boundaries element" - }, { "rule": "React-createRef", "path": "ts/components/conversation/ConversationHeader.tsx", @@ -7627,14 +7464,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-07-30T16:57:33.618Z" }, - { - "rule": "React-createRef", - "path": "ts/components/conversation/InlineNotificationWrapper.js", - "line": " this.focusRef = react_1.default.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2019-11-06T19:56:38.557Z", - "reasonDetail": "Used to manage focus" - }, { "rule": "React-createRef", "path": "ts/components/conversation/InlineNotificationWrapper.tsx", @@ -7643,30 +7472,6 @@ "updated": "2019-11-06T19:56:38.557Z", "reasonDetail": "Used to manage focus" }, - { - "rule": "React-createRef", - "path": "ts/components/conversation/Message.js", - "line": " this.reactionsContainerRef = react_1.default.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2020-08-28T16:12:19.904Z", - "reasonDetail": "Used for detecting clicks outside reaction viewer" - }, - { - "rule": "React-createRef", - "path": "ts/components/conversation/Message.js", - "line": " this.focusRef = react_1.default.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2021-03-05T20:05:07.474Z", - "reasonDetail": "Used for managing focus only" - }, - { - "rule": "React-createRef", - "path": "ts/components/conversation/Message.js", - "line": " this.audioButtonRef = react_1.default.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2021-03-05T20:05:07.474Z", - "reasonDetail": "Used for propagating click from the Message to MessageAudio's button" - }, { "rule": "React-createRef", "path": "ts/components/conversation/Message.tsx", @@ -7698,22 +7503,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-07-30T16:57:33.618Z" }, - { - "rule": "React-createRef", - "path": "ts/components/conversation/MessageDetail.js", - "line": " this.focusRef = react_1.default.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2019-11-01T22:46:33.013Z", - "reasonDetail": "Used for setting focus only" - }, - { - "rule": "React-createRef", - "path": "ts/components/conversation/MessageDetail.js", - "line": " this.messageContainerRef = react_1.default.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2021-08-20T16:48:00.885Z", - "reasonDetail": "Needed to confine Poppers. We don't actually manipulate this DOM reference." - }, { "rule": "React-useRef", "path": "ts/components/conversation/Quote.tsx", @@ -7722,22 +7511,6 @@ "updated": "2021-01-20T21:30:08.430Z", "reasonDetail": "Doesn't touch the DOM." }, - { - "rule": "React-createRef", - "path": "ts/components/conversation/Timeline.js", - "line": " this.listRef = react_1.default.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2019-07-31T00:19:18.696Z", - "reasonDetail": "Timeline needs to interact with its child List directly" - }, - { - "rule": "React-createRef", - "path": "ts/components/conversation/Timeline.js", - "line": " this.containerRef = react_1.default.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2021-08-20T16:48:00.885Z", - "reasonDetail": "Needed to confine Poppers. We don't actually manipulate this DOM reference." - }, { "rule": "React-useRef", "path": "ts/components/conversation/conversation-details/AddGroupMembersModal/ChooseGroupMembersModal.tsx", @@ -7766,14 +7539,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-07-30T16:57:33.618Z" }, - { - "rule": "React-createRef", - "path": "ts/components/conversation/media-gallery/MediaGallery.js", - "line": " this.focusRef = react_1.default.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2019-11-01T22:46:33.013Z", - "reasonDetail": "Used for setting focus only" - }, { "rule": "React-createRef", "path": "ts/components/conversation/media-gallery/MediaGallery.tsx", @@ -7790,14 +7555,6 @@ "updated": "2021-12-06T23:07:28.947Z", "reasonDetail": "Doesn't touch the DOM." }, - { - "rule": "React-createRef", - "path": "ts/components/stickers/StickerManager.js", - "line": " const focusRef = React.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2019-11-21T06:13:49.384Z", - "reasonDetail": "Used for setting focus only" - }, { "rule": "React-useRef", "path": "ts/hooks/useIntersectionObserver.ts", @@ -7812,35 +7569,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-09-17T20:16:37.959Z" }, - { - "rule": "React-useRef", - "path": "ts/hooks/useRestoreFocus.js", - "line": " const lastFocusedRef = React.useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2021-07-30T01:08:01.309Z", - "reasonDetail": "Used to store the previous-focused item, again to set focus" - }, - { - "rule": "React-useRef", - "path": "ts/hooks/useRestoreFocus.js", - "line": " const toFocusRef = React.useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2021-09-17T17:37:46.279Z" - }, - { - "rule": "React-useRef", - "path": "ts/hooks/useRestoreFocus.js", - "line": " const toFocusRef = React.useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2021-10-22T00:52:39.251Z" - }, - { - "rule": "React-useRef", - "path": "ts/hooks/useRestoreFocus.js", - "line": " const lastFocusedRef = React.useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2021-10-22T00:52:39.251Z" - }, { "rule": "React-useRef", "path": "ts/hooks/useRestoreFocus.ts", @@ -7869,13 +7597,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-10-22T00:52:39.251Z" }, - { - "rule": "jQuery-load(", - "path": "ts/jobs/helpers/syncHelpers.js", - "line": " await window.ConversationController.load();", - "reasonCategory": "falseMatch", - "updated": "2021-12-15T19:58:28.089Z" - }, { "rule": "jQuery-load(", "path": "ts/jobs/helpers/syncHelpers.ts", @@ -7883,13 +7604,6 @@ "reasonCategory": "falseMatch", "updated": "2021-11-04T16:14:03.477Z" }, - { - "rule": "jQuery-load(", - "path": "ts/jobs/normalMessageSendJobQueue.js", - "line": " await window.ConversationController.load();", - "reasonCategory": "falseMatch", - "updated": "2021-11-04T16:14:03.477Z" - }, { "rule": "jQuery-load(", "path": "ts/jobs/normalMessageSendJobQueue.ts", @@ -7897,13 +7611,6 @@ "reasonCategory": "falseMatch", "updated": "2021-12-15T19:58:28.089Z" }, - { - "rule": "jQuery-load(", - "path": "ts/jobs/reactionJobQueue.js", - "line": " await window.ConversationController.load();", - "reasonCategory": "falseMatch", - "updated": "2021-11-04T16:14:03.477Z" - }, { "rule": "jQuery-load(", "path": "ts/jobs/reactionJobQueue.ts", @@ -7911,34 +7618,6 @@ "reasonCategory": "falseMatch", "updated": "2021-11-04T16:14:03.477Z" }, - { - "rule": "jQuery-append(", - "path": "ts/logging/uploadDebugLog.js", - "line": " form.append('key', uploadKey);", - "reasonCategory": "falseMatch", - "updated": "2020-12-17T18:08:07.752Z" - }, - { - "rule": "jQuery-append(", - "path": "ts/logging/uploadDebugLog.js", - "line": " form.append(key, value);", - "reasonCategory": "falseMatch", - "updated": "2020-12-17T18:08:07.752Z" - }, - { - "rule": "jQuery-append(", - "path": "ts/logging/uploadDebugLog.js", - "line": " form.append('Content-Type', contentType);", - "reasonCategory": "falseMatch", - "updated": "2020-12-17T18:08:07.752Z" - }, - { - "rule": "jQuery-append(", - "path": "ts/logging/uploadDebugLog.js", - "line": " form.append('file', contentBuffer, {", - "reasonCategory": "falseMatch", - "updated": "2020-12-17T18:08:07.752Z" - }, { "rule": "jQuery-append(", "path": "ts/logging/uploadDebugLog.ts", @@ -7967,22 +7646,6 @@ "reasonCategory": "falseMatch", "updated": "2020-12-17T18:08:07.752Z" }, - { - "rule": "jQuery-$(", - "path": "ts/manage_full_screen_class.js", - "line": "$(document).ready(() => {", - "reasonCategory": "usageTrusted", - "updated": "2021-01-21T23:06:13.270Z", - "reasonDetail": "Doesn't manipulate the DOM." - }, - { - "rule": "jQuery-$(", - "path": "ts/manage_full_screen_class.js", - "line": " $(document.body).toggleClass('full-screen', isFullScreen);", - "reasonCategory": "usageTrusted", - "updated": "2021-01-21T23:06:13.270Z", - "reasonDetail": "Manipulates a trusted class." - }, { "rule": "jQuery-$(", "path": "ts/manage_full_screen_class.ts", @@ -7999,21 +7662,6 @@ "updated": "2021-01-21T23:06:13.270Z", "reasonDetail": "Manipulates a trusted class." }, - { - "rule": "React-createRef", - "path": "ts/quill/mentions/completion.js", - "line": " this.suggestionListRef = react_1.default.createRef();", - "reasonCategory": "usageTrusted", - "updated": "2020-10-30T23:03:08.319Z" - }, - { - "rule": "DOM-innerHTML", - "path": "ts/quill/signal-clipboard/index.js", - "line": " return div.innerHTML;", - "reasonCategory": "usageTrusted", - "updated": "2020-11-06T17:43:07.381Z", - "reasonDetail": "used for figuring out clipboard contents" - }, { "rule": "DOM-innerHTML", "path": "ts/quill/signal-clipboard/index.ts", @@ -8022,22 +7670,6 @@ "updated": "2020-11-06T17:43:07.381Z", "reasonDetail": "used for figuring out clipboard contents" }, - { - "rule": "jQuery-$(", - "path": "ts/set_os_class.js", - "line": " $(document.body).addClass(className);", - "reasonCategory": "usageTrusted", - "updated": "2021-01-21T23:06:13.270Z", - "reasonDetail": "Adds a trusted CSS class." - }, - { - "rule": "jQuery-$(", - "path": "ts/set_os_class.js", - "line": "$(document).ready(() => {", - "reasonCategory": "usageTrusted", - "updated": "2021-01-21T23:06:13.270Z", - "reasonDetail": "Doesn't manipulate the DOM." - }, { "rule": "jQuery-$(", "path": "ts/set_os_class.ts", @@ -8054,13 +7686,6 @@ "updated": "2021-01-21T23:06:13.270Z", "reasonDetail": "Doesn't manipulate the DOM." }, - { - "rule": "jQuery-load(", - "path": "ts/state/ducks/app.js", - "line": " await window.ConversationController.load();", - "reasonCategory": "falseMatch", - "updated": "2021-11-04T16:14:03.477Z" - }, { "rule": "jQuery-load(", "path": "ts/state/ducks/app.ts", @@ -8076,13 +7701,6 @@ "updated": "2021-12-06T23:07:28.947Z", "reasonDetail": "Doesn't touch the DOM." }, - { - "rule": "jQuery-load(", - "path": "ts/types/Stickers.js", - "line": "async function load() {", - "reasonCategory": "falseMatch", - "updated": "2021-07-02T02:57:58.052Z" - }, { "rule": "jQuery-load(", "path": "ts/types/Stickers.ts", @@ -8090,13 +7708,6 @@ "reasonCategory": "falseMatch", "updated": "2019-04-26T17:48:30.675Z" }, - { - "rule": "jQuery-load(", - "path": "ts/util/avatarDataToBytes.js", - "line": " await font.load();", - "reasonCategory": "usageTrusted", - "updated": "2021-08-03T21:17:38.615Z" - }, { "rule": "jQuery-load(", "path": "ts/util/avatarDataToBytes.ts", @@ -8104,46 +7715,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-08-03T21:17:38.615Z" }, - { - "rule": "jQuery-$(", - "path": "ts/util/createIPCEvents.js", - "line": " if ($('.dark-overlay').length) {", - "reasonCategory": "usageTrusted", - "updated": "2021-08-18T18:22:55.307Z", - "reasonDetail": "Legacy code" - }, - { - "rule": "jQuery-$(", - "path": "ts/util/createIPCEvents.js", - "line": " $(document.body).prepend('
');", - "reasonCategory": "usageTrusted", - "updated": "2021-08-18T18:22:55.307Z", - "reasonDetail": "Legacy code" - }, - { - "rule": "jQuery-$(", - "path": "ts/util/createIPCEvents.js", - "line": " $('.dark-overlay').on('click', () => $('.dark-overlay').remove());", - "reasonCategory": "usageTrusted", - "updated": "2021-08-18T18:22:55.307Z", - "reasonDetail": "Legacy code" - }, - { - "rule": "jQuery-$(", - "path": "ts/util/createIPCEvents.js", - "line": " }, removeDarkOverlay: () => $('.dark-overlay').remove(), showKeyboardShortcuts: () => window.showKeyboardShortcuts(), deleteAllData: async () => {", - "reasonCategory": "usageTrusted", - "updated": "2021-08-18T18:22:55.307Z", - "reasonDetail": "Legacy code" - }, - { - "rule": "jQuery-prepend(", - "path": "ts/util/createIPCEvents.js", - "line": " $(document.body).prepend('
');", - "reasonCategory": "usageTrusted", - "updated": "2021-08-18T18:22:55.307Z", - "reasonDetail": "Legacy code" - }, { "rule": "jQuery-$(", "path": "ts/util/createIPCEvents.ts", @@ -8184,13 +7755,6 @@ "updated": "2021-08-18T18:22:55.307Z", "reasonDetail": "Legacy code" }, - { - "rule": "jQuery-load(", - "path": "ts/util/sendReceipts.js", - "line": " await window.ConversationController.load();", - "reasonCategory": "falseMatch", - "updated": "2021-12-15T19:58:28.089Z" - }, { "rule": "jQuery-load(", "path": "ts/util/sendReceipts.ts", @@ -8198,13 +7762,6 @@ "reasonCategory": "falseMatch", "updated": "2021-12-15T19:58:28.089Z" }, - { - "rule": "jQuery-$(", - "path": "ts/util/setupI18n.js", - "line": " const FIND_REPLACEMENTS = /\\$([^$]+)\\$/g;", - "reasonCategory": "falseMatch", - "updated": "2021-09-17T21:51:57.475Z" - }, { "rule": "jQuery-$(", "path": "ts/util/setupI18n.ts", @@ -8212,90 +7769,6 @@ "reasonCategory": "falseMatch", "updated": "2021-09-17T21:51:57.475Z" }, - { - "rule": "jQuery-$(", - "path": "ts/views/inbox_view.js", - "line": " template: () => $('#app-loading-screen').html(),", - "reasonCategory": "usageTrusted", - "updated": "2021-09-15T21:07:50.995Z" - }, - { - "rule": "jQuery-$(", - "path": "ts/views/inbox_view.js", - "line": " this.$('.message').text(message);", - "reasonCategory": "usageTrusted", - "updated": "2021-09-15T21:07:50.995Z" - }, - { - "rule": "jQuery-$(", - "path": "ts/views/inbox_view.js", - "line": " template: () => $('#two-column').html(),", - "reasonCategory": "usageTrusted", - "updated": "2021-09-15T21:07:50.995Z" - }, - { - "rule": "jQuery-$(", - "path": "ts/views/inbox_view.js", - "line": " el: this.$('.conversation-stack'),", - "reasonCategory": "usageTrusted", - "updated": "2021-09-15T21:07:50.995Z" - }, - { - "rule": "jQuery-$(", - "path": "ts/views/inbox_view.js", - "line": " this.$('.left-pane-placeholder').replaceWith(this.leftPaneView.el);", - "reasonCategory": "usageTrusted", - "updated": "2021-10-08T17:39:41.541Z" - }, - { - "rule": "jQuery-$(", - "path": "ts/views/inbox_view.js", - "line": " this.$('.no-conversation-open').toggle(!isAnyConversationOpen);", - "reasonCategory": "usageTrusted", - "updated": "2021-10-08T17:40:22.770Z" - }, - { - "rule": "jQuery-$(", - "path": "ts/views/inbox_view.js", - "line": " this.$('.whats-new-placeholder').append(this.whatsNewLink.el);", - "reasonCategory": "usageTrusted", - "updated": "2021-10-22T20:58:48.103Z" - }, - { - "rule": "jQuery-append(", - "path": "ts/views/inbox_view.js", - "line": " this.$('.whats-new-placeholder').append(this.whatsNewLink.el);", - "reasonCategory": "usageTrusted", - "updated": "2021-10-22T20:58:48.103Z" - }, - { - "rule": "jQuery-appendTo(", - "path": "ts/views/inbox_view.js", - "line": " view.$el.appendTo(this.el);", - "reasonCategory": "usageTrusted", - "updated": "2021-09-20T22:27:31.785Z" - }, - { - "rule": "jQuery-html(", - "path": "ts/views/inbox_view.js", - "line": " template: () => $('#app-loading-screen').html(),", - "reasonCategory": "usageTrusted", - "updated": "2021-09-15T21:07:50.995Z" - }, - { - "rule": "jQuery-html(", - "path": "ts/views/inbox_view.js", - "line": " template: () => $('#two-column').html(),", - "reasonCategory": "usageTrusted", - "updated": "2021-09-15T21:07:50.995Z" - }, - { - "rule": "jQuery-prependTo(", - "path": "ts/views/inbox_view.js", - "line": " this.appLoadingScreen.$el.prependTo(this.el);", - "reasonCategory": "usageTrusted", - "updated": "2021-09-15T21:07:50.995Z" - }, { "rule": "jQuery-$(", "path": "ts/views/inbox_view.ts", @@ -8380,13 +7853,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-09-15T21:07:50.995Z" }, - { - "rule": "DOM-innerHTML", - "path": "ts/windows/loading/start.js", - "line": " message.innerHTML = window.SignalContext.i18n('optimizingApplication');", - "reasonCategory": "usageTrusted", - "updated": "2021-09-17T21:02:59.414Z" - }, { "rule": "DOM-innerHTML", "path": "ts/windows/loading/start.ts", diff --git a/ts/util/lint/linter.ts b/ts/util/lint/linter.ts index 630cb473ddd7..c59910236afb 100644 --- a/ts/util/lint/linter.ts +++ b/ts/util/lint/linter.ts @@ -31,6 +31,9 @@ const excludedFilesRegexp = RegExp( '.+\\.stories\\.js', '.+\\.stories\\.tsx', + // Compiled files + '^ts/.+\\.js', + // High-traffic files in our project '^app/.+(ts|js)', '^ts/models/messages.js', @@ -74,6 +77,7 @@ const excludedFilesRegexp = RegExp( '^.github/.+', // Modules we trust + '^node_modules/@signalapp/signal-client/.+', '^node_modules/core-js-pure/.+', '^node_modules/core-js/.+', '^node_modules/fbjs/.+', @@ -104,6 +108,7 @@ const excludedFilesRegexp = RegExp( '^node_modules/react-color/.+/(?:core-js|fbjs|lodash)/.+', // Modules used only in test/development scenarios + '^node_modules/esbuild/.+', '^node_modules/@babel/.+', '^node_modules/@chanzuckerberg/axe-storybook-testing/.+', '^node_modules/@svgr/.+', diff --git a/tsconfig.json b/tsconfig.json index 84062611ab35..7b012e701539 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { // Basic Options - "target": "es2017", // Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. + "target": "es2020", // Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. "module": "commonjs", // Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. // Specify library files to be included in the compilation. "lib": [ diff --git a/webpack-heic-worker.config.ts b/webpack-heic-worker.config.ts deleted file mode 100644 index 9648cb8cf947..000000000000 --- a/webpack-heic-worker.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2019-2020 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -import { resolve } from 'path'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { Configuration } from 'webpack'; - -const context = __dirname; - -const workerConfig: Configuration = { - context, - mode: 'development', - devtool: false, - entry: ['./ts/workers/heicConverterWorker.js'], - target: 'node', - output: { - path: resolve(context, 'ts', 'workers'), - filename: 'heicConverter.bundle.js', - publicPath: './', - }, -}; - -export default [workerConfig]; diff --git a/webpack-preload.config.ts b/webpack-preload.config.ts deleted file mode 100644 index c84832942f78..000000000000 --- a/webpack-preload.config.ts +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2019-2022 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -import { resolve } from 'path'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { Configuration } from 'webpack'; -import TerserPlugin = require('terser-webpack-plugin'); - -const context = __dirname; -const { NODE_ENV: mode = 'development' } = process.env; - -const EXTERNAL_MODULE = new Set([ - '@signalapp/signal-client', - '@signalapp/signal-client/zkgroup', - 'backbone', - 'better-sqlite3', - 'fs-xattr', - 'fsevents', - 'got', - 'jquery', - 'mac-screen-capture-permissions', - 'node-fetch', - 'pino', - 'proxy-agent', - 'ringrtc', - 'sharp', - 'websocket', - - // Uses fast-glob and dynamic requires - './preload_test', - - // Needs to exports `electronRequire` - './ts/CI', -]); - -const preloadConfig: Configuration = { - context, - mode: mode as Configuration['mode'], - devtool: mode === 'development' ? 'inline-source-map' : false, - entry: ['./preload.js'], - // Stack-traces have to be readable so don't mangle function names. - optimization: { - minimizer: [ - new TerserPlugin({ - parallel: true, - terserOptions: { - mangle: false, - keep_classnames: true, - keep_fnames: true, - }, - }), - ], - }, - target: 'electron-preload', - output: { - path: resolve(context), - filename: 'preload.bundle.js', - publicPath: './', - }, - resolve: { - extensions: ['.js'], - alias: {}, - mainFields: ['browser', 'main'], - }, - externals: [ - ({ request = '' }, callback) => { - if (EXTERNAL_MODULE.has(request)) { - return callback(undefined, `commonjs2 ${request}`); - } - - callback(); - }, - ], -}; - -export default [preloadConfig]; diff --git a/webpack-sql-worker.config.ts b/webpack-sql-worker.config.ts deleted file mode 100644 index 9d2ae5411ea8..000000000000 --- a/webpack-sql-worker.config.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019-2020 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -import { resolve, join } from 'path'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { Configuration } from 'webpack'; - -const context = __dirname; - -// A path relative to `ts/sql/` in `asar.unpacked` -const libDir = join('..', '..', 'node_modules', 'better-sqlite3'); -const bindingFile = join(libDir, 'build', 'Release', 'better_sqlite3.node'); - -const workerConfig: Configuration = { - context, - mode: 'development', - devtool: false, - entry: ['./ts/sql/mainWorker.js'], - target: 'node', - output: { - path: resolve(context, 'ts', 'sql'), - filename: 'mainWorker.bundle.js', - publicPath: './', - }, - resolve: { - extensions: ['.js'], - alias: { - bindings: join(context, 'ts', 'sql', 'mainWorkerBindings.js'), - }, - }, - externals: { - 'better_sqlite3.node': `commonjs2 ${bindingFile}`, - }, -}; - -export default [workerConfig]; diff --git a/yarn.lock b/yarn.lock index fe8b96828fe8..8f7743be2a73 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1342,10 +1342,10 @@ "@react-spring/shared" "~9.4.0" "@react-spring/types" "~9.4.0" -"@signalapp/signal-client@0.11.1": - version "0.11.1" - resolved "https://registry.yarnpkg.com/@signalapp/signal-client/-/signal-client-0.11.1.tgz#f1f859453c2d187e5f47ab02707ae4580edaa6fc" - integrity sha512-TXvspNNq5fRMMM7SDMjSzPd7lBPRt7oSb5tzJNoLVHNOwwSAwdpo+P6fzN5LszeNJYNjOXlXTSuBD4HB8v4TMg== +"@signalapp/signal-client@0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@signalapp/signal-client/-/signal-client-0.12.4.tgz#19023456c9249db6afb01762b1841e18cc3614be" + integrity sha512-52XpJO2Xng4G+cV4ocV2uvzkSomVRodsyuILAx++o/A0jR4bup/thbvpJ/abi1oHOggdJJ0jn2nKgPl/2UAC2A== dependencies: node-gyp-build "^4.2.3" uuid "^8.3.0" @@ -6216,6 +6216,114 @@ es6-weak-map@^2.0.2: es6-iterator "^2.0.1" es6-symbol "^3.1.1" +esbuild-android-arm64@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.3.tgz#f0fc0a892dd6f2f42baf68f9ac24c9bfcfdaba20" + integrity sha512-v/vdnGJiSGWOAXzg422T9qb4S+P3tOaYtc5n3FDR27Bh3/xQDS7PdYz/yY7HhOlVp0eGwWNbPHEi8FcEhXjsuw== + +esbuild-darwin-64@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.3.tgz#074268b97df08dc2ea60ddd3c29b05fd93ff63d3" + integrity sha512-swY5OtEg6cfWdgc/XEjkBP7wXSyXXeZHEsWMdh1bDiN1D6GmRphk9SgKFKTj+P3ZHhOGIcC1+UdIwHk5bUcOig== + +esbuild-darwin-arm64@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.3.tgz#72a62c7e5c58a2321f0bb839f1368878d4a5a814" + integrity sha512-6i9dXPk8oT87wF6VHmwzSad76eMRU2Rt+GXrwF3Y4DCJgnPssJbabNQ9gurkuEX8M0YnEyJF0d1cR7rpTzcEiA== + +esbuild-freebsd-64@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.3.tgz#63f507254f41ccbab97bb6dce655e7dbc127f351" + integrity sha512-WDY5ENsmyceeE+95U3eI+FM8yARY5akWkf21M/x/+v2P5OVsYqCYELglSeAI5Y7bhteCVV3g4i2fRqtkmprdSA== + +esbuild-freebsd-arm64@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.3.tgz#6520f6c8339df943633586d0d597ac2ee1f1958d" + integrity sha512-4BEEGcP0wBzg04pCCWXlgaPuksQHHfwHvYgCIsi+7IsuB17ykt6MHhTkHR5b5pjI/jNtRhPfMsDODUyftQJgvw== + +esbuild-linux-32@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.3.tgz#813d7baf2d33675c9264a07b09a26c39d588abb2" + integrity sha512-8yhsnjLG/GwCA1RAIndjmCHWViRB2Ol0XeOh2fCXS9qF8tlVrJB7qAiHZpm2vXx+yjOA/bFLTxzU+5pMKqkn5A== + +esbuild-linux-64@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.3.tgz#6356ff2d2c6ec978eb6e794a8891cc5cfadab3f1" + integrity sha512-eNq4aixfbwXHIJq4bQDe+XaSNV1grxqpZYs/zHbp0HGHf6SBNlTI02uyTbYGpIzlXmCEPS9tpPCi7BTU45kcJQ== + +esbuild-linux-arm64@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.3.tgz#a289bb67a5207e021d1ac8cae3532771eda473a6" + integrity sha512-wPLyRoqoV/tEMQ7M24DpAmCMyKqBmtgZY35w2tXM8X5O5b2Ohi7fkPSmd6ZgLIxZIApWt88toA8RT0S7qoxcOA== + +esbuild-linux-arm@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.3.tgz#b193de64458d4829be18206e58d127296367c189" + integrity sha512-YcMvJHAQnWrWKb+eLxN9e/iWUC/3w01UF/RXuMknqOW3prX8UQ63QknWz9/RI8BY/sdrdgPEbSmsTU2jy2cayQ== + +esbuild-linux-mips64le@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.3.tgz#d3c826fc746f1cbf3aea696017b001625ea28b59" + integrity sha512-DdmfM5rcuoqjQL3px5MbquAjZWnySB5LdTrg52SSapp0gXMnGcsM6GY2WVta02CMKn5qi7WPVG4WbqTWE++tJw== + +esbuild-linux-ppc64le@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.3.tgz#483974c92555eefe86d623145ff5f328074b6c9b" + integrity sha512-ujdqryj0m135Ms9yaNDVFAcLeRtyftM/v2v7Osji5zElf2TivSMdFxdrYnYICuHfkm8c8gHg1ncwqitL0r+nnA== + +esbuild-netbsd-64@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.3.tgz#76442f9d2d6e6dc796d18eb321256ccdc68ead53" + integrity sha512-Z/UB9OUdwo1KDJCSGnVueDuKowRZRkduLvRMegHtDBHC3lS5LfZ3RdM1i+4MMN9iafyk8Q9FNcqIXI178ZujvA== + +esbuild-openbsd-64@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.3.tgz#13b0adfd39e165f0dfd30af3e629c601b1b5fa36" + integrity sha512-9I1uoMDeogq3zQuTe3qygmXYjImnvc6rBn51LLbLniQDlfvqHPBMnAZ/5KshwtXXIIMkCwByytDZdiuzRRlTvQ== + +esbuild-sunos-64@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.3.tgz#f8ce1a0c6f165b82d589c7f3de01baf094587fd2" + integrity sha512-pldqx/Adxl4V4ymiyKxOOyJmHn6nUIo3wqk2xBx07iDgmL2XTcDDQd7N4U4QGu9LnYN4ZF+8IdOYa3oRRpbjtg== + +esbuild-windows-32@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.3.tgz#f555cbf0fca5974c3c303d9d9ff0d39e08f26916" + integrity sha512-AqzvA/KbkC2m3kTXGpljLin3EttRbtoPTfBn6w6n2m9MWkTEbhQbE1ONoOBxhO5tExmyJdL/6B87TJJD5jEFBQ== + +esbuild-windows-64@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.3.tgz#02c9804f9ca5e587ccb8b18e46a00f9237e54689" + integrity sha512-HGg3C6113zLGB5hN41PROTnBuoh/arG2lQdOird6xFl9giff1cAfMQOUJUfODKD57dDqHjQ1YGW8gOkg0/IrWw== + +esbuild-windows-arm64@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.3.tgz#8bcf737feddde3ccf4d2d6d581b2422b45a9b6e2" + integrity sha512-qB2izYu4VpigGnOrAN2Yv7ICYLZWY/AojZtwFfteViDnHgW4jXPYkHQIXTISJbRz25H2cYiv+MfRQYK31RNjlw== + +esbuild@0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.3.tgz#38db1d26aaeccc43f478225974538e2c4de9d6b1" + integrity sha512-zyEC5hkguW2oieXRXp8VJzQdcO/1FxCS5GjzqOHItRlojXnx/cTavsrkxdWvBH9li2lUq0bN+LeeVEmyCwiR/Q== + optionalDependencies: + esbuild-android-arm64 "0.14.3" + esbuild-darwin-64 "0.14.3" + esbuild-darwin-arm64 "0.14.3" + esbuild-freebsd-64 "0.14.3" + esbuild-freebsd-arm64 "0.14.3" + esbuild-linux-32 "0.14.3" + esbuild-linux-64 "0.14.3" + esbuild-linux-arm "0.14.3" + esbuild-linux-arm64 "0.14.3" + esbuild-linux-mips64le "0.14.3" + esbuild-linux-ppc64le "0.14.3" + esbuild-netbsd-64 "0.14.3" + esbuild-openbsd-64 "0.14.3" + esbuild-sunos-64 "0.14.3" + esbuild-windows-32 "0.14.3" + esbuild-windows-64 "0.14.3" + esbuild-windows-arm64 "0.14.3" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"