Convert signal.js and preload.js to Typescript

This commit is contained in:
Scott Nonnenberg
2022-06-13 14:39:35 -07:00
committed by GitHub
parent e18510e41c
commit 2464e0a9c1
94 changed files with 2113 additions and 1848 deletions
+9 -3
View File
@@ -83,6 +83,10 @@ export type AttachmentType = {
key?: string;
};
export type AttachmentWithHydratedData = AttachmentType & {
data: Uint8Array;
};
export enum TextAttachmentStyleType {
DEFAULT = 0,
REGULAR = 1,
@@ -379,19 +383,21 @@ export function hasData(attachment: AttachmentType): boolean {
export function loadData(
readAttachmentData: (path: string) => Promise<Uint8Array>
): (attachment?: AttachmentType) => Promise<AttachmentType> {
): (attachment: AttachmentType) => Promise<AttachmentWithHydratedData> {
if (!is.function_(readAttachmentData)) {
throw new TypeError("'readAttachmentData' must be a function");
}
return async (attachment?: AttachmentType): Promise<AttachmentType> => {
return async (
attachment: AttachmentType
): Promise<AttachmentWithHydratedData> => {
if (!isValid(attachment)) {
throw new TypeError("'attachment' is not valid");
}
const isAlreadyLoaded = Boolean(attachment.data);
if (isAlreadyLoaded) {
return attachment;
return attachment as AttachmentWithHydratedData;
}
if (!is.string(attachment.path)) {
+41 -22
View File
@@ -4,7 +4,7 @@
import { isFunction, isObject, isString, omit } from 'lodash';
import * as Contact from './EmbeddedContact';
import type { AttachmentType } from './Attachment';
import type { AttachmentType, AttachmentWithHydratedData } from './Attachment';
import {
autoOrientJPEG,
captureDimensionsAndScreenshot,
@@ -24,11 +24,10 @@ import type { EmbeddedContactType } from './EmbeddedContact';
import type {
MessageAttributesType,
PreviewMessageType,
PreviewType,
QuotedMessageType,
StickerMessageType,
} from '../model-types.d';
import type { LinkPreviewType } from './message/LinkPreviews';
import type { StickerType, StickerWithHydratedData } from './Stickers';
export { hasExpiration } from './Message';
@@ -45,7 +44,7 @@ export type ContextType = {
width: number;
height: number;
}>;
getRegionCode: () => string;
getRegionCode: () => string | undefined;
logger: LoggerType;
makeImageThumbnail: (params: {
size: number;
@@ -65,12 +64,12 @@ export type ContextType = {
maxVersion?: number;
revokeObjectUrl: (objectUrl: string) => void;
writeNewAttachmentData: (data: Uint8Array) => Promise<string>;
writeNewStickerData: (sticker: StickerMessageType) => Promise<string>;
writeNewStickerData: (data: Uint8Array) => Promise<string>;
};
type WriteExistingAttachmentDataType = (
attachment: Pick<AttachmentType, 'data' | 'path'>
) => Promise<void>;
) => Promise<string>;
export type ContextWithMessageType = ContextType & {
message: MessageAttributesType;
@@ -343,7 +342,7 @@ export const _mapPreviewAttachments =
);
}
const upgradeWithContext = async (preview: PreviewType) => {
const upgradeWithContext = async (preview: LinkPreviewType) => {
const { image } = preview;
if (!image) {
return preview;
@@ -544,7 +543,17 @@ export const processNewAttachment = async (
makeImageThumbnail,
makeVideoScreenshot,
logger,
}: ContextType
}: Pick<
ContextType,
| 'writeNewAttachmentData'
| 'getAbsoluteAttachmentPath'
| 'makeObjectUrl'
| 'revokeObjectUrl'
| 'getImageDimensions'
| 'makeImageThumbnail'
| 'makeVideoScreenshot'
| 'logger'
>
): Promise<AttachmentType> => {
if (!isFunction(writeNewAttachmentData)) {
throw new TypeError('context.writeNewAttachmentData is required');
@@ -595,13 +604,19 @@ export const processNewAttachment = async (
};
export const processNewSticker = async (
stickerData: StickerMessageType,
stickerData: Uint8Array,
{
writeNewStickerData,
getAbsoluteStickerPath,
getImageDimensions,
logger,
}: ContextType
}: Pick<
ContextType,
| 'writeNewStickerData'
| 'getAbsoluteStickerPath'
| 'getImageDimensions'
| 'logger'
>
): Promise<{ path: string; width: number; height: number }> => {
if (!isFunction(writeNewStickerData)) {
throw new TypeError('context.writeNewStickerData is required');
@@ -633,7 +648,7 @@ export const processNewSticker = async (
type LoadAttachmentType = (
attachment: AttachmentType
) => Promise<AttachmentType>;
) => Promise<AttachmentWithHydratedData>;
export const createAttachmentLoader = (
loadAttachmentData: LoadAttachmentType
@@ -694,16 +709,16 @@ export const loadContactData = (
loadAttachmentData: LoadAttachmentType
): ((
contact: Array<EmbeddedContactType> | undefined
) => Promise<Array<EmbeddedContactType> | null>) => {
) => Promise<Array<EmbeddedContactType> | undefined>) => {
if (!isFunction(loadAttachmentData)) {
throw new TypeError('loadContactData: loadAttachmentData is required');
}
return async (
contact: Array<EmbeddedContactType> | undefined
): Promise<Array<EmbeddedContactType> | null> => {
): Promise<Array<EmbeddedContactType> | undefined> => {
if (!contact) {
return null;
return undefined;
}
return Promise.all(
@@ -736,12 +751,14 @@ export const loadContactData = (
export const loadPreviewData = (
loadAttachmentData: LoadAttachmentType
): ((preview: PreviewMessageType) => Promise<PreviewMessageType>) => {
): ((
preview: Array<LinkPreviewType> | undefined
) => Promise<Array<LinkPreviewType>>) => {
if (!isFunction(loadAttachmentData)) {
throw new TypeError('loadPreviewData: loadAttachmentData is required');
}
return async (preview: PreviewMessageType) => {
return async (preview: Array<LinkPreviewType> | undefined) => {
if (!preview || !preview.length) {
return [];
}
@@ -763,14 +780,16 @@ export const loadPreviewData = (
export const loadStickerData = (
loadAttachmentData: LoadAttachmentType
): ((sticker: StickerMessageType) => Promise<StickerMessageType | null>) => {
): ((
sticker: StickerType | undefined
) => Promise<StickerWithHydratedData | undefined>) => {
if (!isFunction(loadAttachmentData)) {
throw new TypeError('loadStickerData: loadAttachmentData is required');
}
return async (sticker: StickerMessageType) => {
return async (sticker: StickerType | undefined) => {
if (!sticker || !sticker.data) {
return null;
return undefined;
}
return {
@@ -966,8 +985,8 @@ export const createAttachmentDataWriter = ({
};
const writePreviewImage = async (
item: PreviewType
): Promise<PreviewType> => {
item: LinkPreviewType
): Promise<LinkPreviewType> => {
const { image } = item;
if (!image) {
return omit(item, ['image']);
+66
View File
@@ -0,0 +1,66 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { z } from 'zod';
import { themeSettingSchema } from './StorageUIKeys';
import { environmentSchema } from '../environment';
const configRequiredStringSchema = z.string().nonempty();
export type ConfigRequiredStringType = z.infer<
typeof configRequiredStringSchema
>;
const configOptionalStringSchema = configRequiredStringSchema.or(z.undefined());
export type configOptionalStringType = z.infer<
typeof configOptionalStringSchema
>;
export const rendererConfigSchema = z.object({
appInstance: configOptionalStringSchema,
appStartInitialSpellcheckSetting: z.boolean(),
buildCreation: z.number(),
buildExpiration: z.number(),
cdnUrl0: configRequiredStringSchema,
cdnUrl2: configRequiredStringSchema,
certificateAuthority: configRequiredStringSchema,
contentProxyUrl: configRequiredStringSchema,
crashDumpsPath: configRequiredStringSchema,
directoryEnclaveId: configOptionalStringSchema,
directoryTrustAnchor: configOptionalStringSchema,
directoryUrl: configOptionalStringSchema,
directoryV2CodeHashes: z.array(z.string().nonempty()).or(z.undefined()),
directoryV2PublicKey: configOptionalStringSchema,
directoryV2Url: configOptionalStringSchema,
directoryVersion: z.number(),
enableCI: z.boolean(),
environment: environmentSchema,
homePath: configRequiredStringSchema,
hostname: configRequiredStringSchema,
locale: configRequiredStringSchema,
name: configRequiredStringSchema,
nodeVersion: configRequiredStringSchema,
proxyUrl: configOptionalStringSchema,
reducedMotionSetting: z.boolean(),
serverPublicParams: configRequiredStringSchema,
serverTrustRoot: configRequiredStringSchema,
serverUrl: configRequiredStringSchema,
sfuUrl: configRequiredStringSchema,
storageUrl: configRequiredStringSchema,
theme: themeSettingSchema,
updatesUrl: configRequiredStringSchema,
userDataPath: configRequiredStringSchema,
version: configRequiredStringSchema,
// Only used by main window
isMainWindowFullScreen: z.boolean(),
// Only for tests
argv: configOptionalStringSchema,
// Only for permission popup window
forCalling: z.boolean(),
forCamera: z.boolean(),
});
export type RendererConfigType = z.infer<typeof rendererConfigSchema>;
+38 -15
View File
@@ -12,12 +12,12 @@ import { maybeParseUrl } from '../util/url';
import * as Bytes from '../Bytes';
import * as Errors from './errors';
import { deriveStickerPackKey, decryptAttachment } from '../Crypto';
import type { MIMEType } from './MIME';
import { IMAGE_WEBP } from './MIME';
import type { MIMEType } from './MIME';
import { sniffImageMimeType } from '../util/sniffImageMimeType';
import type { AttachmentType } from './Attachment';
import type { AttachmentType, AttachmentWithHydratedData } from './Attachment';
import type {
StickerType,
StickerType as StickerFromDBType,
StickerPackType,
StickerPackStatusType,
} from '../sql/Interface';
@@ -26,6 +26,20 @@ import { SignalService as Proto } from '../protobuf';
import * as log from '../logging/log';
import type { StickersStateType } from '../state/ducks/stickers';
export type StickerType = {
packId: string;
stickerId: number;
packKey: string;
emoji?: string;
data?: AttachmentType;
path?: string;
width?: number;
height?: number;
};
export type StickerWithHydratedData = StickerType & {
data: AttachmentWithHydratedData;
};
export type RecentStickerType = Readonly<{
stickerId: number;
packId: string;
@@ -300,11 +314,16 @@ async function downloadSticker(
packKey: string,
proto: Proto.StickerPack.ISticker,
{ ephemeral }: { ephemeral?: boolean } = {}
): Promise<Omit<StickerType, 'isCoverOnly'>> {
): Promise<Omit<StickerFromDBType, 'isCoverOnly'>> {
const { id, emoji } = proto;
strictAssert(id !== undefined && id !== null, "Sticker id can't be null");
const ciphertext = await window.textsecure.messaging.getSticker(packId, id);
const { messaging } = window.textsecure;
if (!messaging) {
throw new Error('messaging is not available!');
}
const ciphertext = await messaging.getSticker(packId, id);
const plaintext = decryptSticker(packKey, ciphertext);
const sticker = ephemeral
@@ -401,9 +420,12 @@ export async function downloadEphemeralPack(
};
stickerPackAdded(placeholder);
const ciphertext = await window.textsecure.messaging.getStickerPackManifest(
packId
);
const { messaging } = window.textsecure;
if (!messaging) {
throw new Error('messaging is not available!');
}
const ciphertext = await messaging.getStickerPackManifest(packId);
const plaintext = decryptSticker(packKey, ciphertext);
const proto = Proto.StickerPack.decode(plaintext);
const firstStickerProto = proto.stickers ? proto.stickers[0] : null;
@@ -599,9 +621,12 @@ async function doDownloadStickerPack(
};
stickerPackAdded(placeholder);
const ciphertext = await window.textsecure.messaging.getStickerPackManifest(
packId
);
const { messaging } = window.textsecure;
if (!messaging) {
throw new Error('messaging is not available!');
}
const ciphertext = await messaging.getStickerPackManifest(packId);
const plaintext = decryptSticker(packKey, ciphertext);
const proto = Proto.StickerPack.decode(plaintext);
const firstStickerProto = proto.stickers ? proto.stickers[0] : undefined;
@@ -776,7 +801,7 @@ export function getStickerPackStatus(
export function getSticker(
packId: string,
stickerId: number
): StickerType | undefined {
): StickerFromDBType | undefined {
const pack = getStickerPack(packId);
if (!pack || !pack.stickers) {
@@ -803,9 +828,7 @@ export async function copyStickerToAttachments(
const { path, size } =
await window.Signal.Migrations.copyIntoAttachmentsDirectory(absolutePath);
const { data } = await window.Signal.Migrations.loadAttachmentData({
path,
});
const data = await window.Signal.Migrations.readAttachmentData(path);
let contentType: MIMEType;
const sniffedMimeType = sniffImageMimeType(data);
+3 -9
View File
@@ -12,19 +12,15 @@ import type { PhoneNumberSharingMode } from '../util/phoneNumberSharingMode';
import type { RetryItemType } from '../util/retryPlaceholders';
import type { ConfigMapType as RemoteConfigType } from '../RemoteConfig';
import type { SystemTraySetting } from './SystemTraySetting';
import type {
ExtendedStorageID,
RemoteRecord,
UnknownRecord,
} from './StorageService';
import type { ExtendedStorageID, UnknownRecord } from './StorageService';
import type { GroupCredentialType } from '../textsecure/WebAPI';
import type {
KeyPairType,
SessionResetsType,
StorageServiceCredentials,
} from '../textsecure/Types.d';
import { UUIDStringType } from './UUID';
import type { ThemeSettingType } from './StorageUIKeys';
import { RegisteredChallengeType } from '../challenge';
export type SerializedCertificateType = {
@@ -34,8 +30,6 @@ export type SerializedCertificateType = {
export type ZoomFactorType = 0.75 | 1 | 1.25 | 1.5 | 2 | number;
export type ThemeSettingType = 'system' | 'light' | 'dark';
export type NotificationSettingType = 'message' | 'name' | 'count' | 'off';
export type IdentityKeyMap = Record<
+5
View File
@@ -1,8 +1,13 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { z } from 'zod';
import type { StorageAccessType } from './Storage.d';
export const themeSettingSchema = z.enum(['system', 'light', 'dark']);
export type ThemeSettingType = z.infer<typeof themeSettingSchema>;
// Configuration keys that only affect UI
export const STORAGE_UI_KEYS: ReadonlyArray<keyof StorageAccessType> = [
'always-relay-calls',
+6 -4
View File
@@ -23,12 +23,14 @@ export type RenderTextCallbackType = (options: {
key: number;
}) => JSX.Element | string;
export type ReplacementValuesType = {
[key: string]: string | number | undefined;
};
export type ReplacementValuesType =
| Array<string>
| {
[key: string]: string | number | undefined;
};
export type LocalizerType = {
(key: string, values?: Array<string> | ReplacementValuesType): string;
(key: string, values?: ReplacementValuesType): string;
getLocale(): string;
};
+1 -1
View File
@@ -8,7 +8,7 @@ export type LinkPreviewType = {
description?: string;
domain: string;
url: string;
isStickerPack: boolean;
isStickerPack?: boolean;
image?: Readonly<AttachmentType>;
date?: number;
};