@cocalc/hub
Version:
CoCalc: Backend webserver component
101 lines • 4.13 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const lru_cache_1 = __importDefault(require("lru-cache"));
const async_utils_1 = require("@cocalc/util/async-utils");
const logger_1 = __importDefault(require("../logger"));
const database_1 = require("../servers/database");
const { user_has_write_access_to_project, user_has_read_access_to_project, } = require("../access");
const hash_1 = __importDefault(require("@cocalc/server/auth/hash"));
const add_user_to_project_1 = __importDefault(require("@cocalc/server/projects/add-user-to-project"));
const is_sandbox_1 = __importDefault(require("@cocalc/server/projects/is-sandbox"));
const winston = (0, logger_1.default)("proxy: has-access");
// 5 minute cache: grant "yes" for a while
const yesCache = new lru_cache_1.default({ max: 20000, maxAge: 1000 * 60 * 5 });
// 10 second cache: recheck "no" more frequently
const noCache = new lru_cache_1.default({ max: 20000, maxAge: 1000 * 10 });
async function hasAccess(opts) {
if (opts.isPersonal) {
// In personal mode, anyone who can access localhost has full
// access to everything, since this is meant to be used on
// single-user personal computer.
return true;
}
const { project_id, remember_me, type } = opts;
const key = project_id + remember_me + type;
for (const cache of [yesCache, noCache]) {
if (cache.has(key))
return !!cache.get(key);
}
// not cached, so we have to determine access.
let access;
const dbg = (m) => {
winston.debug(`(${type} access to ${project_id}): ${m}`);
};
try {
dbg("get remember_me message");
const x = remember_me.split("$");
const hash = (0, hash_1.default)(x[0], x[1], parseInt(x[2]), x[3]);
const signed_in_mesg = await (0, async_utils_1.callback2)(database_1.database.get_remember_me, {
hash,
cache: true,
});
if (signed_in_mesg == null) {
throw Error("not signed in");
}
const { account_id, email_address } = signed_in_mesg;
dbg(`account_id="${account_id}", email_address="${email_address}"`);
dbg(`now check if user has ${type} access to project`);
if (type === "write") {
access = await (0, async_utils_1.callback2)(user_has_write_access_to_project, {
database: database_1.database,
project_id,
account_id,
});
if (!access) {
// if the project is a sandbox project, we add the user as a collaborator
// and grant access.
if (await (0, is_sandbox_1.default)(project_id)) {
dbg("granting sandbox access");
await (0, add_user_to_project_1.default)({ project_id, account_id });
access = true;
}
}
if (access) {
// Record that user is going to actively access
// this project. This is important since it resets
// the idle timeout.
database_1.database.touch({
account_id,
project_id,
});
}
}
else if (type == "read") {
access = await (0, async_utils_1.callback2)(user_has_read_access_to_project, {
database: database_1.database,
project_id,
account_id,
});
}
else {
throw Error(`invalid access type ${type}`);
}
}
catch (err) {
dbg(`error trying to determine access; denying for now -- ${err}`);
access = false;
}
dbg(`determined that access=${access}`);
if (access) {
yesCache.set(key, access);
}
else {
noCache.set(key, access);
}
return access;
}
exports.default = hasAccess;
//# sourceMappingURL=check-for-access-to-project.js.map