diff --git a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/AppClientTest.kt b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/AppClientTest.kt index 229e2b1c25..27962bebcd 100644 --- a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/AppClientTest.kt +++ b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/AppClientTest.kt @@ -30,23 +30,45 @@ class AppClientTest: RealmTest() { } @Test - fun setCustomHttpHeadersTest() { - val myEncryptionKey = getEncryptionKey() - val config1 = - // :snippet-start: configure-app-client + fun configureAppClient() { + val config = + // :snippet-start: configure-app-client // Creates an App with custom configuration values AppConfiguration.Builder(YOUR_APP_ID) // Replace with your App ID + // Specify your custom configuration values .appName("my-app-name") + .appVersion("1.0.0") + .baseUrl("http://localhost:9090") + .build() + // :snippet-end: + assertEquals(config.appName, "my-app-name") + assertEquals(config.baseUrl, "http://localhost:9090") + assertEquals(config.appVersion, "1.0.0") + } + + @Test + fun encryptAppMetadata() { + val myEncryptionKey = getEncryptionKey() + val config = + // :snippet-start: encrypted-app-client + AppConfiguration.Builder(YOUR_APP_ID) + // Specify the encryption key .encryptionKey(myEncryptionKey) .build() // :snippet-end: + assertTrue(config.encryptionKey.contentEquals(myEncryptionKey)) + } + + @Test + fun setCustomHttpHeadersTest() { + val config1 = AppConfiguration.Builder(YOUR_APP_ID) + .appName("my-app-name") + .build() val config2 = // :snippet-start: set-custom-http-headers AppConfiguration.Builder(YOUR_APP_ID) .authorizationHeaderName("MyApp-Authorization") - .customRequestHeaders { - put("X-MyApp-Version", "1.0.0") - } + .customRequestHeaders { put("X-MyApp-Version", "1.0.0") } .build() // :snippet-end: assertEquals(config1.authorizationHeaderName, "Authorization") diff --git a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/EncryptARealmTest.kt b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/EncryptARealmTest.kt index cc38e3fdfb..a950befb1f 100644 --- a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/EncryptARealmTest.kt +++ b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/EncryptARealmTest.kt @@ -2,9 +2,15 @@ package com.mongodb.realm.realmkmmapp import io.realm.kotlin.Realm import io.realm.kotlin.RealmConfiguration +import io.realm.kotlin.ext.query import io.realm.kotlin.internal.platform.runBlocking +import io.realm.kotlin.mongodb.App +import io.realm.kotlin.mongodb.Credentials +import io.realm.kotlin.mongodb.sync.SyncConfiguration import kotlin.random.Random import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue class EncryptARealmTest : RealmTest() { @Test @@ -15,7 +21,8 @@ class EncryptARealmTest : RealmTest() { // generate a new 64-byte encryption key val key = ByteArray(64) if (seed != null) { - // If there is a seed provided, create a random number with that seed and fill the byte array with random bytes + // If there is a seed provided, create a random number with that seed + // and fill the byte array with random bytes Random(seed).nextBytes(key) } else { // fill the byte array with random bytes @@ -23,31 +30,53 @@ class EncryptARealmTest : RealmTest() { } return key } + // :remove-start: + assertTrue(getRandomKey().size == 64) + val generatedKey = getRandomKey() + // :remove-end: runBlocking { // Create the configuration - val config = RealmConfiguration.Builder( - setOf(Frog::class)) + val config = RealmConfiguration.Builder(setOf(Frog::class)) // :remove-start: .deleteRealmIfMigrationNeeded() .directory("tmp/encrypted") // :remove-end: - // specify the encryptionKey - .encryptionKey(getRandomKey()) + // Specify the encryption key + .encryptionKey(generatedKey) .build() - // :remove-start: - Realm.deleteRealm(config) - // :remove-end: - // Open a realm with the encryption key. + // Open the realm with the configuration val realm = Realm.open(config) - Log.v("Successfully opened realm:" + - realm.configuration.name - ) - + Log.v("Successfully opened encrypted realm: ${realm.configuration.name}") // :remove-start: + assertEquals(generatedKey, realm.configuration.encryptionKey) realm.close() + Realm.deleteRealm(config) // :remove-end: } // :snippet-end: } + + @Test + fun encryptSyncedRealm() { + val generatedKey = getEncryptionKey() + val app = App.create(yourFlexAppId) + runBlocking { + val user = app.login(Credentials.anonymous()) + // :snippet-start: encrypt-synced-realm + val syncConfig = SyncConfiguration.Builder(user, setOf(Frog::class)) + .initialSubscriptions { realm -> + add(realm.query()) + } + // Specify the encryption key + .encryptionKey(generatedKey) + .build() + val realm = Realm.open(syncConfig) + Log.v("Successfully opened encrypted realm: ${realm.configuration.name}") + // :snippet-end: + assertEquals(generatedKey, realm.configuration.encryptionKey) + realm.close() + user.delete() + } + } } \ No newline at end of file diff --git a/source/examples/generated/kotlin/AppClientTest.snippet.configure-app-client.kt b/source/examples/generated/kotlin/AppClientTest.snippet.configure-app-client.kt index 7afd3ed07d..cba5512f89 100644 --- a/source/examples/generated/kotlin/AppClientTest.snippet.configure-app-client.kt +++ b/source/examples/generated/kotlin/AppClientTest.snippet.configure-app-client.kt @@ -1,5 +1,7 @@ // Creates an App with custom configuration values AppConfiguration.Builder(YOUR_APP_ID) // Replace with your App ID + // Specify your custom configuration values .appName("my-app-name") - .encryptionKey(myEncryptionKey) + .appVersion("1.0.0") + .baseUrl("http://localhost:9090") .build() diff --git a/source/examples/generated/kotlin/AppClientTest.snippet.encrypted-app-client.kt b/source/examples/generated/kotlin/AppClientTest.snippet.encrypted-app-client.kt new file mode 100644 index 0000000000..e40c172327 --- /dev/null +++ b/source/examples/generated/kotlin/AppClientTest.snippet.encrypted-app-client.kt @@ -0,0 +1,4 @@ +AppConfiguration.Builder(YOUR_APP_ID) + // Specify the encryption key + .encryptionKey(myEncryptionKey) + .build() diff --git a/source/examples/generated/kotlin/AppClientTest.snippet.set-custom-http-headers.kt b/source/examples/generated/kotlin/AppClientTest.snippet.set-custom-http-headers.kt index 70dd11e5e2..f5977f47ce 100644 --- a/source/examples/generated/kotlin/AppClientTest.snippet.set-custom-http-headers.kt +++ b/source/examples/generated/kotlin/AppClientTest.snippet.set-custom-http-headers.kt @@ -1,6 +1,4 @@ AppConfiguration.Builder(YOUR_APP_ID) .authorizationHeaderName("MyApp-Authorization") - .customRequestHeaders { - put("X-MyApp-Version", "1.0.0") - } + .customRequestHeaders { put("X-MyApp-Version", "1.0.0") } .build() diff --git a/source/examples/generated/kotlin/EncryptARealmTest.snippet.encrypt-a-realm.kt b/source/examples/generated/kotlin/EncryptARealmTest.snippet.encrypt-a-realm.kt index 7c77265ed6..75b2920762 100644 --- a/source/examples/generated/kotlin/EncryptARealmTest.snippet.encrypt-a-realm.kt +++ b/source/examples/generated/kotlin/EncryptARealmTest.snippet.encrypt-a-realm.kt @@ -3,7 +3,8 @@ fun getRandomKey(seed: Long? = null): ByteArray { // generate a new 64-byte encryption key val key = ByteArray(64) if (seed != null) { - // If there is a seed provided, create a random number with that seed and fill the byte array with random bytes + // If there is a seed provided, create a random number with that seed + // and fill the byte array with random bytes Random(seed).nextBytes(key) } else { // fill the byte array with random bytes @@ -14,15 +15,11 @@ fun getRandomKey(seed: Long? = null): ByteArray { runBlocking { // Create the configuration - val config = RealmConfiguration.Builder( - setOf(Frog::class)) - // specify the encryptionKey - .encryptionKey(getRandomKey()) + val config = RealmConfiguration.Builder(setOf(Frog::class)) + // Specify the encryption key + .encryptionKey(generatedKey) .build() - // Open a realm with the encryption key. + // Open the realm with the configuration val realm = Realm.open(config) - Log.v("Successfully opened realm:" + - realm.configuration.name - ) - + Log.v("Successfully opened encrypted realm: ${realm.configuration.name}") } diff --git a/source/examples/generated/kotlin/EncryptARealmTest.snippet.encrypt-synced-realm.kt b/source/examples/generated/kotlin/EncryptARealmTest.snippet.encrypt-synced-realm.kt new file mode 100644 index 0000000000..67cae36e88 --- /dev/null +++ b/source/examples/generated/kotlin/EncryptARealmTest.snippet.encrypt-synced-realm.kt @@ -0,0 +1,9 @@ +val syncConfig = SyncConfiguration.Builder(user, setOf(Frog::class)) + .initialSubscriptions { realm -> + add(realm.query()) + } + // Specify the encryption key + .encryptionKey(generatedKey) + .build() +val realm = Realm.open(syncConfig) +Log.v("Successfully opened encrypted realm: ${realm.configuration.name}") diff --git a/source/sdk/dotnet/realm-files/encrypt-a-realm.txt b/source/sdk/dotnet/realm-files/encrypt-a-realm.txt index 3c1aa08461..bf23d657a8 100644 --- a/source/sdk/dotnet/realm-files/encrypt-a-realm.txt +++ b/source/sdk/dotnet/realm-files/encrypt-a-realm.txt @@ -28,6 +28,14 @@ integrity using a :wikipedia:`hash-based message authentication code .. include:: /includes/encrypt-use-strong-cryptographic-hash.rst +.. note:: Cannot Encrypt an Existing Unencrypted Realm + + You must encrypt a realm the first time you open it. + If you try to open an existing unencrypted realm using a configuration + that contains an encryption key, Realm throws an error. + + .. update with writeCopy API when available + Considerations -------------- diff --git a/source/sdk/flutter/realm-database/realm-files/encrypt.txt b/source/sdk/flutter/realm-database/realm-files/encrypt.txt index 6353445848..c0c7850e51 100644 --- a/source/sdk/flutter/realm-database/realm-files/encrypt.txt +++ b/source/sdk/flutter/realm-database/realm-files/encrypt.txt @@ -27,6 +27,17 @@ integrity using a :wikipedia:`hash-based message authentication code .. include:: /includes/encrypt-use-strong-cryptographic-hash.rst +.. note:: Encrypt a Realm on Open or Copy Unencrypted Realm + + You must encrypt a realm the first time you open it. + If you try to open an existing unencrypted realm using a configuration + that contains an encryption key, Realm throws an error. + + Alternatively, you can copy the unencrypted realm data to a new + encrypted realm using the + :flutter-sdk:`Realm.writeCopy() ` method. + Refer to :ref:`` for more information. + Considerations -------------- diff --git a/source/sdk/kotlin/app-services/connect-to-app-services-backend.txt b/source/sdk/kotlin/app-services/connect-to-app-services-backend.txt index 915d1ab56f..e624931487 100644 --- a/source/sdk/kotlin/app-services/connect-to-app-services-backend.txt +++ b/source/sdk/kotlin/app-services/connect-to-app-services-backend.txt @@ -60,20 +60,39 @@ Configure the App Client You can add optional arguments to the ``AppConfiguration`` for more granular control of your app connection details, such as custom -timeouts for connections and keys for local encryption. +request headers and keys for local encryption. To control the additional configuration options, use the `AppConfiguration.Builder -<{+kotlin-sync-prefix+}io.realm.kotlin.mongodb/-app-configuration/-builder/index.html>`__ and call the ``.build()`` method to pass a configuration -object: +<{+kotlin-sync-prefix+}io.realm.kotlin.mongodb/-app-configuration/-builder/index.html>`__ +and call the ``.build()`` method to pass a configuration object: .. literalinclude:: /examples/generated/kotlin/AppClientTest.snippet.configure-app-client.kt :language: kotlin .. include:: /includes/multiple-app-client-details-and-app-config-cache.rst +.. _kotlin-encrypt-app-metadata: + +Encrypt App Metadata +~~~~~~~~~~~~~~~~~~~~ + +When you connect to App Services, Realm creates additional metadata files on +a device. For more information about these metadata files, refer to +:ref:``. + +You can encrypt the metadata that App Services stores on client devices, +similar to how you :ref:``. + +To encrypt App metadata, pass your encryption key to the +`encryptionKey <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb/-app-configuration/encryption-key.html>`__ +property when you initialize the App: + +.. literalinclude:: /examples/generated/kotlin/AppClientTest.snippet.encrypted-app-client.kt + :language: kotlin + Set Custom HTTP Headers ------------------------ +~~~~~~~~~~~~~~~~~~~~~~~ .. versionadded:: 1.11.0 diff --git a/source/sdk/kotlin/realm-database/realm-files/encrypt-a-realm.txt b/source/sdk/kotlin/realm-database/realm-files/encrypt-a-realm.txt index 414cf9b0a6..f0e9300c2e 100644 --- a/source/sdk/kotlin/realm-database/realm-files/encrypt-a-realm.txt +++ b/source/sdk/kotlin/realm-database/realm-files/encrypt-a-realm.txt @@ -10,13 +10,10 @@ Encrypt a Realm - Kotlin SDK :depth: 2 :class: singlecol -Overview --------- - You can encrypt your realms to ensure that the data stored to disk can't be read outside of your application. You encrypt the realm file on -disk with AES-256 + SHA-2 by supplying a 64-byte encryption key when -:ref:`opening the realm `. +disk with AES-256 + SHA-2 by supplying a 64-byte encryption key when first +:ref:`opening the realm `. Realm transparently encrypts and decrypts data with standard :wikipedia:`AES-256 encryption ` using the @@ -27,13 +24,76 @@ integrity using a :wikipedia:`hash-based message authentication code .. include:: /includes/encrypt-use-strong-cryptographic-hash.rst -Considerations --------------- +.. note:: Encrypt a Realm on Open or Copy Unencrypted Realm + + You must encrypt a realm the first time you open it. + If you try to open an existing unencrypted realm using a configuration + that contains an encryption key, Realm throws an error. + + Alternatively, you can copy the unencrypted realm data to a new + encrypted realm using the + `Realm.writeCopyTo() <{+kotlin-local-prefix+}io.realm.kotlin/-realm/write-copy-to.html>`__ + method. + Refer to :ref:`` for more information. + +Encrypt a Local Realm +--------------------- + +To encrypt a local realm, pass your encryption key to the +`encryptionKey <{+kotlin-local-prefix+}io.realm.kotlin/-configuration/encryption-key.html>`__ +property in the +`RealmConfiguration.Builder() <{+kotlin-local-prefix+}io.realm.kotlin/-realm-configuration/index.html>`__ +used to open the realm. + +The following code demonstrates how to generate an encryption key and +open an encrypted local realm: + +.. literalinclude:: /examples/generated/kotlin/EncryptARealmTest.snippet.encrypt-a-realm.kt + :language: kotlin + :emphasize-lines: 19-20 + +.. _kotlin-encrypt-a-synced-realm: + +Encrypt a Synced Realm +---------------------- + +If your app uses Atlas Device Sync, you can encrypt a synced realm, similar +to encrypting a local realm. + +To encrypt a synced realm, pass your encryption key to the +`encryptionKey <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb/-app-configuration/encryption-key.html>`__ +property in the +`SyncConfiguration.Builder() +<{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync-configuration/-builder/-builder.html>`__ +used to open the realm. + +The following code demonstrates how to open an encrypted synced realm: + +.. literalinclude:: /examples/generated/kotlin/EncryptARealmTest.snippet.encrypt-synced-realm.kt + :language: kotlin + :emphasize-lines: 5-6 + +Refer to :ref:`` for more information. + +Encryption and Atlas Device Sync +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. include:: /includes/encrypt-atlas-device-sync.rst + +If you need unique keys for each user of your application, you can use an OAuth provider or +use one of the :ref:`Realm authentication providers ` +and an :ref:`authentication trigger` +to create a 64-bit key and store that key in a :ref:`user object `. + +Encrypt App Metadata +~~~~~~~~~~~~~~~~~~~~ + +You can also encrypt the App Services App metadata that Realm stores on the device. -The following are key impacts to consider when encrypting a realm. +To learn more, refer to :ref:``. -Storing & Reusing Keys -~~~~~~~~~~~~~~~~~~~~~~ +Store & Reuse Keys +------------------ You **must** pass the same encryption key every time you open the encrypted realm. If you don't provide a key or specify the wrong key for an encrypted @@ -49,24 +109,12 @@ It is the developer's responsibility to ensure that attackers cannot access the key. Performance Impact -~~~~~~~~~~~~~~~~~~ +------------------ Reads and writes on encrypted realms can be up to 10% slower than unencrypted realms. -Encryption and Atlas Device Sync -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You can encrypt a :ref:`synced realm `. - -.. include:: /includes/encrypt-atlas-device-sync.rst - -If you need unique keys for each user of your application, you can use an OAuth provider or -use one of the :ref:`Realm authentication providers ` -and an :ref:`authentication trigger` -to create a 64-bit key and store that key in a :ref:`user object `. - -Multiple Processes -~~~~~~~~~~~~~~~~~~ +Access Encrypted Realms from Multiple Processes +----------------------------------------------- .. versionchanged:: 10.8.0 @@ -76,14 +124,3 @@ the same encrypted realm in multiple processes. If your app uses Realm Kotlin SDK version 10.7.1 or earlier, attempting to open an encrypted realm from multiple processes throws this error: ``Encrypted interprocess sharing is currently unsupported.`` - -Example -------- - -.. include:: /includes/encrypt-use-strong-cryptographic-hash.rst - -The following code demonstrates how to generate an encryption key and -open an encrypted realm: - -.. literalinclude:: /examples/generated/kotlin/EncryptARealmTest.snippet.encrypt-a-realm.kt - :language: kotlin \ No newline at end of file diff --git a/source/sdk/node/realm-files/encrypt.txt b/source/sdk/node/realm-files/encrypt.txt index 3f3fe9c2c9..af3e38b37f 100644 --- a/source/sdk/node/realm-files/encrypt.txt +++ b/source/sdk/node/realm-files/encrypt.txt @@ -23,6 +23,19 @@ integrity using a :wikipedia:`hash-based message authentication code .. include:: /includes/encrypt-use-strong-cryptographic-hash.rst +.. note:: Encrypt a Realm on Open or Copy Unencrypted Realm + + You must encrypt a realm the first time you open it. + If you try to open an existing unencrypted realm using a configuration + that contains an encryption key, Realm throws an error. + + Alternatively, you can copy the unencrypted realm data to a new + encrypted realm using the + :js-sdk:`Realm.writeCopyTo() ` + method. + Refer to :ref:`` + for more information. + The following code demonstrates how to generate an encryption key and open an encrypted realm: diff --git a/source/sdk/react-native/realm-files/encrypt.txt b/source/sdk/react-native/realm-files/encrypt.txt index 1e1ed2af22..aaaa57807f 100644 --- a/source/sdk/react-native/realm-files/encrypt.txt +++ b/source/sdk/react-native/realm-files/encrypt.txt @@ -22,6 +22,14 @@ integrity using a :wikipedia:`hash-based message authentication code .. include:: /includes/encrypt-use-strong-cryptographic-hash.rst +.. note:: Cannot Encrypt an Existing Unencrypted Realm + + You must encrypt a realm the first time you open it. + If you try to open an existing unencrypted realm using a configuration + that contains an encryption key, Realm throws an error. + + .. update with writeCopy API info once available + The following code demonstrates how to generate an encryption key and open an encrypted realm: diff --git a/source/sdk/swift/realm-files/encrypt-a-realm.txt b/source/sdk/swift/realm-files/encrypt-a-realm.txt index 9c5a1b832a..3b0d474296 100644 --- a/source/sdk/swift/realm-files/encrypt-a-realm.txt +++ b/source/sdk/swift/realm-files/encrypt-a-realm.txt @@ -26,6 +26,14 @@ integrity using a :wikipedia:`hash-based message authentication code .. include:: /includes/encrypt-use-strong-cryptographic-hash.rst +.. note:: Cannot Encrypt an Existing Unencrypted Realm + + You must encrypt a realm the first time you open it. + If you try to open an existing unencrypted realm using a configuration + that contains an encryption key, Realm throws an error. + + .. update with writeCopy API when available + Considerations --------------