Block WebAPI during active registration
This commit is contained in:
parent
9e9e5274cf
commit
8070b8b14f
3 changed files with 100 additions and 35 deletions
|
@ -172,24 +172,32 @@ export default class AccountManager extends EventTarget {
|
|||
const profileKey = getRandomBytes(PROFILE_KEY_LENGTH);
|
||||
const accessKey = deriveAccessKey(profileKey);
|
||||
|
||||
await this.createAccount({
|
||||
number,
|
||||
verificationCode,
|
||||
identityKeyPair,
|
||||
pniKeyPair,
|
||||
profileKey,
|
||||
accessKey,
|
||||
});
|
||||
const registrationBaton = this.server.startRegistration();
|
||||
try {
|
||||
await this.createAccount({
|
||||
number,
|
||||
verificationCode,
|
||||
identityKeyPair,
|
||||
pniKeyPair,
|
||||
profileKey,
|
||||
accessKey,
|
||||
});
|
||||
|
||||
await this.clearSessionsAndPreKeys();
|
||||
await this.clearSessionsAndPreKeys();
|
||||
|
||||
await Promise.all(
|
||||
[UUIDKind.ACI, UUIDKind.PNI].map(async kind => {
|
||||
const keys = await this.generateKeys(SIGNED_KEY_GEN_BATCH_SIZE, kind);
|
||||
await this.server.registerKeys(keys, kind);
|
||||
await this.confirmKeys(keys, kind);
|
||||
})
|
||||
);
|
||||
await Promise.all(
|
||||
[UUIDKind.ACI, UUIDKind.PNI].map(async kind => {
|
||||
const keys = await this.generateKeys(
|
||||
SIGNED_KEY_GEN_BATCH_SIZE,
|
||||
kind
|
||||
);
|
||||
await this.server.registerKeys(keys, kind);
|
||||
await this.confirmKeys(keys, kind);
|
||||
})
|
||||
);
|
||||
} finally {
|
||||
this.server.finishRegistration(registrationBaton);
|
||||
}
|
||||
await this.registrationDone();
|
||||
});
|
||||
}
|
||||
|
@ -276,23 +284,30 @@ export default class AccountManager extends EventTarget {
|
|||
);
|
||||
}
|
||||
|
||||
await this.createAccount({
|
||||
number: provisionMessage.number,
|
||||
verificationCode: provisionMessage.provisioningCode,
|
||||
identityKeyPair: provisionMessage.identityKeyPair,
|
||||
profileKey: provisionMessage.profileKey,
|
||||
deviceName,
|
||||
userAgent: provisionMessage.userAgent,
|
||||
readReceipts: provisionMessage.readReceipts,
|
||||
});
|
||||
await clearSessionsAndPreKeys();
|
||||
// TODO: DESKTOP-2794
|
||||
const keys = await this.generateKeys(
|
||||
SIGNED_KEY_GEN_BATCH_SIZE,
|
||||
UUIDKind.ACI
|
||||
);
|
||||
await this.server.registerKeys(keys, UUIDKind.ACI);
|
||||
await this.confirmKeys(keys, UUIDKind.ACI);
|
||||
const registrationBaton = this.server.startRegistration();
|
||||
|
||||
try {
|
||||
await this.createAccount({
|
||||
number: provisionMessage.number,
|
||||
verificationCode: provisionMessage.provisioningCode,
|
||||
identityKeyPair: provisionMessage.identityKeyPair,
|
||||
profileKey: provisionMessage.profileKey,
|
||||
deviceName,
|
||||
userAgent: provisionMessage.userAgent,
|
||||
readReceipts: provisionMessage.readReceipts,
|
||||
});
|
||||
await clearSessionsAndPreKeys();
|
||||
// TODO: DESKTOP-2794
|
||||
const keys = await this.generateKeys(
|
||||
SIGNED_KEY_GEN_BATCH_SIZE,
|
||||
UUIDKind.ACI
|
||||
);
|
||||
await this.server.registerKeys(keys, UUIDKind.ACI);
|
||||
await this.confirmKeys(keys, UUIDKind.ACI);
|
||||
} finally {
|
||||
this.server.finishRegistration(registrationBaton);
|
||||
}
|
||||
|
||||
await this.registrationDone();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ import type { Readable } from 'stream';
|
|||
import { assert, strictAssert } from '../util/assert';
|
||||
import { isRecord } from '../util/isRecord';
|
||||
import * as durations from '../util/durations';
|
||||
import type { ExplodePromiseResultType } from '../util/explodePromise';
|
||||
import { explodePromise } from '../util/explodePromise';
|
||||
import { getUserAgent } from '../util/getUserAgent';
|
||||
import { getStreamWithTimeout } from '../util/getStreamWithTimeout';
|
||||
import { formatAcceptLanguageHeader } from '../util/userLanguages';
|
||||
|
@ -633,6 +635,7 @@ type AjaxOptionsType = {
|
|||
urlParameters?: string;
|
||||
username?: string;
|
||||
validateResponse?: any;
|
||||
isRegistration?: true;
|
||||
} & (
|
||||
| {
|
||||
unauthenticated?: false;
|
||||
|
@ -766,6 +769,8 @@ export type GetUuidsForE164sV2OptionsType = Readonly<{
|
|||
}>;
|
||||
|
||||
export type WebAPIType = {
|
||||
startRegistration(): unknown;
|
||||
finishRegistration(baton: unknown): void;
|
||||
confirmCode: (
|
||||
number: string,
|
||||
code: string,
|
||||
|
@ -1067,6 +1072,8 @@ export function initialize({
|
|||
const PARSE_GROUP_LOG_RANGE_HEADER =
|
||||
/$versions (\d{1,10})-(\d{1,10})\/(d{1,10})/;
|
||||
|
||||
let activeRegistration: ExplodePromiseResultType<void> | undefined;
|
||||
|
||||
const socketManager = new SocketManager({
|
||||
url,
|
||||
certificateAuthority,
|
||||
|
@ -1117,6 +1124,7 @@ export function initialize({
|
|||
confirmCode,
|
||||
createGroup,
|
||||
deleteUsername,
|
||||
finishRegistration,
|
||||
fetchLinkPreviewImage,
|
||||
fetchLinkPreviewMetadata,
|
||||
getAttachment,
|
||||
|
@ -1165,6 +1173,7 @@ export function initialize({
|
|||
sendMessagesUnauth,
|
||||
sendWithSenderKey,
|
||||
setSignedPreKey,
|
||||
startRegistration,
|
||||
updateDeviceName,
|
||||
uploadAvatar,
|
||||
uploadGroupAvatar,
|
||||
|
@ -1186,6 +1195,18 @@ export function initialize({
|
|||
): Promise<unknown>;
|
||||
|
||||
async function _ajax(param: AjaxOptionsType): Promise<unknown> {
|
||||
if (
|
||||
!param.unauthenticated &&
|
||||
activeRegistration &&
|
||||
!param.isRegistration
|
||||
) {
|
||||
log.info('WebAPI: request blocked by active registration');
|
||||
const start = Date.now();
|
||||
await activeRegistration.promise;
|
||||
const duration = Date.now() - start;
|
||||
log.info(`WebAPI: request unblocked after ${duration}ms`);
|
||||
}
|
||||
|
||||
if (!param.urlParameters) {
|
||||
param.urlParameters = '';
|
||||
}
|
||||
|
@ -1635,6 +1656,31 @@ export function initialize({
|
|||
}
|
||||
}
|
||||
|
||||
function startRegistration() {
|
||||
strictAssert(
|
||||
activeRegistration === undefined,
|
||||
'Registration already in progress'
|
||||
);
|
||||
|
||||
activeRegistration = explodePromise<void>();
|
||||
log.info('WebAPI: starting registration');
|
||||
|
||||
return activeRegistration;
|
||||
}
|
||||
|
||||
function finishRegistration(registration: unknown) {
|
||||
strictAssert(activeRegistration !== undefined, 'No active registration');
|
||||
strictAssert(
|
||||
activeRegistration === registration,
|
||||
'Invalid registration baton'
|
||||
);
|
||||
|
||||
log.info('WebAPI: finishing registration');
|
||||
const current = activeRegistration;
|
||||
activeRegistration = undefined;
|
||||
current.resolve();
|
||||
}
|
||||
|
||||
async function confirmCode(
|
||||
number: string,
|
||||
code: string,
|
||||
|
@ -1677,6 +1723,7 @@ export function initialize({
|
|||
password = newPassword;
|
||||
|
||||
const response = (await _ajax({
|
||||
isRegistration: true,
|
||||
call,
|
||||
httpType: 'PUT',
|
||||
responseType: 'json',
|
||||
|
@ -1749,6 +1796,7 @@ export function initialize({
|
|||
};
|
||||
|
||||
await _ajax({
|
||||
isRegistration: true,
|
||||
call: 'keys',
|
||||
urlParameters: `?${uuidKindToQuery(uuidKind)}`,
|
||||
httpType: 'PUT',
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
export function explodePromise<T>(): {
|
||||
export type ExplodePromiseResultType<T> = Readonly<{
|
||||
promise: Promise<T>;
|
||||
resolve: (value: T) => void;
|
||||
reject: (error: Error) => void;
|
||||
} {
|
||||
}>;
|
||||
|
||||
export function explodePromise<T>(): ExplodePromiseResultType<T> {
|
||||
let resolve: (value: T) => void;
|
||||
let reject: (error: Error) => void;
|
||||
|
||||
|
|
Loading…
Reference in a new issue