Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3388281
D10503.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D10503.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D10503: Implement SQLiteQueryExecutor method to create main compaction
Attached
Detach File
Event Timeline
Log In to Comment