Skip to content

Commit

Permalink
(DOCSP-33626) Document metadata encryption (#3068)
Browse files Browse the repository at this point in the history
  • Loading branch information
krollins-mdb and cbullinger authored Nov 6, 2023
1 parent 12f0090 commit 60532d0
Show file tree
Hide file tree
Showing 25 changed files with 489 additions and 74 deletions.
2 changes: 1 addition & 1 deletion examples/node/scripts/bluehawk-one.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ then
# Bluehawk a single file
echo "${GREEN_BG_BOLD} Bluehawk: ${CLEAR} ${GREEN}Generate samples from '$FILE_NAME' ${CLEAR}"

bluehawk snip $INPUT_FILE -o $OUTPUT_DIRECTORY --format=rst
npx bluehawk snip $INPUT_FILE -o $OUTPUT_DIRECTORY --format=rst

# TODO: There's probably a more idiomatic way to do this results filtering.
GENERATED_FILES=$(find $OUTPUT_DIRECTORY -type f | grep -i $BASE_FILE_NAME)
Expand Down
64 changes: 64 additions & 0 deletions examples/node/v12/__tests__/metadata.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// :snippet-start: imports
import Realm, { BSON, MetadataMode } from "realm";
// :snippet-end:
import { Task } from "./models/models.ts";
import { APP_ID } from "../config.ts";

describe("Handle Realm Metadata", () => {
test("encrypting realm metadata", () => {
// :snippet-start: encrypt-metadata
// Retrieve encryption key from secure location or create one
const encryptionKey = new ArrayBuffer(64);

// Use encryption key in app configuration
const config = {
id: APP_ID,
// :emphasize-start:
metadata: { mode: MetadataMode.Encryption, encryptionKey: encryptionKey },
// :emphasize-end:
};
const app = new Realm.App(config);
// :snippet-end:

expect(app).toBeInstanceOf(Realm.App);
});

test("encrypting a realm", async () => {
const taskId = new BSON.ObjectId();
// :snippet-start: encrypt-realm
// Retrieve encryption key from secure location or create one
const encryptionKey = new ArrayBuffer(64);

// Use encryption key in realm configuration
const config = {
schema: [Task],
encryptionKey: encryptionKey, // :emphasize:
};

const realm = await Realm.open(config);
// :snippet-end:
expect(realm.isClosed).toBeFalsy;

realm.write(() => {
realm.create(Task, {
_id: taskId,
name: "Sweep the floor",
});
});

const Tasks = realm.objects(Task);
expect(Tasks.length).toBeGreaterThan(0);

realm.close();

// Reopen realm with key
const openRealmAgain = await Realm.open({
schema: [Task],
encryptionKey: encryptionKey,
});

const existingTask = openRealmAgain.objectForPrimaryKey(Task, taskId);
expect(existingTask).toBeTruthy;
expect(existingTask?._id).toEqual(taskId);
});
});
69 changes: 69 additions & 0 deletions examples/node/v12/__tests__/metadata.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// :snippet-start: imports
import Realm, {
AppConfiguration,
BSON,
MetadataMode,
Configuration,
} from "realm";
// :snippet-end:
import { Task } from "./models/models";
import { APP_ID } from "../config";

describe("Handle Realm Metadata", () => {
test("encrypting realm metadata", () => {
// :snippet-start: encrypt-metadata
// Retrieve encryption key from secure location or create one
const encryptionKey = new ArrayBuffer(64);

// Use encryption key in app configuration
const config: AppConfiguration = {
id: APP_ID,
// :emphasize-start:
metadata: { mode: MetadataMode.Encryption, encryptionKey: encryptionKey },
// :emphasize-end:
};
const app = new Realm.App(config);
// :snippet-end:

expect(app).toBeInstanceOf(Realm.App);
});

test("encrypting a realm", async () => {
const taskId = new BSON.ObjectId();
// :snippet-start: encrypt-realm
// Retrieve encryption key from secure location or create one
const encryptionKey = new ArrayBuffer(64);

// Use encryption key in realm configuration
const config: Configuration = {
schema: [Task],
encryptionKey: encryptionKey, // :emphasize:
};

const realm = await Realm.open(config);
// :snippet-end:
expect(realm.isClosed).toBeFalsy;

realm.write(() => {
realm.create(Task, {
_id: taskId,
name: "Sweep the floor",
});
});

const Tasks = realm.objects(Task);
expect(Tasks.length).toBeGreaterThan(0);

realm.close();

// Reopen realm with key
const openRealmAgain = await Realm.open({
schema: [Task],
encryptionKey: encryptionKey,
});

const existingTask = openRealmAgain.objectForPrimaryKey(Task, taskId);
expect(existingTask).toBeTruthy;
expect(existingTask?._id).toEqual(taskId);
});
});
23 changes: 23 additions & 0 deletions examples/node/v12/__tests__/models/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Realm, { BSON, ObjectSchema } from "realm";

export class Task extends Realm.Object<Task> {
_id!: BSON.ObjectId;
name!: String;
status?: String;
progressMinutes?: Number;
owner?: String;
dueDate?: Date;

static schema: ObjectSchema = {
name: "Task",
properties: {
_id: "objectId",
name: "string",
status: "string?",
progressMinutes: "int?",
owner: "string?",
dueDate: "date?",
},
primaryKey: "_id",
};
}
14 changes: 7 additions & 7 deletions examples/node/v12/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/node/v12/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"license": "ISC",
"dependencies": {
"fs-extra": "^11.1.1",
"realm": "^12.1.0"
"realm": "^12.3.0"
},
"devDependencies": {
"@babel/core": "^7.21.8",
Expand Down
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
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;
}) => {
const metadataConfig = {
// :emphasize-start:
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',
},
});
Loading

0 comments on commit 60532d0

Please sign in to comment.