Reorder getSendTarget logic for clarity
This commit is contained in:
parent
c10d59458f
commit
49161b7e17
5 changed files with 78 additions and 59 deletions
|
@ -47,6 +47,7 @@ import type {
|
||||||
CustomColorType,
|
CustomColorType,
|
||||||
CustomColorDataType,
|
CustomColorDataType,
|
||||||
} from '../../types/Colors';
|
} from '../../types/Colors';
|
||||||
|
import { SEALED_SENDER } from '../../types/SealedSender';
|
||||||
import type {
|
import type {
|
||||||
ConversationAttributesType,
|
ConversationAttributesType,
|
||||||
CustomError,
|
CustomError,
|
||||||
|
@ -81,7 +82,7 @@ import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||||
import { SendStatus } from '../../messages/MessageSendState';
|
import { SendStatus } from '../../messages/MessageSendState';
|
||||||
import type { SendStateByConversationId } from '../../messages/MessageSendState';
|
import type { SendStateByConversationId } from '../../messages/MessageSendState';
|
||||||
import { SeenStatus } from '../../MessageSeenStatus';
|
import { SeenStatus } from '../../MessageSeenStatus';
|
||||||
import { constantTimeEqual } from '../../Crypto';
|
import { constantTimeEqual, deriveAccessKey } from '../../Crypto';
|
||||||
import * as Bytes from '../../Bytes';
|
import * as Bytes from '../../Bytes';
|
||||||
import { BACKUP_VERSION, WALLPAPER_TO_BUBBLE_COLOR } from './constants';
|
import { BACKUP_VERSION, WALLPAPER_TO_BUBBLE_COLOR } from './constants';
|
||||||
import { UnsupportedBackupVersion } from './errors';
|
import { UnsupportedBackupVersion } from './errors';
|
||||||
|
@ -945,6 +946,10 @@ export class BackupImportStream extends Writable {
|
||||||
profileKey: contact.profileKey
|
profileKey: contact.profileKey
|
||||||
? Bytes.toBase64(contact.profileKey)
|
? Bytes.toBase64(contact.profileKey)
|
||||||
: undefined,
|
: undefined,
|
||||||
|
accessKey: contact.profileKey
|
||||||
|
? Bytes.toBase64(deriveAccessKey(contact.profileKey))
|
||||||
|
: undefined,
|
||||||
|
sealedSender: SEALED_SENDER.UNKNOWN,
|
||||||
profileSharing: contact.profileSharing === true,
|
profileSharing: contact.profileSharing === true,
|
||||||
profileName: dropNull(contact.profileGivenName),
|
profileName: dropNull(contact.profileGivenName),
|
||||||
profileFamilyName: dropNull(contact.profileFamilyName),
|
profileFamilyName: dropNull(contact.profileFamilyName),
|
||||||
|
|
|
@ -36,6 +36,7 @@ import { createProxyAgent } from '../util/createProxyAgent';
|
||||||
import type { ProxyAgent } from '../util/createProxyAgent';
|
import type { ProxyAgent } from '../util/createProxyAgent';
|
||||||
import type { FetchFunctionType } from '../util/uploads/tusProtocol';
|
import type { FetchFunctionType } from '../util/uploads/tusProtocol';
|
||||||
import { VerificationTransport } from '../types/VerificationTransport';
|
import { VerificationTransport } from '../types/VerificationTransport';
|
||||||
|
import { ZERO_ACCESS_KEY } from '../types/SealedSender';
|
||||||
import { toLogFormat } from '../types/errors';
|
import { toLogFormat } from '../types/errors';
|
||||||
import { isPackIdValid, redactPackId } from '../types/Stickers';
|
import { isPackIdValid, redactPackId } from '../types/Stickers';
|
||||||
import type {
|
import type {
|
||||||
|
@ -362,7 +363,20 @@ async function _promiseAjax<Type extends ResponseType, OutputShape>(
|
||||||
const logType = socketManager ? '(WS)' : '(REST)';
|
const logType = socketManager ? '(WS)' : '(REST)';
|
||||||
const redactedURL = options.redactUrl ? options.redactUrl(url) : url;
|
const redactedURL = options.redactUrl ? options.redactUrl(url) : url;
|
||||||
|
|
||||||
const unauthLabel = options.unauthenticated ? ' (unauth)' : '';
|
const { accessKey, basicAuth, groupSendToken, unauthenticated } = options;
|
||||||
|
|
||||||
|
let unauthLabel = '';
|
||||||
|
if (options.unauthenticated) {
|
||||||
|
if (groupSendToken != null) {
|
||||||
|
unauthLabel = ' (unauth+gse)';
|
||||||
|
} else if (accessKey === ZERO_ACCESS_KEY) {
|
||||||
|
unauthLabel = ' (unauth+zero-key)';
|
||||||
|
} else if (accessKey != null) {
|
||||||
|
unauthLabel = ' (unauth+key)';
|
||||||
|
} else {
|
||||||
|
unauthLabel = ' (unauth)';
|
||||||
|
}
|
||||||
|
}
|
||||||
const logId = `${options.type} ${logType} ${redactedURL}${unauthLabel}`;
|
const logId = `${options.type} ${logType} ${redactedURL}${unauthLabel}`;
|
||||||
log.info(logId);
|
log.info(logId);
|
||||||
|
|
||||||
|
@ -375,7 +389,6 @@ async function _promiseAjax<Type extends ResponseType, OutputShape>(
|
||||||
fetchOptions.headers['Content-Length'] = contentLength.toString();
|
fetchOptions.headers['Content-Length'] = contentLength.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
const { accessKey, basicAuth, groupSendToken, unauthenticated } = options;
|
|
||||||
if (basicAuth) {
|
if (basicAuth) {
|
||||||
fetchOptions.headers.Authorization = `Basic ${basicAuth}`;
|
fetchOptions.headers.Authorization = `Basic ${basicAuth}`;
|
||||||
} else if (unauthenticated) {
|
} else if (unauthenticated) {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
// Copyright 2021 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
export const ZERO_ACCESS_KEY = 'AAAAAAAAAAAAAAAAAAAAAA==';
|
||||||
|
|
||||||
export enum SEALED_SENDER {
|
export enum SEALED_SENDER {
|
||||||
UNKNOWN = 0,
|
UNKNOWN = 0,
|
||||||
ENABLED = 1,
|
ENABLED = 1,
|
||||||
|
|
|
@ -7,23 +7,16 @@ import type {
|
||||||
SendMetadataType,
|
SendMetadataType,
|
||||||
SendOptionsType,
|
SendOptionsType,
|
||||||
} from '../textsecure/SendMessage';
|
} from '../textsecure/SendMessage';
|
||||||
import * as Bytes from '../Bytes';
|
|
||||||
import { getRandomBytes, getZeroes } from '../Crypto';
|
|
||||||
import { getConversationMembers } from './getConversationMembers';
|
import { getConversationMembers } from './getConversationMembers';
|
||||||
import { isDirectConversation, isMe } from './whatTypeOfConversation';
|
import { isDirectConversation, isMe } from './whatTypeOfConversation';
|
||||||
import { senderCertificateService } from '../services/senderCertificate';
|
import { senderCertificateService } from '../services/senderCertificate';
|
||||||
import { shouldSharePhoneNumberWith } from './phoneNumberSharingMode';
|
import { shouldSharePhoneNumberWith } from './phoneNumberSharingMode';
|
||||||
import type { SerializedCertificateType } from '../textsecure/OutgoingMessage';
|
import type { SerializedCertificateType } from '../textsecure/OutgoingMessage';
|
||||||
import { SenderCertificateMode } from '../textsecure/OutgoingMessage';
|
import { SenderCertificateMode } from '../textsecure/OutgoingMessage';
|
||||||
|
import { ZERO_ACCESS_KEY, SEALED_SENDER } from '../types/SealedSender';
|
||||||
import { isNotNil } from './isNotNil';
|
import { isNotNil } from './isNotNil';
|
||||||
import { maybeCreateGroupSendEndorsementState } from './groupSendEndorsements';
|
import { maybeCreateGroupSendEndorsementState } from './groupSendEndorsements';
|
||||||
|
import { missingCaseError } from './missingCaseError';
|
||||||
const SEALED_SENDER = {
|
|
||||||
UNKNOWN: 0,
|
|
||||||
ENABLED: 1,
|
|
||||||
DISABLED: 2,
|
|
||||||
UNRESTRICTED: 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function getSendOptionsForRecipients(
|
export async function getSendOptionsForRecipients(
|
||||||
recipients: ReadonlyArray<string>,
|
recipients: ReadonlyArray<string>,
|
||||||
|
@ -94,61 +87,69 @@ export async function getSendOptions(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const { accessKey, sealedSender } = conversationAttrs;
|
const { accessKey } = conversationAttrs;
|
||||||
const { e164, serviceId } = conversationAttrs;
|
const { e164, serviceId } = conversationAttrs;
|
||||||
|
|
||||||
|
let sealedSender = conversationAttrs.sealedSender as
|
||||||
|
| SEALED_SENDER
|
||||||
|
| undefined;
|
||||||
|
|
||||||
const senderCertificate =
|
const senderCertificate =
|
||||||
await getSenderCertificateForDirectConversation(conversationAttrs);
|
await getSenderCertificateForDirectConversation(conversationAttrs);
|
||||||
|
|
||||||
let identifierData: SendIdentifierData | null = null;
|
let identifierData: SendIdentifierData | null = null;
|
||||||
// If we've never fetched user's profile, we default to what we have
|
if (story) {
|
||||||
if (sealedSender === SEALED_SENDER.UNKNOWN || story) {
|
// Always send story using zero access key
|
||||||
identifierData = {
|
sealedSender = SEALED_SENDER.UNRESTRICTED;
|
||||||
accessKey:
|
|
||||||
accessKey ||
|
|
||||||
(story
|
|
||||||
? Bytes.toBase64(getZeroes(16))
|
|
||||||
: Bytes.toBase64(getRandomBytes(16))),
|
|
||||||
senderCertificate,
|
|
||||||
groupSendToken: null,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sealedSender === SEALED_SENDER.DISABLED) {
|
switch (sealedSender) {
|
||||||
if (serviceId != null && groupId != null) {
|
case SEALED_SENDER.DISABLED:
|
||||||
const { state: groupSendEndorsementState, didRefreshGroupState } =
|
// Try to get GSE token
|
||||||
await maybeCreateGroupSendEndorsementState(
|
if (serviceId != null && groupId != null) {
|
||||||
groupId,
|
const { state: groupSendEndorsementState, didRefreshGroupState } =
|
||||||
alreadyRefreshedGroupState
|
await maybeCreateGroupSendEndorsementState(
|
||||||
);
|
groupId,
|
||||||
|
alreadyRefreshedGroupState
|
||||||
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
groupSendEndorsementState != null &&
|
groupSendEndorsementState != null &&
|
||||||
groupSendEndorsementState.hasMember(serviceId)
|
groupSendEndorsementState.hasMember(serviceId)
|
||||||
) {
|
) {
|
||||||
const token = groupSendEndorsementState.buildToken(
|
const token = groupSendEndorsementState.buildToken(
|
||||||
new Set([serviceId])
|
new Set([serviceId])
|
||||||
);
|
);
|
||||||
if (token != null) {
|
if (token != null) {
|
||||||
identifierData = {
|
identifierData = {
|
||||||
accessKey: null,
|
accessKey: null,
|
||||||
senderCertificate,
|
senderCertificate,
|
||||||
groupSendToken: token,
|
groupSendToken: token,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
} else if (didRefreshGroupState && !alreadyRefreshedGroupState) {
|
||||||
|
return getSendOptions(conversationAttrs, options, true);
|
||||||
}
|
}
|
||||||
} else if (didRefreshGroupState && !alreadyRefreshedGroupState) {
|
|
||||||
return getSendOptions(conversationAttrs, options, true);
|
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
} else {
|
case SEALED_SENDER.UNRESTRICTED:
|
||||||
identifierData = {
|
identifierData = {
|
||||||
accessKey:
|
accessKey: ZERO_ACCESS_KEY,
|
||||||
accessKey && sealedSender === SEALED_SENDER.ENABLED
|
senderCertificate,
|
||||||
? accessKey
|
groupSendToken: null,
|
||||||
: Bytes.toBase64(getRandomBytes(16)),
|
};
|
||||||
senderCertificate,
|
break;
|
||||||
groupSendToken: null,
|
case SEALED_SENDER.ENABLED:
|
||||||
};
|
case SEALED_SENDER.UNKNOWN:
|
||||||
|
case undefined:
|
||||||
|
identifierData = {
|
||||||
|
accessKey: accessKey || ZERO_ACCESS_KEY,
|
||||||
|
senderCertificate,
|
||||||
|
groupSendToken: null,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw missingCaseError(sealedSender);
|
||||||
}
|
}
|
||||||
|
|
||||||
let sendMetadata: SendMetadataType = {};
|
let sendMetadata: SendMetadataType = {};
|
||||||
|
|
|
@ -13,7 +13,6 @@ import {
|
||||||
SenderCertificate,
|
SenderCertificate,
|
||||||
UnidentifiedSenderMessageContent,
|
UnidentifiedSenderMessageContent,
|
||||||
} from '@signalapp/libsignal-client';
|
} from '@signalapp/libsignal-client';
|
||||||
import * as Bytes from '../Bytes';
|
|
||||||
import { senderCertificateService } from '../services/senderCertificate';
|
import { senderCertificateService } from '../services/senderCertificate';
|
||||||
import type { SendLogCallbackType } from '../textsecure/OutgoingMessage';
|
import type { SendLogCallbackType } from '../textsecure/OutgoingMessage';
|
||||||
import {
|
import {
|
||||||
|
@ -53,7 +52,7 @@ import type {
|
||||||
} from '../model-types.d';
|
} from '../model-types.d';
|
||||||
import type { SendTypesType } from './handleMessageSend';
|
import type { SendTypesType } from './handleMessageSend';
|
||||||
import { handleMessageSend, shouldSaveProto } from './handleMessageSend';
|
import { handleMessageSend, shouldSaveProto } from './handleMessageSend';
|
||||||
import { SEALED_SENDER } from '../types/SealedSender';
|
import { SEALED_SENDER, ZERO_ACCESS_KEY } from '../types/SealedSender';
|
||||||
import { parseIntOrThrow } from './parseIntOrThrow';
|
import { parseIntOrThrow } from './parseIntOrThrow';
|
||||||
import {
|
import {
|
||||||
multiRecipient200ResponseSchema,
|
multiRecipient200ResponseSchema,
|
||||||
|
@ -87,7 +86,6 @@ const DAY = 24 * HOUR;
|
||||||
const MAX_RECURSION = 10;
|
const MAX_RECURSION = 10;
|
||||||
|
|
||||||
const ACCESS_KEY_LENGTH = 16;
|
const ACCESS_KEY_LENGTH = 16;
|
||||||
const ZERO_ACCESS_KEY = Bytes.toBase64(new Uint8Array(ACCESS_KEY_LENGTH));
|
|
||||||
|
|
||||||
// Public API:
|
// Public API:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue