UNPKG

realm-object-server

Version:

Realm Object Server

417 lines 26.9 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const chai_1 = require("chai"); const superagent = require("superagent"); const uuid = require("uuid"); const TestServer_1 = require("../TestServer"); const Token_1 = require("../shared/Token"); const index_1 = require("../index"); const RealmType_1 = require("../realms/RealmType"); const shared_1 = require("../shared"); describe("RealmDirectoryService Tests", function () { let server; let service; let adminToken; let adminTokenRequest; let adminRealm; let authService; before(() => __awaiter(this, void 0, void 0, function* () { server = new TestServer_1.TestServer(); yield server.start({}); service = server.getService("realms"); authService = server.getService("auth"); adminToken = server.tokenValidator.parse(server.adminToken); adminRealm = service["adminRealm"]; adminTokenRequest = { authToken: adminToken, socket: {} }; })); after(() => __awaiter(this, void 0, void 0, function* () { yield server.shutdown().catch((err) => { }); })); describe("state after start", () => { it("registered the internal realms used by ROS", () => __awaiter(this, void 0, void 0, function* () { chai_1.assert.isDefined(adminRealm.objectForPrimaryKey("RealmFile", "/__admin")); })); }); describe("findByPath()", () => { describe("when the realm does not exist", () => { const shouldCreate = "true"; const realmType = RealmType_1.RealmType.full; describe("and the token is an admin token", () => { it("creates a realm and returns it", () => __awaiter(this, void 0, void 0, function* () { chai_1.expect(adminRealm.objectForPrimaryKey("RealmFile", "/products")).to.be.undefined; const response = yield service["findByPath"]("%2Fproducts", adminTokenRequest, shouldCreate, realmType); chai_1.expect(response.path).to.equal("/products"); chai_1.expect(response.syncLabel).to.be.ok; chai_1.expect(adminRealm.objectForPrimaryKey("RealmFile", "/products")).to.be.ok; })); it("creates a realm in a user's folder", () => __awaiter(this, void 0, void 0, function* () { const user = yield authService.createOrUpdateUser(uuid.v4(), "nickname", false); const realmPath = `/${user.userId}/myrealm`; chai_1.expect(adminRealm.objectForPrimaryKey("RealmFile", realmPath)).to.be.undefined; const response = yield service["findByPath"](realmPath, adminTokenRequest, shouldCreate, realmType); chai_1.expect(response.path).to.equal(realmPath); chai_1.expect(response.syncLabel).to.be.ok; chai_1.expect(adminRealm.objectForPrimaryKey("RealmFile", realmPath)).to.be.ok; })); for (const useTilde of [true, false]) { it(`grants correct permissions when ownerId is provided and ~ is ${useTilde ? "" : "not "}used`, () => __awaiter(this, void 0, void 0, function* () { const user = yield authService.createOrUpdateUser(uuid.v4(), "nickname", false); const realmPath = `/${user.userId}/myrealm`; chai_1.expect(adminRealm.objectForPrimaryKey("RealmFile", realmPath)).to.be.undefined; const pathToFind = useTilde ? realmPath.replace(user.userId, "~") : realmPath; const response = yield service["findByPath"](pathToFind, adminTokenRequest, shouldCreate, realmType, user.userId); chai_1.expect(response.path).to.equal(realmPath); chai_1.expect(response.syncLabel).to.be.ok; const realmFile = adminRealm.objectForPrimaryKey("RealmFile", realmPath); chai_1.expect(realmFile).to.be.ok; chai_1.expect(realmFile.owner.userId).to.equal(user.userId); const permissions = adminRealm.objects("Permission").filtered("realmFile = $0", realmFile); chai_1.expect(permissions.length).to.equal(1); chai_1.expect(permissions[0].user.userId).to.equal(user.userId); chai_1.expect(permissions[0].mayRead).to.be.true; chai_1.expect(permissions[0].mayWrite).to.be.true; chai_1.expect(permissions[0].mayManage).to.be.true; })); } }); describe("and the user is not an admin", () => { const shouldCreate = "true"; const realmType = RealmType_1.RealmType.full; const assertPermissions = (realmFile, userId) => { const permissions = adminRealm.objects("Permission").filtered("realmFile = $0 && user.userId = $1", realmFile, userId); chai_1.expect(permissions.length).to.equal(1); chai_1.expect(permissions[0].mayRead).to.true; chai_1.expect(permissions[0].mayWrite).to.true; chai_1.expect(permissions[0].mayManage).to.true; }; for (const useTilde of [true, false]) { it(`creates a realm and returns it when ~ is ${useTilde ? "" : "not "}used`, () => __awaiter(this, void 0, void 0, function* () { const user = yield authService.createOrUpdateUser(uuid.v4(), "nickname", false); const realmPath = `/${user.userId}/myrealm`; chai_1.expect(adminRealm.objectForPrimaryKey("RealmFile", realmPath)).to.be.undefined; const pathToFind = useTilde ? realmPath.replace(user.userId, "~") : realmPath; const response = yield service["findByPath"](pathToFind, { authToken: { identity: user.userId, } }, shouldCreate, realmType); chai_1.expect(response.path).to.equal(realmPath); chai_1.expect(response.syncLabel).to.be.ok; const realmFile = adminRealm.objectForPrimaryKey("RealmFile", realmPath); chai_1.expect(realmFile).to.be.ok; chai_1.expect(realmFile.owner.userId).to.equal(user.userId); assertPermissions(realmFile, user.userId); })); } it("fails to create realm in other user's folder", () => __awaiter(this, void 0, void 0, function* () { const joe = yield authService.createOrUpdateUser(uuid.v4(), "nickname", false); const bob = yield authService.createOrUpdateUser(uuid.v4(), "nickname", false); const realmPath = `/${bob.userId}/myrealm`; chai_1.assert.isUndefined(adminRealm.objectForPrimaryKey("RealmFile", realmPath)); const request = { authToken: { identity: joe.userId } }; yield chai_1.assert.isRejected(service["findByPath"](realmPath, request, shouldCreate, realmType), "The path is invalid or current user has no access."); })); it("fails to impersonate other user", () => __awaiter(this, void 0, void 0, function* () { const joe = yield authService.createOrUpdateUser(uuid.v4(), "nickname", false); const bob = yield authService.createOrUpdateUser(uuid.v4(), "nickname", false); const joePath = `/${joe.userId}/myrealm`; const bobPath = `/${bob.userId}/myrealm`; chai_1.assert.isUndefined(adminRealm.objectForPrimaryKey("RealmFile", joePath)); chai_1.assert.isUndefined(adminRealm.objectForPrimaryKey("RealmFile", bobPath)); const request = { authToken: { identity: joe.userId } }; yield chai_1.assert.isRejected(service["findByPath"](joePath, request, shouldCreate, realmType, bob.userId), "The path is invalid or current user has no access."); yield chai_1.assert.isRejected(service["findByPath"](bobPath, request, shouldCreate, realmType, bob.userId), "The path is invalid or current user has no access."); })); it("successfully impersonates themselves", () => __awaiter(this, void 0, void 0, function* () { const user = yield authService.createOrUpdateUser(uuid.v4(), "nickname", false); const realmPath = `/${user.userId}/myrealm`; chai_1.assert.isUndefined(adminRealm.objectForPrimaryKey("RealmFile", realmPath)); const response = yield service["findByPath"](realmPath, { authToken: { identity: user.userId, } }, shouldCreate, realmType, user.userId); chai_1.assert.equal(response.path, realmPath); chai_1.assert.isDefined(response.syncLabel); const realmFile = adminRealm.objectForPrimaryKey("RealmFile", realmPath); chai_1.expect(realmFile).to.be.ok; chai_1.expect(realmFile.owner.userId).to.equal(user.userId); assertPermissions(realmFile, user.userId); })); }); describe("and path is invalid", () => { const shouldCreate = "true"; const realmType = RealmType_1.RealmType.full; for (const p of ["myrealm.realm", "cæt", ".hello"]) { it(`should reject /${p} with an error`, () => __awaiter(this, void 0, void 0, function* () { const user = yield authService.createOrUpdateUser(uuid.v4(), "nickname", false); const realmPath = `/${user.userId}/${p}`; yield chai_1.assert.isRejected(service["findByPath"](realmPath, { authToken: { identity: user.userId, } }, shouldCreate, realmType)); chai_1.assert.isUndefined(adminRealm.objectForPrimaryKey("RealmFile", realmPath)); })); } }); describe("and the realm is partial", () => { const shouldCreate = "true"; let user; let referenceRealm; const syncLabel = "shardedLabel"; let referenceRealmPath; beforeEach(() => __awaiter(this, void 0, void 0, function* () { user = yield authService.createOrUpdateUser(uuid.v4(), "nickname", false); referenceRealmPath = `/${user.userId}/testReference`; referenceRealm = yield service["findByPath"](referenceRealmPath, { authToken: { identity: user.userId }, }, shouldCreate, RealmType_1.RealmType.reference); })); it("should return a syncLabel equal to the reference realm's syncLabel", () => __awaiter(this, void 0, void 0, function* () { const referenceRalmFile = adminRealm.objectForPrimaryKey("RealmFile", referenceRealmPath); adminRealm.write(() => { referenceRalmFile.syncLabel = syncLabel; }); const realmPath = `${referenceRealm.path}/__partial/${user.userId}/partialPath`; const response = yield chai_1.assert.isFulfilled(service["findByPath"](realmPath, { authToken: { identity: user.userId, } }, shouldCreate, RealmType_1.RealmType.partial)); chai_1.assert.equal(response.syncLabel, syncLabel); })); it("should fail when the partial path is invalid", () => __awaiter(this, void 0, void 0, function* () { const realmPath = `/${user.userId}/partialPath`; yield chai_1.assert.isRejected(service["findByPath"](realmPath, { authToken: { identity: user.userId, } }, shouldCreate, RealmType_1.RealmType.partial), "Your request parameters did not validate. 'realmPath': realmPath for a partial realm is invalid"); })); }); }); }); describe("remove()", () => { let revokedToken; let userToken; before(() => __awaiter(this, void 0, void 0, function* () { revokedToken = new Token_1.RefreshToken({ isAdmin: false, identity: "revoked-identity", appId: "some.appId.com", }); userToken = new Token_1.RefreshToken({ isAdmin: false, identity: "user-identity", appId: "some.appId.com", expires: (Date.now() / 1000) + 60, }); const adminToken = yield server.createSignedAdminToken(); yield superagent.post(`${server.url}/auth/revoke`).set({ Authorization: adminToken, }).send({ token: revokedToken.sign(server.privateKey), }); })); describe("when a revoked token is provided", () => { it("should reject with an error", () => __awaiter(this, void 0, void 0, function* () { yield chai_1.assert.isRejected(service["remove"]("/some-path", { authToken: revokedToken }), "The path is invalid or current user has no access."); })); }); describe("when a regular user refresh token is provided", () => { it("should reject with an error", () => __awaiter(this, void 0, void 0, function* () { yield chai_1.assert.isRejected(service["remove"]("/some-path", { authToken: userToken }), "The path is invalid or current user has no access."); })); }); describe("when the realm file is not found", () => { it("should reject with an error", () => __awaiter(this, void 0, void 0, function* () { yield chai_1.assert.isRejected(service["remove"]("/some-path", adminTokenRequest), "The Realm could not be found"); })); }); describe("when the sync worker is unavailable", () => { it("should reject with an error", () => __awaiter(this, void 0, void 0, function* () { yield service["findOrCreateRealmFile"]("/file-to-delete", null, RealmType_1.RealmType.full, "otherLabel"); yield chai_1.assert.isRejected(service["remove"]("/file-to-delete", adminTokenRequest), "The requested service is temporarily unavailable."); })); }); describe("when the sync worker is available", () => { const realmType = RealmType_1.RealmType.full; it("should remove the realm", () => __awaiter(this, void 0, void 0, function* () { yield service["findOrCreateRealmFile"]("/file-to-delete2", null, realmType); yield chai_1.assert.isFulfilled(service["remove"]("/file-to-delete2", adminTokenRequest)); })); it("should not remove the realm - if protected", () => __awaiter(this, void 0, void 0, function* () { const protectedRealmPaths = [ "/__admin", "/__revocation", "/__wildcardpermissions", "/__password", "/__configuration" ]; const assertFailureWhenDeletingRealm = (path) => __awaiter(this, void 0, void 0, function* () { yield chai_1.assert.isRejected(service["remove"](path, adminTokenRequest), "This Realm is protected from removal"); }); for (const path of protectedRealmPaths) { yield service["findOrCreateRealmFile"](path, null, realmType); yield assertFailureWhenDeletingRealm(path); } })); }); describe("when the Realm is a reference Realm", () => { const getRealmFile = (path) => { return adminRealm.objectForPrimaryKey("RealmFile", path); }; it("should remove its partial views", () => __awaiter(this, void 0, void 0, function* () { yield service["findOrCreateRealmFile"]("/reference-to-delete", null, RealmType_1.RealmType.reference); yield service["findOrCreateRealmFile"]("/reference-to-delete/__partial/abc/123", null, RealmType_1.RealmType.partial); yield service["findOrCreateRealmFile"]("/reference-to-delete/__partial/def/456", null, RealmType_1.RealmType.partial); chai_1.expect(getRealmFile("/reference-to-delete")).to.be.ok; chai_1.expect(getRealmFile("/reference-to-delete/__partial/abc/123")).to.be.ok; chai_1.expect(getRealmFile("/reference-to-delete/__partial/def/456")).to.be.ok; yield chai_1.assert.isFulfilled(service["remove"]("/reference-to-delete", adminTokenRequest)); chai_1.expect(getRealmFile("/reference-to-delete")).to.be.undefined; chai_1.expect(getRealmFile("/reference-to-delete/__partial/abc/123")).to.be.undefined; chai_1.expect(getRealmFile("/reference-to-delete/__partial/def/456")).to.be.undefined; })); }); }); describe("changeType", () => { const assertError = (promise, error) => __awaiter(this, void 0, void 0, function* () { const actual = yield chai_1.assert.isRejected(promise); chai_1.assert.equal(actual.status, error.status); chai_1.assert.equal(actual.code, error.code); }); const assertType = (path, type) => __awaiter(this, void 0, void 0, function* () { const shouldCreate = "false"; const result = yield service["findByPath"](path, adminTokenRequest, shouldCreate); chai_1.assert.equal(result.realmType, type); }); describe("when a token is not provided", () => { it("should reject with an error", () => __awaiter(this, void 0, void 0, function* () { yield assertError(service["changeType"]("%2Fproducts", RealmType_1.RealmType.full, {}), new index_1.errors.realm.AccessDenied()); })); }); describe("when token is not admin token", () => { it("should reject with an error", () => __awaiter(this, void 0, void 0, function* () { const nonAdminToken = new Token_1.RefreshToken({ isAdmin: false, appId: "", identity: uuid.v4() }); yield assertError(service["changeType"]("%2Fproducts", RealmType_1.RealmType.full, { authToken: nonAdminToken }), new index_1.errors.realm.AccessDenied()); })); }); describe("when realmType is not provided", () => { it("should reject with an error", () => __awaiter(this, void 0, void 0, function* () { yield assertError(service["changeType"]("%2Fproducts", undefined, adminTokenRequest), new index_1.errors.realm.InvalidParameters()); })); }); describe("when realmType is invalid", () => { it("should reject with an error", () => __awaiter(this, void 0, void 0, function* () { yield assertError(service["changeType"]("%2Fproducts", "foo", adminTokenRequest), new index_1.errors.realm.InvalidParameters()); })); }); describe("when realmPath doesn't exist", () => { it("should reject with an error", () => __awaiter(this, void 0, void 0, function* () { yield assertError(service["changeType"](`%2F${uuid.v4()}`, RealmType_1.RealmType.full, adminTokenRequest), new index_1.errors.realm.RealmNotFound()); })); }); describe("when realmPath exists", () => { describe("and type is already the desired", () => __awaiter(this, void 0, void 0, function* () { it("should succeed", () => __awaiter(this, void 0, void 0, function* () { const path = `%2F${uuid.v4()}`; const shouldCreate = "true"; const realmType = RealmType_1.RealmType.full; yield service["findByPath"](path, adminTokenRequest, shouldCreate, realmType); yield chai_1.assert.isFulfilled(service["changeType"](path, realmType, adminTokenRequest)); yield assertType(path, RealmType_1.RealmType.full); })); })); describe("and type needs to change", () => __awaiter(this, void 0, void 0, function* () { it("should succeed", () => __awaiter(this, void 0, void 0, function* () { const path = `%2F${uuid.v4()}`; const shouldCreate = "true"; const realmType = RealmType_1.RealmType.full; yield service["findByPath"](path, adminTokenRequest, shouldCreate, realmType); yield chai_1.assert.isFulfilled(service["changeType"](path, RealmType_1.RealmType.reference, adminTokenRequest)); yield assertType(path, RealmType_1.RealmType.reference); })); })); }); }); describe("compact", () => { const assertError = (promise, error) => __awaiter(this, void 0, void 0, function* () { const actual = yield chai_1.assert.isRejected(promise); chai_1.assert.equal(actual.status, error.status); chai_1.assert.equal(actual.code, error.code); }); describe("when a token is not provided", () => { it("should reject with an error", () => __awaiter(this, void 0, void 0, function* () { yield assertError(service["compact"]({}), new index_1.errors.realm.AccessDenied()); })); }); describe("when token is not admin token", () => { it("should reject with an error", () => __awaiter(this, void 0, void 0, function* () { const nonAdminToken = new Token_1.RefreshToken({ isAdmin: false, appId: "", identity: uuid.v4() }); yield assertError(service["compact"]({ authToken: nonAdminToken }), new index_1.errors.realm.AccessDenied()); })); }); describe("when token is admin", () => { it("should resolve", () => __awaiter(this, void 0, void 0, function* () { yield chai_1.assert.isFulfilled(service["compact"](adminTokenRequest)); })); }); }); describe("as event emitter", () => { it("emits realmCreated when a full Realm is created", () => __awaiter(this, void 0, void 0, function* () { const promise = shared_1.waitForEvent(service, "realmCreated"); const realmPath = uuid.v4(); yield service["findByPath"](`%2F${realmPath}`, adminTokenRequest, "true", RealmType_1.RealmType.full); const { path, type, overallStats } = yield promise; const expectedRealms = adminRealm.objects("RealmFile").filtered("realmType = $0 AND !path beginswith '/__'", RealmType_1.RealmType.full).length; chai_1.assert.equal(path, `/${realmPath}`); chai_1.assert.equal(type, RealmType_1.RealmType.full); chai_1.assert.equal(overallStats[RealmType_1.RealmType.full], expectedRealms); })); it("emits realmCreated when a reference Realm is created", () => __awaiter(this, void 0, void 0, function* () { const referencePromise = shared_1.waitForEvent(service, "realmCreated"); const referenceRealmPath = uuid.v4(); yield service["findByPath"](`%2F${referenceRealmPath}`, adminTokenRequest, "true", RealmType_1.RealmType.reference); const { path: referencePath, type: referenceType, overallStats } = yield referencePromise; const expectedRealms = adminRealm.objects("RealmFile").filtered("realmType = $0", RealmType_1.RealmType.reference).length; chai_1.assert.equal(referencePath, `/${referenceRealmPath}`); chai_1.assert.equal(referenceType, RealmType_1.RealmType.reference); chai_1.assert.equal(overallStats[RealmType_1.RealmType.reference], expectedRealms); })); it("emits realmCreated when a partial Realm is created", () => __awaiter(this, void 0, void 0, function* () { const referenceRealmPath = uuid.v4(); const user = yield authService.createOrUpdateUser(uuid.v4(), "nickname", false); const partialRealmPath = `${referenceRealmPath}/__partial/${user.userId}/something`; yield service["findByPath"](`%2F${referenceRealmPath}`, adminTokenRequest, "true", RealmType_1.RealmType.reference); const partialPromise = shared_1.waitForEvent(service, "realmCreated"); yield service["findByPath"](partialRealmPath, { authToken: { identity: user.userId, } }, "true", RealmType_1.RealmType.partial); const { path: partialPath, type: partialType, overallStats } = yield partialPromise; const expectedRealms = adminRealm.objects("RealmFile").filtered("realmType = $0", RealmType_1.RealmType.partial).length; chai_1.assert.equal(partialPath, `/${partialRealmPath}`); chai_1.assert.equal(partialType, RealmType_1.RealmType.partial); chai_1.assert.equal(overallStats[RealmType_1.RealmType.partial], expectedRealms); })); }); }); //# sourceMappingURL=RealmDirectoryService.spec.js.map