Use esbuild

This commit is contained in:
Fedor Indutny 2022-02-11 13:38:52 -08:00 committed by GitHub
parent 3c1ccce9bd
commit 0174687542
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 528 additions and 906 deletions

View file

@ -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<LoggerType, 'warn'> = log
): Promise<Response> {
const urlsSeen = new Set<string>();
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<string | Uint8Array>,
httpCharset: string | null,
abortSignal: AbortSignal
abortSignal: AbortSignal,
logger: Pick<LoggerType, 'warn'> = log
): Promise<HTMLDocument> => {
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<LoggerType, 'warn'> = 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<LoggerType, 'warn'> = log
): Promise<null | LinkPreviewMetadata> {
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<LoggerType, 'warn'> = log
): Promise<null | LinkPreviewImage> {
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;
}

View file

@ -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<ConversationModel>;
ourConversationId: string;
storage: Pick<StorageInterface, 'get' | 'put'>;
getProfileFn?: typeof getProfile;
}): Promise<void> {
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()}`
);

View file

@ -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 =>

View file

@ -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);
});
});

View file

@ -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);
});
});

View file

@ -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<ReturnType<WebAPIType['getConfig']>>
): Promise<void> {
const fakeServer = {
async getConfig() {
return newConfig;
},
} as Partial<WebAPIType> as unknown as WebAPIType;
await refreshRemoteConfig(fakeServer);
}

View file

@ -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<LoggerType, 'warn'>;
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
)
);

View file

@ -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({

View file

@ -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')
);

View file

@ -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(),

View file

@ -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', () => {

View file

@ -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

View file

@ -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('<div class=\"dark-overlay\"></div>');",
"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('<div class=\"dark-overlay\"></div>');",
"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",

View file

@ -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/.+',