Stop using deprecated PniCredential

This commit is contained in:
Fedor Indutny 2022-09-21 09:18:48 -07:00 committed by GitHub
parent b7526d4e26
commit 59da9c7ae5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 38 additions and 241 deletions

View File

@ -193,7 +193,7 @@
"@babel/preset-typescript": "7.17.12",
"@electron/fuses": "1.5.0",
"@mixer/parallel-prettier": "2.0.1",
"@signalapp/mock-server": "2.9.0",
"@signalapp/mock-server": "2.9.1",
"@storybook/addon-a11y": "6.5.6",
"@storybook/addon-actions": "6.5.6",
"@storybook/addon-controls": "6.5.6",

View File

@ -35,7 +35,6 @@ import type {
} from './model-types.d';
import {
createProfileKeyCredentialPresentation,
createPNICredentialPresentation,
decodeProfileKeyCredentialPresentation,
decryptGroupBlob,
decryptProfileKey,
@ -1357,15 +1356,15 @@ export function buildPromotePendingAdminApprovalMemberChange({
export type BuildPromoteMemberChangeOptionsType = Readonly<{
group: ConversationAttributesType;
serverPublicParamsBase64: string;
profileKeyCredentialBase64?: string;
pniCredentialBase64?: string;
profileKeyCredentialBase64: string;
isPendingPniAciProfileKey: boolean;
}>;
export function buildPromoteMemberChange({
group,
profileKeyCredentialBase64,
pniCredentialBase64,
serverPublicParamsBase64,
isPendingPniAciProfileKey = false,
}: BuildPromoteMemberChangeOptionsType): Proto.GroupChange.Actions {
const actions = new Proto.GroupChange.Actions();
@ -1381,31 +1380,20 @@ export function buildPromoteMemberChange({
serverPublicParamsBase64
);
let presentation: Uint8Array;
if (profileKeyCredentialBase64 !== undefined) {
presentation = createProfileKeyCredentialPresentation(
clientZkProfileCipher,
profileKeyCredentialBase64,
group.secretParams
);
const presentation = createProfileKeyCredentialPresentation(
clientZkProfileCipher,
profileKeyCredentialBase64,
group.secretParams
);
actions.promotePendingMembers = [
if (isPendingPniAciProfileKey) {
actions.promoteMembersPendingPniAciProfileKey = [
{
presentation,
},
];
} else {
strictAssert(
pniCredentialBase64,
'Either pniCredential or profileKeyCredential must be present'
);
presentation = createPNICredentialPresentation(
clientZkProfileCipher,
pniCredentialBase64,
group.secretParams
);
actions.promoteMembersPendingPniAciProfileKey = [
actions.promotePendingMembers = [
{
presentation,
},

3
ts/model-types.d.ts vendored
View File

@ -293,7 +293,8 @@ export type ConversationAttributesType = {
};
profileKeyCredential?: string | null;
profileKeyCredentialExpiration?: number | null;
pniCredential?: string | null;
// TODO: DESKTOP-4223
pniCredential?: void;
lastProfile?: ConversationLastProfileType;
quotedMessageId?: string | null;
sealedSender?: unknown;

View File

@ -503,19 +503,17 @@ export class ConversationModel extends window.Backbone
// We need the user's profileKeyCredential, which requires a roundtrip with the
// server, and most definitely their profileKey. A getProfiles() call will
// ensure that we have as much as we can get with the data we have.
if (!us.get('profileKeyCredential')) {
await us.getProfiles();
}
const profileKeyCredentialBase64 = us.get('profileKeyCredential');
strictAssert(profileKeyCredentialBase64, 'Must have profileKeyCredential');
if (uuidKind === UUIDKind.ACI) {
if (!us.get('profileKeyCredential')) {
await us.getProfiles();
}
const profileKeyCredentialBase64 = us.get('profileKeyCredential');
strictAssert(
profileKeyCredentialBase64,
'Must have profileKeyCredential'
);
return window.Signal.Groups.buildPromoteMemberChange({
group: this.attributes,
isPendingPniAciProfileKey: false,
profileKeyCredentialBase64,
serverPublicParamsBase64: window.getServerPublicParams(),
});
@ -523,17 +521,10 @@ export class ConversationModel extends window.Backbone
strictAssert(uuidKind === UUIDKind.PNI, 'Must be a PNI promotion');
// Similarly we need `pniCredential` even if this would require a server
// roundtrip.
if (!us.get('pniCredential')) {
await us.getProfiles();
}
const pniCredentialBase64 = us.get('pniCredential');
strictAssert(pniCredentialBase64, 'Must have pniCredential');
return window.Signal.Groups.buildPromoteMemberChange({
group: this.attributes,
pniCredentialBase64,
isPendingPniAciProfileKey: true,
profileKeyCredentialBase64,
serverPublicParamsBase64: window.getServerPublicParams(),
});
}
@ -1945,11 +1936,6 @@ export class ConversationModel extends window.Backbone
if (e164 !== oldValue) {
this.set('e164', e164 || undefined);
// When our own number has changed - reset pniCredential
if (isMe(this.attributes)) {
this.set({ pniCredential: null });
}
if (oldValue && e164) {
this.addChangeNumberNotification(oldValue, e164);
}
@ -4782,7 +4768,6 @@ export class ConversationModel extends window.Backbone
this.set({
profileKeyCredential: null,
profileKeyCredentialExpiration: null,
pniCredential: null,
accessKey: null,
sealedSender: SEALED_SENDER.UNKNOWN,
});

View File

@ -1,10 +1,7 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type {
ProfileKeyCredentialRequestContext,
ClientZkProfileOperations,
} from '@signalapp/libsignal-client/zkgroup';
import type { ProfileKeyCredentialRequestContext } from '@signalapp/libsignal-client/zkgroup';
import PQueue from 'p-queue';
import type { ConversationModel } from '../models/conversations';
@ -22,10 +19,8 @@ import { sleep } from '../util/sleep';
import { MINUTE, SECOND } from '../util/durations';
import {
generateProfileKeyCredentialRequest,
generatePNICredentialRequest,
getClientZkProfileOperations,
handleProfileKeyCredential,
handleProfileKeyPNICredential,
} from '../util/zkgroup';
import { isMe } from '../util/whatTypeOfConversation';
import { getUserLanguages } from '../util/userLanguages';
@ -36,7 +31,6 @@ import { SEALED_SENDER } from '../types/SealedSender';
import { HTTPError } from '../textsecure/Errors';
import { Address } from '../types/Address';
import { QualifiedAddress } from '../types/QualifiedAddress';
import { UUIDKind } from '../types/UUID';
import { trimForDisplay, verifyAccessKey, decryptProfile } from '../Crypto';
type JobType = {
@ -343,20 +337,8 @@ async function doGetProfile(c: ConversationModel): Promise<void> {
}
}
if (isMe(c.attributes) && profileKey && profileKeyVersion) {
try {
await maybeGetPNICredential(c, {
clientZkProfileCipher,
profileKey,
profileKeyVersion,
userLanguages,
});
} catch (error) {
log.warn(
'getProfile failed to get our own PNI credential',
Errors.toLogFormat(error)
);
}
if (isMe(c.attributes)) {
c.unset('pniCredential');
}
if (profile.identityKey) {
@ -582,68 +564,6 @@ async function doGetProfile(c: ConversationModel): Promise<void> {
window.Signal.Data.updateConversation(c.attributes);
}
async function maybeGetPNICredential(
c: ConversationModel,
{
clientZkProfileCipher,
profileKey,
profileKeyVersion,
userLanguages,
}: {
clientZkProfileCipher: ClientZkProfileOperations;
profileKey: string;
profileKeyVersion: string;
userLanguages: ReadonlyArray<string>;
}
): Promise<void> {
// Already present and up-to-date
if (c.get('pniCredential')) {
return;
}
strictAssert(isMe(c.attributes), 'Has to fetch PNI credential for ourselves');
log.info('maybeGetPNICredential: requesting PNI credential');
const { storage, messaging } = window.textsecure;
strictAssert(
messaging,
'maybeGetPNICredential: window.textsecure.messaging not available'
);
const ourACI = storage.user.getCheckedUuid(UUIDKind.ACI);
const ourPNI = storage.user.getCheckedUuid(UUIDKind.PNI);
const {
requestHex: profileKeyCredentialRequestHex,
context: profileCredentialRequestContext,
} = generatePNICredentialRequest(
clientZkProfileCipher,
ourACI.toString(),
ourPNI.toString(),
profileKey
);
const profile = await messaging.getProfile(ourACI, {
userLanguages,
profileKeyVersion,
profileKeyCredentialRequest: profileKeyCredentialRequestHex,
credentialType: 'pni',
});
strictAssert(
profile.pniCredential,
'We must get the credential for ourselves'
);
const pniCredential = handleProfileKeyPNICredential(
clientZkProfileCipher,
profileCredentialRequestContext,
profile.pniCredential
);
c.set({ pniCredential });
log.info('maybeGetPNICredential: updated PNI credential');
}
export async function updateIdentityKey(
identityKey: string,
uuid: UUID

View File

@ -12,7 +12,7 @@ import type { App } from '../bootstrap';
export const debug = createDebug('mock:test:gv2');
describe('gv2', function needsName() {
describe('pnp/accept gv2 invite', function needsName() {
this.timeout(durations.MINUTE);
let bootstrap: Bootstrap;

View File

@ -10,7 +10,7 @@ import type { App } from '../bootstrap';
export const debug = createDebug('mock:test:change-number');
describe('PNP change number', function needsName() {
describe('pnp/change number', function needsName() {
this.timeout(durations.MINUTE);
let bootstrap: Bootstrap;

View File

@ -21,7 +21,7 @@ export const debug = createDebug('mock:test:pni-signature');
const IdentifierType = Proto.ManifestRecord.Identifier.Type;
describe('PNI Signature', function needsName() {
describe('pnp/PNI Signature', function needsName() {
this.timeout(durations.MINUTE);
let bootstrap: Bootstrap;

View File

@ -16,7 +16,7 @@ const IdentifierType = Proto.ManifestRecord.Identifier.Type;
export const debug = createDebug('mock:test:gv2');
describe('gv2', function needsName() {
describe('pnp/send gv2 invite', function needsName() {
this.timeout(durations.MINUTE);
let bootstrap: Bootstrap;

View File

@ -694,8 +694,6 @@ export type ProfileType = Readonly<{
uuid?: string;
credential?: string;
// Only present when `credentialType` is `pni`
pniCredential?: string;
capabilities?: CapabilitiesType;
paymentAddress?: string;
badges?: unknown;
@ -753,7 +751,6 @@ export type CdsLookupOptionsType = Readonly<{
type GetProfileCommonOptionsType = Readonly<
{
userLanguages: ReadonlyArray<string>;
credentialType?: 'pni' | 'expiringProfileKey';
} & (
| {
profileKeyVersion?: undefined;
@ -1584,7 +1581,6 @@ export function initialize({
{
profileKeyVersion,
profileKeyCredentialRequest,
credentialType = 'expiringProfileKey',
}: GetProfileCommonOptionsType
) {
let profileUrl = `/${identifier}`;
@ -1593,7 +1589,7 @@ export function initialize({
if (profileKeyCredentialRequest !== undefined) {
profileUrl +=
`/${profileKeyCredentialRequest}` +
`?credentialType=${credentialType}`;
'?credentialType=expiringProfileKey';
}
} else {
strictAssert(

View File

@ -1,10 +1,7 @@
// Copyright 2020-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type {
ProfileKeyCredentialRequestContext,
PniCredentialRequestContext,
} from '@signalapp/libsignal-client/zkgroup';
import type { ProfileKeyCredentialRequestContext } from '@signalapp/libsignal-client/zkgroup';
import {
AuthCredentialWithPni,
ClientZkAuthOperations,
@ -17,15 +14,11 @@ import {
ExpiringProfileKeyCredential,
ProfileKeyCredentialPresentation,
ExpiringProfileKeyCredentialResponse,
PniCredential,
PniCredentialResponse,
PniCredentialPresentation,
ServerPublicParams,
UuidCiphertext,
NotarySignature,
} from '@signalapp/libsignal-client/zkgroup';
import { UUID } from '../types/UUID';
import type { UUIDStringType } from '../types/UUID';
import type { UUID, UUIDStringType } from '../types/UUID';
export * from '@signalapp/libsignal-client/zkgroup';
@ -54,32 +47,6 @@ export function decodeProfileKeyCredentialPresentation(
};
}
export function decryptPniCredentialPresentation(
clientZkGroupCipher: ClientZkGroupCipher,
presentationBuffer: Uint8Array
): { profileKey: Uint8Array; pni: UUIDStringType; aci: UUIDStringType } {
const presentation = new PniCredentialPresentation(
Buffer.from(presentationBuffer)
);
const pniCiphertext = presentation.getPniCiphertext();
const aciCiphertext = presentation.getAciCiphertext();
const aci = clientZkGroupCipher.decryptUuid(aciCiphertext);
const pni = clientZkGroupCipher.decryptUuid(pniCiphertext);
const profileKeyCiphertext = presentation.getProfileKeyCiphertext();
const profileKey = clientZkGroupCipher.decryptProfileKey(
profileKeyCiphertext,
aci
);
return {
profileKey: profileKey.serialize(),
aci: UUID.cast(aci),
pni: UUID.cast(pni),
};
}
export function decryptProfileKey(
clientZkGroupCipher: ClientZkGroupCipher,
profileKeyCiphertextBuffer: Uint8Array,
@ -185,29 +152,6 @@ export function generateProfileKeyCredentialRequest(
};
}
export function generatePNICredentialRequest(
clientZkProfileCipher: ClientZkProfileOperations,
aci: UUIDStringType,
pni: UUIDStringType,
profileKeyBase64: string
): { context: PniCredentialRequestContext; requestHex: string } {
const profileKeyArray = Buffer.from(profileKeyBase64, 'base64');
const profileKey = new ProfileKey(profileKeyArray);
const context = clientZkProfileCipher.createPniCredentialRequestContext(
aci,
pni,
profileKey
);
const request = context.getRequest();
const requestArray = request.serialize();
return {
context,
requestHex: requestArray.toString('hex'),
};
}
export function getAuthCredentialPresentation(
clientZkAuthOperations: ClientZkAuthOperations,
authCredentialBase64: string,
@ -253,25 +197,6 @@ export function createProfileKeyCredentialPresentation(
return presentation.serialize();
}
export function createPNICredentialPresentation(
clientZkProfileCipher: ClientZkProfileOperations,
pniCredentialBase64: string,
groupSecretParamsBase64: string
): Uint8Array {
const pniCredentialArray = Buffer.from(pniCredentialBase64, 'base64');
const pniCredential = new PniCredential(pniCredentialArray);
const secretParams = new GroupSecretParams(
Buffer.from(groupSecretParamsBase64, 'base64')
);
const presentation = clientZkProfileCipher.createPniCredentialPresentation(
secretParams,
pniCredential
);
return presentation.serialize();
}
export function getClientZkAuthOperations(
serverPublicParamsBase64: string
): ClientZkAuthOperations {
@ -324,24 +249,6 @@ export function handleProfileKeyCredential(
};
}
export function handleProfileKeyPNICredential(
clientZkProfileCipher: ClientZkProfileOperations,
context: PniCredentialRequestContext,
responseBase64: string
): string {
const response = new PniCredentialResponse(
Buffer.from(responseBase64, 'base64')
);
const pniCredential = clientZkProfileCipher.receivePniCredential(
context,
response
);
const credentialArray = pniCredential.serialize();
return credentialArray.toString('base64');
}
export function deriveProfileKeyCommitment(
profileKeyBase64: string,
uuid: UUIDStringType

View File

@ -1905,10 +1905,10 @@
node-gyp-build "^4.2.3"
uuid "^8.3.0"
"@signalapp/mock-server@2.9.0":
version "2.9.0"
resolved "https://registry.yarnpkg.com/@signalapp/mock-server/-/mock-server-2.9.0.tgz#7b86b7843cd828db5167d9152214646cabe76724"
integrity sha512-rowEcBwGb53C7gQTR9WTQrS3kO4WB43qTVlA2qeEUIzMruJb44klgrmo1QUiMTtGYuByDApbAC4yOcVNYmae4w==
"@signalapp/mock-server@2.9.1":
version "2.9.1"
resolved "https://registry.yarnpkg.com/@signalapp/mock-server/-/mock-server-2.9.1.tgz#f6cde436d2f6665fbacda425c8b661dedd733831"
integrity sha512-KkMnIcBVmZwGLPzsri2PukKioTg50fsthvAmyjG3iDiuQ9KUaTPKpTf0DT/jFXzkQmwUCjs4MKIQqJYjXZWvvw==
dependencies:
"@signalapp/libsignal-client" "^0.20.0"
debug "^4.3.2"