Social Graph: read-only state sync with primary device

This commit is contained in:
Josh Perez 2020-07-06 20:56:56 -04:00 committed by Scott Nonnenberg
parent 12745a2c79
commit 8502d23576
19 changed files with 1035 additions and 57 deletions

View file

@ -10,6 +10,12 @@ import { getRandomValue } from '../Crypto';
import PQueue from 'p-queue';
import { v4 as getGuid } from 'uuid';
import {
StorageServiceCallOptionsType,
StorageServiceCredentials,
TextSecureType,
} from '../textsecure.d';
// tslint:disable no-bitwise
function _btoa(str: any) {
@ -196,6 +202,7 @@ function getContentType(response: Response) {
}
type HeaderListType = { [name: string]: string };
type HTTPCodeType = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
type PromiseAjaxOptionsType = {
accessKey?: string;
@ -212,7 +219,7 @@ type PromiseAjaxOptionsType = {
responseType?: 'json' | 'arraybuffer' | 'arraybufferwithdetails';
stack?: string;
timeout?: number;
type: 'GET' | 'POST' | 'PUT' | 'DELETE';
type: HTTPCodeType;
unauthenticated?: boolean;
user?: string;
validateResponse?: any;
@ -479,13 +486,17 @@ const URL_CALLS = {
getIceServers: 'v1/accounts/turn',
attachmentId: 'v2/attachments/form/upload',
deliveryCert: 'v1/certificate/delivery',
supportUnauthenticatedDelivery: 'v1/devices/unauthenticated_delivery',
registerCapabilities: 'v1/devices/capabilities',
devices: 'v1/devices',
keys: 'v2/keys',
messages: 'v1/messages',
profile: 'v1/profile',
registerCapabilities: 'v1/devices/capabilities',
signed: 'v2/keys/signed',
storageManifest: 'v1/storage/manifest',
storageModify: 'v1/storage/',
storageRead: 'v1/storage/read',
storageToken: 'v1/storage/auth',
supportUnauthenticatedDelivery: 'v1/devices/unauthenticated_delivery',
getStickerPackUpload: 'v1/sticker/pack/form',
whoami: 'v1/accounts/whoami',
config: 'v1/config',
@ -493,6 +504,7 @@ const URL_CALLS = {
type InitializeOptionsType = {
url: string;
storageUrl: string;
cdnUrlObject: {
readonly '0': string;
readonly [propName: string]: string;
@ -513,12 +525,18 @@ type MessageType = any;
type AjaxOptionsType = {
accessKey?: string;
call: keyof typeof URL_CALLS;
httpType: 'GET' | 'POST' | 'PUT' | 'DELETE';
contentType?: string;
data?: ArrayBuffer | Buffer | string;
host?: string;
httpType: HTTPCodeType;
jsonData?: any;
password?: string;
responseType?: 'json' | 'arraybuffer' | 'arraybufferwithdetails';
schema?: any;
timeout?: number;
unauthenticated?: boolean;
urlParameters?: string;
username?: string;
validateResponse?: any;
};
@ -571,6 +589,9 @@ export type WebAPIType = {
getSenderCertificate: (withUuid?: boolean) => Promise<any>;
getSticker: (packId: string, stickerId: string) => Promise<any>;
getStickerPackManifest: (packId: string) => Promise<StickerPackManifestType>;
getStorageCredentials: TextSecureType['messaging']['getStorageCredentials'];
getStorageManifest: TextSecureType['messaging']['getStorageManifest'];
getStorageRecords: TextSecureType['messaging']['getStorageRecords'];
makeProxiedRequest: (
targetUrl: string,
options?: ProxiedRequestOptionsType
@ -650,6 +671,7 @@ export type ProxiedRequestOptionsType = {
// tslint:disable-next-line max-func-body-length
export function initialize({
url,
storageUrl,
cdnUrlObject,
certificateAuthority,
contentProxyUrl,
@ -659,6 +681,9 @@ export function initialize({
if (!is.string(url)) {
throw new Error('WebAPI.initialize: Invalid server url');
}
if (!is.string(storageUrl)) {
throw new Error('WebAPI.initialize: Invalid storageUrl');
}
if (!is.object(cdnUrlObject)) {
throw new Error('WebAPI.initialize: Invalid cdnUrlObject');
}
@ -713,6 +738,9 @@ export function initialize({
getSenderCertificate,
getSticker,
getStickerPackManifest,
getStorageCredentials,
getStorageManifest,
getStorageRecords,
makeProxiedRequest,
putAttachment,
registerCapabilities,
@ -737,16 +765,16 @@ export function initialize({
return _outerAjax(null, {
certificateAuthority,
contentType: 'application/json; charset=utf-8',
data: param.jsonData && _jsonThing(param.jsonData),
host: url,
password,
contentType: param.contentType || 'application/json; charset=utf-8',
data: param.data || (param.jsonData && _jsonThing(param.jsonData)),
host: param.host || url,
password: param.password || password,
path: URL_CALLS[param.call] + param.urlParameters,
proxyUrl,
responseType: param.responseType,
timeout: param.timeout,
type: param.httpType,
user: username,
user: param.username || username,
validateResponse: param.validateResponse,
version,
unauthenticated: param.unauthenticated,
@ -821,6 +849,50 @@ export function initialize({
});
}
async function getStorageCredentials(): Promise<StorageServiceCredentials> {
return _ajax({
call: 'storageToken',
httpType: 'GET',
responseType: 'json',
schema: { username: 'string', password: 'string' },
});
}
async function getStorageManifest(
options: StorageServiceCallOptionsType = {}
): Promise<ArrayBuffer> {
const { credentials, greaterThanVersion } = options;
return _ajax({
call: 'storageManifest',
contentType: 'application/x-protobuf',
host: storageUrl,
httpType: 'GET',
responseType: 'arraybuffer',
urlParameters: greaterThanVersion
? `/version/${greaterThanVersion}`
: '',
...credentials,
});
}
async function getStorageRecords(
data: ArrayBuffer,
options: StorageServiceCallOptionsType = {}
): Promise<ArrayBuffer> {
const { credentials } = options;
return _ajax({
call: 'storageRead',
contentType: 'application/x-protobuf',
data,
host: storageUrl,
httpType: 'PUT',
responseType: 'arraybuffer',
...credentials,
});
}
async function registerSupportForUnauthenticatedDelivery() {
return _ajax({
call: 'supportUnauthenticatedDelivery',