diff --git a/CHANGELOG.md b/CHANGELOG.md index 00c226ab99..424e4a8fe9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ x.x.x Release notes (yyyy-MM-dd) ### Fixed * A warning to polyfill `crypto.getRandomValues` was triggered prematurely ([#3714](https://github.com/realm/realm-js/issues/3714), since v10.4.0) +* Mutual exclusive configuration options (`sync`/`inMemory` and `sync`/`migration`) could lead to a crash. ([#3771](https://github.com/realm/realm-js/issues/3771), since v1.0.0) * Disabled executable stack on Linux. ([#3752](https://github.com/realm/realm-js/issues/3752), since v10.2.0) * Don't hang when using the network after hot-reloading an RN app. ([#3668](https://github.com/realm/realm-js/issues/3668)) @@ -3569,8 +3570,6 @@ The feature known as Partial synchronization has been renamed to Query-based syn callback would produce incorrect results. ### Internal -* Upgraded Realm Core from v10.7.1 to 10.7.1. -* Upgraded Realm Core from v10.6.0 to 10.7.1 * None. 2.0.1 Release notes (2017-10-23) @@ -3585,8 +3584,6 @@ The feature known as Partial synchronization has been renamed to Query-based syn * None. ### Internal -* Upgraded Realm Core from v10.7.1 to 10.7.1. -* Upgraded Realm Core from v10.6.0 to 10.7.1 * Upgraded to Realm Sync 2.1.0. 2.0.0 Release notes (2017-10-17) diff --git a/docs/realm.js b/docs/realm.js index 7eca5fe5b4..d9bcb12f73 100644 --- a/docs/realm.js +++ b/docs/realm.js @@ -343,16 +343,16 @@ class Realm { } /** * This describes the different options used to create a {@link Realm} instance. - * + * * See {@tutorial http-proxy} for details on how use an HTTP forward proxy with this library. - * + * * @typedef Realm~Configuration * @type {Object} * @property {ArrayBuffer|ArrayBufferView} [encryptionKey] - The 512-bit (64-byte) encryption * key used to encrypt and decrypt all data in the Realm. * @property {callback(Realm, Realm)} [migration] - The function to run if a migration is needed. * This function should provide all the logic for converting data models from previous schemas - * to the new schema. + * to the new schema. This option is incompatible with `sync`. * This function takes two arguments: * - `oldRealm` - The Realm before migration is performed. * - `newRealm` - The Realm that uses the latest `schema`, which should be modified as necessary. @@ -378,7 +378,7 @@ class Realm { * still requires a path (can be the default path) to identify the Realm so other processes can * open the same Realm. The file will also be used as swap space if the Realm becomes bigger than * what fits in memory, but it is not persistent and will be removed when the last instance - * is closed. + * is closed. This option is incompatible with `sync`. * @property {boolean} [readOnly=false] - Specifies if this Realm should be opened as read-only. * @property {boolean} [disableFormatUpgrade=false] - Specifies if this Realm's file format should * be automatically upgraded if it was created with an older version of the Realm library. diff --git a/src/js_realm.hpp b/src/js_realm.hpp index c2529e7c28..717b7a4cd0 100644 --- a/src/js_realm.hpp +++ b/src/js_realm.hpp @@ -571,6 +571,9 @@ bool RealmClass::get_realm_config(ContextType ctx, size_t argc, const ValueTy static const String in_memory_string = "inMemory"; ValueType in_memory_value = Object::get_property(ctx, object, in_memory_string); if (!Value::is_undefined(ctx, in_memory_value) && Value::validated_to_boolean(ctx, in_memory_value, "inMemory")) { + if (config.force_sync_history || config.sync_config) { + throw std::invalid_argument("Options 'inMemory' and 'sync' are mutual exclusive."); + } config.in_memory = true; } @@ -625,6 +628,10 @@ bool RealmClass::get_realm_config(ContextType ctx, size_t argc, const ValueTy static const String migration_string = "migration"; ValueType migration_value = Object::get_property(ctx, object, migration_string); if (!Value::is_undefined(ctx, migration_value)) { + if (config.force_sync_history || config.sync_config) { + throw std::invalid_argument("Options 'migration' and 'sync' are mutual exclusive."); + } + FunctionType migration_function = Value::validated_to_function(ctx, migration_value, "migration"); if (config.schema_mode == SchemaMode::ResetFile) { @@ -669,6 +676,9 @@ bool RealmClass::get_realm_config(ContextType ctx, size_t argc, const ValueTy static const String disable_format_upgrade_string = "disableFormatUpgrade"; ValueType disable_format_upgrade_value = Object::get_property(ctx, object, disable_format_upgrade_string); if (!Value::is_undefined(ctx, disable_format_upgrade_value)) { + if (config.force_sync_history || config.sync_config) { + throw std::invalid_argument("Options 'disableFormatUpgrade' and 'sync' are mutual exclusive."); + } config.disable_format_upgrade = Value::validated_to_boolean(ctx, disable_format_upgrade_value, "disableFormatUpgrade"); } } diff --git a/tests/js/session-tests.js b/tests/js/session-tests.js index 04f1bbbf25..3712947fcd 100644 --- a/tests/js/session-tests.js +++ b/tests/js/session-tests.js @@ -149,6 +149,37 @@ module.exports = { TestCase.assertNull(realm.syncSession); }, + async testRealmInvalidSyncConfiguration1() { + const config = { + sync: true, + inMemory: true, + }; + + return new Promise((resolve, reject) => { + return Realm.open(config) + .then(_ => reject()) + .catch(_ => resolve()); + }); + }, + + async testRealmInvalidSyncConfiguration2() { + const partition = Utils.genPartition(); + let credentials = Realm.Credentials.anonymous(); + let app = new Realm.App(appConfig); + + + return new Promise((resolve, reject) => { + return app.logIn(credentials) + .then(user => { + let config = getSyncConfiguration(user, partition); + config.migration = (_) => { /* empty function */ }; + return Realm.open(config) + .then(_ => reject()) + .catch(_ => resolve()); + }); + }); + }, + testRealmOpen() { if (!isNodeProcess) { return; diff --git a/tests/package-lock.json b/tests/package-lock.json index 74a197970c..55c02ab6e5 100644 --- a/tests/package-lock.json +++ b/tests/package-lock.json @@ -840,7 +840,7 @@ "version": "file:..", "requires": { "bindings": "^1.5.0", - "bson": "^4.2.0", + "bson": "^4.4.0", "command-line-args": "^4.0.6", "deepmerge": "2.1.0", "deprecated-react-native-listview": "0.0.6", @@ -850,7 +850,7 @@ "node-addon-api": "^3.1.0", "node-fetch": "^2.6.1", "node-machine-id": "^1.1.10", - "prebuild-install": "^5.3.5", + "prebuild-install": "^6.1.1", "progress": "^2.0.3", "prop-types": "^15.6.2", "realm-network-transport": "^0.7.0", diff --git a/types/index.d.ts b/types/index.d.ts index 3f427c3809..559912d651 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -107,25 +107,38 @@ declare namespace Realm { error?: ErrorCallback; } - /** - * realm configuration - * @see { @link https://realm.io/docs/javascript/latest/api/Realm.html#~Configuration } - */ - interface Configuration { + interface BaseConfiguration { encryptionKey?: ArrayBuffer | ArrayBufferView | Int8Array; - migration?: MigrationCallback; + schema?: (ObjectClass | ObjectSchema)[]; + schemaVersion?: number; shouldCompactOnLaunch?: (totalBytes: number, usedBytes: number) => boolean; path?: string; fifoFilesFallbackPath?: string; readOnly?: boolean; + } + + interface ConfigurationWithSync extends BaseConfiguration { + sync: SyncConfiguration; + migration?: never; + inMemory?: never; + deleteRealmIfMigrationNeeded?: never; + disableFormatUpgrade?: never; + } + + interface ConfigurationWithoutSync extends BaseConfiguration { + sync?: never; + migration?: MigrationCallback; inMemory?: boolean; - schema?: (ObjectClass | ObjectSchema)[]; - schemaVersion?: number; - sync?: SyncConfiguration; deleteRealmIfMigrationNeeded?: boolean; disableFormatUpgrade?: boolean; } + /** + * realm configuration + * @see { @link https://realm.io/docs/javascript/latest/api/Realm.html#~Configuration } + */ + type Configuration = ConfigurationWithSync | ConfigurationWithoutSync; + /** * realm configuration used for overriding default configuration values. * @see { @link https://realm.io/docs/javascript/latest/api/Realm.html#~Configuration } @@ -143,9 +156,6 @@ declare namespace Realm { type ObjectChangeCallback = (object: Object, changes: ObjectChangeSet) => void; - interface PartialConfiguration extends Partial { - } - /** * Object * @see { @link https://realm.io/docs/javascript/latest/api/Realm.Object.html }