@iobroker/db-objects-redis
Version:
The Library contains the Database classes for Redis based objects database client.
466 lines (465 loc) • 18.7 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var objectsUtils_exports = {};
__export(objectsUtils_exports, {
CONSTS: () => CONSTS2,
ERRORS: () => ERRORS,
REG_CHECK_ID: () => REG_CHECK_ID,
checkFile: () => checkFile,
checkFileRights: () => checkFileRights,
checkObject: () => checkObject,
checkObjectRights: () => checkObjectRights,
getMimeType: () => getMimeType,
getUserGroup: () => getUserGroup,
sanitizePath: () => sanitizePath
});
module.exports = __toCommonJS(objectsUtils_exports);
var import_node_path = __toESM(require("node:path"), 1);
var import_deep_clone = __toESM(require("deep-clone"), 1);
var import_db_base = require("@iobroker/db-base");
var CONSTS = __toESM(require("../../lib/objects/constants.js"), 1);
var import_mime_types = __toESM(require("mime-types"), 1);
var CONSTS2 = __toESM(require("../../lib/objects/constants.js"), 1);
const ERRORS = CONSTS.ERRORS;
const REG_CHECK_ID = CONSTS.REG_CHECK_ID;
const USER_STARTS_WITH = CONSTS.USER_STARTS_WITH;
const GROUP_STARTS_WITH = CONSTS.GROUP_STARTS_WITH;
const textTypes = [".js", ".json", ".svg"];
function getKnownMimeType(ext) {
try {
const mimeType = import_mime_types.default.lookup(ext);
if (mimeType) {
return { mimeType, isBinary: !mimeType.startsWith("text/") && !textTypes.includes(ext) };
}
} catch {
}
return null;
}
const defaultAcl = {
groups: [],
acl: {
file: {
list: false,
read: false,
write: false,
create: false,
delete: false
},
object: {
list: false,
read: false,
write: false,
create: false,
delete: false
},
state: {
list: false,
read: false,
write: false,
create: false,
delete: false
},
users: {
list: false,
read: false,
write: false,
create: false,
delete: false
}
}
};
let users = {};
let groups = [];
function getMimeType(ext, isTextData) {
if (!ext) {
return { mimeType: isTextData ? "text/plain" : "application/octet-stream", isBinary: !isTextData };
}
ext = ext.toLowerCase();
const mimeInfo = getKnownMimeType(ext);
if (mimeInfo) {
return mimeInfo;
}
return { mimeType: isTextData ? "text/plain" : "application/octet-stream", isBinary: !isTextData };
}
function checkFile(fileOptions, options, flag, defaultNewAcl) {
if (typeof fileOptions.acl !== "object") {
fileOptions = {};
fileOptions.mimeType = (0, import_deep_clone.default)(fileOptions);
fileOptions.acl = {
owner: defaultNewAcl && defaultNewAcl.owner || CONSTS.SYSTEM_ADMIN_USER,
ownerGroup: defaultNewAcl && defaultNewAcl.ownerGroup || CONSTS.SYSTEM_ADMIN_GROUP,
permissions: defaultNewAcl && defaultNewAcl.file || CONSTS.ACCESS_USER_RW | CONSTS.ACCESS_GROUP_READ | CONSTS.ACCESS_EVERY_READ
// '0644'
};
}
fileOptions.acl.ownerGroup = fileOptions.acl.ownerGroup || defaultNewAcl && defaultNewAcl.ownerGroup || CONSTS.SYSTEM_ADMIN_GROUP;
fileOptions.acl.owner = fileOptions.acl.owner || defaultNewAcl && defaultNewAcl.owner || CONSTS.SYSTEM_ADMIN_USER;
fileOptions.acl.permissions = fileOptions.acl.permissions || defaultNewAcl && defaultNewAcl.file || CONSTS.ACCESS_USER_RW | CONSTS.ACCESS_GROUP_READ | CONSTS.ACCESS_EVERY_READ;
if (options.user !== CONSTS.SYSTEM_ADMIN_USER && options.groups.indexOf(CONSTS.SYSTEM_ADMIN_GROUP) === -1 && fileOptions.acl) {
if (fileOptions.acl.owner !== options.user) {
if (options.groups.indexOf(fileOptions.acl.ownerGroup) !== -1) {
if (!(fileOptions.acl.permissions & flag << 4)) {
return false;
}
} else {
if (!(fileOptions.acl.permissions & flag)) {
return false;
}
}
} else {
if (!(fileOptions.acl.permissions & flag << 8)) {
return false;
}
}
}
return true;
}
function checkFileRights(objects, id, name, options, flag, callback) {
const _options = options || {};
if (!_options.user) {
_options.user = "system.user.admin";
_options.params = _options;
_options.group = "system.group.administrator";
}
if (!_options.acl) {
objects.getUserGroup(_options.user, (_user, groups2, acl) => {
_options.acl = acl || {};
_options.groups = groups2;
_options.group = groups2 ? groups2[0] : null;
checkFileRights(objects, id, name, _options, flag, callback);
});
return;
}
if (flag === CONSTS.ACCESS_WRITE && !_options.acl.file.write) {
return import_db_base.tools.maybeCallbackWithError(callback, ERRORS.ERROR_PERMISSION, _options);
}
if (flag === CONSTS.ACCESS_READ && !_options.acl.file.read) {
return import_db_base.tools.maybeCallbackWithError(callback, ERRORS.ERROR_PERMISSION, _options);
}
_options.checked = true;
objects.checkFile(id, name, _options, flag, (err, options2, opt) => {
if (err) {
return import_db_base.tools.maybeCallbackWithError(callback, ERRORS.ERROR_PERMISSION, options2);
}
return import_db_base.tools.maybeCallbackWithError(callback, null, options2, opt);
});
}
function getDefaultAdminRights(acl, _isState) {
return {
...acl,
file: {
list: true,
read: true,
write: true,
create: true,
delete: true
},
object: {
create: true,
list: true,
read: true,
write: true,
delete: true
},
users: {
create: true,
list: true,
read: true,
write: true,
delete: true
},
state: {
read: true,
write: true,
delete: true,
create: true,
list: true
},
other: {
execute: false,
http: false,
sendto: false
}
};
}
function getUserGroup(objects, user, callback) {
if (!user || typeof user !== "string" || !user.startsWith(USER_STARTS_WITH)) {
console.log(`invalid user name: ${user}`);
return import_db_base.tools.maybeCallbackWithError(callback, `invalid user name: ${user}`, (0, import_deep_clone.default)(user), [], (0, import_deep_clone.default)(defaultAcl.acl));
}
if (users[user]) {
return import_db_base.tools.maybeCallbackWithError(callback, null, user, users[user].groups, users[user].acl);
}
let error;
objects.getObjectList({ startkey: "system.group.", endkey: "system.group.\u9999" }, { checked: true }, (err, arr) => {
if (err) {
error = err;
}
groups = [];
if (arr) {
for (const g in arr.rows) {
const val = arr.rows[g].value;
if (!val) {
continue;
}
groups[g] = val;
if (groups[g]._id === CONSTS.SYSTEM_ADMIN_GROUP) {
groups[g].common.acl = getDefaultAdminRights(groups[g].common.acl);
}
}
}
objects.getObjectList({ startkey: "system.user.", endkey: "system.user.\u9999" }, { checked: true }, (err2, arr2) => {
if (err2) {
error = err2;
}
users = {};
if (arr2) {
for (const row of arr2.rows) {
users[row.value._id] = (0, import_deep_clone.default)(defaultAcl);
}
}
users[CONSTS.SYSTEM_ADMIN_USER] = users[CONSTS.SYSTEM_ADMIN_USER] || (0, import_deep_clone.default)(defaultAcl);
users[CONSTS.SYSTEM_ADMIN_USER].acl = getDefaultAdminRights(users[CONSTS.SYSTEM_ADMIN_USER].acl);
for (let g = 0; g < groups.length; g++) {
if (!groups[g] || !groups[g].common || !groups[g].common.members) {
continue;
}
for (let m = 0; m < groups[g].common.members.length; m++) {
const u = groups[g].common.members[m];
if (!users[u]) {
error = error || `Unknown user in group "${groups[g]._id.replace("system.group.", "")}": ${u}`;
continue;
}
users[u].groups.push(groups[g]._id);
if (groups[g].common.acl && groups[g].common.acl.file) {
if (!users[u].acl || !users[u].acl.file) {
users[u].acl = users[u].acl || {};
users[u].acl.file = users[u].acl.file || {};
users[u].acl.file.create = groups[g].common.acl.file.create;
users[u].acl.file.read = groups[g].common.acl.file.read;
users[u].acl.file.write = groups[g].common.acl.file.write;
users[u].acl.file.delete = groups[g].common.acl.file.delete;
users[u].acl.file.list = groups[g].common.acl.file.list;
} else {
users[u].acl.file.create = users[u].acl.file.create || groups[g].common.acl.file.create;
users[u].acl.file.read = users[u].acl.file.read || groups[g].common.acl.file.read;
users[u].acl.file.write = users[u].acl.file.write || groups[g].common.acl.file.write;
users[u].acl.file.delete = users[u].acl.file.delete || groups[g].common.acl.file.delete;
users[u].acl.file.list = users[u].acl.file.list || groups[g].common.acl.file.list;
}
}
if (groups[g].common.acl && groups[g].common.acl.object) {
if (!users[u].acl || !users[u].acl.object) {
users[u].acl = users[u].acl || {};
users[u].acl.object = users[u].acl.object || {};
users[u].acl.object.create = groups[g].common.acl.object.create;
users[u].acl.object.read = groups[g].common.acl.object.read;
users[u].acl.object.write = groups[g].common.acl.object.write;
users[u].acl.object.delete = groups[g].common.acl.object.delete;
users[u].acl.object.list = groups[g].common.acl.object.list;
} else {
users[u].acl.object.create = users[u].acl.object.create || groups[g].common.acl.object.create;
users[u].acl.object.read = users[u].acl.object.read || groups[g].common.acl.object.read;
users[u].acl.object.write = users[u].acl.object.write || groups[g].common.acl.object.write;
users[u].acl.object.delete = users[u].acl.object.delete || groups[g].common.acl.object.delete;
users[u].acl.object.list = users[u].acl.object.list || groups[g].common.acl.object.list;
}
}
if (groups[g].common.acl && groups[g].common.acl.users) {
if (!users[u].acl || !users[u].acl.users) {
users[u].acl = users[u].acl || {};
users[u].acl.users = users[u].acl.users || {};
users[u].acl.users.create = groups[g].common.acl.users.create;
users[u].acl.users.read = groups[g].common.acl.users.read;
users[u].acl.users.write = groups[g].common.acl.users.write;
users[u].acl.users.delete = groups[g].common.acl.users.delete;
users[u].acl.users.list = groups[g].common.acl.users.list;
} else {
users[u].acl.users.create = users[u].acl.users.create || groups[g].common.acl.users.create;
users[u].acl.users.read = users[u].acl.users.read || groups[g].common.acl.users.read;
users[u].acl.users.write = users[u].acl.users.write || groups[g].common.acl.users.write;
users[u].acl.users.delete = users[u].acl.users.delete || groups[g].common.acl.users.delete;
users[u].acl.users.list = users[u].acl.users.list || groups[g].common.acl.users.list;
}
}
if (groups[g].common.acl && groups[g].common.acl.state) {
if (!users[u].acl || !users[u].acl.state) {
users[u].acl = users[u].acl || {};
users[u].acl.state = users[u].acl.state || {};
users[u].acl.state.create = groups[g].common.acl.state?.create;
users[u].acl.state.read = groups[g].common.acl.state?.read;
users[u].acl.state.write = groups[g].common.acl.state?.write;
users[u].acl.state.delete = groups[g].common.acl.state?.delete;
users[u].acl.state.list = groups[g].common.acl.state?.list;
} else {
users[u].acl.state.create = users[u].acl.state.create || groups[g].common.acl.state?.create;
users[u].acl.state.read = users[u].acl.state.read || groups[g].common.acl.state?.read;
users[u].acl.state.write = users[u].acl.state.write || groups[g].common.acl.state?.write;
users[u].acl.state.delete = users[u].acl.state.delete || groups[g].common.acl.state?.delete;
users[u].acl.state.list = users[u].acl.state.list || groups[g].common.acl.state?.list;
}
}
}
}
return import_db_base.tools.maybeCallbackWithError(callback, error, user, users[user] ? users[user].groups : [], users[user] ? users[user].acl : (0, import_deep_clone.default)(defaultAcl.acl));
});
});
}
function sanitizePath(id, name) {
if (!name) {
name = "";
}
if (name[0] === "/") {
name = name.substring(1);
}
if (!id) {
throw new Error("Empty ID");
}
id = id.replace(/[\][*,;'"`<>\\?/]/g, "");
id = id.replace(/\.\./g, "");
if (name.includes("..")) {
name = import_node_path.default.normalize(`/${name}`);
}
if (name.includes("..")) {
name = name.replace(/\.\./g, "");
name = import_node_path.default.normalize(`/${name}`);
}
name = name.replace(/\\/g, "/");
if (name[0] === "/") {
name = name.substring(1);
}
return { id, name };
}
function checkObject(obj, options, flag) {
if (!obj || !("common" in obj) || !obj.acl || flag === CONSTS.ACCESS_LIST) {
return true;
}
if (options.user === CONSTS.SYSTEM_ADMIN_USER) {
return true;
}
if (options.group === CONSTS.SYSTEM_ADMIN_GROUP || options.groups.includes(CONSTS.SYSTEM_ADMIN_GROUP)) {
return true;
}
if (flag === CONSTS.ACCESS_DELETE || flag === CONSTS.ACCESS_CREATE) {
return false;
}
if (obj.acl.owner !== options.user) {
if (options.group && options.group === obj.acl.ownerGroup || options.groups && options.groups.includes(obj.acl.ownerGroup)) {
if (!(obj.acl.object & flag << 4)) {
return false;
}
} else {
if (!(obj.acl.object & flag)) {
return false;
}
}
} else {
if (!(obj.acl.object & flag << 8)) {
return false;
}
}
return true;
}
function checkObjectRights(objects, id, object, options, flag, callback) {
options = options || {};
if (!options.user) {
options = {
user: CONSTS.SYSTEM_ADMIN_USER,
params: options,
group: CONSTS.SYSTEM_ADMIN_GROUP,
groups: [CONSTS.SYSTEM_ADMIN_GROUP],
acl: getDefaultAdminRights()
};
}
if (!options.acl) {
return objects.getUserGroup(options.user, (_user, groups2, acl) => {
options = options || {};
options.acl = acl || {};
options.groups = groups2;
options.group = groups2 ? groups2[0] : null;
checkObjectRights(objects, id, object, options, flag, callback);
});
}
if (options.user === CONSTS.SYSTEM_ADMIN_USER || options.group === CONSTS.SYSTEM_ADMIN_GROUP || options.groups && options.groups.includes(CONSTS.SYSTEM_ADMIN_GROUP)) {
return import_db_base.tools.maybeCallbackWithError(callback, null, options);
}
if (typeof id === "string" && (id.startsWith(USER_STARTS_WITH) || id.startsWith(GROUP_STARTS_WITH))) {
if (flag === CONSTS.ACCESS_WRITE && !options.acl.users.write) {
return import_db_base.tools.maybeCallbackWithError(callback, ERRORS.ERROR_PERMISSION, options);
}
if (flag === CONSTS.ACCESS_READ && !options.acl.users.read) {
return import_db_base.tools.maybeCallbackWithError(callback, ERRORS.ERROR_PERMISSION, options);
}
if (flag === CONSTS.ACCESS_DELETE && !options.acl.users.delete) {
return import_db_base.tools.maybeCallbackWithError(callback, ERRORS.ERROR_PERMISSION, options);
}
if (flag === CONSTS.ACCESS_LIST && !options.acl.users.list) {
return import_db_base.tools.maybeCallbackWithError(callback, ERRORS.ERROR_PERMISSION, options);
}
if (flag === CONSTS.ACCESS_CREATE && !options.acl.users.create) {
return import_db_base.tools.maybeCallbackWithError(callback, ERRORS.ERROR_PERMISSION, options);
}
if (flag === CONSTS.ACCESS_DELETE) {
flag = CONSTS.ACCESS_WRITE;
}
}
if (flag === CONSTS.ACCESS_WRITE && !options.acl.object.write) {
import_db_base.tools.maybeCallbackWithError(callback, ERRORS.ERROR_PERMISSION, options);
}
if (flag === CONSTS.ACCESS_READ && !options.acl.object.read) {
return import_db_base.tools.maybeCallbackWithError(callback, ERRORS.ERROR_PERMISSION, options);
}
if (flag === CONSTS.ACCESS_DELETE && !options.acl.object.delete) {
return import_db_base.tools.maybeCallbackWithError(callback, ERRORS.ERROR_PERMISSION, options);
}
if (flag === CONSTS.ACCESS_LIST && !options.acl.object.list) {
return import_db_base.tools.maybeCallbackWithError(callback, ERRORS.ERROR_PERMISSION, options);
}
if (flag === CONSTS.ACCESS_DELETE) {
flag = CONSTS.ACCESS_WRITE;
}
if (id && !checkObject(object, options, flag)) {
return import_db_base.tools.maybeCallbackWithError(callback, ERRORS.ERROR_PERMISSION, options);
}
return import_db_base.tools.maybeCallbackWithError(callback, null, options);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
CONSTS,
ERRORS,
REG_CHECK_ID,
checkFile,
checkFileRights,
checkObject,
checkObjectRights,
getMimeType,
getUserGroup,
sanitizePath
});
//# sourceMappingURL=objectsUtils.js.map