Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F2897413
D10067.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
11 KB
Referenced Files
None
Subscribers
None
D10067.diff
View Options
diff --git a/lib/types/backup-types.js b/lib/types/backup-types.js
--- a/lib/types/backup-types.js
+++ b/lib/types/backup-types.js
@@ -25,6 +25,6 @@
export type BackupEncrypted = {
+backupID: string,
- +userKeys: Uint8Array,
- +userData: Uint8Array,
+ +userKeys: string,
+ +userData: string,
};
diff --git a/native/backup/api.js b/native/backup/api.js
--- a/native/backup/api.js
+++ b/native/backup/api.js
@@ -8,22 +8,24 @@
import { toBase64URL } from 'lib/utils/base64.js';
import { handleHTTPResponseError } from 'lib/utils/services-utils.js';
-import { getBackupBytesFromBlob } from './conversion-utils.js';
+import { getBackupStringFromBlob } from './conversion-utils.js';
import { commUtilsModule } from '../native-modules.js';
function getBackupFormData(backup: BackupEncrypted): FormData {
const { backupID, userKeys, userData } = backup;
- const userKeysHash = commUtilsModule.sha256(userKeys.buffer);
- const userDataHash = commUtilsModule.sha256(userData.buffer);
- const userKeysStr = commUtilsModule.base64EncodeBuffer(userKeys.buffer);
- const userDataStr = commUtilsModule.base64EncodeBuffer(userData.buffer);
+ const userKeysHash = commUtilsModule.sha256(
+ commUtilsModule.encodeStringToUTF8ArrayBuffer(userKeys),
+ );
+ const userDataHash = commUtilsModule.sha256(
+ commUtilsModule.encodeStringToUTF8ArrayBuffer(userData),
+ );
const formData = new FormData();
formData.append('backup_id', backupID);
formData.append('user_keys_hash', toBase64URL(userKeysHash));
- formData.append('user_keys', userKeysStr);
+ formData.append('user_keys', backup.userKeys);
formData.append('user_data_hash', toBase64URL(userDataHash));
- formData.append('user_data', userDataStr);
+ formData.append('user_data', backup.userData);
formData.append('attachments', '');
return formData;
}
@@ -71,7 +73,7 @@
async function getUserKeys(
backupID: string,
auth: BackupAuth,
-): Promise<Uint8Array> {
+): Promise<string> {
const authHeader = getBackupAuthorizationHeader(auth);
const getUserKeysEndpoint = backupService.httpEndpoints.GET_USER_KEYS;
@@ -88,13 +90,13 @@
handleHTTPResponseError(getUserKeysResponse);
const blob = await getUserKeysResponse.blob();
- return getBackupBytesFromBlob(blob);
+ return getBackupStringFromBlob(blob);
}
async function getUserData(
backupID: string,
auth: BackupAuth,
-): Promise<Uint8Array> {
+): Promise<string> {
const authHeader = getBackupAuthorizationHeader(auth);
const getUserDataEndpoint = backupService.httpEndpoints.GET_USER_DATA;
@@ -111,7 +113,7 @@
handleHTTPResponseError(getUserDataResponse);
const blob = await getUserDataResponse.blob();
- return getBackupBytesFromBlob(blob);
+ return getBackupStringFromBlob(blob);
}
export { uploadBackup, getBackupID, getUserKeys, getUserData };
diff --git a/native/backup/constants.js b/native/backup/constants.js
--- a/native/backup/constants.js
+++ b/native/backup/constants.js
@@ -1,5 +1,3 @@
// @flow
-export const BACKUP_ID_LENGTH = 32; //256 bits
-
export const BACKUP_HASH_STORAGE_KEY = 'RECENT_USER_DATA_HASH';
diff --git a/native/backup/conversion-utils.js b/native/backup/conversion-utils.js
--- a/native/backup/conversion-utils.js
+++ b/native/backup/conversion-utils.js
@@ -3,11 +3,9 @@
import { commUtilsModule } from '../native-modules.js';
import { arrayBufferFromBlob } from '../utils/blob-utils-module.js';
-function getBackupBytesFromBlob(blob: Blob): Uint8Array {
+function getBackupStringFromBlob(blob: Blob): string {
const buffer = arrayBufferFromBlob(blob);
- const str = commUtilsModule.decodeUTF8ArrayBufferToString(buffer);
- const decodedBuffer = commUtilsModule.base64DecodeBuffer(str);
- return new Uint8Array(decodedBuffer);
+ return commUtilsModule.decodeUTF8ArrayBufferToString(buffer);
}
function convertObjToBytes<T>(obj: T): Uint8Array {
@@ -21,4 +19,4 @@
return JSON.parse(str);
}
-export { getBackupBytesFromBlob, convertObjToBytes, convertBytesToObj };
+export { getBackupStringFromBlob, convertObjToBytes, convertBytesToObj };
diff --git a/native/backup/encryption.js b/native/backup/encryption.js
deleted file mode 100644
--- a/native/backup/encryption.js
+++ /dev/null
@@ -1,62 +0,0 @@
-// @flow
-
-import { hexToUintArray } from 'lib/media/data-utils.js';
-import type {
- Backup,
- BackupEncrypted,
- UserData,
- UserKeys,
-} from 'lib/types/backup-types.js';
-
-import { convertBytesToObj, convertObjToBytes } from './conversion-utils.js';
-import { fetchNativeKeychainCredentials } from '../account/native-credentials.js';
-import { commCoreModule } from '../native-modules.js';
-import * as AES from '../utils/aes-crypto-module.js';
-
-async function getBackupKey(backupID: string): Promise<Uint8Array> {
- const nativeCredentials = await fetchNativeKeychainCredentials();
- if (!nativeCredentials) {
- throw new Error('Native credentials are missing');
- }
- const { password } = nativeCredentials;
- const backupKey = await commCoreModule.computeBackupKey(password, backupID);
- return new Uint8Array(backupKey);
-}
-
-async function encryptBackup(backup: Backup): Promise<BackupEncrypted> {
- const { backupID, userKeys, userData } = backup;
- const userKeysBytes = convertObjToBytes(userKeys);
- const backupKey = await getBackupKey(backupID);
- const ct1 = AES.encrypt(backupKey, userKeysBytes);
-
- const userDataBytes = convertObjToBytes(userData);
- const backupDataKey = hexToUintArray(userKeys.backupDataKey);
- const ct2 = AES.encrypt(backupDataKey, userDataBytes);
-
- return { backupID, userKeys: ct1, userData: ct2 };
-}
-
-async function decryptUserKeys(
- backupID: string,
- userKeysBytes: ArrayBuffer,
-): Promise<UserKeys> {
- const backupKey = await getBackupKey(backupID);
- const decryptedUserKeys = AES.decrypt(
- backupKey,
- new Uint8Array(userKeysBytes),
- );
- return convertBytesToObj<UserKeys>(decryptedUserKeys);
-}
-
-async function decryptUserData(
- backupDataKey: string,
- userDataBytes: ArrayBuffer,
-): Promise<UserData> {
- const decryptedUserData = AES.decrypt(
- hexToUintArray(backupDataKey),
- new Uint8Array(userDataBytes),
- );
- return convertBytesToObj<UserData>(decryptedUserData);
-}
-
-export { getBackupKey, encryptBackup, decryptUserKeys, decryptUserData };
diff --git a/native/backup/use-client-backup.js b/native/backup/use-client-backup.js
--- a/native/backup/use-client-backup.js
+++ b/native/backup/use-client-backup.js
@@ -3,20 +3,17 @@
import _isEqual from 'lodash/fp/isEqual.js';
import * as React from 'react';
-import { uintArrayToHexString } from 'lib/media/data-utils.js';
import { isLoggedIn } from 'lib/selectors/user-selectors.js';
-import type { BackupAuth, UserData, UserKeys } from 'lib/types/backup-types.js';
+import type {
+ BackupAuth,
+ UserData,
+ BackupEncrypted,
+} from 'lib/types/backup-types.js';
import { getBackupID, getUserData, getUserKeys, uploadBackup } from './api.js';
-import { BACKUP_ID_LENGTH } from './constants.js';
-import {
- decryptUserData,
- decryptUserKeys,
- encryptBackup,
-} from './encryption.js';
+import { fetchNativeKeychainCredentials } from '../account/native-credentials.js';
import { commCoreModule } from '../native-modules.js';
import { useSelector } from '../redux/redux-utils.js';
-import { generateKey } from '../utils/aes-crypto-module.js';
import { getContentSigningKey } from '../utils/crypto-utils.js';
// purpose of this result is to improve logging and
@@ -25,7 +22,6 @@
getBackupID?: boolean,
getUserKeys?: boolean,
getUserData?: boolean,
- decryptUserKeys?: boolean,
decryptUserData?: boolean,
userDataIntegrity?: boolean,
error?: Error,
@@ -38,6 +34,14 @@
) => Promise<RestoreBackupResult>,
};
+async function getBackupSecret(): Promise<string> {
+ const nativeCredentials = await fetchNativeKeychainCredentials();
+ if (!nativeCredentials) {
+ throw new Error('Native credentials are missing');
+ }
+ return nativeCredentials.password;
+}
+
function useClientBackup(): ClientBackup {
const accessToken = useSelector(state => state.commServicesAccessToken);
const currentUserID = useSelector(
@@ -52,24 +56,16 @@
}
console.info('Start uploading backup...');
- const backupDataKey = generateKey();
-
- const [ed25519, backupID] = await Promise.all([
- getContentSigningKey(),
- commCoreModule.generateRandomString(BACKUP_ID_LENGTH),
- ]);
+ const backupSecret = await getBackupSecret();
- const userKeys: UserKeys = {
- backupDataKey: uintArrayToHexString(backupDataKey),
- ed25519,
- };
+ const encryptedBackupStr = await commCoreModule.createNewBackup(
+ backupSecret,
+ JSON.stringify(userData),
+ );
- const encryptedBackup = await encryptBackup({
- backupID,
- userKeys,
- userData,
- });
+ const encryptedBackup: BackupEncrypted = JSON.parse(encryptedBackupStr);
+ const ed25519 = await getContentSigningKey();
const backupAuth: BackupAuth = {
userID: currentUserID,
accessToken: accessToken ? accessToken : '',
@@ -92,7 +88,6 @@
getBackupID: undefined,
getUserKeys: undefined,
getUserData: undefined,
- decryptUserKeys: undefined,
decryptUserData: undefined,
userDataIntegrity: undefined,
error: undefined,
@@ -101,7 +96,7 @@
const backupIDPromise: Promise<?string> = (async () => {
try {
// We are using UserID instead of the username.
- // The reason is tha the initial version of the backup service
+ // The reason is that the initial version of the backup service
// cannot get UserID based on username.
const backupID = await getBackupID(currentUserID);
result.getBackupID = true;
@@ -128,7 +123,7 @@
deviceID: ed25519,
};
- const userKeysPromise: Promise<?Uint8Array> = (async () => {
+ const userKeysPromise: Promise<?string> = (async () => {
try {
const userKeysResponse = await getUserKeys(backupID, backupAuth);
result.getUserKeys = true;
@@ -139,7 +134,7 @@
return undefined;
}
})();
- const userDataPromise: Promise<?Uint8Array> = (async () => {
+ const userDataPromise: Promise<?string> = (async () => {
try {
const userDataResponse = await getUserData(backupID, backupAuth);
result.getUserData = true;
@@ -162,33 +157,24 @@
return result;
}
- let userKeys;
- try {
- userKeys = await decryptUserKeys(backupID, userKeysResponse.buffer);
- result.decryptUserKeys = true;
- } catch (e) {
- result.decryptUserKeys = false;
- result.error = e;
- }
-
- if (!userKeys) {
- result.decryptUserKeys = false;
- result.error = new Error('UserKeys is empty');
- return result;
- }
-
if (!userDataResponse) {
result.getUserData = false;
result.error = new Error('UserData response is empty');
return result;
}
- let userData;
+ const backupSecret = await getBackupSecret();
+
+ let userData: UserData;
try {
- userData = await decryptUserData(
- userKeys.backupDataKey,
- userDataResponse.buffer,
+ const restoreResultStr = await commCoreModule.restoreBackup(
+ backupID,
+ backupSecret,
+ userKeysResponse,
+ userDataResponse,
);
+ const { userData: userDataStr } = JSON.parse(restoreResultStr);
+ userData = JSON.parse(userDataStr);
result.decryptUserData = true;
} catch (e) {
result.decryptUserData = false;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Oct 5, 11:19 PM (21 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2246810
Default Alt Text
D10067.diff (11 KB)
Attached To
Mode
D10067: [native] Backup testing button
Attached
Detach File
Event Timeline
Log In to Comment