Skip to content

Commit

Permalink
- Update RN realm dependency
Browse files Browse the repository at this point in the history
- Add React Native versions of encryption
  • Loading branch information
krollins-mdb committed Nov 3, 2023
1 parent a47abd2 commit d3c78a5
Show file tree
Hide file tree
Showing 11 changed files with 191 additions and 29 deletions.
48 changes: 40 additions & 8 deletions examples/react-native/v12/TestApp/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {Logger} from './src/components/logger/Logger';
import {ObjectModels} from './src/components/object-models/ObjectModels';
import {RelationshipExamples} from './src/components/relationships/RealmWrapper';
import {CompensatingWriteErrorHandling} from './src/components/errors/CompensatingWriteWrapper';
import {EncryptMetadata} from './src/components/encryption/EncryptMetadata';

// Screens
import {SubscriptionScreen} from './src/screens/SubscriptionScreen';
Expand All @@ -22,6 +23,9 @@ import {RootStackParamList} from './src/navigation/types';

const Drawer = createDrawerNavigator<RootStackParamList>();

// Create encryption key for encryption examples.
const encryptionKey = new ArrayBuffer(64);

/*
// Each screen has its own RealmProvider and realm. However, they all point to
// the default path. This means you'll get an error when you try to navigate
Expand All @@ -38,18 +42,46 @@ function App(): JSX.Element {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Geospatial" component={Geospatial} />
<Drawer.Screen name="FullTextSearch" component={FtsQuery} />
<Drawer.Screen name="Logger" component={Logger} />
<Drawer.Screen name="ObjectModels" component={ObjectModels} />
<Drawer.Screen name="Subscriptions" component={SubscriptionScreen} />
<Drawer.Screen name="Relationships" component={RelationshipExamples} />
<Drawer.Screen
name="Home"
component={HomeScreen}
/>
<Drawer.Screen
name="Geospatial"
component={Geospatial}
/>
<Drawer.Screen
name="FullTextSearch"
component={FtsQuery}
/>
<Drawer.Screen
name="Logger"
component={Logger}
/>
<Drawer.Screen
name="ObjectModels"
component={ObjectModels}
/>
<Drawer.Screen
name="Subscriptions"
component={SubscriptionScreen}
/>
<Drawer.Screen
name="Relationships"
component={RelationshipExamples}
/>
<Drawer.Screen
name="Errors"
component={CompensatingWriteErrorHandling}
/>
<Drawer.Screen name="Authentication" component={AuthenticationScreen} />
<Drawer.Screen
name="Authentication"
component={AuthenticationScreen}
/>
<Drawer.Screen
name="Encryption"
component={() => <EncryptMetadata encryptionKey={encryptionKey} />}
/>
</Drawer.Navigator>
</NavigationContainer>
);
Expand Down
2 changes: 1 addition & 1 deletion examples/react-native/v12/TestApp/babel.config.cjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
// 'module:metro-react-native-babel-preset',
'module:metro-react-native-babel-preset',
'@babel/preset-typescript',
],
plugins: ['react-native-reanimated/plugin'],
Expand Down
8 changes: 4 additions & 4 deletions examples/react-native/v12/TestApp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion examples/react-native/v12/TestApp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"react-native-reanimated": "^3.4.2",
"react-native-safe-area-context": "^4.7.1",
"react-native-screens": "^3.24.0",
"realm": "^12.2.1"
"realm": "^12.2.3"
},
"devDependencies": {
"@babel/core": "^7.20.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'react-native';
import React from 'react';
import {render, screen} from '@testing-library/react-native';

import {EncryptMetadata} from './EncryptMetadata';

// Create encryption key for encryption examples.
const encryptionKey = new ArrayBuffer(64);

test('linking an anonymous user with an email/password account', async () => {
render(<EncryptMetadata encryptionKey={encryptionKey} />);

const encryptionResultTextNode = await screen.findByTestId('is-realm-app');
expect(encryptionResultTextNode).toBeInTheDocument;
expect(encryptionResultTextNode.children[1]).toBe('true');
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// :snippet-start: imports
import React from 'react';
import {Text, View} from 'react-native';
import {MetadataMode} from 'realm';
import {AppProvider} from '@realm/react';
// :snippet-end:
import {StyleSheet} from 'react-native';
import {useApp} from '@realm/react';
import {APP_ID} from '../../../appServicesConfig';

// :snippet-start: encrypt-metadata
// :replace-start: {
// "terms": {
// "export ": ""
// }
// }
export const EncryptMetadata = ({
encryptionKey,
}: {
encryptionKey: ArrayBuffer;
}) => {
// :emphasize-start:
const metadataConfig = {
mode: MetadataMode.Encryption,
encryptionKey: encryptionKey,
};
// :emphasize-end:

return (
<AppProvider
id={APP_ID}
metadata={metadataConfig}>
<RestOfApp />
</AppProvider>
);
};
// :replace-end:
// :snippet-end:

const RestOfApp = () => {
const app = useApp();

return (
<View style={styles.section}>
<Text testID="is-realm-app">
Is an instance of `Realm.App`?: {app ? 'true' : 'false'}
</Text>
</View>
);
};

const styles = StyleSheet.create({
section: {
flex: 1,
marginTop: 8,
paddingVertical: 12,
alignItems: 'center',
},
});
3 changes: 3 additions & 0 deletions examples/react-native/v12/TestApp/src/navigation/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export type RootStackParamList = {
Relationships: undefined;
Errors: undefined;
Authentication: undefined;
Encryption: {
encryptionKey: ArrayBuffer;
};
};

export type SubscriptionStackParamList = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.. code-block:: typescript
:emphasize-lines: 6-9
const EncryptMetadata = ({
encryptionKey,
}: {
encryptionKey: ArrayBuffer;
}) => {
const metadataConfig = {
mode: MetadataMode.Encryption,
encryptionKey: encryptionKey,
};
return (
<AppProvider
id={APP_ID}
metadata={metadataConfig}>
<RestOfApp />
</AppProvider>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.. code-block:: typescript
import React from 'react';
import {Text, View} from 'react-native';
import {MetadataMode} from 'realm';
import {AppProvider} from '@realm/react';
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,24 @@ from the ``realm`` package, then pass in your ``App ID``.
import Realm from 'realm';

const app = Realm.App.getApp("<Your App ID>");

.. _react-native-encrypt-app-metadata:

Encrypt App Metadata
--------------------

You can encrypt the metadata App Services stores on client devices. Use the
values of the :js-sdk:`MetadataMode enum <enums/_internal_.MetadataMode.html>`
to determine encryption behavior.

To encrypt App metadata:

#. Import ``MetadataMode`` from ``Realm``.
#. Create an App configuration object that contains the ``metadata`` property.
#. Set ``metadata.mode`` to a value from the ``MetadataMode`` enum.
#. Set ``metadata.encryptionKey`` to the key you want to use for encryption.
#. Pass the App configuration object to ``new Realm.App()``.

.. include:: /examples/generated/react-native/v12/EncryptMetadata.snippet.imports.tsx.rst

.. include:: /examples/generated/react-native/v12/EncryptMetadata.snippet.encrypt-metadata.tsx.rst
34 changes: 19 additions & 15 deletions source/sdk/react-native/realm-files/encrypt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ integrity using a :wikipedia:`hash-based message authentication code

.. include:: /includes/encrypt-use-strong-cryptographic-hash.rst

Considerations
--------------
The following code demonstrates how to generate an encryption key and
open an encrypted realm:

.. literalinclude:: /examples/generated/react-native/ts/encrypted-realm.test.snippet.encrypted-realm.tsx
:language: typescript

The following are key impacts to consider when encrypting a realm.

Storing & Reusing 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
Expand All @@ -38,12 +41,12 @@ Apps should store the encryption key securely, typically in the target
platform's secure key/value storage, so that other apps cannot read 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 <react-native-open-a-synced-realm>`.

Expand All @@ -54,24 +57,25 @@ use one of the :ref:`Realm authentication providers <users-and-authentication>`
and an :ref:`authentication trigger<authentication-triggers>`
to create a 64-bit key and store that key in a :ref:`user object <user-objects>`.

Accessing an Encrypted Realm from Multiple Processes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Access an Encrypted Realm from Multiple Processes
-------------------------------------------------

.. versionchanged:: ``[email protected]``

Starting with Realm React Native SDK version 11.8.0, Realm supports opening
Starting with Realm React Native SDK version v11.8.0, Realm supports opening
the same encrypted realm in multiple processes.

If your app uses Realm React Native SDK version 11.7.0 or earlier, attempting to
If your app uses Realm React Native SDK version v11.7.0 or earlier, attempting to
open an encrypted realm from multiple processes throws this error:
``Encrypted interprocess sharing is currently unsupported.``

Example
-------
Encrypt App Services App Metadata
---------------------------------

The following code demonstrates how to generate an encryption key and
open an encrypted realm:
If you use Atlas Device Sync with your realm, your App Services App uses an
on-device metadata file to determine changes that should sync.

.. literalinclude:: /examples/generated/react-native/ts/encrypted-realm.test.snippet.encrypted-realm.tsx
:language: typescript
You can encrypt this metadata file in a similar manner as encrypting your
realm.

To learn more, refer to :ref:`Ecrypt App Metadata <react-native-encrypt-app-metadata>`.

0 comments on commit d3c78a5

Please sign in to comment.