Refresh PNI on startup

This commit is contained in:
Fedor Indutny 2022-07-18 15:32:00 -07:00 committed by GitHub
parent a4cf2e0948
commit 5c2016ec40
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 90 additions and 75 deletions

View file

@ -146,7 +146,7 @@ import { showToast } from './util/showToast';
import { startInteractionMode } from './windows/startInteractionMode';
import type { MainWindowStatsType } from './windows/context';
import { deliveryReceiptsJobQueue } from './jobs/deliveryReceiptsJobQueue';
import { updateOurUsername } from './util/updateOurUsername';
import { updateOurUsernameAndPni } from './util/updateOurUsernameAndPni';
import { ReactionSource } from './reactions/ReactionSource';
import { singleProtoJobQueue } from './jobs/singleProtoJobQueue';
import { getInitialState } from './state/getInitialState';
@ -2213,18 +2213,6 @@ export async function startApp(): Promise<void> {
return unlinkAndDisconnect(RemoveAllConfiguration.Full);
}
if (!window.textsecure.storage.user.getUuid(UUIDKind.PNI)) {
log.info('PNI not captured during registration, fetching');
const { pni } = await server.whoami();
if (!pni) {
log.error('No PNI found, unlinking');
return unlinkAndDisconnect(RemoveAllConfiguration.Soft);
}
log.info('Setting PNI to', pni);
await window.textsecure.storage.user.setPni(pni);
}
if (connectCount === 1) {
try {
// Note: we always have to register our capabilities all at once, so we do this
@ -2239,7 +2227,7 @@ export async function startApp(): Promise<void> {
changeNumber: true,
stories: true,
}),
updateOurUsername(),
updateOurUsernameAndPni(),
]);
} catch (error) {
log.error(
@ -2249,6 +2237,11 @@ export async function startApp(): Promise<void> {
}
}
if (!window.textsecure.storage.user.getUuid(UUIDKind.PNI)) {
log.error('PNI not captured during registration, unlinking softly');
return unlinkAndDisconnect(RemoveAllConfiguration.Soft);
}
if (firstRun === true && deviceId !== 1) {
const hasThemeSetting = Boolean(window.storage.get('theme-setting'));
if (
@ -3625,7 +3618,10 @@ export async function startApp(): Promise<void> {
case FETCH_LATEST_ENUM.LOCAL_PROFILE: {
const ourUuid = window.textsecure.storage.user.getUuid()?.toString();
const ourE164 = window.textsecure.storage.user.getNumber();
await Promise.all([getProfile(ourUuid, ourE164), updateOurUsername()]);
await Promise.all([
getProfile(ourUuid, ourE164),
updateOurUsernameAndPni(),
]);
break;
}
case FETCH_LATEST_ENUM.STORAGE_MANIFEST:

View file

@ -3,7 +3,7 @@
import { singleProtoJobQueue } from '../jobs/singleProtoJobQueue';
import dataInterface from '../sql/Client';
import { updateOurUsername } from '../util/updateOurUsername';
import { updateOurUsernameAndPni } from '../util/updateOurUsernameAndPni';
import * as Errors from '../types/errors';
import * as log from '../logging/log';
import MessageSender from '../textsecure/SendMessage';
@ -21,7 +21,7 @@ export async function writeUsername({
}
const me = window.ConversationController.getOurConversationOrThrow();
await updateOurUsername();
await updateOurUsernameAndPni();
if (me.get('username') !== previousUsername) {
throw new Error('Username has changed on another device');

View file

@ -33,6 +33,7 @@ import { ourProfileKeyService } from '../services/ourProfileKey';
import { assert, strictAssert } from '../util/assert';
import { getRegionCodeForNumber } from '../util/libphonenumberUtil';
import { getProvisioningUrl } from '../util/getProvisioningUrl';
import { isNotNil } from '../util/isNotNil';
import { SignalService as Proto } from '../protobuf';
import * as log from '../logging/log';
@ -43,19 +44,6 @@ const PREKEY_ROTATION_AGE = DAY * 1.5;
const PROFILE_KEY_LENGTH = 32;
const SIGNED_KEY_GEN_BATCH_SIZE = 100;
function getIdentifier(id: string | undefined) {
if (!id || !id.length) {
return id;
}
const parts = id.split('.');
if (!parts.length) {
return id;
}
return parts[0];
}
export type GeneratedKeysType = {
preKeys: Array<{
keyId: number;
@ -529,8 +517,9 @@ export default class AccountManager extends EventTarget {
password = password.substring(0, password.length - 2);
const registrationId = generateRegistrationId();
const previousNumber = getIdentifier(storage.get('number_id'));
const previousUuid = getIdentifier(storage.get('uuid_id'));
const previousNumber = storage.user.getNumber();
const previousACI = storage.user.getUuid(UUIDKind.ACI)?.toString();
const previousPNI = storage.user.getUuid(UUIDKind.PNI)?.toString();
let encryptedDeviceName;
if (deviceName) {
@ -556,11 +545,11 @@ export default class AccountManager extends EventTarget {
const ourUuid = UUID.cast(response.uuid);
const ourPni = UUID.cast(response.pni);
const uuidChanged = previousUuid && ourUuid && previousUuid !== ourUuid;
const uuidChanged = previousACI && ourUuid && previousACI !== ourUuid;
// We only consider the number changed if we didn't have a UUID before
const numberChanged =
!previousUuid && previousNumber && previousNumber !== number;
!previousACI && previousNumber && previousNumber !== number;
if (uuidChanged || numberChanged) {
if (uuidChanged) {
@ -592,15 +581,17 @@ export default class AccountManager extends EventTarget {
await senderCertificateService.clear();
if (previousUuid) {
const previousUuids = [previousACI, previousPNI].filter(isNotNil);
if (previousUuids.length > 0) {
await Promise.all([
storage.put(
'identityKeyMap',
omit(storage.get('identityKeyMap') || {}, previousUuid)
omit(storage.get('identityKeyMap') || {}, previousUuids)
),
storage.put(
'registrationIdMap',
omit(storage.get('registrationIdMap') || {}, previousUuid)
omit(storage.get('registrationIdMap') || {}, previousUuids)
),
]);
}
@ -849,4 +840,31 @@ export default class AccountManager extends EventTarget {
log.info('registration done');
this.dispatchEvent(new Event('registration'));
}
async setPni(pni: string): Promise<void> {
const { storage } = window.textsecure;
const oldPni = storage.user.getUuid(UUIDKind.PNI)?.toString();
if (oldPni === pni) {
return;
}
if (oldPni) {
await Promise.all([
storage.put(
'identityKeyMap',
omit(storage.get('identityKeyMap') || {}, oldPni)
),
storage.put(
'registrationIdMap',
omit(storage.get('registrationIdMap') || {}, oldPni)
),
]);
}
log.info(`AccountManager.setPni: updating pni from ${oldPni} to ${pni}`);
await storage.user.setPni(pni);
await storage.protocol.hydrateCaches();
}
}

View file

@ -2407,7 +2407,4 @@ export default class MessageSender {
async deleteUsername(): Promise<ReturnType<WebAPIType['deleteUsername']>> {
return this.server.deleteUsername();
}
async whoami(): Promise<ReturnType<WebAPIType['whoami']>> {
return this.server.whoami();
}
}

View file

@ -33,7 +33,7 @@ import type { SocketStatus } from '../types/SocketStatus';
import { toLogFormat } from '../types/errors';
import { isPackIdValid, redactPackId } from '../types/Stickers';
import type { UUID, UUIDStringType } from '../types/UUID';
import { isValidUuid, UUIDKind } from '../types/UUID';
import { UUIDKind } from '../types/UUID';
import * as Bytes from '../Bytes';
import { getRandomValue } from '../Crypto';
import * as linkPreviewFetch from '../linkPreviews/linkPreviewFetch';
@ -750,12 +750,15 @@ export type MakeProxiedRequestResultType =
totalSize: number;
};
export type WhoamiResultType = Readonly<{
uuid?: UUIDStringType;
pni?: UUIDStringType;
number?: string;
username?: string;
}>;
const whoamiResultZod = z
.object({
uuid: z.string(),
pni: z.string(),
number: z.string(),
username: z.string().or(z.null()).optional(),
})
.passthrough();
export type WhoamiResultType = z.infer<typeof whoamiResultZod>;
export type ConfirmCodeResultType = Readonly<{
uuid: UUIDStringType;
@ -1396,18 +1399,7 @@ export function initialize({
responseType: 'json',
});
if (!isRecord(response)) {
return {};
}
return {
uuid: isValidUuid(response.uuid) ? response.uuid : undefined,
pni: isValidUuid(response.pni) ? response.pni : undefined,
number:
typeof response.number === 'string' ? response.number : undefined,
username:
typeof response.username === 'string' ? response.username : undefined,
};
return whoamiResultZod.parse(response);
}
async function sendChallengeResponse(challengeResponse: ChallengeType) {

View file

@ -1,16 +0,0 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
export async function updateOurUsername(): Promise<void> {
if (!window.textsecure.messaging) {
throw new Error(
'updateOurUsername: window.textsecure.messaging not available'
);
}
const me = window.ConversationController.getOurConversationOrThrow();
const { username } = await window.textsecure.messaging.whoami();
me.set({ username });
window.Signal.Data.updateConversation(me.attributes);
}

View file

@ -0,0 +1,28 @@
// Copyright 2021-2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { strictAssert } from './assert';
import { dropNull } from './dropNull';
export async function updateOurUsernameAndPni(): Promise<void> {
const { server } = window.textsecure;
strictAssert(
server,
'updateOurUsernameAndPni: window.textsecure.server not available'
);
const me = window.ConversationController.getOurConversationOrThrow();
const { username, pni } = await server.whoami();
me.set({ username: dropNull(username) });
window.Signal.Data.updateConversation(me.attributes);
const manager = window.getAccountManager();
strictAssert(
manager,
'updateOurUsernameAndPni: AccountManager not available'
);
await manager.setPni(pni);
}