Page MenuHomePhabricator

D10503.diff
No OneTemporary

D10503.diff

diff --git a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h
--- a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h
+++ b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h
@@ -84,6 +84,8 @@
#ifdef EMSCRIPTEN
virtual std::vector<WebThread> getAllThreadsWeb() const = 0;
virtual void replaceThreadWeb(const WebThread &thread) const = 0;
+#else
+ virtual void createMainCompaction(std::string backupID) const = 0;
#endif
};
diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
--- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
+++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
@@ -91,6 +91,7 @@
#else
static void clearSensitiveData();
static void initialize(std::string &databasePath);
+ void createMainCompaction(std::string backupID) const override;
#endif
};
diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp
--- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp
+++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp
@@ -10,6 +10,7 @@
#ifndef EMSCRIPTEN
#include "CommSecureStore.h"
+#include "PlatformSpecificTools.h"
#endif
#define ACCOUNT_ID 1
@@ -570,9 +571,11 @@
return false;
}
-void set_encryption_key(sqlite3 *db) {
+void set_encryption_key(
+ sqlite3 *db,
+ const std::string &encryptionKey = SQLiteQueryExecutor::encryptionKey) {
std::string set_encryption_key_query =
- "PRAGMA key = \"x'" + SQLiteQueryExecutor::encryptionKey + "'\";";
+ "PRAGMA key = \"x'" + encryptionKey + "'\";";
char *error_set_key;
sqlite3_exec(
@@ -650,6 +653,14 @@
trace_queries(db);
}
+// This is a temporary solution. In future we want to keep
+// a separate table for blob hashes. Tracked on Linear:
+// https://linear.app/comm/issue/ENG-6261/introduce-blob-hash-table
+std::string blob_hash_from_blob_service_uri(const std::string &media_uri) {
+ static const std::string blob_service_prefix = "comm-blob-service://";
+ return media_uri.substr(blob_service_prefix.size());
+}
+
bool file_exists(const std::string &file_path) {
std::ifstream file(file_path.c_str());
return file.good();
@@ -872,75 +883,9 @@
return true;
}
-void SQLiteQueryExecutor::migrate() {
-// We don't want to run `PRAGMA key = ...;`
-// on main web database. The context is here:
-// https://linear.app/comm/issue/ENG-6398/issues-with-sqlcipher-on-web
-#ifndef EMSCRIPTEN
- validate_encryption();
-#endif
-
- sqlite3 *db;
- sqlite3_open(SQLiteQueryExecutor::sqliteFilePath.c_str(), &db);
- on_database_open(db);
-
- std::stringstream db_path;
- db_path << "db path: " << SQLiteQueryExecutor::sqliteFilePath.c_str()
- << std::endl;
- Logger::log(db_path.str());
-
- auto db_version = get_database_version(db);
- std::stringstream version_msg;
- version_msg << "db version: " << db_version << std::endl;
- Logger::log(version_msg.str());
-
- if (db_version == 0) {
- auto db_created = set_up_database(db);
- if (!db_created) {
- sqlite3_close(db);
- Logger::log("Database structure creation error.");
- throw std::runtime_error("Database structure creation error");
- }
- Logger::log("Database structure created.");
-
- sqlite3_close(db);
- return;
- }
-
- for (const auto &[idx, migration] : migrations) {
- const auto &[applyMigration, shouldBeInTransaction] = migration;
-
- MigrationResult migrationResult;
- if (shouldBeInTransaction) {
- migrationResult = applyMigrationWithTransaction(db, applyMigration, idx);
- } else {
- migrationResult =
- applyMigrationWithoutTransaction(db, applyMigration, idx);
- }
-
- if (migrationResult == MigrationResult::NOT_APPLIED) {
- continue;
- }
-
- std::stringstream migration_msg;
- if (migrationResult == MigrationResult::FAILURE) {
- migration_msg << "migration " << idx << " failed." << std::endl;
- Logger::log(migration_msg.str());
- sqlite3_close(db);
- throw std::runtime_error(migration_msg.str());
- }
- if (migrationResult == MigrationResult::SUCCESS) {
- migration_msg << "migration " << idx << " succeeded." << std::endl;
- Logger::log(migration_msg.str());
- }
- }
-
- sqlite3_close(db);
-}
-
-auto &SQLiteQueryExecutor::getStorage() {
- static auto storage = make_storage(
- SQLiteQueryExecutor::sqliteFilePath,
+auto getEncryptedStorageAtPath(const std::string &databasePath) {
+ auto storage = make_storage(
+ databasePath,
make_index("messages_idx_thread_time", &Message::thread, &Message::time),
make_index("media_idx_container", &Media::container),
make_table(
@@ -1021,6 +966,78 @@
return storage;
}
+void SQLiteQueryExecutor::migrate() {
+// We don't want to run `PRAGMA key = ...;`
+// on main web database. The context is here:
+// https://linear.app/comm/issue/ENG-6398/issues-with-sqlcipher-on-web
+#ifndef EMSCRIPTEN
+ validate_encryption();
+#endif
+
+ sqlite3 *db;
+ sqlite3_open(SQLiteQueryExecutor::sqliteFilePath.c_str(), &db);
+ on_database_open(db);
+
+ std::stringstream db_path;
+ db_path << "db path: " << SQLiteQueryExecutor::sqliteFilePath.c_str()
+ << std::endl;
+ Logger::log(db_path.str());
+
+ auto db_version = get_database_version(db);
+ std::stringstream version_msg;
+ version_msg << "db version: " << db_version << std::endl;
+ Logger::log(version_msg.str());
+
+ if (db_version == 0) {
+ auto db_created = set_up_database(db);
+ if (!db_created) {
+ sqlite3_close(db);
+ Logger::log("Database structure creation error.");
+ throw std::runtime_error("Database structure creation error");
+ }
+ Logger::log("Database structure created.");
+
+ sqlite3_close(db);
+ return;
+ }
+
+ for (const auto &[idx, migration] : migrations) {
+ const auto &[applyMigration, shouldBeInTransaction] = migration;
+
+ MigrationResult migrationResult;
+ if (shouldBeInTransaction) {
+ migrationResult = applyMigrationWithTransaction(db, applyMigration, idx);
+ } else {
+ migrationResult =
+ applyMigrationWithoutTransaction(db, applyMigration, idx);
+ }
+
+ if (migrationResult == MigrationResult::NOT_APPLIED) {
+ continue;
+ }
+
+ std::stringstream migration_msg;
+ if (migrationResult == MigrationResult::FAILURE) {
+ migration_msg << "migration " << idx << " failed." << std::endl;
+ Logger::log(migration_msg.str());
+ sqlite3_close(db);
+ throw std::runtime_error(migration_msg.str());
+ }
+ if (migrationResult == MigrationResult::SUCCESS) {
+ migration_msg << "migration " << idx << " succeeded." << std::endl;
+ Logger::log(migration_msg.str());
+ }
+ }
+
+ sqlite3_close(db);
+}
+
+auto &SQLiteQueryExecutor::getStorage() {
+ static auto storage =
+ getEncryptedStorageAtPath(SQLiteQueryExecutor::sqliteFilePath);
+ return storage;
+}
+
SQLiteQueryExecutor::SQLiteQueryExecutor() {
SQLiteQueryExecutor::migrate();
}
@@ -1407,6 +1424,78 @@
});
}
+void SQLiteQueryExecutor::createMainCompaction(std::string backupID) const {
+ std::string finalBackupPath =
+ PlatformSpecificTools::getBackupFilePath(backupID, false);
+ std::string finalAttachmentsPath =
+ PlatformSpecificTools::getBackupFilePath(backupID, true);
+
+ std::string tempBackupPath = finalBackupPath + "_tmp";
+ std::string tempAttachmentsPath = finalAttachmentsPath + "_tmp";
+
+ if (file_exists(tempBackupPath)) {
+ Logger::log(
+ "Attempting to delete temporary backup file from previous backup "
+ "attempt.");
+ attempt_delete_file(
+ tempBackupPath,
+ "Failed to delete temporary backup file from previous backup attempt.");
+ }
+
+ if (file_exists(tempAttachmentsPath)) {
+ Logger::log(
+ "Attempting to delete temporary attachments file from previous backup "
+ "attempt.");
+ attempt_delete_file(
+ tempAttachmentsPath,
+ "Failed to delete temporary attachments file from previous backup "
+ "attempt.");
+ }
+
+ auto backupStorage = getEncryptedStorageAtPath(tempBackupPath);
+ auto backupObj =
+ SQLiteQueryExecutor::getStorage().make_backup_to(backupStorage);
+ int backupResult = backupObj.step(-1);
+
+ if (backupResult == SQLITE_BUSY || backupResult == SQLITE_LOCKED) {
+ throw std::runtime_error(
+ "Programmer error. Database in transaction during backup attempt.");
+ } else if (backupResult != SQLITE_DONE) {
+ std::stringstream error_message;
+ error_message << "Failed to create database backup. Details: "
+ << sqlite3_errstr(backupResult);
+ throw std::runtime_error(error_message.str());
+ }
+ backupStorage.vacuum();
+
+ attempt_rename_file(
+ tempBackupPath,
+ finalBackupPath,
+ "Failed to rename complete temporary backup file to final backup file.");
+
+ std::ofstream tempAttachmentsFile(tempAttachmentsPath);
+ if (!tempAttachmentsFile.is_open()) {
+ throw std::runtime_error(
+ "Unable to create attachments file for backup id: " + backupID);
+ }
+
+ auto blobServiceURIRows = SQLiteQueryExecutor::getStorage().select(
+ columns(&Media::uri), where(like(&Media::uri, "comm-blob-service://%")));
+
+ for (const auto &blobServiceURIRow : blobServiceURIRows) {
+ std::string blobServiceURI = std::get<0>(blobServiceURIRow);
+ std::string blobHash = blob_hash_from_blob_service_uri(blobServiceURI);
+ tempAttachmentsFile << blobHash << "\n";
+ }
+ tempAttachmentsFile.close();
+
+ attempt_rename_file(
+ tempAttachmentsPath,
+ finalAttachmentsPath,
+ "Failed to rename complete temporary attachments file to final "
+ "attachments file.");
+}
+
void SQLiteQueryExecutor::assign_encryption_key() {
std::string encryptionKey = comm::crypto::Tools::generateRandomHexString(
SQLiteQueryExecutor::sqlcipherEncryptionKeySize);
diff --git a/web/database/_generated/comm_query_executor.wasm b/web/database/_generated/comm_query_executor.wasm
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 30, 1:31 PM (4 m, 36 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2601124
Default Alt Text
D10503.diff (10 KB)

Event Timeline