When incoming message should've been sealed sender, reply with profile key

This commit is contained in:
Evan Hahn 2021-05-05 11:39:16 -05:00 committed by GitHub
parent 18c86898d1
commit 8ef14e6f39
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 384 additions and 38 deletions

View file

@ -0,0 +1,87 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from '../util/assert';
import * as log from '../logging/log';
// We define a stricter storage here that returns `unknown` instead of `any`.
type Storage = {
get(key: string): unknown;
put(key: string, value: unknown): Promise<void>;
remove(key: string): Promise<void>;
onready: (callback: () => unknown) => void;
};
export class OurProfileKeyService {
private getPromise: undefined | Promise<undefined | ArrayBuffer>;
private promisesBlockingGet: Array<Promise<unknown>> = [];
private storage?: Storage;
initialize(storage: Storage): void {
log.info('Our profile key service: initializing');
const storageReadyPromise = new Promise<void>(resolve => {
storage.onready(() => {
resolve();
});
});
this.promisesBlockingGet = [storageReadyPromise];
this.storage = storage;
}
get(): Promise<undefined | ArrayBuffer> {
if (this.getPromise) {
log.info(
'Our profile key service: was already fetching. Piggybacking off of that'
);
} else {
log.info('Our profile key service: kicking off a new fetch');
this.getPromise = this.doGet();
}
return this.getPromise;
}
async set(newValue: undefined | ArrayBuffer): Promise<void> {
log.info('Our profile key service: updating profile key');
assert(this.storage, 'OurProfileKeyService was not initialized');
if (newValue) {
await this.storage.put('profileKey', newValue);
} else {
await this.storage.remove('profileKey');
}
}
blockGetWithPromise(promise: Promise<unknown>): void {
this.promisesBlockingGet.push(promise);
}
private async doGet(): Promise<undefined | ArrayBuffer> {
log.info(
`Our profile key service: waiting for ${this.promisesBlockingGet.length} promises before fetching`
);
await Promise.allSettled(this.promisesBlockingGet);
this.promisesBlockingGet = [];
delete this.getPromise;
assert(this.storage, 'OurProfileKeyService was not initialized');
log.info('Our profile key service: fetching profile key from storage');
const result = this.storage.get('profileKey');
if (result === undefined || result instanceof ArrayBuffer) {
return result;
}
assert(
false,
'Profile key in storage was defined, but not an ArrayBuffer. Returning undefined'
);
return undefined;
}
}
export const ourProfileKeyService = new OurProfileKeyService();

View file

@ -34,6 +34,7 @@ import { storageJobQueue } from '../util/JobQueue';
import { sleep } from '../util/sleep';
import { isMoreRecentThan } from '../util/timestamp';
import { isStorageWriteFeatureEnabled } from '../storage/isFeatureEnabled';
import { ourProfileKeyService } from './ourProfileKey';
const {
eraseStorageServiceStateFromConversations,
@ -1156,7 +1157,9 @@ export const runStorageServiceSyncJob = debounce(() => {
return;
}
storageJobQueue(async () => {
await sync();
}, `sync v${window.storage.get('manifestVersion')}`);
ourProfileKeyService.blockGetWithPromise(
storageJobQueue(async () => {
await sync();
}, `sync v${window.storage.get('manifestVersion')}`)
);
}, 500);

View file

@ -38,6 +38,7 @@ import {
getSafeLongFromTimestamp,
getTimestampFromLong,
} from '../util/timestampLongUtils';
import { ourProfileKeyService } from './ourProfileKey';
const { updateConversation } = dataInterface;
@ -851,7 +852,7 @@ export async function mergeAccountRecord(
window.storage.put('phoneNumberDiscoverability', discoverability);
if (profileKey) {
window.storage.put('profileKey', profileKey.toArrayBuffer());
ourProfileKeyService.set(profileKey.toArrayBuffer());
}
if (pinnedConversations) {