From 59da9c7ae52078c8ce6328f12a2c87ac9d81fb3b Mon Sep 17 00:00:00 2001 From: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com> Date: Wed, 21 Sep 2022 09:18:48 -0700 Subject: [PATCH] Stop using deprecated PniCredential --- package.json | 2 +- ts/groups.ts | 34 +++----- ts/model-types.d.ts | 3 +- ts/models/conversations.ts | 35 +++----- ts/services/profiles.ts | 86 +------------------ ts/test-mock/pnp/accept_gv2_invite_test.ts | 2 +- ts/test-mock/pnp/change_number_test.ts | 2 +- ts/test-mock/pnp/pni_signature_test.ts | 2 +- ts/test-mock/pnp/send_gv2_invite_test.ts | 2 +- ts/textsecure/WebAPI.ts | 6 +- ts/util/zkgroup.ts | 97 +--------------------- yarn.lock | 8 +- 12 files changed, 38 insertions(+), 241 deletions(-) diff --git a/package.json b/package.json index 031d56390..a829149a0 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/ts/groups.ts b/ts/groups.ts index 8391444bf..737b02d62 100644 --- a/ts/groups.ts +++ b/ts/groups.ts @@ -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, }, diff --git a/ts/model-types.d.ts b/ts/model-types.d.ts index 43f629ab5..1663ed358 100644 --- a/ts/model-types.d.ts +++ b/ts/model-types.d.ts @@ -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; diff --git a/ts/models/conversations.ts b/ts/models/conversations.ts index ceebabed9..09560d6b4 100644 --- a/ts/models/conversations.ts +++ b/ts/models/conversations.ts @@ -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, }); diff --git a/ts/services/profiles.ts b/ts/services/profiles.ts index d0a14cc95..e1218d164 100644 --- a/ts/services/profiles.ts +++ b/ts/services/profiles.ts @@ -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 { } } - 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 { window.Signal.Data.updateConversation(c.attributes); } -async function maybeGetPNICredential( - c: ConversationModel, - { - clientZkProfileCipher, - profileKey, - profileKeyVersion, - userLanguages, - }: { - clientZkProfileCipher: ClientZkProfileOperations; - profileKey: string; - profileKeyVersion: string; - userLanguages: ReadonlyArray; - } -): Promise { - // 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 diff --git a/ts/test-mock/pnp/accept_gv2_invite_test.ts b/ts/test-mock/pnp/accept_gv2_invite_test.ts index 9b75cc158..34481db96 100644 --- a/ts/test-mock/pnp/accept_gv2_invite_test.ts +++ b/ts/test-mock/pnp/accept_gv2_invite_test.ts @@ -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; diff --git a/ts/test-mock/pnp/change_number_test.ts b/ts/test-mock/pnp/change_number_test.ts index 4977d4184..c8b2b255d 100644 --- a/ts/test-mock/pnp/change_number_test.ts +++ b/ts/test-mock/pnp/change_number_test.ts @@ -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; diff --git a/ts/test-mock/pnp/pni_signature_test.ts b/ts/test-mock/pnp/pni_signature_test.ts index 5ae276823..de74ad55b 100644 --- a/ts/test-mock/pnp/pni_signature_test.ts +++ b/ts/test-mock/pnp/pni_signature_test.ts @@ -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; diff --git a/ts/test-mock/pnp/send_gv2_invite_test.ts b/ts/test-mock/pnp/send_gv2_invite_test.ts index 566387427..d5888abf0 100644 --- a/ts/test-mock/pnp/send_gv2_invite_test.ts +++ b/ts/test-mock/pnp/send_gv2_invite_test.ts @@ -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; diff --git a/ts/textsecure/WebAPI.ts b/ts/textsecure/WebAPI.ts index 659eee92d..54b881277 100644 --- a/ts/textsecure/WebAPI.ts +++ b/ts/textsecure/WebAPI.ts @@ -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; - 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( diff --git a/ts/util/zkgroup.ts b/ts/util/zkgroup.ts index 686f0e00f..a3e1b7e3c 100644 --- a/ts/util/zkgroup.ts +++ b/ts/util/zkgroup.ts @@ -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 diff --git a/yarn.lock b/yarn.lock index fd2d9f918..3ad0b4bf3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"