mirror of
https://github.com/status-im/realm-js.git
synced 2025-01-11 06:46:03 +00:00
Expose user serialize and deserialize methods (#1996)
* Expose serialize and deserialize methods
* Changelog and docs
* Forgot to save changelog 🤦♂️
* Add input validation
This commit is contained in:
parent
a10ffae469
commit
477b900530
23
CHANGELOG.md
23
CHANGELOG.md
@ -1,3 +1,26 @@
|
||||
X.Y.Z Release notes
|
||||
=============================================================
|
||||
### Compatibility
|
||||
* Sync protocol: 24
|
||||
* Server-side history format: 4
|
||||
* File format: 7
|
||||
* Realm Object Server: 3.0.0 or later
|
||||
|
||||
### Breaking changes
|
||||
* None.
|
||||
|
||||
### Enhancements
|
||||
* Exposed `User.serialize` to create a persistable representation of a user instance, as well as
|
||||
`User.deserialize` to later inflate a `User` instance that can be used to connect to Realm Object
|
||||
Server and open synchronized Realms (#1276).
|
||||
|
||||
### Bug fixes
|
||||
* Removed a false negative warning when using `User.createConfiguration`.
|
||||
|
||||
### Internal
|
||||
* Realm Core v5.7.2.
|
||||
* Realm Sync v3.9.1.
|
||||
|
||||
2.15.3 Release notes (2018-8-24)
|
||||
=============================================================
|
||||
### Compatibility
|
||||
|
14
docs/sync.js
14
docs/sync.js
@ -398,6 +398,12 @@ class User {
|
||||
*/
|
||||
static adminUser(adminToken, server) {}
|
||||
|
||||
/**
|
||||
* Creates a new sync user instance from the serialized representation.
|
||||
* @param {object} serialized - the serialized version of the user, obtained by calling {@link User#serialize}.
|
||||
*/
|
||||
static deserialize(serialized) {}
|
||||
|
||||
/**
|
||||
* A dictionary containing users that are currently logged in.
|
||||
* The keys in the dictionary are user identities, values are corresponding User objects.
|
||||
@ -452,6 +458,14 @@ class User {
|
||||
*/
|
||||
createConfiguration(config) {}
|
||||
|
||||
/**
|
||||
* Serializes a user to an object, that can be persisted or passed to another component to create a new instance
|
||||
* by calling {@link User.deserialize}. The serialized user instance includes the user's refresh token and should
|
||||
* be treated as sensitive data.
|
||||
* @returns {object} an object, containing the user identity, server url, and refresh token.
|
||||
*/
|
||||
serialize() {}
|
||||
|
||||
/**
|
||||
* Logs out the user from the Realm Object Server.
|
||||
*/
|
||||
|
10
lib/index.d.ts
vendored
10
lib/index.d.ts
vendored
@ -283,6 +283,13 @@ declare namespace Realm.Sync {
|
||||
user: UserInfo
|
||||
}
|
||||
|
||||
interface SerializedUser {
|
||||
server: string;
|
||||
refreshToken: string;
|
||||
identity: string;
|
||||
isAdmin: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* User
|
||||
* @see { @link https://realm.io/docs/javascript/latest/api/Realm.Sync.User.html }
|
||||
@ -323,8 +330,11 @@ declare namespace Realm.Sync {
|
||||
|
||||
static confirmEmail(server:string, confirmation_token:string): Promise<void>;
|
||||
|
||||
static deserialize(serialized: SerializedUser): Realm.Sync.User;
|
||||
|
||||
createConfiguration(config?: Realm.PartialConfiguration): Realm.Configuration
|
||||
authenticate(server: string, provider: string, options: any): Promise<Realm.Sync.User>;
|
||||
serialize(): SerializedUser;
|
||||
logout(): void;
|
||||
openManagementRealm(): Realm;
|
||||
retrieveAccount(provider: string, username: string): Promise<Account>;
|
||||
|
@ -38,6 +38,25 @@ function checkTypes(args, types) {
|
||||
}
|
||||
}
|
||||
|
||||
function checkObjectTypes(obj, types) {
|
||||
for (const name of Object.getOwnPropertyNames(types)) {
|
||||
const actualType = typeof obj[name];
|
||||
let targetType = types[name];
|
||||
const isOptional = targetType[targetType.length - 1] === '?';
|
||||
if (isOptional) {
|
||||
targetType = targetType.slice(0, -1);
|
||||
}
|
||||
|
||||
if (!isOptional && actualType === 'undefined') {
|
||||
throw new Error(`${name} is required, but a value was not provided.`);
|
||||
}
|
||||
|
||||
if (actualType !== targetType) {
|
||||
throw new TypeError(`${name} must be of type '${targetType}' but was of type '${actualType}' instead.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform a HTTP request, enqueuing it if too many requests are already in
|
||||
// progress to avoid hammering the server.
|
||||
const performFetch = (function() {
|
||||
@ -407,6 +426,17 @@ const staticMethods = {
|
||||
return _authenticate(this, server, json)
|
||||
},
|
||||
|
||||
deserialize(serialized) {
|
||||
checkObjectTypes(serialized, {
|
||||
server: 'string',
|
||||
identity: 'string',
|
||||
refreshToken: 'string',
|
||||
isAdmin: 'boolean',
|
||||
});
|
||||
|
||||
return this.createUser(serialized.server, serialized.identity, serialized.refreshToken, false, serialized.isAdmin || false);
|
||||
},
|
||||
|
||||
requestPasswordReset(server, email) {
|
||||
checkTypes(arguments, ['string', 'string']);
|
||||
const json = {
|
||||
@ -478,6 +508,14 @@ const instanceMethods = {
|
||||
.then(() => console.log('User is logged out'))
|
||||
.catch((e) => print_error(e));
|
||||
},
|
||||
serialize() {
|
||||
return {
|
||||
server: this.server,
|
||||
refreshToken: this.token,
|
||||
identity: this.identity,
|
||||
isAdmin: this.isAdmin,
|
||||
};
|
||||
},
|
||||
openManagementRealm() {
|
||||
let url = url_parse(this.server);
|
||||
if (url.protocol === 'http:') {
|
||||
@ -525,7 +563,7 @@ const instanceMethods = {
|
||||
createConfiguration(config) {
|
||||
|
||||
if (config && config.sync) {
|
||||
if (console.warn !== undefined) {
|
||||
if (config.sync.user && console.warn !== undefined) {
|
||||
console.warn(`'user' property will be overridden by ${this.identity}`);
|
||||
}
|
||||
if (config.sync.partial !== undefined && config.sync.fullSynchronization !== undefined) {
|
||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "realm",
|
||||
"version": "2.15.2",
|
||||
"version": "2.15.3",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -369,6 +369,87 @@ module.exports = {
|
||||
})
|
||||
}, "'partial' and 'fullSynchronization' were both set. 'partial' has been deprecated, use only 'fullSynchronization'");
|
||||
});
|
||||
},
|
||||
|
||||
testSerialize() {
|
||||
const username = uuid();
|
||||
return Realm.Sync.User.register('http://localhost:9080', username, 'password').then((user) => {
|
||||
const serialized = user.serialize();
|
||||
TestCase.assertFalse(serialized.isAdmin);
|
||||
TestCase.assertEqual(serialized.identity, user.identity);
|
||||
TestCase.assertEqual(serialized.server, 'http://localhost:9080');
|
||||
TestCase.assertEqual(serialized.refreshToken, user.token);
|
||||
});
|
||||
},
|
||||
|
||||
testDeserialize() {
|
||||
const username = uuid();
|
||||
return Realm.Sync.User.register('http://localhost:9080', username, 'password')
|
||||
.then((user) => {
|
||||
const userConfig = user.createConfiguration({
|
||||
schema: [{ name: 'Dog', properties: { name: 'string' } }],
|
||||
sync: {
|
||||
url: 'realm://localhost:9080/~/foo',
|
||||
fullSynchronization: true,
|
||||
}
|
||||
});
|
||||
|
||||
const realm = new Realm(userConfig);
|
||||
realm.write(() => {
|
||||
realm.create('Dog', {
|
||||
name: 'Doggo'
|
||||
});
|
||||
});
|
||||
|
||||
const session = realm.syncSession;
|
||||
return new Promise((resolve, reject) => {
|
||||
let callback = (transferred, total) => {
|
||||
if (transferred >= total) {
|
||||
session.removeProgressNotification(callback);
|
||||
realm.close();
|
||||
Realm.deleteFile(userConfig);
|
||||
resolve(user.serialize());
|
||||
}
|
||||
}
|
||||
session.addProgressNotification('upload', 'forCurrentlyOutstandingWork', callback);
|
||||
});
|
||||
}).then((serialized) => {
|
||||
const deserialized = Realm.Sync.User.deserialize(serialized);
|
||||
const config = deserialized.createConfiguration({
|
||||
schema: [{ name: 'Dog', properties: { name: 'string' } }],
|
||||
sync: {
|
||||
url: 'realm://localhost:9080/~/foo',
|
||||
fullSynchronization: true,
|
||||
}
|
||||
});
|
||||
|
||||
return Realm.open(config);
|
||||
}).then((realm) => {
|
||||
const dogs = realm.objects('Dog');
|
||||
TestCase.assertEqual(dogs.length, 1);
|
||||
TestCase.assertEqual(dogs[0].name, 'Doggo');
|
||||
});
|
||||
},
|
||||
|
||||
testDeserializeInvalidInput() {
|
||||
const dummy = {
|
||||
server: '123',
|
||||
identity: '123',
|
||||
refreshToken: '123',
|
||||
isAdmin: false,
|
||||
};
|
||||
|
||||
for (const name of Object.getOwnPropertyNames(dummy)) {
|
||||
const clone = Object.assign({}, dummy);
|
||||
// Set to invalid type
|
||||
clone[name] = 123;
|
||||
|
||||
TestCase.assertThrowsContaining(() => Realm.Sync.User.deserialize(clone), `${name} must be of type '${typeof dummy[name]}'`);
|
||||
|
||||
// Set to undefined
|
||||
clone[name] = undefined;
|
||||
TestCase.assertThrowsContaining(() => Realm.Sync.User.deserialize(clone), `${name} is required, but a value was not provided.`);
|
||||
}
|
||||
}
|
||||
|
||||
/* This test fails because of realm-object-store #243 . We should use 2 users.
|
||||
|
Loading…
x
Reference in New Issue
Block a user