@cocalc/database
Version:
CoCalc: code for working with our PostgreSQL database
136 lines • 5.36 kB
JavaScript
;
/*
* 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