Skip to content

Commit

Permalink
Add encryption support
Browse files Browse the repository at this point in the history
  • Loading branch information
leemaguire committed Oct 11, 2023
1 parent 035ed49 commit 6093f59
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 27 deletions.
14 changes: 12 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,21 @@ X.Y.Z Release notes (YYYY-MM-DD)
* Using a property type of vector of enums would cause a compilation error (since 0.1.0).

### Enhancements
* The Sync metadata Realm is now encrypted by default unless the `REALM_DISABLE_METADATA_ENCRYPTION` environment variable is set.
* The Sync metadata Realm is now encrypted by default on Apple platforms unless the `REALM_DISABLE_METADATA_ENCRYPTION` environment variable is set.
To enable encryption on the metadata Realm on other platforms you must set an encryption key on `realm::App::configuration`.
```cpp
std::array<char, 64> example_key = {...};
realm::App::configuration app_config;
app_config.app_id = ...
app_config.metadata_encryption_key = example_key;
auto encrypted_app = realm::App(app_config);
```
* Add ability to encrypt a Realm. Usage: `realm::config::set_encryption_key(const std::array<char, 64>&)`.
### Breaking Changes
* None
* `realm::App(const std::string &app_id, const std::optional<std::string> &base_url,
const std::optional<std::string> &path, const std::optional<std::map<std::string, std::string>> &custom_http_headers)` has been deprecated.
use `realm::App(const realm::App::configuration&);` instead.
### Compatibility
* Fileformat: Generates files with format v22.
Expand Down
50 changes: 35 additions & 15 deletions src/cpprealm/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,16 +343,24 @@ namespace realm {
return credentials(app::AppCredentials::function(payload));
}

App::App(const std::string &app_id,
const std::optional<std::string> &base_url,
const std::optional<std::string> &path,
const std::optional<std::map<std::string, std::string>> &custom_http_headers) {
App::App(const configuration& config) {
#if QT_CORE_LIB
util::Scheduler::set_default_factory(util::make_qt);
#endif
SyncClientConfig config;
SyncClientConfig client_config;

#if REALM_PLATFORM_APPLE
bool should_encrypt = !getenv("REALM_DISABLE_METADATA_ENCRYPTION");
config.metadata_mode = should_encrypt ? SyncManager::MetadataMode::Encryption : SyncManager::MetadataMode::NoEncryption;
#else
bool should_encrypt = config.metadata_encryption_key && !getenv("REALM_DISABLE_METADATA_ENCRYPTION");
#endif
client_config.metadata_mode = should_encrypt ? SyncManager::MetadataMode::Encryption : SyncManager::MetadataMode::NoEncryption;
if (config.metadata_encryption_key) {
auto key = std::vector<char>();
key.resize(64);
key.assign(config.metadata_encryption_key->begin(), config.metadata_encryption_key->end());
client_config.custom_encryption_key = std::move(key);
}

#ifdef QT_CORE_LIB
auto qt_path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).toStdString();
Expand All @@ -361,19 +369,19 @@ namespace realm {
}
config.base_file_path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).toStdString();
#else
if (path) {
config.base_file_path = *path;
if (config.path) {
client_config.base_file_path = *config.path;
} else {
config.base_file_path = std::filesystem::current_path().make_preferred().generic_string();
client_config.base_file_path = std::filesystem::current_path().make_preferred().generic_string();
}
#endif
config.user_agent_binding_info = "RealmCpp/0.0.1";
config.user_agent_application_info = app_id;
client_config.user_agent_binding_info = "RealmCpp/0.0.1";
client_config.user_agent_application_info = config.app_id;

auto app_config = app::App::Config();
app_config.app_id = app_id;
app_config.transport = std::make_shared<internal::DefaultTransport>(custom_http_headers);
app_config.base_url = base_url ? base_url : util::Optional<std::string>();
app_config.app_id = config.app_id;
app_config.transport = std::make_shared<internal::DefaultTransport>(config.custom_http_headers);
app_config.base_url = config.base_url ? config.base_url : util::Optional<std::string>();
auto device_info = app::App::Config::DeviceInfo();

device_info.framework_name = "Realm Cpp",
Expand All @@ -382,7 +390,19 @@ namespace realm {
device_info.sdk = "Realm Cpp";
app_config.device_info = std::move(device_info);

m_app = app::App::get_shared_app(std::move(app_config), config);
m_app = app::App::get_shared_app(std::move(app_config), client_config);
}

App::App(const std::string &app_id,
const std::optional<std::string> &base_url,
const std::optional<std::string> &path,
const std::optional<std::map<std::string, std::string>> &custom_http_headers) {
configuration c;
c.app_id = app_id;
c.base_url = base_url;
c.path = path;
c.custom_http_headers = custom_http_headers;
*this = App(std::move(c));
}

std::future<void> App::register_user(const std::string &username, const std::string &password) {
Expand Down
11 changes: 11 additions & 0 deletions src/cpprealm/app.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,22 @@ bool operator!=(const user& lhs, const user& rhs);

class App {
public:
struct configuration {
std::string app_id;
std::optional<std::string> base_url;
std::optional<std::string> path;
std::optional<std::map<std::string, std::string>> custom_http_headers;
std::optional<std::array<char, 64>> metadata_encryption_key;
};

[[deprecated("Use App(const configuration&) instead.")]]
explicit App(const std::string& app_id,
const std::optional<std::string>& base_url = {},
const std::optional<std::string>& path = {},
const std::optional<std::map<std::string, std::string>>& custom_http_headers = {});

App(const configuration&);

struct credentials {
using auth_code = util::TaggedString<class auth_code_tag>;
using id_token = util::TaggedString<class id_token_tag>;
Expand Down
2 changes: 1 addition & 1 deletion tests/alpha/app_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ static std::string create_jwt(const std::string& appId)
}

TEST_CASE("app", "[app]") {
auto app = realm::App(Admin::shared().cached_app_id(), Admin::shared().base_url());
auto app = realm::App(realm::App::configuration({Admin::shared().cached_app_id(), Admin::shared().base_url()}));

SECTION("auth_providers_promise") {
auto run_login = [&app](realm::App::credentials&& credentials) {
Expand Down
2 changes: 1 addition & 1 deletion tests/alpha/asymmetric_object_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ using namespace realm;
TEST_CASE("asymmetric object", "[sync]") {
SECTION("basic", "[sync]") {
auto asymmetric_app_id = Admin::shared().create_app({}, "test", true);
auto app = realm::App(asymmetric_app_id, Admin::shared().base_url());
auto app = realm::App(realm::App::configuration({asymmetric_app_id, Admin::shared().base_url()}));
auto user = app.login(realm::App::credentials::anonymous()).get();
auto p = realm::async_open<AllTypesAsymmetricObject, EmbeddedFoo>(user.flexible_sync_configuration());
auto tsr = p.get_future().get();
Expand Down
4 changes: 2 additions & 2 deletions tests/alpha/flx_sync_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using namespace realm;

TEST_CASE("flx_sync", "[sync]") {
auto app = realm::App(Admin::shared().cached_app_id(), Admin::shared().base_url());
auto app = realm::App(realm::App::configuration({Admin::shared().cached_app_id(), Admin::shared().base_url()}));
SECTION("all") {
app.get_sync_manager().set_log_level(logger::level::off);
auto user = app.login(realm::App::credentials::anonymous()).get();
Expand Down Expand Up @@ -92,7 +92,7 @@ TEST_CASE("flx_sync", "[sync]") {
}

TEST_CASE("realm_is_populated_on_async_open", "[sync]") {
auto app = realm::App(Admin::shared().cached_app_id(), Admin::shared().base_url());
auto app = realm::App(realm::App::configuration({Admin::shared().cached_app_id(), Admin::shared().base_url()}));
SECTION("all") {
{
auto user = app.login(realm::App::credentials::anonymous()).get();
Expand Down
15 changes: 15 additions & 0 deletions tests/experimental/db/realm_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,19 @@ namespace realm::experimental {
t.join();
p.get_future().get();
}

TEST_CASE("encrypted realm") {
std::array<char, 64> example_key = {0,0,0,0,0,0,0,0, 1,1,0,0,0,0,0,0, 2,2,0,0,0,0,0,0, 3,3,0,0,0,0,0,0, 4,4,0,0,0,0,0,0, 5,5,0,0,0,0,0,0, 6,6,0,0,0,0,0,0, 7,7,0,0,0,0,0,0};
realm_path path;

auto config = realm::db_config();
config.set_encryption_key(example_key);
config.set_path(path);
auto realm = experimental::db(config);

// Missing encryption key
auto config2 = realm::db_config();
config2.set_path(path);
REQUIRE_THROWS(experimental::db(config2));
}
}
4 changes: 2 additions & 2 deletions tests/experimental/sync/app_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using namespace realm;

TEST_CASE("app", "[sync]") {
auto app = realm::App(Admin::shared().cached_app_id(), Admin::shared().base_url());
auto app = realm::App(realm::App::configuration({Admin::shared().cached_app_id(), Admin::shared().base_url()}));

SECTION("get_current_user") {
auto user = app.login(realm::App::credentials::anonymous()).get();
Expand All @@ -31,7 +31,7 @@ TEST_CASE("app", "[sync]") {

SECTION("clear_cached_apps") {
auto temp_app_id = Admin::shared().create_app({"str_col", "_id"});
auto temp_app = realm::App(temp_app_id, Admin::shared().base_url());
auto temp_app = realm::App(realm::App::configuration({temp_app_id, Admin::shared().base_url()}));
auto cached_app = temp_app.get_cached_app(temp_app_id, Admin::shared().base_url());
CHECK(cached_app.has_value());
app.clear_cached_apps();
Expand Down
2 changes: 1 addition & 1 deletion tests/experimental/sync/asymmetric_object_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ using namespace realm;
TEST_CASE("asymmetric object", "[sync_beta]") {
SECTION("basic", "[sync]") {
auto asymmetric_app_id = Admin::shared().create_app({}, "test", true);
auto app = realm::App(asymmetric_app_id, Admin::shared().base_url());
auto app = realm::App(realm::App::configuration({asymmetric_app_id, Admin::shared().base_url()}));
auto user = app.login(realm::App::credentials::anonymous()).get();
auto synced_realm = experimental::open<experimental::AllTypesAsymmetricObject, experimental::EmbeddedFoo>(user.flexible_sync_configuration());

Expand Down
11 changes: 8 additions & 3 deletions tests/experimental/sync/flexible_sync_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using namespace realm;

TEST_CASE("flexible_sync_beta", "[sync]") {
auto app = realm::App(Admin::shared().cached_app_id(), Admin::shared().base_url());
auto app = realm::App(realm::App::configuration({Admin::shared().cached_app_id(), Admin::shared().base_url()}));
SECTION("all") {
app.get_sync_manager().set_log_level(logger::level::all);
auto user = app.login(realm::App::credentials::anonymous()).get();
Expand Down Expand Up @@ -77,10 +77,15 @@ TEST_CASE("flexible_sync_beta", "[sync]") {
}

SECTION("encrypted sync realm") {
auto encrypted_app = realm::App(Admin::shared().cached_app_id(), Admin::shared().base_url());
std::array<char, 64> example_key = {0,0,0,0,0,0,0,0, 1,1,0,0,0,0,0,0, 2,2,0,0,0,0,0,0, 3,3,0,0,0,0,0,0, 4,4,0,0,0,0,0,0, 5,5,0,0,0,0,0,0, 6,6,0,0,0,0,0,0, 7,7,0,0,0,0,0,0};
realm::App::configuration app_config;
app_config.app_id = Admin::shared().create_app({"str_col", "_id"});
app_config.base_url = Admin::shared().base_url();
app_config.metadata_encryption_key = example_key;
auto encrypted_app = realm::App(app_config);
auto user = encrypted_app.login(realm::App::credentials::anonymous()).get();
auto flx_sync_config = user.flexible_sync_configuration();
flx_sync_config.set_encryption_key({0,0,0,0,0,0,0,0, 1,1,0,0,0,0,0,0, 2,2,0,0,0,0,0,0, 3,3,0,0,0,0,0,0, 4,4,0,0,0,0,0,0, 5,5,0,0,0,0,0,0, 6,6,0,0,0,0,0,0, 7,7,0,0,0,0,0,0});
flx_sync_config.set_encryption_key(example_key);
auto synced_realm = experimental::db(flx_sync_config);

auto update_success = synced_realm.subscriptions().update([](realm::mutable_sync_subscription_set &subs) {
Expand Down

0 comments on commit 6093f59

Please sign in to comment.