UNPKG

@iobroker/db-objects-redis

Version:

The Library contains the Database classes for Redis based objects database client.

466 lines (465 loc) 18.7 kB
"use strict"; 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