Stop using deprecated PniCredential
This commit is contained in:
parent
b7526d4e26
commit
59da9c7ae5
12 changed files with 38 additions and 241 deletions
|
@ -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",
|
||||
|
|
34
ts/groups.ts
34
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,
|
||||
},
|
||||
|
|
3
ts/model-types.d.ts
vendored
3
ts/model-types.d.ts
vendored
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue