From 891de54560bb7cb59d29564f2ce120a265f5947e Mon Sep 17 00:00:00 2001 From: Babayaga Date: Tue, 17 Feb 2026 21:10:22 +0100 Subject: [PATCH] ACL 2/2 --- packages/acl/package-lock.json | 379 ++++++++-------- packages/acl/package.json | 22 +- packages/acl/src/ACLC.ts | 745 -------------------------------- packages/acl/src/backend.ts | 87 ---- packages/acl/src/data/File.ts | 51 --- packages/acl/src/data/Memory.ts | 178 -------- packages/acl/src/interfaces.ts | 3 +- packages/acl/tsconfig.json | 10 +- 8 files changed, 213 insertions(+), 1262 deletions(-) delete mode 100644 packages/acl/src/ACLC.ts delete mode 100644 packages/acl/src/backend.ts delete mode 100644 packages/acl/src/data/File.ts delete mode 100644 packages/acl/src/data/Memory.ts diff --git a/packages/acl/package-lock.json b/packages/acl/package-lock.json index 2d59d1b0..beadd627 100644 --- a/packages/acl/package-lock.json +++ b/packages/acl/package-lock.json @@ -1,24 +1,17 @@ { "name": "@polymech/acl", - "version": "0.1.5", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@polymech/acl", - "version": "0.1.5", + "version": "0.2.0", "license": "MIT", "dependencies": { - "@polymech/cache": "file:../cache", - "@polymech/commons": "file:../commons", - "@polymech/core": "file:../core", - "@polymech/fs": "file:../fs", - "@polymech/log": "file:../log", - "p-map": "7.0.3", - "p-throttle": "7.0.0", - "ts-retry": "6.0.0", - "yargs": "17.7.2", - "zod": "3.24.3" + "ignore": "^7.0.5", + "mime": "^4.1.0", + "pino": "^9.6.0" }, "bin": { "pm-acl": "dist-in/main.js" @@ -31,12 +24,13 @@ "@vitest/coverage-v8": "^2.1.8", "@vitest/ui": "2.1.9", "typescript": "^5.7.2", - "zod-to-json-schema": "3.24.1" + "vitest": "^2.1.8" } }, "../cache": { "name": "@polymech/cache", "version": "0.4.8", + "extraneous": true, "license": "BSD-3-Clause", "dependencies": { "@polymech/commons": "file:../commons", @@ -57,6 +51,7 @@ "../commons": { "name": "@polymech/commons", "version": "0.2.6", + "extraneous": true, "license": "BSD", "dependencies": { "@polymech/core": "file:../core", @@ -90,6 +85,7 @@ "../core": { "name": "@polymech/core", "version": "0.2.6", + "extraneous": true, "license": "BSD", "dependencies": { "tslog": "^3.3.3", @@ -105,6 +101,7 @@ "../fs": { "name": "@polymech/fs", "version": "0.13.41", + "extraneous": true, "license": "BSD-3-Clause", "dependencies": { "@polymech/core": "file:../core", @@ -135,6 +132,7 @@ "../log": { "name": "@polymech/log", "version": "0.2.6", + "extraneous": true, "license": "BSD", "dependencies": { "@polymech/core": "file:../core", @@ -686,6 +684,16 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -961,6 +969,12 @@ "node": ">= 8" } }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -979,26 +993,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@polymech/cache": { - "resolved": "../cache", - "link": true - }, - "node_modules/@polymech/commons": { - "resolved": "../commons", - "link": true - }, - "node_modules/@polymech/core": { - "resolved": "../core", - "link": true - }, - "node_modules/@polymech/fs": { - "resolved": "../fs", - "link": true - }, - "node_modules/@polymech/log": { - "resolved": "../log", - "link": true - }, "node_modules/@repo/typescript-config": { "resolved": "../typescript-config", "link": true @@ -1421,6 +1415,16 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/@typescript-eslint/parser": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", @@ -1805,6 +1809,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -1814,6 +1819,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -1852,6 +1858,15 @@ "node": ">=12" } }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1946,24 +1961,11 @@ "node": ">= 16" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -1976,6 +1978,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, "license": "MIT" }, "node_modules/concat-map": { @@ -2072,6 +2075,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, "license": "MIT" }, "node_modules/es-module-lexer": { @@ -2120,15 +2124,6 @@ "@esbuild/win32-x64": "0.21.5" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -2241,6 +2236,16 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2510,15 +2515,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -2615,6 +2611,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globby/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -2640,10 +2646,9 @@ "license": "MIT" }, "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "license": "MIT", "engines": { "node": ">= 4" @@ -2709,6 +2714,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -2981,6 +2987,21 @@ "node": ">=8.6" } }, + "node_modules/mime": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.1.0.tgz", + "integrity": "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==", + "funding": [ + "https://github.com/sponsors/broofa" + ], + "license": "MIT", + "bin": { + "mime": "bin/cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/minimatch": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", @@ -3050,6 +3071,15 @@ "dev": true, "license": "MIT" }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3110,30 +3140,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", - "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-throttle": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/p-throttle/-/p-throttle-7.0.0.tgz", - "integrity": "sha512-aio0v+S0QVkH1O+9x4dHtD4dgCExACcL+3EtNaGqC01GBudS9ijMuUsmN8OVScyV4OOp0jqdLShZFuSlbL/AsA==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -3248,6 +3254,43 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pino": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.14.0.tgz", + "integrity": "sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -3287,6 +3330,22 @@ "node": ">= 0.8.0" } }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -3318,13 +3377,19 @@ ], "license": "MIT" }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 12.13.0" } }, "node_modules/resolve-from": { @@ -3434,6 +3499,15 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/semver": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", @@ -3515,6 +3589,15 @@ "node": ">=8" } }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -3525,6 +3608,15 @@ "node": ">=0.10.0" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -3543,6 +3635,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -3573,6 +3666,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3681,6 +3775,15 @@ "dev": true, "license": "MIT" }, + "node_modules/thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -3810,12 +3913,6 @@ "typescript": ">=4.2.0" } }, - "node_modules/ts-retry": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ts-retry/-/ts-retry-6.0.0.tgz", - "integrity": "sha512-WsVRE/P+VNYbiQC3E6TeIXBRCQj7vzjN4MlXd84AC88K7WwuWShN7A3Q/QSV/yd1hjO8qn2Cevdqny2HMwKUaA==", - "license": "MIT" - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -3880,6 +3977,7 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -4067,23 +4165,6 @@ "node": ">=0.10.0" } }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", @@ -4110,42 +4191,6 @@ "dev": true, "license": "ISC" }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -4158,26 +4203,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/zod": { - "version": "3.24.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz", - "integrity": "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==", - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.1.tgz", - "integrity": "sha512-3h08nf3Vw3Wl3PK+q3ow/lIil81IT2Oa7YpQyUUDsEWbXveMesdfK1xBd2RhCkynwZndAxixji/7SYJJowr62w==", - "dev": true, - "license": "ISC", - "peerDependencies": { - "zod": "^3.24.1" - } } } } diff --git a/packages/acl/package.json b/packages/acl/package.json index e8debd0b..233c6fec 100644 --- a/packages/acl/package.json +++ b/packages/acl/package.json @@ -1,6 +1,6 @@ { "name": "@polymech/acl", - "version": "0.1.5", + "version": "0.2.0", "type": "module", "publishConfig": { "access": "public" @@ -20,23 +20,15 @@ }, "scripts": { "build": "tsc", - "start": "node dist/index.js", "dev": "tsc -p . --watch", + "test:core": "vitest run src/acl.test.ts", "lint": "eslint src --ext .ts" }, "dependencies": { - "@polymech/cache": "file:../cache", - "@polymech/commons": "file:../commons", - "@polymech/core": "file:../core", - "@polymech/fs": "file:../fs", - "@polymech/log": "file:../log", - "p-map": "7.0.3", - "p-throttle": "7.0.0", - "ts-retry": "6.0.0", - "yargs": "17.7.2", - "zod": "3.24.3" + "ignore": "^7.0.5", + "mime": "^4.1.0", + "pino": "^9.6.0" }, - "keywords": [], "devDependencies": { "@repo/typescript-config": "file:../typescript-config", "@types/node": "22.10.2", @@ -45,6 +37,6 @@ "@vitest/coverage-v8": "^2.1.8", "@vitest/ui": "2.1.9", "typescript": "^5.7.2", - "zod-to-json-schema": "3.24.1" + "vitest": "^2.1.8" } -} \ No newline at end of file +} diff --git a/packages/acl/src/ACLC.ts b/packages/acl/src/ACLC.ts deleted file mode 100644 index b33d1bb9..00000000 --- a/packages/acl/src/ACLC.ts +++ /dev/null @@ -1,745 +0,0 @@ -/* - ACL System inspired on Zend_ACL. - All functions accept strings, objects or arrays unless specified otherwise. - - '*' is used to express 'all' - - Database structure in Redis (using default prefix 'acl') - - Users: - - acl_roles_{userid} = set(roles) - - Roles: - - acl_roles = {roleNames} // Used to remove all the permissions associated to ONE resource. - - acl_parents_{roleName} = set(parents) - acl_resources_{roleName} = set(resourceNames) - - Permissions: - acl_allows_{resourceName}_{roleName} = set(permissions) - Note: user ids, role names and resource names are all case sensitive. - - Roadmap: - - Add support for locking resources. If a user has roles that gives him permissions to lock - a resource, then he can get exclusive write operation on the locked resource. - This lock should expire if the resource has not been accessed in some time. -*/ -import * as _ from 'lodash'; -import * as bluebird from 'bluebird'; -import { contract } from './contract'; -import { ILogger, IAcl, IBucketsOption, IBackend, Action } from './interfaces'; -import { Value, Values, strings, Callback, AnyCallback, AllowedCallback } from './interfaces'; -contract.debug = true; - -function makeArray(arr: any | Object): Array { - return Array.isArray(arr) ? arr : [arr]; -} - -function allowsBucket(role: string): string { - return 'allows_' + role; -} - -function keyFromAllowsBucket(str: string): string { - return str.replace(/^allows_/, ''); -} - -export class ACL implements IAcl { - logger: any; - backend: any; - options: any; - constructor(backend: IBackend, logger: ILogger | any, options?: any) { - const buckets: IBucketsOption = { - meta: 'meta', - parents: 'parents', - permissions: 'permissions', - resources: 'resources', - roles: 'roles', - users: 'users' - }; - - options = _.extend({ - buckets: buckets - }, options); - - this.logger = logger; - this.backend = backend; - this.options = options; - } - - public allow(roles: Values, resources: strings, permissions: strings, cb?: Callback): Promise { - contract(arguments) - .params('string|array', 'string|array', 'string|array', 'function') - .params('string|array', 'string|array', 'string|array') - .params('array', 'function') - .params('array') - .end(); - - if ((arguments.length === 1) || ((arguments.length === 2) && _.isObject(roles) && _.isFunction(resources))) { - return this._allowEx(roles).nodeify(resources); - } else { - let _this = this; - roles = makeArray(roles); - resources = makeArray(resources); - let backend = _this.backend; - let transaction = _this.backend.begin(); - backend.add(transaction, _this.options.buckets.meta, 'roles', roles); - resources.forEach(function (resource) { - _.each(roles, (role) => { - backend.add(transaction, allowsBucket(resource), role, permissions); - }); - }); - roles.forEach(function (role) { - _this.backend.add(transaction, _this.options.buckets.resources, role, resources); - }); - return backend.endAsync(transaction).nodeify(cb); - } - } - /* addUserRoles( userId, roles, function(err) ) - * Adds roles to a given user id. - @param {String|Number} User id. - @param {String|Array} Role(s) to add to the user id. - @param {Function} Callback called when finished. - @return {Promise} Promise resolved when finished - */ - public addUserRoles(userId: Value, roles: strings, cb?: Callback): Promise { - contract(arguments) - .params('string|number', 'string|array', 'function') - .params('string|number', 'string|array') - .end(); - - let transaction = this.backend.begin(); - this.backend.add(transaction, this.options.buckets.meta, 'users', userId); - this.backend.add(transaction, this.options.buckets.users, userId, roles); - - if (Array.isArray(roles)) { - let _this = this; - - roles.forEach(function (role) { - _this.backend.add(transaction, _this.options.buckets.roles, role, userId); - }); - } - else { - this.backend.add(transaction, this.options.buckets.roles, roles, userId); - } - - return this.backend.endAsync(transaction).nodeify(cb); - } - /* - removeUserRoles( userId, roles, function(err) ) - Remove roles from a given user. - @param {String|Number} User id. - @param {String|Array} Role(s) to remove to the user id. - @param {Function} Callback called when finished. - @return {Promise} Promise resolved when finished - */ - public removeUserRoles(userId: Value, roles: strings, cb?: Callback): Promise { - contract(arguments) - .params('string|number', 'string|array', 'function') - .params('string|number', 'string|array') - .end(); - - let transaction = this.backend.begin(); - this.backend.remove(transaction, this.options.buckets.users, userId, roles); - - if (Array.isArray(roles)) { - let _this = this; - - roles.forEach(function (role) { - _this.backend.remove(transaction, _this.options.buckets.roles, role, userId); - }); - } - else { - this.backend.remove(transaction, this.options.buckets.roles, roles, userId); - } - - return this.backend.endAsync(transaction).nodeify(cb); - } - /* - userRoles( userId, function(err, roles) ) - Return all the roles from a given user. - - @param {String|Number} User id. - @param {Function} Callback called when finished. - @return {Promise} Promise resolved with an array of user roles - */ - public userRoles(userId: Value, cb?: (err: Error, roles: string[]) => any): bluebird { - return this.backend.getAsync(this.options.buckets.users, userId).nodeify(cb); - } - /* - roleUsers( roleName, function(err, users) ) - Return all users who has a given role. - @param {String|Number} rolename. - @param {Function} Callback called when finished. - @return {Promise} Promise resolved with an array of users - */ - public roleUsers(role: Value, cb?: (err: Error, users: Values) => any): Promise { - return this.backend.getAsync(this.options.buckets.roles, role).nodeify(cb); - } - /* - hasRole( userId, rolename, function(err, is_in_role) ) - Return boolean whether user is in the role - @param {String|Number} User id. - @param {String|Number} rolename. - @param {Function} Callback called when finished. - @return {Promise} Promise resolved with boolean of whether user is in role - */ - public hasRole(userId: Value, role: string, cb?: (err: Error, isInRole: boolean) => any): bluebird { - return this.userRoles(userId).then(function (roles) { - return roles.indexOf(role) !== -1; - }).nodeify(cb); - } - - /* - addRoleParents( role, parents, function(err) ) - Adds a parent or parent list to role. - @param {String} Child role. - @param {String|Array} Parent role(s) to be added. - @param {Function} Callback called when finished. - @return {Promise} Promise resolved when finished - */ - public addRoleParents(role: string, parents: Values, cb?: Callback): Promise { - contract(arguments) - .params('string|number', 'string|array', 'function') - .params('string|number', 'string|array') - .end(); - - let transaction = this.backend.begin(); - this.backend.add(transaction, this.options.buckets.meta, 'roles', role); - this.backend.add(transaction, this.options.buckets.parents, role, parents); - return this.backend.endAsync(transaction).nodeify(cb); - }; - - /* - removeRoleParents( role, parents, function(err) ) - - Removes a parent or parent list from role. - - If `parents` is not specified, removes all parents. - - @param {String} Child role. - @param {String|Array} Parent role(s) to be removed [optional]. - @param {Function} Callback called when finished [optional]. - @return {Promise} Promise resolved when finished. - */ - public removeRoleParents(role: any, parents: Function, cb: Function) { - contract(arguments) - .params('string', 'string|array', 'function') - .params('string', 'string|array') - .params('string', 'function') - .params('string') - .end(); - - if (!cb && _.isFunction(parents)) { - cb = parents; - parents = null; - } - - let transaction = this.backend.begin(); - if (parents) { - this.backend.remove(transaction, this.options.buckets.parents, role, parents); - } else { - this.backend.del(transaction, this.options.buckets.parents, role); - } - return this.backend.endAsync(transaction).nodeify(cb); - } - /* - removeRole( role, function(err) ) - - Removes a role from the system. - - @param {String} Role to be removed - @param {Function} Callback called when finished. - */ - public removeRole(role: string, cb?: Callback): Promise { - contract(arguments) - .params('string', 'function') - .params('string').end(); - - let _this = this; - // Note that this is not fully transactional. - return this.backend.getAsync(this.options.buckets.resources, role).then((resources) => { - let transaction = _this.backend.begin(); - resources.forEach((resource) => { - let bucket = allowsBucket(resource); - _this.backend.del(transaction, bucket, role); - }); - _this.backend.del(transaction, _this.options.buckets.resources, role); - _this.backend.del(transaction, _this.options.buckets.parents, role); - _this.backend.del(transaction, _this.options.buckets.roles, role); - _this.backend.remove(transaction, _this.options.buckets.meta, 'roles', role); - - // `users` collection keeps the removed role - // because we don't know what users have `role` assigned. - return _this.backend.endAsync(transaction); - }).nodeify(cb); - }; - /* - removeResource( resource, function(err) ) - Removes a resource from the system - @param {String} Resource to be removed - @param {Function} Callback called when finished. - @return {Promise} Promise resolved when finished - */ - public removeResource(resource: string, cb?: Callback): Promise { - contract(arguments) - .params('string', 'function') - .params('string') - .end(); - - let _this = this; - return this.backend.getAsync(this.options.buckets.meta, 'roles').then(function (roles: Array) { - let transaction = _this.backend.begin(); - _this.backend.del(transaction, allowsBucket(resource), roles); - roles.forEach((role) => { - _this.backend.remove(transaction, _this.options.buckets.resources, role, resource); - }); - return _this.backend.endAsync(transaction); - }).nodeify(cb); - } - /* - allow( roles, resources, permissions, function(err) ) - Adds the given permissions to the given roles over the given resources. - - @param {String|Array} role(s) to add permissions to. - @param {String|Array} resource(s) to add permisisons to. - @param {String|Array} permission(s) to add to the roles over the resources. - @param {Function} Callback called when finished. - - allow( permissionsArray, function(err) ) - - @param {Array} Array with objects expressing what permissions to give. - - [{roles:{String|Array}, allows:[{resources:{String|Array}, permissions:{String|Array}]] - - @param {Function} Callback called when finished. - @return {Promise} Promise resolved when finished - */ - public removeAllow(role: string, resources: strings, permissions: strings, cb?: Callback): Promise { - contract(arguments) - .params('string', 'string|array', 'string|array', 'function') - .params('string', 'string|array', 'string|array') - .params('string', 'string|array', 'function') - .params('string', 'string|array') - .end(); - - resources = makeArray(resources); - if (cb || (permissions && !_.isFunction(permissions))) { - permissions = makeArray(permissions); - } else { - cb = (permissions as any); - permissions = null; - } - - return this.removePermissions(role, resources, permissions, cb); - }; - /* - removePermissions( role, resources, permissions) - Remove permissions from the given roles owned by the given role. - Note: we loose atomicity when removing empty role_resources. - @param {String} - @param {String|Array} - @param {String|Array} - */ - public removePermissions(role: string, resources: strings, permissions: strings, cb?: Function): Promise { - let _this = this; - let transaction = _this.backend.begin(); - _.each(resources, resource => { - let bucket = allowsBucket(resource); - if (permissions) { - _this.backend.remove(transaction, bucket, role, permissions); - } else { - _this.backend.del(transaction, bucket, role); - _this.backend.remove(transaction, _this.options.buckets.resources, role, resource); - } - }); - - // Remove resource from role if no rights for that role exists. - // Not fully atomic... - return _this.backend.endAsync(transaction).then(function () { - let transaction = _this.backend.begin(); - return bluebird.all(_.map(resources, resource => { - let bucket = allowsBucket(resource); - return _this.backend.getAsync(bucket, role).then(function (permissions) { - if (permissions.length === 0) { - _this.backend.remove(transaction, _this.options.buckets.resources, role, resource); - } - }); - })).then(function () { - return _this.backend.endAsync(transaction); - }); - }).nodeify(cb); - }; - /* - allowedPermissions( userId, resources, function(err, obj) ) - Returns all the allowable permissions a given user have to - access the given resources. - It returns an array of objects where every object maps a - resource name to a list of permissions for that resource. - - @param {String|Number} User id. - @param {String|Array} resource(s) to ask permissions for. - @param {Function} Callback called when finished. - */ - public allowedPermissions(userId: Value, resources: strings, cb?: AnyCallback): bluebird { - if (!userId) { - return cb(null, {}); - } - - contract(arguments) - .params('string|number', 'string|array', 'function') - .params('string|number', 'string|array') - .end(); - - if (this.backend.unionsAsync) { - return this.optimizedAllowedPermissions(userId, resources, cb); - } - - let _this = this; - resources = makeArray(resources); - return this.userRoles(userId).then(roles => { - let result = {}; - - return bluebird.all(_.map(resources, resource => { - return _this._resourcePermissions(roles, resource).then(function (permissions) { - result[resource] = permissions; - }); - })).then(function () { - return result; - }); - - }).nodeify(cb); - } - /* - optimizedAllowedPermissions( userId, resources, function(err, obj) ) - - Returns all the allowable permissions a given user have to - access the given resources. - - It returns a map of resource name to a list of permissions for that resource. - - This is the same as allowedPermissions, it just takes advantage of the unions - function if available to reduce the number of backend queries. - - @param {String|Number} User id. - @param {String|Array} resource(s) to ask permissions for. - @param {Function} Callback called when finished. - */ - public optimizedAllowedPermissions(userId, resources, cb) { - if (!userId) { - return cb(null, {}); - } - - contract(arguments) - .params('string|number', 'string|array', 'function|undefined') - .params('string|number', 'string|array') - .end(); - - resources = makeArray(resources); - let self = this; - - return this._allUserRoles(userId).then(function (roles) { - let buckets = resources.map(allowsBucket); - if (roles.length === 0) { - let emptyResult = {}; - buckets.forEach(function (bucket) { - emptyResult[bucket] = []; - }); - return bluebird.resolve(emptyResult); - } - - return self.backend.unionsAsync(buckets, roles); - }).then(function (response) { - let result = {}; - Object.keys(response).forEach(function (bucket) { - result[keyFromAllowsBucket(bucket)] = response[bucket]; - }); - - return result; - }).nodeify(cb); - } - /* - isAllowed( userId, resource, permissions, function(err, allowed) ) - - Checks if the given user is allowed to access the resource for the given - permissions (note: it must fulfill all the permissions). - - @param {String|Number} User id. - @param {String|Array} resource(s) to ask permissions for. - @param {String|Array} asked permissions. - @param {Function} Callback called wish the result. - */ - public isAllowed(userId: Value, resource: strings, permissions: strings, cb?: AllowedCallback): Promise { - contract(arguments) - .params('string|number', 'string', 'string|array', 'function') - .params('string|number', 'string', 'string|array') - .end(); - - let _this = this; - return this.backend.getAsync(this.options.buckets.users, userId).then(function (roles) { - if (roles.length) { - return _this.areAnyRolesAllowed(roles, resource, permissions); - } else { - return false; - } - }).nodeify(cb); - } - - /* - areAnyRolesAllowed( roles, resource, permissions, function(err, allowed) ) - - Returns true if any of the given roles have the right permissions. - - @param {String|Array} Role(s) to check the permissions for. - @param {String} resource(s) to ask permissions for. - @param {String|Array} asked permissions. - @param {Function} Callback called with the result. - */ - public areAnyRolesAllowed(roles: strings, resource: strings, permissions: strings, cb?: AllowedCallback): Promise { - contract(arguments) - .params('string|array', 'string', 'string|array', 'function') - .params('string|array', 'string', 'string|array') - .end(); - - roles = makeArray(roles); - permissions = makeArray(permissions); - - if (roles.length === 0) { - return (bluebird as any).resolve(false).nodeify(cb); - } else { - return this._checkPermissions(roles, resource, permissions).nodeify(cb); - } - } - /* - whatResources(role, function(err, {resourceName: [permissions]}) - - Returns what resources a given role or roles have permissions over. - - whatResources(role, permissions, function(err, resources) ) - - Returns what resources a role has the given permissions over. - - @param {String|Array} Roles - @param {String[Array} Permissions - @param {Function} Callback called wish the result. - */ - public whatResources(roles: strings, permissions: strings, cb?: AnyCallback): Promise { - contract(arguments) - .params('string|array') - .params('string|array', 'string|array') - .params('string|array', 'function') - .params('string|array', 'string|array', 'function') - .end(); - - roles = makeArray(roles); - if (_.isFunction(permissions)) { - cb = (permissions); - permissions = undefined; - } else if (permissions) { - permissions = makeArray(permissions); - } - - return this.permittedResources(roles, permissions, cb); - } - - public permittedResources(roles: strings, permissions: strings, cb?: Function): Promise { - let _this = this; - let result: any = _.isUndefined(permissions) ? {} : []; - return this._rolesResources(roles).then(function (resources) { - return bluebird.all(resources.map(function (resource) { - return _this._resourcePermissions(roles, resource).then(function (p) { - if (permissions) { - let commonPermissions = _.intersection(permissions, p); - if (commonPermissions.length > 0) { - result.push(resource); - } - } else { - result[resource] = p; - } - }); - })).then(function () { - return result; - }); - }).nodeify(cb); - } - - // ----------------------------------------------------------------------------- - // - // Private methods - // - // ----------------------------------------------------------------------------- - - // - // Same as allow but accepts a more compact input. - // - private _allowEx(objs): any { - let _this = this; - objs = makeArray(objs); - - let demuxed = []; - objs.forEach(function (obj) { - let roles = obj.roles; - obj.allows.forEach(function (allow) { - demuxed.push({ - roles: roles, - resources: allow.resources, - permissions: allow.permissions - }); - }); - }); - - return bluebird.reduce(demuxed, function (values, obj) { - const roles: Values = obj.roles; - const resources: strings = obj.resources; - const permissions: strings = obj.permissions; - return _this.allow(roles, resources, permissions, null); - }, null); - } - - // - // Returns the parents of the given roles - // - private _rolesParents(roles) { - return this.backend.unionAsync(this.options.buckets.parents, roles); - } - // - // Return all roles in the hierarchy including the given roles. - // - /* - Acl.prototype._allRoles = function(roleNames, cb){ - var _this = this, roles; - - _this._rolesParents(roleNames, function(err, parents){ - roles = _.union(roleNames, parents); - async.whilst( - function (){ - return parents.length >0; - }, - function (cb) { - _this._rolesParents(parents, function(err, result){ - if(!err){ - roles = _.union(roles, parents); - parents = result; - } - cb(err); - }); - }, - function(err){ - cb(err, roles); - } - ); - }); - }; - */ - // - // Return all roles in the hierarchy including the given roles. - // - private _allRoles(roleNames) { - let _this = this; - - return this._rolesParents(roleNames).then(function (parents) { - if (parents.length > 0) { - return _this._allRoles(parents).then(function (parentRoles) { - return _.union(roleNames, parentRoles); - }); - } else { - return roleNames; - } - }); - } - - // - // Return all roles in the hierarchy of the given user. - // - private _allUserRoles(userId) { - let _this = this; - - return this.userRoles(userId).then(function (roles) { - if (roles && roles.length > 0) { - return _this._allRoles(roles); - } else { - return []; - } - }); - } - - // - // Returns an array with resources for the given roles. - // - private _rolesResources(roles) { - let _this = this; - roles = makeArray(roles); - - return this._allRoles(roles).then(function (allRoles) { - let result = []; - - // check if bluebird.map simplifies this code - return bluebird.all(allRoles.map(function (role) { - return _this.backend.getAsync(_this.options.buckets.resources, role).then(function (resources) { - result = result.concat(resources); - }); - })).then(function () { - return result; - }); - }); - } - - // - // Returns the permissions for the given resource and set of roles - // - private _resourcePermissions(roles, resource): any { - let _this = this; - - if (roles.length === 0) { - return bluebird.resolve([]); - } else { - return this.backend.unionAsync(allowsBucket(resource), roles).then(function (resourcePermissions) { - return _this._rolesParents(roles).then(function (parents) { - if (parents && parents.length) { - return _this._resourcePermissions(parents, resource).then(function (morePermissions) { - return _.union(resourcePermissions, morePermissions); - }); - } else { - return resourcePermissions; - } - }); - }); - } - } - - // - // NOTE: This function will not handle circular dependencies and result in a crash. - // - private _checkPermissions(roles, resource, permissions): any { - let _this = this; - return this.backend.unionAsync(allowsBucket(resource), roles).then(function (resourcePermissions) { - if (resourcePermissions.indexOf('*') !== -1) { - return true; - } else { - permissions = permissions.filter(function (p) { - return resourcePermissions.indexOf(p) === -1; - }); - - if (permissions.length === 0) { - return true; - } else { - return _this.backend.unionAsync(_this.options.buckets.parents, roles).then(function (parents) { - if (parents && parents.length) { - return _this._checkPermissions(parents, resource, permissions); - } else { - return false; - } - }); - } - } - }); - } - -}; - -// ----------------------------------------------------------------------------- -// -// Helpers -// -// ----------------------------------------------------------------------------- diff --git a/packages/acl/src/backend.ts b/packages/acl/src/backend.ts deleted file mode 100644 index daa53838..00000000 --- a/packages/acl/src/backend.ts +++ /dev/null @@ -1,87 +0,0 @@ -/* - Backend Interface. - - Implement this API for providing a backend for the acl module. -*/ - -import { contract } from './contract'; -import { IBucketsOption, Action, Value, Values, IBackend } from './interfaces'; - -export let Backend = { - /* - Begins a transaction. - */ - begin: function () { - // returns a transaction object - }, - - /* - Ends a transaction (and executes it) - */ - end: function (transaction, cb) { - contract(arguments).params('object', 'function').end(); - // Execute transaction - }, - - /* - Cleans the whole storage. - */ - clean: function (cb) { - contract(arguments).params('function').end(); - }, - - /* - Gets the contents at the bucket's key. - */ - get: function (bucket, key, cb) { - contract(arguments) - .params('string', 'string|number', 'function') - .end(); - }, - - /* - Gets the union of contents of the specified keys in each of the specified buckets and returns - a mapping of bucket to union. - */ - unions: function (bucket, keys, cb) { - contract(arguments) - .params('array', 'array', 'function') - .end(); - }, - - /* - Returns the union of the values in the given keys. - */ - union: function (bucket, keys, cb) { - contract(arguments) - .params('string', 'array', 'function') - .end(); - }, - - /* - Adds values to a given key inside a bucket. - */ - add: function (transaction, bucket, key, values) { - contract(arguments) - .params('object', 'string', 'string|number', 'string|array|number') - .end(); - }, - - /* - Delete the given key(s) at the bucket - */ - del: function (transaction, bucket, keys) { - contract(arguments) - .params('object', 'string', 'string|array') - .end(); - }, - - /* - Removes values from a given key inside a bucket. - */ - remove: function (transaction, bucket, key, values) { - contract(arguments) - .params('object', 'string', 'string|number', 'string|array|number') - .end(); - } -}; diff --git a/packages/acl/src/data/File.ts b/packages/acl/src/data/File.ts deleted file mode 100644 index ec0af771..00000000 --- a/packages/acl/src/data/File.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { IObjectLiteral } from '../../interfaces/index'; -import { IStoreIO } from '../../interfaces/Store'; -import { Memory } from './Memory'; -import * as fs from 'fs'; -import * as mkdirp from 'mkdirp'; -import * as _path from 'path'; -const writeFileAtomic = require('write-file-atomic'); -const permissionError = 'You don\'t have access to this file.'; -const defaultPathMode: number = parseInt('0700', 8); -const writeFileOptions: IObjectLiteral = { mode: parseInt('0600', 8) }; -export class File extends Memory implements IStoreIO { - configPath: string; - read(path?: string): any { - path = path || this.configPath; - try { - this._buckets = JSON.parse(fs.readFileSync(path, 'utf8')); - } catch (err) { - // create dir if it doesn't exist - if (err.code === 'ENOENT') { - mkdirp.sync(_path.dirname(path), defaultPathMode); - return {}; - } - // improve the message of permission errors - if (err.code === 'EACCES') { - err.message = err.message + '\n' + permissionError + '\n'; - } - // empty the file if it encounters invalid JSON - if (err.name === 'SyntaxError') { - writeFileAtomic.sync(path, '', writeFileOptions); - return {}; - } - throw err; - } - } - write(path?: string): any { - path = path || this.configPath; - const data = this.data(); - try { - // make sure the folder exists as it - // could have been deleted in the meantime - mkdirp.sync(_path.dirname(path), defaultPathMode); - writeFileAtomic.sync(path, JSON.stringify(data, null, 4), writeFileOptions); - } catch (err) { - // improve the message of permission errors - if (err.code === 'EACCES') { - err.message = err.message + '\n' + permissionError + '\n'; - } - throw err; - } - } -} diff --git a/packages/acl/src/data/Memory.ts b/packages/acl/src/data/Memory.ts deleted file mode 100644 index 3ee31f89..00000000 --- a/packages/acl/src/data/Memory.ts +++ /dev/null @@ -1,178 +0,0 @@ -/* - Memory Backend. - In-memory implementation of the storage. -*/ -import * as _ from 'lodash'; -import { contract } from '../contract'; -import { Action, IBackend, Value, Values } from '../interfaces'; -import { IObjectLiteral, List } from '../../interfaces/index'; -import * as bluebird from 'bluebird'; -function makeArray(arr) { - return Array.isArray(arr) ? arr : [arr]; -} -export class Memory implements IBackend { - endAsync = bluebird.promisify(this.end); - getAsync = bluebird.promisify(this.get); - cleanAsync = bluebird.promisify(this.clean); - unionAsync = bluebird.promisify(this.union); - unionsAsync = bluebird.promisify(this.unions); - _buckets: IObjectLiteral; - data() { - return this._buckets as Action[]; - } - constructor() { - this._buckets = {}; - } - /* - Begins a transaction. - */ - begin() { - // returns a transaction object(just an array of functions will do here.) - return []; - }; - - /* - Ends a transaction (and executes it) - */ - end(transaction: Action[], cb: Action) { - contract(arguments).params('array', 'function').end(); - // Execute transaction - for (let i = 0, len = transaction.length; i < len; i++) { - transaction[i](); - } - cb(); - } - /* - Cleans the whole storage. - */ - clean(cb: Action) { - contract(arguments).params('function').end(); - this._buckets = {}; - cb(); - } - /* - Gets the contents at the bucket's key. - */ - get(bucket: string, key: Value, cb: Action) { - contract(arguments) - .params('string', 'string|number', 'function') - .end(); - - if (this._buckets[bucket]) { - (cb as Function)(null, this._buckets[bucket][key] || []); - } else { - (cb as Function)(null, []); - } - } - /* - Gets the union of the keys in each of the specified buckets - */ - unions(buckets, keys, cb) { - contract(arguments) - .params('array', 'array', 'function') - .end(); - - const self = this; - let results = {}; - - buckets.forEach(function (bucket) { - if (self._buckets[bucket]) { - results[bucket] = _.uniq(_.flatten(_.values(_.pick(self._buckets[bucket], keys)))); - } else { - results[bucket] = []; - } - }); - cb(null, results); - } - /* - Returns the union of the values in the given keys. - */ - union(bucket: string, keys: Values[], cb: Action): void { - contract(arguments) - .params('string', 'array', 'function') - .end(); - - let match; - let re; - if (!this._buckets[bucket]) { - Object.keys(this._buckets).some(function (b) { - re = new RegExp("^" + b + "$"); - match = re.test(bucket); - if (match) { bucket = b; } - return match; - }); - } - - if (this._buckets[bucket]) { - const keyArrays = []; - for (let i = 0, len = keys.length; i < len; i++) { - if (this._buckets[bucket][keys[i] as Value]) { - keyArrays.push.apply(keyArrays, this._buckets[bucket][keys[i] as Value]); - } - } - (cb as Function)(undefined, _.union(keyArrays)); - } else { - (cb as Function)(undefined, []); - } - } - - /* - Adds values to a given key inside a bucket. - */ - add(transaction: Action[], bucket: string, key: Value, values: Values) { - contract(arguments) - .params('array', 'string', 'string|number', 'string|array|number') - .end(); - - const self = this; - values = makeArray(values); - - transaction.push(function () { - if (!self._buckets[bucket]) { - self._buckets[bucket] = {}; - } - if (!self._buckets[bucket][key]) { - self._buckets[bucket][key] = values; - } else { - self._buckets[bucket][key] = _.union(values as List, self._buckets[bucket][key]); - } - }); - } - - /* - Delete the given key(s) at the bucket - */ - del(transaction: Action[], bucket: string, keys: Values) { - contract(arguments) - .params('array', 'string', 'string|array') - .end(); - - const self = this; - keys = makeArray(keys); - transaction.push(function () { - if (self._buckets[bucket]) { - for (let i = 0, len = (keys as List).length; i < len; i++) { - delete self._buckets[bucket][keys[i]]; - } - } - }); - } - - /* - Removes values from a given key inside a bucket. - */ - remove(transaction: Action[], bucket: string, key: Value, values: Values) { - contract(arguments) - .params('array', 'string', 'string|number', 'string|array|number') - .end(); - - const self = this; - values = makeArray(values); - transaction.push(function () { - let old; - if (self._buckets[bucket] && (old = self._buckets[bucket][key])) { - self._buckets[bucket][key] = _.difference(old, values as List); - } - }); - } -} diff --git a/packages/acl/src/interfaces.ts b/packages/acl/src/interfaces.ts index 121bea25..a2b54a30 100644 --- a/packages/acl/src/interfaces.ts +++ b/packages/acl/src/interfaces.ts @@ -81,8 +81,7 @@ export interface IAcl { isAllowed(userId: Value, resource: string, permissions: Values): Promise; areAnyRolesAllowed(roles: Values, resource: string, permissions: Values): Promise; - whatResources(roles: Values): Promise>; - whatResources(roles: Values, permissions: Values): Promise; + whatResources(roles: Values, permissions?: Values): Promise | string[]>; } // --------------------------------------------------------------------------- diff --git a/packages/acl/tsconfig.json b/packages/acl/tsconfig.json index 0eba7cef..1d71ac13 100644 --- a/packages/acl/tsconfig.json +++ b/packages/acl/tsconfig.json @@ -4,11 +4,10 @@ "outDir": "./dist-in", "rootDir": "src", "baseUrl": ".", - "allowJs": true, - "esModuleInterop": true, "composite": false, - "importHelpers": false, "inlineSourceMap": true, + "strict": true, + "noUncheckedIndexedAccess": true, "paths": { "@/*": [ "src/*" @@ -16,14 +15,11 @@ } }, "include": [ - "src/**/*" + "src/**/*.ts" ], "exclude": [ "node_modules", "dist", "dist-in" - ], - "files": [ - "src/index.ts" ] } \ No newline at end of file