UNPKG

@cocalc/database

Version:

CoCalc: code for working with our PostgreSQL database

136 lines 5.36 kB
"use strict"; /* * This file is part of CoCalc: Copyright © 2020 Sagemath, Inc. * License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.project_datastore_get = exports.project_datastore_del = exports.project_datastore_set = exports.project_has_network_access = void 0; const lodash_1 = require("lodash"); const async_utils_1 = require("@cocalc/util/async-utils"); const query_1 = require("./query"); const debug_1 = __importDefault(require("debug")); const L = (0, debug_1.default)("hub:project-queries"); const consts_1 = require("@cocalc/util/consts"); async function project_has_network_access(db, project_id) { let x; try { x = await (0, async_utils_1.callback2)(db.get_project, { project_id, columns: ["users", "settings"], }); } catch (err) { // error probably means there is no such project or project_id is badly formatted. return false; } if (x.settings != null && x.settings.network) { return true; } if (x.users != null) { for (const account_id in x.users) { if (x.users[account_id] != null && x.users[account_id].upgrades != null && x.users[account_id].upgrades.network) { return true; } } } return false; } exports.project_has_network_access = project_has_network_access; async function get_datastore(opts) { const { db, account_id, project_id } = opts; const q = await (0, query_1.query)({ db, table: "projects", select: ["addons", "users"], where: { project_id }, one: true, }); // this access test is absolutely critial to have! (only project queries set access_check to false) if (q.users[account_id] == null) throw Error(`access denied`); return q.addons?.datastore; } async function project_datastore_set(db, account_id, project_id, config) { // L("project_datastore_set", config); if (config.name == null) throw Error("configuration 'name' is not defined"); if (typeof config.type !== "string") throw Error("configuration 'type' is not defined (must be 'gcs', 'sshfs', ...)"); // check data from user for (const [key, val] of Object.entries(config)) { if (typeof val !== "string" && typeof val !== "boolean") { throw new Error(`Invalid value -- '${key}' is not a valid type`); } if (typeof val === "string" && val.length > 100000) { throw new Error(`Invalid value -- '${key}' is too long`); } } const old_name = config.__old_name; const conf_new = (0, lodash_1.omit)(config, "name", "secret", "__old_name"); // this is implicitly a test if the user has access to modify this -- don't catch it const ds_prev = await get_datastore({ db, account_id, project_id }); // there is a situation where datastore is renamed, i.e. "name" is a new one, // while the previous secret is stored under a different key. So, if __old_name // is set, we pick that one instead. const prev_name = old_name != null ? old_name : config.name; // if a user wants to update the settings, they don't need to have the secret. // an empty value or the dummy text signals to keep the secret as it is... if (ds_prev != null && ds_prev[prev_name] != null && (config.secret === consts_1.DUMMY_SECRET || config.secret === "")) { conf_new.secret = ds_prev[prev_name].secret; } else { conf_new.secret = Buffer.from(config.secret ?? "").toString("base64"); } await (0, query_1.query)({ db, query: "UPDATE projects", where: { "project_id = $::UUID": project_id }, jsonb_merge: { addons: { datastore: { [config.name]: conf_new } } }, }); } exports.project_datastore_set = project_datastore_set; async function project_datastore_del(db, account_id, project_id, name) { L("project_datastore_del", name); if (typeof name !== "string" || name.length == 0) { throw Error("Datastore name not properly set."); } // this is implicitly a test if the user has access to modify this -- don't catch it const ds = await get_datastore({ db, account_id, project_id }); delete ds[name]; await (0, query_1.query)({ db, query: "UPDATE projects", where: { "project_id = $::UUID": project_id }, jsonb_set: { addons: { datastore: ds } }, }); } exports.project_datastore_del = project_datastore_del; async function project_datastore_get(db, account_id, project_id) { try { const ds = await get_datastore({ db, account_id, project_id, }); if (ds != null) { for (const [k, v] of Object.entries(ds)) { ds[k] = (0, lodash_1.omit)(v, "secret"); } } return { addons: { datastore: ds }, }; } catch (err) { return { type: "error", error: `${err}` }; } } exports.project_datastore_get = project_datastore_get; //# sourceMappingURL=project-queries.js.map