diff --git a/keyserver/src/responders/website-responders.js b/keyserver/src/responders/website-responders.js
--- a/keyserver/src/responders/website-responders.js
+++ b/keyserver/src/responders/website-responders.js
@@ -44,6 +44,7 @@
+olmFilename: string,
+commQueryExecutorFilename: string,
+opaqueURL: string,
+ +backupClientFilename: string,
};
let assetInfo: ?AssetInfo = null;
async function getAssetInfo() {
@@ -59,6 +60,7 @@
olmFilename: '',
commQueryExecutorFilename: '',
opaqueURL: 'http://localhost:8080/opaque-ke.wasm',
+ backupClientFilename: '',
};
return assetInfo;
}
@@ -83,6 +85,7 @@
olmFilename: manifest['olm.wasm'],
commQueryExecutorFilename: webworkersManifest['comm_query_executor.wasm'],
opaqueURL: `compiled/${manifest['comm_opaque2_wasm_bg.wasm']}`,
+ backupClientFilename: webworkersManifest['backup_client_bg.wasm'],
};
return assetInfo;
} catch {
@@ -134,6 +137,7 @@
olmFilename,
opaqueURL,
commQueryExecutorFilename,
+ backupClientFilename,
} = await assetInfoPromise;
// prettier-ignore
@@ -185,6 +189,7 @@
var baseURL = "${baseURL}";
var olmFilename = "${olmFilename}";
var commQueryExecutorFilename = "${commQueryExecutorFilename}";
+ var backupClientFilename = "${backupClientFilename}";
var opaqueURL = "${opaqueURL}";
diff --git a/package.json b/package.json
--- a/package.json
+++ b/package.json
@@ -11,7 +11,8 @@
"keyserver/addons/rust-node-addon",
"native/expo-modules/comm-expo-package",
"services/electron-update-server",
- "web/opaque-ke-wasm"
+ "web/opaque-ke-wasm",
+ "shared/backup_client"
],
"scripts": {
"clean": "yarn workspace lib clean && yarn workspace web clean && yarn workspace native clean && yarn workspace keyserver clean && yarn workspace landing clean && yarn workspace desktop clean && yarn workspace rust-node-addon clean && yarn workspace electron-update-server clean && rm -rf node_modules/",
diff --git a/web/database/database-module-provider.js b/web/database/database-module-provider.js
--- a/web/database/database-module-provider.js
+++ b/web/database/database-module-provider.js
@@ -24,6 +24,8 @@
declare var baseURL: string;
declare var commQueryExecutorFilename: string;
+declare var backupClientFilename: string;
+
const databaseStatuses = Object.freeze({
notRunning: 'NOT_RUNNING',
initSuccess: 'INIT_SUCCESS',
@@ -93,6 +95,7 @@
databaseModuleFilePath: `${origin}${baseURL}${WORKERS_MODULES_DIR_PATH}`,
encryptionKey,
commQueryExecutorFilename,
+ backupClientFilename,
});
this.status = { type: databaseStatuses.initSuccess };
console.info('Database initialization success');
diff --git a/web/database/utils/constants.js b/web/database/utils/constants.js
--- a/web/database/utils/constants.js
+++ b/web/database/utils/constants.js
@@ -11,6 +11,7 @@
export const WORKERS_MODULES_DIR_PATH = '/compiled/webworkers';
export const DEFAULT_COMM_QUERY_EXECUTOR_FILENAME = 'comm_query_executor.wasm';
+export const DEFAULT_BACKUP_CLIENT_FILENAME = 'backup-client.wasm';
export const DEFAULT_OLM_FILENAME = 'olm.wasm';
diff --git a/web/database/worker/db-worker.js b/web/database/worker/db-worker.js
--- a/web/database/worker/db-worker.js
+++ b/web/database/worker/db-worker.js
@@ -1,5 +1,6 @@
// @flow
+import initBackupClientModule from 'backup-client';
import localforage from 'localforage';
import {
@@ -31,6 +32,7 @@
localforageConfig,
SQLITE_CONTENT,
SQLITE_ENCRYPTION_KEY,
+ DEFAULT_BACKUP_CLIENT_FILENAME,
} from '../utils/constants.js';
import {
clearSensitiveData,
@@ -102,6 +104,19 @@
);
}
+async function initBackupClient(
+ databaseModuleFilePath: string,
+ backupClientFilename: ?string,
+) {
+ let modulePath;
+ if (backupClientFilename) {
+ modulePath = `${databaseModuleFilePath}/${backupClientFilename}`;
+ } else {
+ modulePath = `http://localhost:8080/${DEFAULT_BACKUP_CLIENT_FILENAME}`;
+ }
+ await initBackupClientModule(modulePath);
+}
+
async function persist() {
persistInProgress = true;
const module = dbModule;
@@ -148,11 +163,19 @@
// database operations
if (message.type === workerRequestMessageTypes.INIT) {
- await initDatabase(
+ const databasePromise = initDatabase(
message.databaseModuleFilePath,
message.commQueryExecutorFilename,
message.encryptionKey,
);
+ let backupClientPromise = new Promise(resolve => resolve());
+ if (!(message.backupClientFilename === undefined)) {
+ backupClientPromise = initBackupClient(
+ message.databaseModuleFilePath,
+ message.backupClientFilename,
+ );
+ }
+ await Promise.all([databasePromise, backupClientPromise]);
return undefined;
} else if (message.type === workerRequestMessageTypes.CLEAR_SENSITIVE_DATA) {
encryptionKey = null;
diff --git a/web/flow-typed/backup-client.js b/web/flow-typed/backup-client.js
new file mode 100644
--- /dev/null
+++ b/web/flow-typed/backup-client.js
@@ -0,0 +1,38 @@
+// @flow
+
+declare module 'backup-client' {
+ declare export default (string | URL) => mixed;
+
+ declare export var RequestedData: {
+ +BackupID: 0,
+ +UserKeys: 1,
+ +UserData: 2,
+ };
+
+ declare type UserIdentity = {
+ +userID: string,
+ +accessToken: string,
+ +deviceID: string,
+ };
+
+ declare type BackupDescriptor = {
+ +type: "BackupID", +backupID: string, +userIdentity: UserIdentity,
+ } | {+type: "Latest", +username: string};
+
+ declare export class BackupClient {
+ constructor(url: string): void;
+
+ downloadBackupData(
+ backupDescriptor: BackupDescriptor,
+ requestedData: $Values,
+ ): Promise;
+
+ downloadLogs(
+ userIdentity: UserIdentity,
+ backupID: string,
+ f: (Uint8Array) => mixed,
+ ): Promise;
+
+ free(): void;
+ }
+}
diff --git a/web/package.json b/web/package.json
--- a/web/package.json
+++ b/web/package.json
@@ -42,6 +42,7 @@
"@babel/runtime": "^7.23.7",
"@commapp/olm": "0.1.0",
"@commapp/opaque-ke-wasm": "npm:@commapp/opaque-ke-wasm@^0.0.3",
+ "backup-client": "0.1.0",
"@emoji-mart/data": "^1.1.2",
"@emoji-mart/react": "^1.1.1",
"@fortawesome/fontawesome-svg-core": "1.2.25",
diff --git a/web/types/worker-types.js b/web/types/worker-types.js
--- a/web/types/worker-types.js
+++ b/web/types/worker-types.js
@@ -37,6 +37,7 @@
+databaseModuleFilePath: string,
+commQueryExecutorFilename: ?string,
+encryptionKey?: ?SubtleCrypto$JsonWebKey,
+ +backupClientFilename?: ?string,
};
export type GenerateDatabaseEncryptionKeyRequestMessage = {
diff --git a/web/webpack.config.cjs b/web/webpack.config.cjs
--- a/web/webpack.config.cjs
+++ b/web/webpack.config.cjs
@@ -152,6 +152,14 @@
},
],
}),
+ new CopyPlugin({
+ patterns: [
+ {
+ from: 'node_modules/backup-client/web/_generated/backup_client_bg.wasm',
+ to: path.join(__dirname, 'dist', 'backup-client.wasm'),
+ },
+ ],
+ }),
];
const prodWebWorkersPlugins = [
@@ -181,6 +189,19 @@
},
],
}),
+ new CopyPlugin({
+ patterns: [
+ {
+ from: 'node_modules/backup-client/web/_generated/backup_client_bg.wasm',
+ to: path.join(
+ __dirname,
+ 'dist',
+ 'webworkers',
+ 'backup-client.[contenthash:12].wasm',
+ ),
+ },
+ ],
+ }),
new WebpackManifestPlugin({
publicPath: '',
}),