Compile protobufs with no-convert/null-defaults
Co-authored-by: Scott Nonnenberg <scott@signal.org>
This commit is contained in:
parent
e8fdd7116b
commit
f52da976f9
12 changed files with 119 additions and 43 deletions
|
@ -28,7 +28,7 @@
|
||||||
"get-expire-time": "node ts/scripts/get-expire-time.js",
|
"get-expire-time": "node ts/scripts/get-expire-time.js",
|
||||||
"copy-components": "node ts/scripts/copy.js",
|
"copy-components": "node ts/scripts/copy.js",
|
||||||
"sass": "sass stylesheets/manifest.scss:stylesheets/manifest.css stylesheets/manifest_bridge.scss:stylesheets/manifest_bridge.css",
|
"sass": "sass stylesheets/manifest.scss:stylesheets/manifest.css stylesheets/manifest_bridge.scss:stylesheets/manifest_bridge.css",
|
||||||
"build-module-protobuf": "pbjs --target static-module --force-long --no-typeurl --no-verify --no-create --wrap commonjs --out ts/protobuf/compiled.js protos/*.proto && pbts --out ts/protobuf/compiled.d.ts ts/protobuf/compiled.js",
|
"build-module-protobuf": "pbjs --target static-module --force-long --no-typeurl --no-verify --no-create --no-convert --null-defaults --wrap commonjs --out ts/protobuf/compiled.js protos/*.proto && pbts --out ts/protobuf/compiled.d.ts ts/protobuf/compiled.js",
|
||||||
"clean-module-protobuf": "rm -f ts/protobuf/compiled.d.ts ts/protobuf/compiled.js",
|
"clean-module-protobuf": "rm -f ts/protobuf/compiled.d.ts ts/protobuf/compiled.js",
|
||||||
"build-protobuf": "yarn build-module-protobuf",
|
"build-protobuf": "yarn build-module-protobuf",
|
||||||
"clean-protobuf": "yarn clean-module-protobuf",
|
"clean-protobuf": "yarn clean-module-protobuf",
|
||||||
|
|
16
ts/groups.ts
16
ts/groups.ts
|
@ -1751,7 +1751,7 @@ export async function fetchMembershipProof({
|
||||||
secretParams,
|
secretParams,
|
||||||
request: (sender, options) => sender.getGroupMembershipToken(options),
|
request: (sender, options) => sender.getGroupMembershipToken(options),
|
||||||
});
|
});
|
||||||
return response.token;
|
return dropNull(response.token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating a group
|
// Creating a group
|
||||||
|
@ -3454,9 +3454,13 @@ async function getGroupUpdates({
|
||||||
if (isChangeSupported) {
|
if (isChangeSupported) {
|
||||||
if (!wrappedGroupChange.isTrusted) {
|
if (!wrappedGroupChange.isTrusted) {
|
||||||
strictAssert(
|
strictAssert(
|
||||||
groupChange.serverSignature && groupChange.actions,
|
groupChange.serverSignature,
|
||||||
'Server signature must be present in untrusted group change'
|
'Server signature must be present in untrusted group change'
|
||||||
);
|
);
|
||||||
|
strictAssert(
|
||||||
|
groupChange.actions,
|
||||||
|
'Actions must be present in untrusted group change'
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
verifyNotarySignature(
|
verifyNotarySignature(
|
||||||
serverPublicParamsBase64,
|
serverPublicParamsBase64,
|
||||||
|
@ -3613,10 +3617,10 @@ async function updateGroupViaPreJoinInfo({
|
||||||
const newAttributes: ConversationAttributesType = {
|
const newAttributes: ConversationAttributesType = {
|
||||||
...group,
|
...group,
|
||||||
description: decryptGroupDescription(
|
description: decryptGroupDescription(
|
||||||
preJoinInfo.descriptionBytes,
|
dropNull(preJoinInfo.descriptionBytes),
|
||||||
secretParams
|
secretParams
|
||||||
),
|
),
|
||||||
name: decryptGroupTitle(preJoinInfo.title, secretParams),
|
name: decryptGroupTitle(dropNull(preJoinInfo.title), secretParams),
|
||||||
left: true,
|
left: true,
|
||||||
members: group.members || [],
|
members: group.members || [],
|
||||||
pendingMembersV2: group.pendingMembersV2 || [],
|
pendingMembersV2: group.pendingMembersV2 || [],
|
||||||
|
@ -3626,7 +3630,7 @@ async function updateGroupViaPreJoinInfo({
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
revision: preJoinInfo.version,
|
revision: dropNull(preJoinInfo.version),
|
||||||
|
|
||||||
temporaryMemberCount: preJoinInfo.memberCount || 1,
|
temporaryMemberCount: preJoinInfo.memberCount || 1,
|
||||||
};
|
};
|
||||||
|
@ -3863,7 +3867,7 @@ async function generateLeftGroupChanges(
|
||||||
masterKey
|
masterKey
|
||||||
);
|
);
|
||||||
|
|
||||||
revision = preJoinInfo.version;
|
revision = dropNull(preJoinInfo.version);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.warn(
|
log.warn(
|
||||||
|
|
|
@ -29,6 +29,7 @@ import { isAccessControlEnabled } from './util';
|
||||||
import { isGroupV1 } from '../util/whatTypeOfConversation';
|
import { isGroupV1 } from '../util/whatTypeOfConversation';
|
||||||
import { longRunningTaskWrapper } from '../util/longRunningTaskWrapper';
|
import { longRunningTaskWrapper } from '../util/longRunningTaskWrapper';
|
||||||
import { sleep } from '../util/sleep';
|
import { sleep } from '../util/sleep';
|
||||||
|
import { dropNull } from '../util/dropNull';
|
||||||
|
|
||||||
export async function joinViaLink(value: string): Promise<void> {
|
export async function joinViaLink(value: string): Promise<void> {
|
||||||
let inviteLinkPassword: string;
|
let inviteLinkPassword: string;
|
||||||
|
@ -116,7 +117,7 @@ export async function joinViaLink(value: string): Promise<void> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAccessControlEnabled(result.addFromInviteLink)) {
|
if (!isAccessControlEnabled(dropNull(result.addFromInviteLink))) {
|
||||||
log.error(
|
log.error(
|
||||||
`joinViaLink/${logId}: addFromInviteLink value of ${result.addFromInviteLink} is invalid`
|
`joinViaLink/${logId}: addFromInviteLink value of ${result.addFromInviteLink} is invalid`
|
||||||
);
|
);
|
||||||
|
@ -138,10 +139,10 @@ export async function joinViaLink(value: string): Promise<void> {
|
||||||
result.addFromInviteLink ===
|
result.addFromInviteLink ===
|
||||||
Proto.AccessControl.AccessRequired.ADMINISTRATOR;
|
Proto.AccessControl.AccessRequired.ADMINISTRATOR;
|
||||||
const title =
|
const title =
|
||||||
decryptGroupTitle(result.title, secretParams) ||
|
decryptGroupTitle(dropNull(result.title), secretParams) ||
|
||||||
window.i18n('icu:unknownGroup');
|
window.i18n('icu:unknownGroup');
|
||||||
const groupDescription = decryptGroupDescription(
|
const groupDescription = decryptGroupDescription(
|
||||||
result.descriptionBytes,
|
dropNull(result.descriptionBytes),
|
||||||
secretParams
|
secretParams
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -316,7 +317,7 @@ export async function joinViaLink(value: string): Promise<void> {
|
||||||
groupInviteLinkPassword: inviteLinkPassword,
|
groupInviteLinkPassword: inviteLinkPassword,
|
||||||
left: true,
|
left: true,
|
||||||
name: title,
|
name: title,
|
||||||
revision: result.version,
|
revision: dropNull(result.version),
|
||||||
temporaryMemberCount: memberCount,
|
temporaryMemberCount: memberCount,
|
||||||
timestamp,
|
timestamp,
|
||||||
});
|
});
|
||||||
|
|
|
@ -518,8 +518,10 @@ async function getGroupPreview(
|
||||||
}
|
}
|
||||||
|
|
||||||
const title =
|
const title =
|
||||||
window.Signal.Groups.decryptGroupTitle(result.title, secretParams) ||
|
window.Signal.Groups.decryptGroupTitle(
|
||||||
window.i18n('icu:unknownGroup');
|
dropNull(result.title),
|
||||||
|
secretParams
|
||||||
|
) || window.i18n('icu:unknownGroup');
|
||||||
const description = window.i18n('icu:GroupV2--join--group-metadata--full', {
|
const description = window.i18n('icu:GroupV2--join--group-metadata--full', {
|
||||||
memberCount: result?.memberCount ?? 0,
|
memberCount: result?.memberCount ?? 0,
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
|
import Long from 'long';
|
||||||
|
|
||||||
import * as Bytes from '../../Bytes';
|
import * as Bytes from '../../Bytes';
|
||||||
import type { LocalUserDataType } from '../../util/sessionTranslation';
|
import type { LocalUserDataType } from '../../util/sessionTranslation';
|
||||||
|
@ -11,6 +12,38 @@ import { sessionRecordToProtobuf } from '../../util/sessionTranslation';
|
||||||
|
|
||||||
const getRecordCopy = (record: any): any => JSON.parse(JSON.stringify(record));
|
const getRecordCopy = (record: any): any => JSON.parse(JSON.stringify(record));
|
||||||
|
|
||||||
|
function protoToJSON(value: unknown): unknown {
|
||||||
|
if (value == null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'string' || typeof value === 'number') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
||||||
|
return Buffer.from(value).toString('base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.map(protoToJSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Long.isLong(value)) {
|
||||||
|
return value.toNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
const res: Record<string, unknown> = {};
|
||||||
|
for (const key of Object.keys(value)) {
|
||||||
|
res[key] = protoToJSON((value as Record<string, unknown>)[key]);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
describe('sessionTranslation', () => {
|
describe('sessionTranslation', () => {
|
||||||
let ourData: LocalUserDataType;
|
let ourData: LocalUserDataType;
|
||||||
|
|
||||||
|
@ -93,6 +126,7 @@ describe('sessionTranslation', () => {
|
||||||
index: 0,
|
index: 0,
|
||||||
key: '6EI/Nw+vHhCoB499OpM/kLkQJFzrfqoAZ00w1ZgnowU=',
|
key: '6EI/Nw+vHhCoB499OpM/kLkQJFzrfqoAZ00w1ZgnowU=',
|
||||||
},
|
},
|
||||||
|
messageKeys: [],
|
||||||
},
|
},
|
||||||
receiverChains: [
|
receiverChains: [
|
||||||
{
|
{
|
||||||
|
@ -121,13 +155,14 @@ describe('sessionTranslation', () => {
|
||||||
localRegistrationId: 3554,
|
localRegistrationId: 3554,
|
||||||
aliceBaseKey: 'BVeHv5MAbMgKeaoO/G1CMBdqhC7bo7Mtc4EWxI0oT19N',
|
aliceBaseKey: 'BVeHv5MAbMgKeaoO/G1CMBdqhC7bo7Mtc4EWxI0oT19N',
|
||||||
},
|
},
|
||||||
|
previousSessions: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const recordCopy = getRecordCopy(record);
|
const recordCopy = getRecordCopy(record);
|
||||||
|
|
||||||
const actual = sessionRecordToProtobuf(record, ourData);
|
const actual = sessionRecordToProtobuf(record, ourData);
|
||||||
|
|
||||||
assert.deepEqual(expected, actual.toJSON());
|
assert.deepEqual(expected, protoToJSON(actual));
|
||||||
|
|
||||||
// We want to ensure that conversion doesn't modify incoming data
|
// We want to ensure that conversion doesn't modify incoming data
|
||||||
assert.deepEqual(record, recordCopy);
|
assert.deepEqual(record, recordCopy);
|
||||||
|
@ -330,6 +365,7 @@ describe('sessionTranslation', () => {
|
||||||
index: 0,
|
index: 0,
|
||||||
key: '6EI/Nw+vHhCoB499OpM/kLkQJFzrfqoAZ00w1ZgnowU=',
|
key: '6EI/Nw+vHhCoB499OpM/kLkQJFzrfqoAZ00w1ZgnowU=',
|
||||||
},
|
},
|
||||||
|
messageKeys: [],
|
||||||
},
|
},
|
||||||
receiverChains: [
|
receiverChains: [
|
||||||
{
|
{
|
||||||
|
@ -436,12 +472,14 @@ describe('sessionTranslation', () => {
|
||||||
chainKey: {
|
chainKey: {
|
||||||
index: 3,
|
index: 3,
|
||||||
},
|
},
|
||||||
|
messageKeys: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
senderRatchetKey: 'BRRAnr1NhizgCPPzmYV9qGBpvwCpSQH0Rx+UOtl78wUg',
|
senderRatchetKey: 'BRRAnr1NhizgCPPzmYV9qGBpvwCpSQH0Rx+UOtl78wUg',
|
||||||
chainKey: {
|
chainKey: {
|
||||||
index: 1,
|
index: 1,
|
||||||
},
|
},
|
||||||
|
messageKeys: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
senderRatchetKey: 'BZvOKPA+kXiCg8TIP/52fu1reCDirC7wb5nyRGce3y4N',
|
senderRatchetKey: 'BZvOKPA+kXiCg8TIP/52fu1reCDirC7wb5nyRGce3y4N',
|
||||||
|
@ -488,31 +526,35 @@ describe('sessionTranslation', () => {
|
||||||
chainKey: {
|
chainKey: {
|
||||||
index: 2,
|
index: 2,
|
||||||
},
|
},
|
||||||
|
messageKeys: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
senderRatchetKey: 'BV7ECvKbwKIAD61BXDYr0xr3JtckuKzR1Hw8cVPWGtlo',
|
senderRatchetKey: 'BV7ECvKbwKIAD61BXDYr0xr3JtckuKzR1Hw8cVPWGtlo',
|
||||||
chainKey: {
|
chainKey: {
|
||||||
index: 3,
|
index: 3,
|
||||||
},
|
},
|
||||||
|
messageKeys: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
senderRatchetKey: 'BTC7rQqoykGR5Aaix7RkAhI5fSXufc6pVGN9OIC8EW5c',
|
senderRatchetKey: 'BTC7rQqoykGR5Aaix7RkAhI5fSXufc6pVGN9OIC8EW5c',
|
||||||
chainKey: {
|
chainKey: {
|
||||||
index: 1,
|
index: 1,
|
||||||
},
|
},
|
||||||
|
messageKeys: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
remoteRegistrationId: 4243,
|
remoteRegistrationId: 4243,
|
||||||
localRegistrationId: 3554,
|
localRegistrationId: 3554,
|
||||||
aliceBaseKey: 'BVeHv5MAbMgKeaoO/G1CMBdqhC7bo7Mtc4EWxI0oT19N',
|
aliceBaseKey: 'BVeHv5MAbMgKeaoO/G1CMBdqhC7bo7Mtc4EWxI0oT19N',
|
||||||
},
|
},
|
||||||
|
previousSessions: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const recordCopy = getRecordCopy(record);
|
const recordCopy = getRecordCopy(record);
|
||||||
|
|
||||||
const actual = sessionRecordToProtobuf(record, ourData);
|
const actual = sessionRecordToProtobuf(record, ourData);
|
||||||
|
|
||||||
assert.deepEqual(expected, actual.toJSON());
|
assert.deepEqual(expected, protoToJSON(actual));
|
||||||
|
|
||||||
// We want to ensure that conversion doesn't modify incoming data
|
// We want to ensure that conversion doesn't modify incoming data
|
||||||
assert.deepEqual(record, recordCopy);
|
assert.deepEqual(record, recordCopy);
|
||||||
|
@ -585,6 +627,7 @@ describe('sessionTranslation', () => {
|
||||||
index: 0,
|
index: 0,
|
||||||
key: '6EI/Nw+vHhCoB499OpM/kLkQJFzrfqoAZ00w1ZgnowU=',
|
key: '6EI/Nw+vHhCoB499OpM/kLkQJFzrfqoAZ00w1ZgnowU=',
|
||||||
},
|
},
|
||||||
|
messageKeys: [],
|
||||||
},
|
},
|
||||||
receiverChains: [
|
receiverChains: [
|
||||||
{
|
{
|
||||||
|
@ -618,13 +661,14 @@ describe('sessionTranslation', () => {
|
||||||
localRegistrationId: 3554,
|
localRegistrationId: 3554,
|
||||||
aliceBaseKey: 'BVeHv5MAbMgKeaoO/G1CMBdqhC7bo7Mtc4EWxI0oT19N',
|
aliceBaseKey: 'BVeHv5MAbMgKeaoO/G1CMBdqhC7bo7Mtc4EWxI0oT19N',
|
||||||
},
|
},
|
||||||
|
previousSessions: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const recordCopy = getRecordCopy(record);
|
const recordCopy = getRecordCopy(record);
|
||||||
|
|
||||||
const actual = sessionRecordToProtobuf(record, ourData);
|
const actual = sessionRecordToProtobuf(record, ourData);
|
||||||
|
|
||||||
assert.deepEqual(expected, actual.toJSON());
|
assert.deepEqual(expected, protoToJSON(actual));
|
||||||
|
|
||||||
// We want to ensure that conversion doesn't modify incoming data
|
// We want to ensure that conversion doesn't modify incoming data
|
||||||
assert.deepEqual(record, recordCopy);
|
assert.deepEqual(record, recordCopy);
|
||||||
|
@ -772,6 +816,7 @@ describe('sessionTranslation', () => {
|
||||||
index: 0,
|
index: 0,
|
||||||
key: '6EI/Nw+vHhCoB499OpM/kLkQJFzrfqoAZ00w1ZgnowU=',
|
key: '6EI/Nw+vHhCoB499OpM/kLkQJFzrfqoAZ00w1ZgnowU=',
|
||||||
},
|
},
|
||||||
|
messageKeys: [],
|
||||||
},
|
},
|
||||||
receiverChains: [
|
receiverChains: [
|
||||||
{
|
{
|
||||||
|
@ -815,6 +860,7 @@ describe('sessionTranslation', () => {
|
||||||
index: 0,
|
index: 0,
|
||||||
key: '6EI/Nw+vHhCoB499OpM/kLkQJFzrfqoAZ00w1ZgnowU=',
|
key: '6EI/Nw+vHhCoB499OpM/kLkQJFzrfqoAZ00w1ZgnowU=',
|
||||||
},
|
},
|
||||||
|
messageKeys: [],
|
||||||
},
|
},
|
||||||
receiverChains: [
|
receiverChains: [
|
||||||
{
|
{
|
||||||
|
@ -857,6 +903,7 @@ describe('sessionTranslation', () => {
|
||||||
index: 0,
|
index: 0,
|
||||||
key: '6EI/Nw+vHhCoB499OpM/kLkQJFzrfqoAZ00w1ZgnowU=',
|
key: '6EI/Nw+vHhCoB499OpM/kLkQJFzrfqoAZ00w1ZgnowU=',
|
||||||
},
|
},
|
||||||
|
messageKeys: [],
|
||||||
},
|
},
|
||||||
receiverChains: [
|
receiverChains: [
|
||||||
{
|
{
|
||||||
|
@ -892,7 +939,7 @@ describe('sessionTranslation', () => {
|
||||||
|
|
||||||
const actual = sessionRecordToProtobuf(record, ourData);
|
const actual = sessionRecordToProtobuf(record, ourData);
|
||||||
|
|
||||||
assert.deepEqual(expected, actual.toJSON());
|
assert.deepEqual(expected, protoToJSON(actual));
|
||||||
|
|
||||||
// We want to ensure that conversion doesn't modify incoming data
|
// We want to ensure that conversion doesn't modify incoming data
|
||||||
assert.deepEqual(record, recordCopy);
|
assert.deepEqual(record, recordCopy);
|
||||||
|
@ -950,6 +997,7 @@ describe('sessionTranslation', () => {
|
||||||
signedPreKeyId: 2995,
|
signedPreKeyId: 2995,
|
||||||
},
|
},
|
||||||
previousCounter: 1,
|
previousCounter: 1,
|
||||||
|
receiverChains: [],
|
||||||
remoteIdentityPublic: 'BRmB2uSNpwbXZJjisIh1p/VgRctUZSVIoiEm2ThjiHoq',
|
remoteIdentityPublic: 'BRmB2uSNpwbXZJjisIh1p/VgRctUZSVIoiEm2ThjiHoq',
|
||||||
remoteRegistrationId: 3188,
|
remoteRegistrationId: 3188,
|
||||||
rootKey: 'GzGfNozK5vDKqL4+fdqpiMRIuHNOndM6iMhGubNR1mk=',
|
rootKey: 'GzGfNozK5vDKqL4+fdqpiMRIuHNOndM6iMhGubNR1mk=',
|
||||||
|
@ -958,19 +1006,21 @@ describe('sessionTranslation', () => {
|
||||||
index: 1,
|
index: 1,
|
||||||
key: 'tl5Eby9q7n8PVeiriKoRjHhu9Y0RxvJ90PMq5MfKwgA=',
|
key: 'tl5Eby9q7n8PVeiriKoRjHhu9Y0RxvJ90PMq5MfKwgA=',
|
||||||
},
|
},
|
||||||
|
messageKeys: [],
|
||||||
senderRatchetKey: 'BRSm55wC8hrG5Rp7l9gxtOhugp5ulcco20upOFCPyyJo',
|
senderRatchetKey: 'BRSm55wC8hrG5Rp7l9gxtOhugp5ulcco20upOFCPyyJo',
|
||||||
senderRatchetKeyPrivate:
|
senderRatchetKeyPrivate:
|
||||||
'IC0mCV0kFVAf+Q4cHid5hR7vy+5F0SvpYYaqsSA6d00=',
|
'IC0mCV0kFVAf+Q4cHid5hR7vy+5F0SvpYYaqsSA6d00=',
|
||||||
},
|
},
|
||||||
sessionVersion: 3,
|
sessionVersion: 3,
|
||||||
},
|
},
|
||||||
|
previousSessions: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const recordCopy = getRecordCopy(record);
|
const recordCopy = getRecordCopy(record);
|
||||||
|
|
||||||
const actual = sessionRecordToProtobuf(record, ourData);
|
const actual = sessionRecordToProtobuf(record, ourData);
|
||||||
|
|
||||||
assert.deepEqual(expected, actual.toJSON());
|
assert.deepEqual(expected, protoToJSON(actual));
|
||||||
|
|
||||||
// We want to ensure that conversion doesn't modify incoming data
|
// We want to ensure that conversion doesn't modify incoming data
|
||||||
assert.deepEqual(record, recordCopy);
|
assert.deepEqual(record, recordCopy);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import type { PrimaryDevice } from '@signalapp/mock-server';
|
import type { PrimaryDevice } from '@signalapp/mock-server';
|
||||||
|
import { Proto } from '@signalapp/mock-server';
|
||||||
import createDebug from 'debug';
|
import createDebug from 'debug';
|
||||||
import Long from 'long';
|
import Long from 'long';
|
||||||
import type { Page } from 'playwright';
|
import type { Page } from 'playwright';
|
||||||
|
@ -48,6 +49,8 @@ describe('unknown contacts', function (this: Mocha.Suite) {
|
||||||
callingMessage: {
|
callingMessage: {
|
||||||
offer: {
|
offer: {
|
||||||
callId: new Long(Math.floor(Math.random() * 1e10)),
|
callId: new Long(Math.floor(Math.random() * 1e10)),
|
||||||
|
type: Proto.CallingMessage.Offer.Type.OFFER_AUDIO_CALL,
|
||||||
|
opaque: new Uint8Array(0),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -50,7 +50,7 @@ import {
|
||||||
import { normalizeAci } from '../util/normalizeAci';
|
import { normalizeAci } from '../util/normalizeAci';
|
||||||
import { isMoreRecentThan, isOlderThan } from '../util/timestamp';
|
import { isMoreRecentThan, isOlderThan } from '../util/timestamp';
|
||||||
import { ourProfileKeyService } from '../services/ourProfileKey';
|
import { ourProfileKeyService } from '../services/ourProfileKey';
|
||||||
import { assertDev, strictAssert } from '../util/assert';
|
import { strictAssert } from '../util/assert';
|
||||||
import { getRegionCodeForNumber } from '../util/libphonenumberUtil';
|
import { getRegionCodeForNumber } from '../util/libphonenumberUtil';
|
||||||
import { isNotNil } from '../util/isNotNil';
|
import { isNotNil } from '../util/isNotNil';
|
||||||
import { missingCaseError } from '../util/missingCaseError';
|
import { missingCaseError } from '../util/missingCaseError';
|
||||||
|
@ -258,12 +258,21 @@ export default class AccountManager extends EventTarget {
|
||||||
|
|
||||||
const bytes = Bytes.fromBase64(base64);
|
const bytes = Bytes.fromBase64(base64);
|
||||||
const proto = Proto.DeviceName.decode(bytes);
|
const proto = Proto.DeviceName.decode(bytes);
|
||||||
assertDev(
|
strictAssert(
|
||||||
proto.ephemeralPublic && proto.syntheticIv && proto.ciphertext,
|
proto.ephemeralPublic,
|
||||||
'Missing required fields in DeviceName'
|
'Missing ephemeralPublic field in DeviceName'
|
||||||
);
|
);
|
||||||
|
strictAssert(proto.syntheticIv, 'Missing syntheticIv field in DeviceName');
|
||||||
|
strictAssert(proto.ciphertext, 'Missing ciphertext field in DeviceName');
|
||||||
|
|
||||||
const name = decryptDeviceName(proto, identityKey.privKey);
|
const name = decryptDeviceName(
|
||||||
|
{
|
||||||
|
ephemeralPublic: proto.ephemeralPublic,
|
||||||
|
syntheticIv: proto.syntheticIv,
|
||||||
|
ciphertext: proto.ciphertext,
|
||||||
|
},
|
||||||
|
identityKey.privKey
|
||||||
|
);
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -398,7 +398,7 @@ export default class MessageReceiver
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decoded = Proto.Envelope.decode(plaintext);
|
const decoded = Proto.Envelope.decode(plaintext);
|
||||||
const serverTimestamp = decoded.serverTimestamp?.toNumber();
|
const serverTimestamp = decoded.serverTimestamp?.toNumber() ?? 0;
|
||||||
|
|
||||||
const ourAci = this.storage.user.getCheckedAci();
|
const ourAci = this.storage.user.getCheckedAci();
|
||||||
|
|
||||||
|
@ -412,14 +412,14 @@ export default class MessageReceiver
|
||||||
messageAgeSec: this.calculateMessageAge(headers, serverTimestamp),
|
messageAgeSec: this.calculateMessageAge(headers, serverTimestamp),
|
||||||
|
|
||||||
// Proto.Envelope fields
|
// Proto.Envelope fields
|
||||||
type: decoded.type,
|
type: decoded.type ?? Proto.Envelope.Type.UNKNOWN,
|
||||||
sourceServiceId: decoded.sourceServiceId
|
sourceServiceId: decoded.sourceServiceId
|
||||||
? normalizeServiceId(
|
? normalizeServiceId(
|
||||||
decoded.sourceServiceId,
|
decoded.sourceServiceId,
|
||||||
'MessageReceiver.handleRequest.sourceServiceId'
|
'MessageReceiver.handleRequest.sourceServiceId'
|
||||||
)
|
)
|
||||||
: undefined,
|
: undefined,
|
||||||
sourceDevice: decoded.sourceDevice,
|
sourceDevice: decoded.sourceDevice ?? 1,
|
||||||
destinationServiceId: decoded.destinationServiceId
|
destinationServiceId: decoded.destinationServiceId
|
||||||
? normalizeServiceId(
|
? normalizeServiceId(
|
||||||
decoded.destinationServiceId,
|
decoded.destinationServiceId,
|
||||||
|
@ -433,12 +433,12 @@ export default class MessageReceiver
|
||||||
'MessageReceiver.handleRequest.updatedPni'
|
'MessageReceiver.handleRequest.updatedPni'
|
||||||
)
|
)
|
||||||
: undefined,
|
: undefined,
|
||||||
timestamp: decoded.timestamp?.toNumber(),
|
timestamp: decoded.timestamp?.toNumber() ?? 0,
|
||||||
content: dropNull(decoded.content),
|
content: dropNull(decoded.content),
|
||||||
serverGuid: decoded.serverGuid,
|
serverGuid: decoded.serverGuid ?? getGuid(),
|
||||||
serverTimestamp,
|
serverTimestamp,
|
||||||
urgent: isBoolean(decoded.urgent) ? decoded.urgent : true,
|
urgent: isBoolean(decoded.urgent) ? decoded.urgent : true,
|
||||||
story: decoded.story,
|
story: decoded.story ?? false,
|
||||||
reportingToken: decoded.reportingToken?.length
|
reportingToken: decoded.reportingToken?.length
|
||||||
? decoded.reportingToken
|
? decoded.reportingToken
|
||||||
: undefined,
|
: undefined,
|
||||||
|
@ -873,7 +873,7 @@ export default class MessageReceiver
|
||||||
messageAgeSec: item.messageAgeSec || 0,
|
messageAgeSec: item.messageAgeSec || 0,
|
||||||
|
|
||||||
// Proto.Envelope fields
|
// Proto.Envelope fields
|
||||||
type: decoded.type,
|
type: decoded.type ?? Proto.Envelope.Type.UNKNOWN,
|
||||||
source: item.source,
|
source: item.source,
|
||||||
sourceServiceId: normalizeServiceId(
|
sourceServiceId: normalizeServiceId(
|
||||||
item.sourceServiceId || decoded.sourceServiceId,
|
item.sourceServiceId || decoded.sourceServiceId,
|
||||||
|
@ -890,11 +890,11 @@ export default class MessageReceiver
|
||||||
'CachedEnvelope.updatedPni'
|
'CachedEnvelope.updatedPni'
|
||||||
)
|
)
|
||||||
: undefined,
|
: undefined,
|
||||||
timestamp: decoded.timestamp?.toNumber(),
|
timestamp: decoded.timestamp?.toNumber() ?? 0,
|
||||||
content: dropNull(decoded.content),
|
content: dropNull(decoded.content),
|
||||||
serverGuid: decoded.serverGuid,
|
serverGuid: decoded.serverGuid ?? getGuid(),
|
||||||
serverTimestamp:
|
serverTimestamp:
|
||||||
item.serverTimestamp || decoded.serverTimestamp?.toNumber(),
|
item.serverTimestamp || decoded.serverTimestamp?.toNumber() || 0,
|
||||||
urgent: isBoolean(item.urgent) ? item.urgent : true,
|
urgent: isBoolean(item.urgent) ? item.urgent : true,
|
||||||
story: Boolean(item.story),
|
story: Boolean(item.story),
|
||||||
reportingToken: item.reportingToken
|
reportingToken: item.reportingToken
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
import { calculateAgreement, createKeyPair, generateKeyPair } from '../Curve';
|
import { calculateAgreement, createKeyPair, generateKeyPair } from '../Curve';
|
||||||
import { SignalService as Proto } from '../protobuf';
|
import { SignalService as Proto } from '../protobuf';
|
||||||
import { strictAssert } from '../util/assert';
|
import { strictAssert } from '../util/assert';
|
||||||
|
import { dropNull } from '../util/dropNull';
|
||||||
|
|
||||||
type ProvisionDecryptResult = {
|
type ProvisionDecryptResult = {
|
||||||
aciKeyPair: KeyPairType;
|
aciKeyPair: KeyPairType;
|
||||||
|
@ -34,9 +35,10 @@ class ProvisioningCipherInner {
|
||||||
provisionEnvelope: Proto.ProvisionEnvelope
|
provisionEnvelope: Proto.ProvisionEnvelope
|
||||||
): Promise<ProvisionDecryptResult> {
|
): Promise<ProvisionDecryptResult> {
|
||||||
strictAssert(
|
strictAssert(
|
||||||
provisionEnvelope.publicKey && provisionEnvelope.body,
|
provisionEnvelope.publicKey,
|
||||||
'Missing required fields in ProvisionEnvelope'
|
'Missing publicKey in ProvisionEnvelope'
|
||||||
);
|
);
|
||||||
|
strictAssert(provisionEnvelope.body, 'Missing body in ProvisionEnvelope');
|
||||||
const masterEphemeral = provisionEnvelope.publicKey;
|
const masterEphemeral = provisionEnvelope.publicKey;
|
||||||
const message = provisionEnvelope.body;
|
const message = provisionEnvelope.body;
|
||||||
if (new Uint8Array(message)[0] !== 1) {
|
if (new Uint8Array(message)[0] !== 1) {
|
||||||
|
@ -78,12 +80,12 @@ class ProvisioningCipherInner {
|
||||||
const ret: ProvisionDecryptResult = {
|
const ret: ProvisionDecryptResult = {
|
||||||
aciKeyPair,
|
aciKeyPair,
|
||||||
pniKeyPair,
|
pniKeyPair,
|
||||||
number: provisionMessage.number,
|
number: dropNull(provisionMessage.number),
|
||||||
aci,
|
aci,
|
||||||
untaggedPni: pni,
|
untaggedPni: pni,
|
||||||
provisioningCode: provisionMessage.provisioningCode,
|
provisioningCode: dropNull(provisionMessage.provisioningCode),
|
||||||
userAgent: provisionMessage.userAgent,
|
userAgent: dropNull(provisionMessage.userAgent),
|
||||||
readReceipts: provisionMessage.readReceipts,
|
readReceipts: provisionMessage.readReceipts ?? false,
|
||||||
};
|
};
|
||||||
if (Bytes.isNotEmpty(provisionMessage.profileKey)) {
|
if (Bytes.isNotEmpty(provisionMessage.profileKey)) {
|
||||||
ret.profileKey = provisionMessage.profileKey;
|
ret.profileKey = provisionMessage.profileKey;
|
||||||
|
|
|
@ -3390,7 +3390,7 @@ export function initialize({
|
||||||
return getGroupLog(
|
return getGroupLog(
|
||||||
{
|
{
|
||||||
...options,
|
...options,
|
||||||
startVersion: joinedAtVersion,
|
startVersion: joinedAtVersion ?? 0,
|
||||||
},
|
},
|
||||||
credentials
|
credentials
|
||||||
);
|
);
|
||||||
|
|
|
@ -203,6 +203,9 @@ function decodeSingleResponse(
|
||||||
resultMap: Map<string, CDSResponseEntryType>,
|
resultMap: Map<string, CDSResponseEntryType>,
|
||||||
response: Proto.CDSClientResponse
|
response: Proto.CDSClientResponse
|
||||||
): void {
|
): void {
|
||||||
|
if (!response.e164PniAciTriples) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (
|
for (
|
||||||
let i = 0;
|
let i = 0;
|
||||||
i < response.e164PniAciTriples.length;
|
i < response.e164PniAciTriples.length;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright 2019 Signal Messenger, LLC
|
// Copyright 2019 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { isNumber, pick, reject, groupBy, values } from 'lodash';
|
import { isNumber, reject, groupBy, values } from 'lodash';
|
||||||
import pMap from 'p-map';
|
import pMap from 'p-map';
|
||||||
import Queue from 'p-queue';
|
import Queue from 'p-queue';
|
||||||
|
|
||||||
|
@ -472,7 +472,8 @@ export async function downloadEphemeralPack(
|
||||||
coverStickerId,
|
coverStickerId,
|
||||||
stickerCount,
|
stickerCount,
|
||||||
status: 'ephemeral' as const,
|
status: 'ephemeral' as const,
|
||||||
...pick(proto, ['title', 'author']),
|
title: proto.title ?? '',
|
||||||
|
author: proto.author ?? '',
|
||||||
};
|
};
|
||||||
stickerPackAdded(pack);
|
stickerPackAdded(pack);
|
||||||
|
|
||||||
|
@ -691,7 +692,8 @@ async function doDownloadStickerPack(
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
stickers: {},
|
stickers: {},
|
||||||
storageNeedsSync: !fromStorageService,
|
storageNeedsSync: !fromStorageService,
|
||||||
...pick(proto, ['title', 'author']),
|
title: proto.title ?? '',
|
||||||
|
author: proto.author ?? '',
|
||||||
};
|
};
|
||||||
await Data.createOrUpdateStickerPack(pack);
|
await Data.createOrUpdateStickerPack(pack);
|
||||||
stickerPackAdded(pack);
|
stickerPackAdded(pack);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue