Skip to content

Passing encryption key via a callback #1636

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Prev Previous commit
Next Next commit
Added experimental API
  • Loading branch information
nhachicha committed Jan 18, 2024
commit 44549febcf41fa76b0681e8ac4fca0f854f2f68c
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
### Enhancements
* [Sync] Added option to use managed WebSockets via OkHttp instead of Realm's built-in WebSocket client for Sync traffic (Only Android and JVM targets for now). Managed WebSockets offer improved support for proxies and firewalls that require authentication. This feature is currently opt-in and can be enabled by using `AppConfiguration.usePlatformNetworking()`. Managed WebSockets will become the default in a future version. (PR [#1528](https://github.com/realm/realm-kotlin/pull/1528)).
* `AutoClientResetFailed` exception now reports as the throwable cause any user exceptions that might occur during a client reset. (Issue [#1580](https://github.com/realm/realm-kotlin/issues/1580))
* Added an experimental configuration API which will allow to pass the encryption key using a callback https://github.com/realm/realm-kotlin/pull/1636.

### Fixed
* Cache notification callback JNI references at startup to ensure that symbols can be resolved in core callbacks. (Issue [#1577](https://github.com/realm/realm-kotlin/issues/1577))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.realm.kotlin

import io.realm.kotlin.Configuration.SharedBuilder
import io.realm.kotlin.annotations.ExperimentalEncryptionCallbackApi
import io.realm.kotlin.internal.MISSING_PLUGIN_MESSAGE
import io.realm.kotlin.internal.REALM_FILE_EXTENSION
import io.realm.kotlin.internal.platform.PATH_SEPARATOR
Expand Down Expand Up @@ -106,6 +107,7 @@ public data class InitialRealmFileConfiguration(
val checksum: String?
)

@ExperimentalEncryptionCallbackApi
public interface EncryptionKeyCallback {
/**
* Provides the native memory address of the 64 byte array containing the key used to encrypt and decrypt the Realm file.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also document that this can be called multiple times and that release is only called once, so they do not accidentially create a new Pointer for every call to this, but only release it once.

This was also why I thought it might make a better API if this was an symmetric API, i.e. called 3 times, and released 3 times, but I do agree that the current behavior is easier to implement for the sake of an POC.

Expand Down Expand Up @@ -170,6 +172,7 @@ public interface Configuration {
*
* @return null on unencrypted Realms.
*/
@OptIn(ExperimentalEncryptionCallbackApi::class)
public val encryptionKeyAsCallback: EncryptionKeyCallback?

/**
Expand Down Expand Up @@ -253,6 +256,7 @@ public interface Configuration {
protected var writeDispatcher: CoroutineDispatcher? = null
protected var schemaVersion: Long = 0
protected var encryptionKey: ByteArray? = null
@OptIn(ExperimentalEncryptionCallbackApi::class)
protected var encryptionKeyAsCallback: EncryptionKeyCallback? = null
protected var compactOnLaunchCallback: CompactOnLaunchCallback? = null
protected var initialDataCallback: InitialDataCallback? = null
Expand Down Expand Up @@ -416,6 +420,7 @@ public interface Configuration {
* val realm = Realm.open(encryptedConf)
*```
*/
@OptIn(ExperimentalEncryptionCallbackApi::class)
public fun encryptionKey(encryptionKeyAsCallback: EncryptionKeyCallback): S =
apply { this.encryptionKeyAsCallback = encryptionKeyAsCallback } as S

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.realm.kotlin

import io.realm.kotlin.annotations.ExperimentalEncryptionCallbackApi
import io.realm.kotlin.internal.ContextLogger
import io.realm.kotlin.internal.RealmConfigurationImpl
import io.realm.kotlin.internal.platform.appFilesDirectory
Expand Down Expand Up @@ -185,6 +186,7 @@ public interface RealmConfiguration : Configuration {
writerDispatcherFactory,
schemaVersion,
encryptionKey,
@OptIn(ExperimentalEncryptionCallbackApi::class)
encryptionKeyAsCallback,
deleteRealmIfMigrationNeeded,
compactOnLaunchCallback,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2023 Realm Inc.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package io.realm.kotlin.annotations

/**
* This annotation mark Realm API for encryption callback **experimental**, i.e.
* there are no guarantees given that this API cannot change without warning between minor and
* major versions. They will not change between patch versions.
*
* For all other purposes these APIs are considered stable, i.e. they undergo the same testing
* as other parts of the API and should behave as documented with no bugs. It is primarily
* marked as experimental because we are unsure if this API provide value and solve the use
* cases that people have. If not, they will be changed or removed altogether.
*/
@MustBeDocumented
@Target(
AnnotationTarget.CLASS,
AnnotationTarget.PROPERTY,
AnnotationTarget.FUNCTION,
AnnotationTarget.TYPEALIAS
)
@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
public annotation class ExperimentalEncryptionCallbackApi
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import io.realm.kotlin.EncryptionKeyCallback
import io.realm.kotlin.InitialDataCallback
import io.realm.kotlin.InitialRealmFileConfiguration
import io.realm.kotlin.LogConfiguration
import io.realm.kotlin.annotations.ExperimentalEncryptionCallbackApi
import io.realm.kotlin.dynamic.DynamicMutableRealm
import io.realm.kotlin.dynamic.DynamicMutableRealmObject
import io.realm.kotlin.dynamic.DynamicRealm
Expand Down Expand Up @@ -61,6 +62,7 @@ public open class ConfigurationImpl(
schemaVersion: Long,
schemaMode: SchemaMode,
private val userEncryptionKey: ByteArray?,
@OptIn(ExperimentalEncryptionCallbackApi::class)
override val encryptionKeyAsCallback: EncryptionKeyCallback?,
compactOnLaunchCallback: CompactOnLaunchCallback?,
userMigration: RealmMigration?,
Expand Down Expand Up @@ -232,6 +234,7 @@ public open class ConfigurationImpl(
RealmInterop.realm_config_set_encryption_key(nativeConfig, key)
}

@OptIn(ExperimentalEncryptionCallbackApi::class)
encryptionKeyAsCallback?.let {
RealmInterop.realm_config_set_encryption_key_from_pointer(nativeConfig, it.keyPointer())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import io.realm.kotlin.InitialDataCallback
import io.realm.kotlin.InitialRealmFileConfiguration
import io.realm.kotlin.LogConfiguration
import io.realm.kotlin.RealmConfiguration
import io.realm.kotlin.annotations.ExperimentalEncryptionCallbackApi
import io.realm.kotlin.internal.interop.SchemaMode
import io.realm.kotlin.internal.util.CoroutineDispatcherFactory
import io.realm.kotlin.migration.RealmMigration
Expand All @@ -41,6 +42,7 @@ internal class RealmConfigurationImpl(
writeDispatcherFactory: CoroutineDispatcherFactory,
schemaVersion: Long,
encryptionKey: ByteArray?,
@OptIn(ExperimentalEncryptionCallbackApi::class)
encryptionKeyAsCallback: EncryptionKeyCallback?,
override val deleteRealmIfMigrationNeeded: Boolean,
compactOnLaunchCallback: CompactOnLaunchCallback?,
Expand All @@ -64,6 +66,7 @@ internal class RealmConfigurationImpl(
false -> SchemaMode.RLM_SCHEMA_MODE_AUTOMATIC
},
encryptionKey,
@OptIn(ExperimentalEncryptionCallbackApi::class)
encryptionKeyAsCallback,
compactOnLaunchCallback,
migration,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package io.realm.kotlin.internal
import io.realm.kotlin.Configuration
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.Realm
import io.realm.kotlin.annotations.ExperimentalEncryptionCallbackApi
import io.realm.kotlin.dynamic.DynamicRealm
import io.realm.kotlin.internal.dynamic.DynamicRealmImpl
import io.realm.kotlin.internal.interop.ClassKey
Expand Down Expand Up @@ -139,6 +140,7 @@ public class RealmImpl private constructor(
}

realmScope.launch {
@OptIn(ExperimentalEncryptionCallbackApi::class)
configuration.encryptionKeyAsCallback?.let {
// if we're using an encryption key as a callback, we preemptively open the notifier and writer Realm
// with the given configuration because the key might be deleted from memory after the Realm is open.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import io.realm.kotlin.LogConfiguration
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.Realm
import io.realm.kotlin.TypedRealm
import io.realm.kotlin.annotations.ExperimentalEncryptionCallbackApi
import io.realm.kotlin.internal.ConfigurationImpl
import io.realm.kotlin.internal.ContextLogger
import io.realm.kotlin.internal.ObjectIdImpl
Expand Down Expand Up @@ -565,6 +566,7 @@ public interface SyncConfiguration : Configuration {
schemaVersion,
SchemaMode.RLM_SCHEMA_MODE_ADDITIVE_DISCOVERED,
encryptionKey,
@OptIn(ExperimentalEncryptionCallbackApi::class)
encryptionKeyAsCallback,
compactOnLaunchCallback,
null, // migration is not relevant for sync,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package io.realm.kotlin.test.common
import io.realm.kotlin.EncryptionKeyCallback
import io.realm.kotlin.Realm
import io.realm.kotlin.RealmConfiguration
import io.realm.kotlin.annotations.ExperimentalEncryptionCallbackApi
import io.realm.kotlin.entities.Sample
import io.realm.kotlin.test.platform.PlatformUtils
import io.realm.kotlin.test.util.use
Expand Down Expand Up @@ -128,6 +129,7 @@ class EncryptionTests {
}
}

@OptIn(ExperimentalEncryptionCallbackApi::class)
@Test
fun openEncryptedRealmWithEncryptionKeyCallback() = runBlocking {
val key: ByteArray = Random.nextBytes(64)
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy