realm-object-server
Version:
417 lines • 26.9 kB
JavaScript
;
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