Adjust some types

This commit is contained in:
Josh Perez 2022-07-12 20:37:21 -04:00 committed by GitHub
parent 9ce4b8977d
commit d7307934bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 223 additions and 175 deletions

View file

@ -21,11 +21,11 @@ import type {
MessageAttributesType,
ConversationAttributesType,
ReactionAttributesType,
ValidateConversationType,
} from './model-types.d';
import * as Bytes from './Bytes';
import * as Timers from './Timers';
import * as indexedDb from './indexeddb';
import type { WhatIsThis } from './window.d';
import type { MenuOptionsType } from './types/menu';
import type { Receipt } from './types/Receipt';
import { SocketStatus } from './types/SocketStatus';
@ -133,8 +133,7 @@ import { onRetryRequest, onDecryptionError } from './util/handleRetry';
import { themeChanged } from './shims/themeChanged';
import { createIPCEvents } from './util/createIPCEvents';
import { RemoveAllConfiguration } from './types/RemoveAllConfiguration';
import { isValidUuid, UUIDKind } from './types/UUID';
import type { UUID } from './types/UUID';
import { isValidUuid, UUIDKind, UUID } from './types/UUID';
import * as log from './logging/log';
import { loadRecentEmojis } from './util/loadRecentEmojis';
import { deleteAllLogs } from './util/deleteAllLogs';
@ -155,6 +154,7 @@ import { conversationJobQueue } from './jobs/conversationJobQueue';
import { SeenStatus } from './MessageSeenStatus';
import MessageSender from './textsecure/SendMessage';
import type AccountManager from './textsecure/AccountManager';
import { validateConversation } from './util/validateConversation';
const MAX_ATTACHMENT_DOWNLOAD_AGE = 3600 * 72 * 1000;
@ -1227,7 +1227,7 @@ export async function startApp(): Promise<void> {
window.reduxActions.user.userChanged({ menuOptions: options });
});
let shortcutGuideView: WhatIsThis | null = null;
let shortcutGuideView: ReactWrapperView | null = null;
window.showKeyboardShortcuts = () => {
if (!shortcutGuideView) {
@ -2724,12 +2724,13 @@ export async function startApp(): Promise<void> {
function onContactReceived(ev: ContactEvent) {
const details = ev.contactDetails;
const c = new window.Whisper.Conversation({
const partialConversation: ValidateConversationType = {
e164: details.number,
uuid: details.uuid,
uuid: UUID.fromString(details.uuid),
type: 'private',
} as Partial<ConversationAttributesType> as WhatIsThis);
const validationError = c.validate();
};
const validationError = validateConversation(partialConversation);
if (validationError) {
log.error(
'Invalid contact received:',
@ -3188,7 +3189,8 @@ export async function startApp(): Promise<void> {
.filter(isNotNil);
}
return new window.Whisper.Message({
const partialMessage: MessageAttributesType = {
id: UUID.generate().toString(),
canReplyToStory: data.message.isStory
? data.message.canReplyToStory
: undefined,
@ -3211,7 +3213,9 @@ export async function startApp(): Promise<void> {
type: data.message.isStory ? 'story' : 'outgoing',
storyDistributionListId: data.storyDistributionListId,
unidentifiedDeliveries,
} as Partial<MessageAttributesType> as WhatIsThis);
};
return new window.Whisper.Message(partialMessage);
}
// Works with 'sent' and 'message' data sent from MessageReceiver, with a little massage
@ -3446,7 +3450,8 @@ export async function startApp(): Promise<void> {
Boolean(data.receivedAtCounter),
`Did not receive receivedAtCounter for message: ${data.timestamp}`
);
return new window.Whisper.Message({
const partialMessage: MessageAttributesType = {
id: UUID.generate().toString(),
canReplyToStory: data.message.isStory
? data.message.canReplyToStory
: undefined,
@ -3460,11 +3465,14 @@ export async function startApp(): Promise<void> {
serverTimestamp: data.serverTimestamp,
source: data.source,
sourceDevice: data.sourceDevice,
sourceUuid: data.sourceUuid,
sourceUuid: data.sourceUuid
? UUID.fromString(data.sourceUuid)
: undefined,
timestamp: data.timestamp,
type: data.message.isStory ? 'story' : 'incoming',
unidentifiedDeliveryReceived: data.unidentifiedDeliveryReceived,
} as Partial<MessageAttributesType> as WhatIsThis);
};
return new window.Whisper.Message(partialMessage);
}
// Returns `false` if this message isn't a group call message.

View file

@ -20,8 +20,9 @@ import type {
} from '../../textsecure/SendMessage';
import type { LinkPreviewType } from '../../types/message/LinkPreviews';
import type { BodyRangesType, StoryContextType } from '../../types/Util';
import type { WhatIsThis } from '../../window.d';
import type { LoggerType } from '../../types/Logging';
import type { StickerWithHydratedData } from '../../types/Stickers';
import type { QuotedMessageType } from '../../model-types.d';
import type {
ConversationQueueJobBundle,
NormalMessageSendJobData,
@ -31,6 +32,7 @@ import { handleMultipleSendErrors } from './handleMultipleSendErrors';
import { ourProfileKeyService } from '../../services/ourProfileKey';
import { isConversationUnregistered } from '../../util/isConversationUnregistered';
import { isConversationAccepted } from '../../util/isConversationAccepted';
import { sendToGroup } from '../../util/sendToGroup';
export async function sendNormalMessage(
conversation: ConversationModel,
@ -207,7 +209,7 @@ export async function sendNormalMessage(
innerPromise = conversation.queueJob(
'conversationQueue/sendNormalMessage',
abortSignal =>
window.Signal.Util.sendToGroup({
sendToGroup({
abortSignal,
contentHint: ContentHint.RESENDABLE,
groupSendOptions: {
@ -428,8 +430,8 @@ async function getMessageSendData({
mentions: undefined | BodyRangesType;
messageTimestamp: number;
preview: Array<LinkPreviewType>;
quote: WhatIsThis;
sticker: WhatIsThis;
quote: QuotedMessageType | null;
sticker: StickerWithHydratedData | undefined;
storyContext?: StoryContextType;
}> {
const {

18
ts/model-types.d.ts vendored
View file

@ -17,7 +17,11 @@ import { ReadStatus } from './messages/MessageReadStatus';
import { SendStateByConversationId } from './messages/MessageSendState';
import { GroupNameCollisionsWithIdsByTitle } from './util/groupMemberNameCollisions';
import { ConversationColorType } from './types/Colors';
import { AttachmentDraftType, AttachmentType } from './types/Attachment';
import {
AttachmentDraftType,
AttachmentType,
ThumbnailType,
} from './types/Attachment';
import { EmbeddedContactType } from './types/EmbeddedContact';
import { SignalService as Proto } from './protobuf';
import { AvatarDataType } from './types/Avatar';
@ -30,11 +34,10 @@ import { SeenStatus } from './MessageSeenStatus';
import { GiftBadgeStates } from './components/conversation/Message';
import { LinkPreviewType } from './types/message/LinkPreviews';
import type { ProcessedQuoteAttachment } from './textsecure/Types.d';
import type { StickerType } from './types/Stickers';
import { MIMEType } from './types/MIME';
export type WhatIsThis = any;
export type LastMessageStatus =
| 'paused'
| 'error'
@ -73,7 +76,9 @@ export type QuotedAttachment = {
};
export type QuotedMessageType = {
attachments: Array<WhatIsThis /* QuotedAttachment */>;
// TODO DESKTOP-3826
// eslint-disable-next-line no-explicit-any
attachments: Array<any>;
// `author` is an old attribute that holds the author's E164. We shouldn't use it for
// new messages, but old messages might have this attribute.
author?: string;
@ -245,6 +250,11 @@ export type ConversationLastProfileType = Readonly<{
profileKeyVersion: string;
}>;
export type ValidateConversationType = Pick<
ConversationAttributesType,
'e164' | 'uuid' | 'type' | 'groupId'
>;
export type ConversationAttributesType = {
accessKey?: string | null;
addedBy?: string;

View file

@ -1,7 +1,7 @@
// Copyright 2020-2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { compact, isNumber, throttle, debounce } from 'lodash';
import { compact, has, isNumber, throttle, debounce } from 'lodash';
import { batch as batchDispatch } from 'react-redux';
import PQueue from 'p-queue';
import { v4 as generateGuid } from 'uuid';
@ -15,28 +15,24 @@ import type {
QuotedMessageType,
SenderKeyInfoType,
VerificationOptions,
WhatIsThis,
} from '../model-types.d';
import { getInitials } from '../util/getInitials';
import { normalizeUuid } from '../util/normalizeUuid';
import {
getRegionCodeForNumber,
parseNumber,
} from '../util/libphonenumberUtil';
import { getRegionCodeForNumber } from '../util/libphonenumberUtil';
import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary';
import type { AttachmentType, ThumbnailType } from '../types/Attachment';
import { toDayMillis } from '../util/timestamp';
import type { AttachmentType } from '../types/Attachment';
import { isGIF } from '../types/Attachment';
import type { CallHistoryDetailsType } from '../types/Calling';
import { CallMode } from '../types/Calling';
import * as EmbeddedContact from '../types/EmbeddedContact';
import * as Conversation from '../types/Conversation';
import type { StickerType, StickerWithHydratedData } from '../types/Stickers';
import * as Stickers from '../types/Stickers';
import type {
ContactWithHydratedAvatar,
GroupV1InfoType,
GroupV2InfoType,
StickerType,
} from '../textsecure/SendMessage';
import createTaskWithTimeout from '../textsecure/TaskWithTimeout';
import MessageSender from '../textsecure/SendMessage';
@ -58,7 +54,7 @@ import { sniffImageMimeType } from '../util/sniffImageMimeType';
import { isValidE164 } from '../util/isValidE164';
import type { MIMEType } from '../types/MIME';
import { IMAGE_JPEG, IMAGE_GIF, IMAGE_WEBP } from '../types/MIME';
import { UUID, isValidUuid, UUIDKind } from '../types/UUID';
import { UUID, UUIDKind } from '../types/UUID';
import type { UUIDStringType } from '../types/UUID';
import { deriveAccessKey, decryptProfileName, decryptProfile } from '../Crypto';
import * as Bytes from '../Bytes';
@ -125,6 +121,7 @@ import { SeenStatus } from '../MessageSeenStatus';
import { getConversationIdForLogging } from '../util/idForLogging';
import { getSendTarget } from '../util/getSendTarget';
import { getRecipients } from '../util/getRecipients';
import { validateConversation } from '../util/validateConversation';
/* eslint-disable more/no-then */
window.Whisper = window.Whisper || {};
@ -3389,71 +3386,7 @@ export class ConversationModel extends window.Backbone
}
override validate(attributes = this.attributes): string | null {
const required = ['type'];
const missing = window._.filter(required, attr => !attributes[attr]);
if (missing.length) {
return `Conversation must have ${missing}`;
}
if (attributes.type !== 'private' && attributes.type !== 'group') {
return `Invalid conversation type: ${attributes.type}`;
}
const atLeastOneOf = ['e164', 'uuid', 'groupId'];
const hasAtLeastOneOf =
window._.filter(atLeastOneOf, attr => attributes[attr]).length > 0;
if (!hasAtLeastOneOf) {
return 'Missing one of e164, uuid, or groupId';
}
const error = this.validateNumber() || this.validateUuid();
if (error) {
return error;
}
return null;
}
validateNumber(): string | null {
if (isDirectConversation(this.attributes) && this.get('e164')) {
const regionCode = window.storage.get('regionCode');
if (!regionCode) {
throw new Error('No region code');
}
const number = parseNumber(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.get('e164')!,
regionCode
);
if (number.isValidNumber) {
this.set({ e164: number.e164 });
return null;
}
let errorMessage: undefined | string;
if (number.error instanceof Error) {
errorMessage = number.error.message;
} else if (typeof number.error === 'string') {
errorMessage = number.error;
}
return errorMessage || 'Invalid phone number';
}
return null;
}
validateUuid(): string | null {
if (isDirectConversation(this.attributes) && this.get('uuid')) {
if (isValidUuid(this.get('uuid'))) {
return null;
}
return 'Invalid UUID';
}
return null;
return validateConversation(attributes);
}
queueJob<T>(
@ -3643,10 +3576,16 @@ export class ConversationModel extends window.Backbone
}
async getQuoteAttachment(
attachments?: Array<WhatIsThis>,
preview?: Array<WhatIsThis>,
sticker?: WhatIsThis
): Promise<WhatIsThis> {
attachments?: Array<AttachmentType>,
preview?: Array<LinkPreviewType>,
sticker?: StickerType
): Promise<
Array<{
contentType: MIMEType;
fileName: string | null;
thumbnail: ThumbnailType | null;
}>
> {
if (attachments && attachments.length) {
const attachmentsToUse = Array.from(take(attachments, 1));
const isGIFQuote = isGIF(attachmentsToUse);
@ -3673,7 +3612,9 @@ export class ConversationModel extends window.Backbone
thumbnail: thumbnail
? {
...(await loadAttachmentData(thumbnail)),
objectUrl: getAbsoluteAttachmentPath(thumbnail.path),
objectUrl: thumbnail.path
? getAbsoluteAttachmentPath(thumbnail.path)
: undefined,
}
: null,
};
@ -3708,7 +3649,9 @@ export class ConversationModel extends window.Backbone
thumbnail: image
? {
...(await loadAttachmentData(image)),
objectUrl: getAbsoluteAttachmentPath(image.path),
objectUrl: image.path
? getAbsoluteAttachmentPath(image.path)
: undefined,
}
: null,
};
@ -3727,7 +3670,7 @@ export class ConversationModel extends window.Backbone
fileName: null,
thumbnail: {
...(await loadAttachmentData(sticker.data)),
objectUrl: getAbsoluteAttachmentPath(path),
objectUrl: path ? getAbsoluteAttachmentPath(path) : undefined,
},
},
];
@ -3797,7 +3740,7 @@ export class ConversationModel extends window.Backbone
contentType = IMAGE_WEBP;
}
const sticker = {
const sticker: StickerWithHydratedData = {
packId,
stickerId,
packKey: key,
@ -3867,7 +3810,7 @@ export class ConversationModel extends window.Backbone
mentions?: BodyRangesType;
preview?: Array<LinkPreviewType>;
quote?: QuotedMessageType;
sticker?: StickerType;
sticker?: StickerWithHydratedData;
},
{
dontClearDraft,
@ -5489,8 +5432,8 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
);
},
reset(...args: Array<WhatIsThis>) {
window.Backbone.Collection.prototype.reset.apply(this, args as WhatIsThis);
reset(models?: Array<ConversationModel>, options?: Backbone.Silenceable) {
window.Backbone.Collection.prototype.reset.call(this, models, options);
this.resetLookups();
},
@ -5534,8 +5477,14 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
this._byGroupId = Object.create(null);
},
add(data: WhatIsThis | Array<WhatIsThis>) {
let hydratedData;
add(
data:
| ConversationModel
| ConversationAttributesType
| Array<ConversationModel>
| Array<ConversationAttributesType>
) {
let hydratedData: Array<ConversationModel> | ConversationModel;
// First, we need to ensure that the data we're working with is Conversation models
if (Array.isArray(data)) {
@ -5544,16 +5493,20 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
const item = data[i];
// We create a new model if it's not already a model
if (!item.get) {
hydratedData.push(new window.Whisper.Conversation(item));
if (has(item, 'get')) {
hydratedData.push(item as ConversationModel);
} else {
hydratedData.push(item);
hydratedData.push(
new window.Whisper.Conversation(item as ConversationAttributesType)
);
}
}
} else if (!data.get) {
hydratedData = new window.Whisper.Conversation(data);
} else if (has(data, 'get')) {
hydratedData = data as ConversationModel;
} else {
hydratedData = data;
hydratedData = new window.Whisper.Conversation(
data as ConversationAttributesType
);
}
// Next, we update our lookups first to prevent infinite loops on the 'add' event
@ -5562,7 +5515,9 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
);
// Lastly, we fire off the add events related to this change
window.Backbone.Collection.prototype.add.call(this, hydratedData);
// Go home Backbone, you're drunk.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
window.Backbone.Collection.prototype.add.call(this, hydratedData as any);
return hydratedData;
},
@ -5583,7 +5538,7 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
);
},
comparator(m: WhatIsThis) {
comparator(m: ConversationModel) {
return -(m.get('active_at') || 0);
},
});

View file

@ -8,7 +8,6 @@ import type {
MessageAttributesType,
MessageReactionType,
QuotedMessageType,
WhatIsThis,
} from '../model-types.d';
import {
filter,
@ -46,7 +45,10 @@ import * as reactionUtil from '../reactions/util';
import * as Stickers from '../types/Stickers';
import * as Errors from '../types/errors';
import * as EmbeddedContact from '../types/EmbeddedContact';
import type { AttachmentType } from '../types/Attachment';
import type {
AttachmentType,
AttachmentWithHydratedData,
} from '../types/Attachment';
import { isImage, isVideo } from '../types/Attachment';
import * as Attachment from '../types/Attachment';
import { stringToMIMEType } from '../types/MIME';
@ -158,6 +160,8 @@ import { isNewReactionReplacingPrevious } from '../reactions/util';
import { parseBoostBadgeListFromServer } from '../badges/parseBadgesFromServer';
import { GiftBadgeStates } from '../components/conversation/Message';
import { downloadAttachment } from '../util/downloadAttachment';
import type { DeleteModel } from '../messageModifiers/Deletes';
import type { StickerWithHydratedData } from '../types/Stickers';
/* eslint-disable more/no-then */
@ -176,9 +180,14 @@ const { getTextWithMentions, GoogleChrome } = window.Signal.Util;
const { getMessageBySender } = window.Signal.Data;
export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
static getLongMessageAttachment: (
attachment: typeof window.WhatIsThis
) => typeof window.WhatIsThis;
static getLongMessageAttachment: (opts: {
attachments: Array<AttachmentWithHydratedData>;
body?: string;
now: number;
}) => {
body?: string;
attachments: Array<AttachmentWithHydratedData>;
};
CURRENT_PROTOCOL_VERSION?: number;
@ -198,9 +207,9 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
cachedOutgoingPreviewData?: Array<LinkPreviewType>;
cachedOutgoingQuoteData?: WhatIsThis;
cachedOutgoingQuoteData?: QuotedMessageType;
cachedOutgoingStickerData?: WhatIsThis;
cachedOutgoingStickerData?: StickerWithHydratedData;
override initialize(attributes: unknown): void {
if (_.isObject(attributes)) {
@ -1910,7 +1919,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// eslint-disable-next-line no-param-reassign
quote.attachments = [
{
contentType: 'image/jpeg',
contentType: MIME.IMAGE_JPEG,
},
];
// eslint-disable-next-line no-param-reassign
@ -1942,7 +1951,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// eslint-disable-next-line no-param-reassign
quote.text = originalMessage.get('body');
if (firstAttachment) {
firstAttachment.thumbnail = undefined;
firstAttachment.thumbnail = null;
}
if (
@ -2336,7 +2345,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
return;
}
const messageId = UUID.generate().toString();
const messageId = message.get('id') || UUID.generate().toString();
// Send delivery receipts, but only for incoming sealed sender messages
// and not for messages from unaccepted conversations
@ -2379,7 +2388,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
const urls = LinkPreview.findLinks(dataMessage.body || '');
const incomingPreview = dataMessage.preview || [];
const preview = incomingPreview.filter(
(item: typeof window.WhatIsThis) =>
(item: LinkPreviewType) =>
(item.image || item.title) &&
urls.includes(item.url) &&
LinkPreview.shouldPreviewHref(item.url)
@ -3215,7 +3224,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
async handleDeleteForEveryone(
del: typeof window.WhatIsThis,
del: DeleteModel,
shouldPersist = true
): Promise<void> {
log.info('Handling DOE.', {

View file

@ -1,11 +1,11 @@
// Copyright 2021 Signal Messenger, LLC
// Copyright 2021-2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { getThemeType } from '../util/getThemeType';
export function themeChanged(): void {
if (window.reduxActions && window.reduxActions.user) {
const theme = window.Events.getThemeSetting();
window.reduxActions.user.userChanged({
theme: theme === 'system' ? window.systemTheme : theme,
});
const theme = getThemeType();
window.reduxActions.user.userChanged({ theme });
}
}

View file

@ -113,7 +113,7 @@ type MigrationsModuleType = {
getAbsoluteStickerPath: (path: string) => string;
getAbsoluteTempPath: (path: string) => string;
loadAttachmentData: (
attachment: AttachmentType
attachment: Pick<AttachmentType, 'data' | 'path'>
) => Promise<AttachmentWithHydratedData>;
loadContactData: (
contact: Array<EmbeddedContactType> | undefined

View file

@ -32,6 +32,7 @@ import type { MenuOptionsType } from '../types/menu';
import { UUIDKind } from '../types/UUID';
import { getEmojiReducerState as emojis } from '../util/loadRecentEmojis';
import type { MainWindowStatsType } from '../windows/context';
import { getThemeType } from '../util/getThemeType';
export function getInitialState({
badges,
@ -63,8 +64,7 @@ export function getInitialState({
window.ConversationController.getOurConversationId();
const ourDeviceId = window.textsecure.storage.user.getDeviceId();
const themeSetting = window.Events.getThemeSetting();
const theme = themeSetting === 'system' ? window.systemTheme : themeSetting;
const theme = getThemeType();
return {
accounts: accounts(),

View file

@ -14,6 +14,7 @@ import {
SenderKeyDistributionMessage,
} from '@signalapp/libsignal-client';
import type { QuotedMessageType } from '../model-types.d';
import { GLOBAL_ZONE } from '../SignalProtocolStore';
import { assert } from '../util/assert';
import { parseIntOrThrow } from '../util/parseIntOrThrow';
@ -110,15 +111,6 @@ export type StickerType = StickerWithHydratedData & {
attachmentPointer?: Proto.IAttachmentPointer;
};
export type QuoteType = {
attachments?: Array<AttachmentType>;
authorUuid?: string;
bodyRanges?: BodyRangesType;
id?: number;
isGiftBadge?: boolean;
text?: string;
};
export type ReactionType = {
emoji?: string;
remove?: boolean;
@ -192,9 +184,9 @@ export type MessageOptionsType = {
needsSync?: boolean;
preview?: ReadonlyArray<LinkPreviewType>;
profileKey?: Uint8Array;
quote?: QuoteType;
quote?: QuotedMessageType | null;
recipients: ReadonlyArray<string>;
sticker?: StickerType;
sticker?: StickerWithHydratedData;
reaction?: ReactionType;
deletedForEveryoneTimestamp?: number;
timestamp: number;
@ -215,9 +207,9 @@ export type GroupSendOptionsType = {
messageText?: string;
preview?: ReadonlyArray<LinkPreviewType>;
profileKey?: Uint8Array;
quote?: QuoteType;
quote?: QuotedMessageType | null;
reaction?: ReactionType;
sticker?: StickerType;
sticker?: StickerWithHydratedData;
storyContext?: StoryContextType;
timestamp: number;
};
@ -246,7 +238,7 @@ class Message {
profileKey?: Uint8Array;
quote?: QuoteType;
quote?: QuotedMessageType | null;
recipients: ReadonlyArray<string>;
@ -1195,9 +1187,9 @@ export default class MessageSender {
options?: SendOptionsType;
preview?: ReadonlyArray<LinkPreviewType> | undefined;
profileKey?: Uint8Array;
quote?: QuoteType;
quote?: QuotedMessageType | null;
reaction?: ReactionType;
sticker?: StickerType;
sticker?: StickerWithHydratedData;
storyContext?: StoryContextType;
timestamp: number;
urgent: boolean;

View file

@ -168,13 +168,10 @@ export type AttachmentDraftType =
size: number;
};
export type ThumbnailType = {
height?: number;
width?: number;
url?: string;
contentType: MIME.MIMEType;
path?: string;
data?: Uint8Array;
export type ThumbnailType = Pick<
AttachmentType,
'height' | 'width' | 'url' | 'contentType' | 'path' | 'data'
> & {
// Only used when quote needed to make an in-memory thumbnail
objectUrl?: string;
};
@ -236,7 +233,7 @@ export async function migrateDataToFileSystem(
// Over time, we can expand this definition to become more narrow, e.g. require certain
// fields, etc.
export function isValid(
rawAttachment?: AttachmentType
rawAttachment?: Pick<AttachmentType, 'data' | 'path'>
): rawAttachment is AttachmentType {
// NOTE: We cannot use `_.isPlainObject` because `rawAttachment` is
// deserialized by protobuf:
@ -396,14 +393,14 @@ export function hasData(attachment: AttachmentType): boolean {
export function loadData(
readAttachmentData: (path: string) => Promise<Uint8Array>
): (attachment: AttachmentType) => Promise<AttachmentWithHydratedData> {
): (
attachment: Pick<AttachmentType, 'data' | 'path'>
) => Promise<AttachmentWithHydratedData> {
if (!is.function_(readAttachmentData)) {
throw new TypeError("'readAttachmentData' must be a function");
}
return async (
attachment: AttachmentType
): Promise<AttachmentWithHydratedData> => {
return async attachment => {
if (!isValid(attachment)) {
throw new TypeError("'attachment' is not valid");
}

View file

@ -651,7 +651,7 @@ export const processNewSticker = async (
};
type LoadAttachmentType = (
attachment: AttachmentType
attachment: Pick<AttachmentType, 'data' | 'path'>
) => Promise<AttachmentWithHydratedData>;
export const createAttachmentLoader = (

View file

@ -2,7 +2,6 @@
// 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']);

18
ts/util/getThemeType.ts Normal file
View file

@ -0,0 +1,18 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { ThemeType } from '../types/Util';
export function getThemeType(): ThemeType {
const themeSetting = window.Events.getThemeSetting();
if (themeSetting === 'light') {
return ThemeType.light;
}
if (themeSetting === 'dark') {
return ThemeType.dark;
}
return window.systemTheme;
}

View file

@ -0,0 +1,62 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { ValidateConversationType } from '../model-types.d';
import { isDirectConversation } from './whatTypeOfConversation';
import { parseNumber } from './libphonenumberUtil';
import { isValidUuid } from '../types/UUID';
export function validateConversation(
attributes: ValidateConversationType
): string | null {
if (attributes.type !== 'private' && attributes.type !== 'group') {
return `Invalid conversation type: ${attributes.type}`;
}
if (!attributes.e164 && !attributes.uuid && !attributes.groupId) {
return 'Missing one of e164, uuid, or groupId';
}
const error = validateNumber(attributes) || validateUuid(attributes);
if (error) {
return error;
}
return null;
}
function validateNumber(attributes: ValidateConversationType): string | null {
if (isDirectConversation(attributes) && attributes.e164) {
const regionCode = window.storage.get('regionCode');
if (!regionCode) {
throw new Error('No region code');
}
const number = parseNumber(attributes.e164, regionCode);
if (number.isValidNumber) {
return null;
}
let errorMessage: undefined | string;
if (number.error instanceof Error) {
errorMessage = number.error.message;
} else if (typeof number.error === 'string') {
errorMessage = number.error;
}
return errorMessage || 'Invalid phone number';
}
return null;
}
function validateUuid(attributes: ValidateConversationType): string | null {
if (isDirectConversation(attributes) && attributes.uuid) {
if (isValidUuid(attributes.uuid)) {
return null;
}
return 'Invalid UUID';
}
return null;
}

14
ts/window.d.ts vendored
View file

@ -98,8 +98,6 @@ import { RendererConfigType } from './types/RendererConfig';
export { Long } from 'long';
export type WhatIsThis = any;
// Synced with the type in ts/shims/showConfirmationDialog
// we are duplicating it here because that file cannot import/export.
type ConfirmationDialogViewProps = {
@ -253,8 +251,6 @@ declare global {
};
WebAudioRecorder: typeof WebAudioRecorderClass;
WhatIsThis: WhatIsThis;
addSetupMenuItems: () => void;
attachmentDownloadQueue: Array<MessageModel> | undefined;
startupProcessingQueue: StartupQueue | undefined;
@ -305,7 +301,7 @@ declare global {
nodeSetImmediate: typeof setImmediate;
onFullScreenChange: (fullScreen: boolean, maximized: boolean) => void;
platform: string;
preloadedImages: Array<WhatIsThis>;
preloadedImages: Array<HTMLImageElement>;
reduxActions: ReduxActions;
reduxStore: Store<StateType>;
restart: () => void;
@ -315,14 +311,14 @@ declare global {
shutdown: () => void;
showDebugLog: () => void;
sendChallengeRequest: (request: IPCChallengeRequest) => void;
setAutoHideMenuBar: (value: WhatIsThis) => void;
setAutoHideMenuBar: (value: boolean) => void;
setBadgeCount: (count: number) => void;
setMenuBarVisibility: (value: WhatIsThis) => void;
setMenuBarVisibility: (value: boolean) => void;
updateSystemTraySetting: (value: SystemTraySetting) => void;
showConfirmationDialog: (options: ConfirmationDialogViewProps) => void;
showKeyboardShortcuts: () => void;
storage: Storage;
systemTheme: WhatIsThis;
systemTheme: ThemeType;
textsecure: typeof textsecure;
titleBarDoubleClick: () => void;
updateTrayIcon: (count: number) => void;
@ -341,7 +337,7 @@ declare global {
WebAPI: WebAPIConnectType;
Whisper: WhisperType;
getServerTrustRoot: () => WhatIsThis;
getServerTrustRoot: () => string;
readyForUpdates: () => void;
logAppLoadedEvent?: (options: { processedCount?: number }) => void;
logAuthenticatedConnect?: () => void;