@spinajs/authz-fs 0.0.0-stage → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -2
- package/lib/cjs/access-config/acl-config.d.ts +23 -0
- package/lib/cjs/access-config/acl-config.d.ts.map +1 -0
- package/lib/cjs/access-config/acl-config.js +36 -0
- package/lib/cjs/access-config/acl-config.js.map +1 -0
- package/lib/cjs/access-config/index.d.ts +34 -0
- package/lib/cjs/access-config/index.d.ts.map +1 -0
- package/lib/cjs/access-config/index.js +89 -0
- package/lib/cjs/access-config/index.js.map +1 -0
- package/lib/cjs/access-config/schema.d.ts +31 -0
- package/lib/cjs/access-config/schema.d.ts.map +1 -0
- package/lib/cjs/access-config/schema.js +55 -0
- package/lib/cjs/access-config/schema.js.map +1 -0
- package/lib/cjs/acl/facade.d.ts +39 -0
- package/lib/cjs/acl/facade.d.ts.map +1 -0
- package/lib/cjs/acl/facade.js +73 -0
- package/lib/cjs/acl/facade.js.map +1 -0
- package/lib/cjs/acl/index.d.ts +6 -0
- package/lib/cjs/acl/index.d.ts.map +1 -0
- package/lib/cjs/acl/index.js +25 -0
- package/lib/cjs/acl/index.js.map +1 -0
- package/lib/cjs/acl/orm-store.d.ts +31 -0
- package/lib/cjs/acl/orm-store.d.ts.map +1 -0
- package/lib/cjs/acl/orm-store.js +199 -0
- package/lib/cjs/acl/orm-store.js.map +1 -0
- package/lib/cjs/acl/relation.d.ts +29 -0
- package/lib/cjs/acl/relation.d.ts.map +1 -0
- package/lib/cjs/acl/relation.js +60 -0
- package/lib/cjs/acl/relation.js.map +1 -0
- package/lib/cjs/acl/shared.d.ts +36 -0
- package/lib/cjs/acl/shared.d.ts.map +1 -0
- package/lib/cjs/acl/shared.js +91 -0
- package/lib/cjs/acl/shared.js.map +1 -0
- package/lib/cjs/acl/store.d.ts +43 -0
- package/lib/cjs/acl/store.d.ts.map +1 -0
- package/lib/cjs/acl/store.js +12 -0
- package/lib/cjs/acl/store.js.map +1 -0
- package/lib/cjs/adapter/index.d.ts +33 -0
- package/lib/cjs/adapter/index.d.ts.map +1 -0
- package/lib/cjs/adapter/index.js +76 -0
- package/lib/cjs/adapter/index.js.map +1 -0
- package/lib/cjs/checks.d.ts +5 -0
- package/lib/cjs/checks.d.ts.map +1 -0
- package/lib/cjs/checks.js +20 -0
- package/lib/cjs/checks.js.map +1 -0
- package/lib/cjs/http/from-fs-path.d.ts +15 -0
- package/lib/cjs/http/from-fs-path.d.ts.map +1 -0
- package/lib/cjs/http/from-fs-path.js +43 -0
- package/lib/cjs/http/from-fs-path.js.map +1 -0
- package/lib/cjs/http/index.d.ts +3 -0
- package/lib/cjs/http/index.d.ts.map +1 -0
- package/lib/cjs/http/index.js +19 -0
- package/lib/cjs/http/index.js.map +1 -0
- package/lib/cjs/http/upload.d.ts +29 -0
- package/lib/cjs/http/upload.d.ts.map +1 -0
- package/lib/cjs/http/upload.js +67 -0
- package/lib/cjs/http/upload.js.map +1 -0
- package/lib/cjs/index.d.ts +9 -0
- package/lib/cjs/index.d.ts.map +1 -0
- package/lib/cjs/index.js +25 -0
- package/lib/cjs/index.js.map +1 -0
- package/lib/cjs/middleware/decide.d.ts +32 -0
- package/lib/cjs/middleware/decide.d.ts.map +1 -0
- package/lib/cjs/middleware/decide.js +51 -0
- package/lib/cjs/middleware/decide.js.map +1 -0
- package/lib/cjs/middleware/index.d.ts +53 -0
- package/lib/cjs/middleware/index.d.ts.map +1 -0
- package/lib/cjs/middleware/index.js +236 -0
- package/lib/cjs/middleware/index.js.map +1 -0
- package/lib/cjs/middleware/owner.d.ts +10 -0
- package/lib/cjs/middleware/owner.d.ts.map +1 -0
- package/lib/cjs/middleware/owner.js +20 -0
- package/lib/cjs/middleware/owner.js.map +1 -0
- package/lib/cjs/middleware/signed-url.d.ts +22 -0
- package/lib/cjs/middleware/signed-url.d.ts.map +1 -0
- package/lib/cjs/middleware/signed-url.js +36 -0
- package/lib/cjs/middleware/signed-url.js.map +1 -0
- package/lib/cjs/migrations/AuthzFsAcl_2026_10_17_00_00_00.d.ts +8 -0
- package/lib/cjs/migrations/AuthzFsAcl_2026_10_17_00_00_00.d.ts.map +1 -0
- package/lib/cjs/migrations/AuthzFsAcl_2026_10_17_00_00_00.js +45 -0
- package/lib/cjs/migrations/AuthzFsAcl_2026_10_17_00_00_00.js.map +1 -0
- package/lib/cjs/migrations/index.d.ts +2 -0
- package/lib/cjs/migrations/index.d.ts.map +1 -0
- package/lib/cjs/migrations/index.js +18 -0
- package/lib/cjs/migrations/index.js.map +1 -0
- package/lib/cjs/package.json +1 -0
- package/lib/cjs/permissions/index.d.ts +3 -0
- package/lib/cjs/permissions/index.d.ts.map +1 -0
- package/lib/cjs/permissions/index.js +7 -0
- package/lib/cjs/permissions/index.js.map +1 -0
- package/lib/cjs/refs/index.d.ts +3 -0
- package/lib/cjs/refs/index.d.ts.map +1 -0
- package/lib/cjs/refs/index.js +21 -0
- package/lib/cjs/refs/index.js.map +1 -0
- package/lib/cjs/refs/refs.d.ts +34 -0
- package/lib/cjs/refs/refs.d.ts.map +1 -0
- package/lib/cjs/refs/refs.js +79 -0
- package/lib/cjs/refs/refs.js.map +1 -0
- package/lib/mjs/access-config/acl-config.d.ts +23 -0
- package/lib/mjs/access-config/acl-config.d.ts.map +1 -0
- package/lib/mjs/access-config/acl-config.js +32 -0
- package/lib/mjs/access-config/acl-config.js.map +1 -0
- package/lib/mjs/access-config/index.d.ts +34 -0
- package/lib/mjs/access-config/index.d.ts.map +1 -0
- package/lib/mjs/access-config/index.js +71 -0
- package/lib/mjs/access-config/index.js.map +1 -0
- package/lib/mjs/access-config/schema.d.ts +31 -0
- package/lib/mjs/access-config/schema.d.ts.map +1 -0
- package/lib/mjs/access-config/schema.js +52 -0
- package/lib/mjs/access-config/schema.js.map +1 -0
- package/lib/mjs/acl/facade.d.ts +39 -0
- package/lib/mjs/acl/facade.d.ts.map +1 -0
- package/lib/mjs/acl/facade.js +69 -0
- package/lib/mjs/acl/facade.js.map +1 -0
- package/lib/mjs/acl/index.d.ts +6 -0
- package/lib/mjs/acl/index.d.ts.map +1 -0
- package/lib/mjs/acl/index.js +6 -0
- package/lib/mjs/acl/index.js.map +1 -0
- package/lib/mjs/acl/orm-store.d.ts +31 -0
- package/lib/mjs/acl/orm-store.d.ts.map +1 -0
- package/lib/mjs/acl/orm-store.js +196 -0
- package/lib/mjs/acl/orm-store.js.map +1 -0
- package/lib/mjs/acl/relation.d.ts +29 -0
- package/lib/mjs/acl/relation.d.ts.map +1 -0
- package/lib/mjs/acl/relation.js +56 -0
- package/lib/mjs/acl/relation.js.map +1 -0
- package/lib/mjs/acl/shared.d.ts +36 -0
- package/lib/mjs/acl/shared.d.ts.map +1 -0
- package/lib/mjs/acl/shared.js +73 -0
- package/lib/mjs/acl/shared.js.map +1 -0
- package/lib/mjs/acl/store.d.ts +43 -0
- package/lib/mjs/acl/store.d.ts.map +1 -0
- package/lib/mjs/acl/store.js +8 -0
- package/lib/mjs/acl/store.js.map +1 -0
- package/lib/mjs/adapter/index.d.ts +33 -0
- package/lib/mjs/adapter/index.d.ts.map +1 -0
- package/lib/mjs/adapter/index.js +73 -0
- package/lib/mjs/adapter/index.js.map +1 -0
- package/lib/mjs/checks.d.ts +5 -0
- package/lib/mjs/checks.d.ts.map +1 -0
- package/lib/mjs/checks.js +16 -0
- package/lib/mjs/checks.js.map +1 -0
- package/lib/mjs/http/from-fs-path.d.ts +15 -0
- package/lib/mjs/http/from-fs-path.d.ts.map +1 -0
- package/lib/mjs/http/from-fs-path.js +40 -0
- package/lib/mjs/http/from-fs-path.js.map +1 -0
- package/lib/mjs/http/index.d.ts +3 -0
- package/lib/mjs/http/index.d.ts.map +1 -0
- package/lib/mjs/http/index.js +3 -0
- package/lib/mjs/http/index.js.map +1 -0
- package/lib/mjs/http/upload.d.ts +29 -0
- package/lib/mjs/http/upload.d.ts.map +1 -0
- package/lib/mjs/http/upload.js +64 -0
- package/lib/mjs/http/upload.js.map +1 -0
- package/lib/mjs/index.d.ts +9 -0
- package/lib/mjs/index.d.ts.map +1 -0
- package/lib/mjs/index.js +9 -0
- package/lib/mjs/index.js.map +1 -0
- package/lib/mjs/middleware/decide.d.ts +32 -0
- package/lib/mjs/middleware/decide.d.ts.map +1 -0
- package/lib/mjs/middleware/decide.js +42 -0
- package/lib/mjs/middleware/decide.js.map +1 -0
- package/lib/mjs/middleware/index.d.ts +53 -0
- package/lib/mjs/middleware/index.d.ts.map +1 -0
- package/lib/mjs/middleware/index.js +231 -0
- package/lib/mjs/middleware/index.js.map +1 -0
- package/lib/mjs/middleware/owner.d.ts +10 -0
- package/lib/mjs/middleware/owner.d.ts.map +1 -0
- package/lib/mjs/middleware/owner.js +16 -0
- package/lib/mjs/middleware/owner.js.map +1 -0
- package/lib/mjs/middleware/signed-url.d.ts +22 -0
- package/lib/mjs/middleware/signed-url.d.ts.map +1 -0
- package/lib/mjs/middleware/signed-url.js +31 -0
- package/lib/mjs/middleware/signed-url.js.map +1 -0
- package/lib/mjs/migrations/AuthzFsAcl_2026_10_17_00_00_00.d.ts +8 -0
- package/lib/mjs/migrations/AuthzFsAcl_2026_10_17_00_00_00.d.ts.map +1 -0
- package/lib/mjs/migrations/AuthzFsAcl_2026_10_17_00_00_00.js +42 -0
- package/lib/mjs/migrations/AuthzFsAcl_2026_10_17_00_00_00.js.map +1 -0
- package/lib/mjs/migrations/index.d.ts +2 -0
- package/lib/mjs/migrations/index.d.ts.map +1 -0
- package/lib/mjs/migrations/index.js +2 -0
- package/lib/mjs/migrations/index.js.map +1 -0
- package/lib/mjs/package.json +1 -0
- package/lib/mjs/permissions/index.d.ts +3 -0
- package/lib/mjs/permissions/index.d.ts.map +1 -0
- package/lib/mjs/permissions/index.js +4 -0
- package/lib/mjs/permissions/index.js.map +1 -0
- package/lib/mjs/refs/index.d.ts +3 -0
- package/lib/mjs/refs/index.d.ts.map +1 -0
- package/lib/mjs/refs/index.js +3 -0
- package/lib/mjs/refs/index.js.map +1 -0
- package/lib/mjs/refs/refs.d.ts +34 -0
- package/lib/mjs/refs/refs.d.ts.map +1 -0
- package/lib/mjs/refs/refs.js +71 -0
- package/lib/mjs/refs/refs.js.map +1 -0
- package/lib/tsconfig.cjs.tsbuildinfo +1 -0
- package/lib/tsconfig.mjs.tsbuildinfo +1 -0
- package/package.json +74 -4
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FS_RESOURCE_TYPES = void 0;
|
|
4
|
+
exports.fsRef = fsRef;
|
|
5
|
+
exports.parseFsRef = parseFsRef;
|
|
6
|
+
exports.fsRow = fsRow;
|
|
7
|
+
exports.fsRowOf = fsRowOf;
|
|
8
|
+
exports.fsAncestors = fsAncestors;
|
|
9
|
+
const authz_1 = require("@spinajs/authz");
|
|
10
|
+
const util_1 = require("@spinajs/util");
|
|
11
|
+
const fs_1 = require("@spinajs/fs");
|
|
12
|
+
const checks_js_1 = require("../checks.js");
|
|
13
|
+
exports.FS_RESOURCE_TYPES = Object.freeze(['fs', 'dir', 'file']);
|
|
14
|
+
// The first ':' of a file or dir id ends the fs name, so a name must not hold one.
|
|
15
|
+
const isFsName = (name) => typeof name === 'string' && name.length > 0 && !name.includes(':');
|
|
16
|
+
/** `{ type: 'fs', id: fsName }` for the root, else `{ type: kind, id: '<fsName>:<normalised path>' }`. */
|
|
17
|
+
function fsRef(fsName, path, kind) {
|
|
18
|
+
(0, checks_js_1.checkFsName)(fsName);
|
|
19
|
+
(0, util_1._check_arg)((0, util_1._one_of)(['file', 'dir']))(kind, 'kind');
|
|
20
|
+
const normalised = (0, fs_1.normalizeFsPath)(path);
|
|
21
|
+
return normalised === '' ? { type: 'fs', id: fsName } : { type: kind, id: `${fsName}:${normalised}` };
|
|
22
|
+
}
|
|
23
|
+
/** undefined for a ref that is not an fs ref, or whose id is not in the form fsRef builds. */
|
|
24
|
+
function parseFsRef(ref) {
|
|
25
|
+
if (!ref || typeof ref.id !== 'string') {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
if (ref.type === 'fs') {
|
|
29
|
+
return isFsName(ref.id) ? { fs: ref.id, path: '', type: 'fs' } : undefined;
|
|
30
|
+
}
|
|
31
|
+
if (ref.type !== 'file' && ref.type !== 'dir') {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
const at = ref.id.indexOf(':');
|
|
35
|
+
const fs = ref.id.slice(0, at);
|
|
36
|
+
const path = ref.id.slice(at + 1);
|
|
37
|
+
if (at <= 0 || path === '' || !isCanonical(path)) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
return { fs, path, type: ref.type };
|
|
41
|
+
}
|
|
42
|
+
/** The row of a ref fsRef builds; null for a ref parseFsRef refuses. */
|
|
43
|
+
function fsRow(ref) {
|
|
44
|
+
const parsed = parseFsRef(ref);
|
|
45
|
+
return parsed ? fsRowOf(parsed.fs, parsed.path, parsed.type) : null;
|
|
46
|
+
}
|
|
47
|
+
/** The row of an already normalised path, with no second normalisation; '' gives the fs row. */
|
|
48
|
+
function fsRowOf(fsName, normalised, type) {
|
|
49
|
+
return normalised === '' ? Object.freeze({ id: fsName, type: 'fs', fs: fsName, path: '' }) : Object.freeze({ id: `${fsName}:${normalised}`, type, fs: fsName, path: normalised });
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* `[self, parent dirs nearest first, fs, GLOBAL]`, null for a ref parseFsRef refuses. This does not know which
|
|
53
|
+
* filesystems exist: an fs name no provider has still gets a chain.
|
|
54
|
+
*/
|
|
55
|
+
function fsAncestors(ref) {
|
|
56
|
+
const parsed = parseFsRef(ref);
|
|
57
|
+
if (!parsed) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const chain = [];
|
|
61
|
+
if (parsed.type !== 'fs') {
|
|
62
|
+
chain.push({ type: parsed.type, id: `${parsed.fs}:${parsed.path}` });
|
|
63
|
+
const segments = parsed.path.split('/');
|
|
64
|
+
for (let n = segments.length - 1; n > 0; n--) {
|
|
65
|
+
chain.push({ type: 'dir', id: `${parsed.fs}:${segments.slice(0, n).join('/')}` });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
chain.push({ type: 'fs', id: parsed.fs }, authz_1.GLOBAL);
|
|
69
|
+
return chain;
|
|
70
|
+
}
|
|
71
|
+
function isCanonical(path) {
|
|
72
|
+
try {
|
|
73
|
+
return (0, fs_1.normalizeFsPath)(path) === path;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=refs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refs.js","sourceRoot":"","sources":["../../../src/refs/refs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { IContainer } from '@spinajs/di';
|
|
2
|
+
export declare const FS_ACL_CONNECTION_KEY = "authz.fsAcl.connection";
|
|
3
|
+
export declare const FS_ACL_DEFAULT_CONNECTION = "default";
|
|
4
|
+
/** The relation of the row owner stamping writes. */
|
|
5
|
+
export declare const FS_ACL_OWNER = "owner";
|
|
6
|
+
export declare const FS_ACL_DEFAULT_RELATIONS: readonly string[];
|
|
7
|
+
/** fs_acl.relation holds this many characters. */
|
|
8
|
+
export declare const FS_ACL_RELATION_MAX_LENGTH = 64;
|
|
9
|
+
/** `authz.fsAcl` (fs middleware design §2). */
|
|
10
|
+
export interface FsAclConfig {
|
|
11
|
+
/** ORM connection of OrmFileAclStore and of its migration. */
|
|
12
|
+
readonly connection: string;
|
|
13
|
+
/** The relations an ACL row may name; FsResourceAdapter serves a RelationResolver for each on fs, dir and file. */
|
|
14
|
+
readonly relations: readonly string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* `authz.fsAcl` of the Configuration in `container`, defaults filled; without a Configuration the defaults (the
|
|
18
|
+
* migration reads the connection before any is resolved). `owner` is always among the relations, first: owner
|
|
19
|
+
* stamping writes it whatever the config lists.
|
|
20
|
+
* @throws AuthzConfigError for a malformed value no schema checked
|
|
21
|
+
*/
|
|
22
|
+
export declare function fsAclConfig(container?: IContainer): FsAclConfig;
|
|
23
|
+
//# sourceMappingURL=acl-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acl-config.d.ts","sourceRoot":"","sources":["../../../src/access-config/acl-config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM9C,eAAO,MAAM,qBAAqB,2BAA2B,CAAC;AAC9D,eAAO,MAAM,yBAAyB,YAAY,CAAC;AACnD,qDAAqD;AACrD,eAAO,MAAM,YAAY,UAAU,CAAC;AACpC,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAAsD,CAAC;AAC7G,kDAAkD;AAClD,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C,+CAA+C;AAC/C,MAAM,WAAW,WAAW;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,mHAAmH;IACnH,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,SAAS,GAAE,UAA6B,GAAG,WAAW,CAUjF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AuthzConfigError } from '@spinajs/authz';
|
|
2
|
+
import { Configuration } from '@spinajs/configuration';
|
|
3
|
+
import { DI } from '@spinajs/di';
|
|
4
|
+
import { isStringArray } from '@spinajs/util';
|
|
5
|
+
import { show } from '../checks.js';
|
|
6
|
+
// Not under authz.fs: that section is keyed by filesystem name.
|
|
7
|
+
export const FS_ACL_CONNECTION_KEY = 'authz.fsAcl.connection';
|
|
8
|
+
export const FS_ACL_DEFAULT_CONNECTION = 'default';
|
|
9
|
+
/** The relation of the row owner stamping writes. */
|
|
10
|
+
export const FS_ACL_OWNER = 'owner';
|
|
11
|
+
export const FS_ACL_DEFAULT_RELATIONS = Object.freeze([FS_ACL_OWNER, 'editor', 'viewer']);
|
|
12
|
+
/** fs_acl.relation holds this many characters. */
|
|
13
|
+
export const FS_ACL_RELATION_MAX_LENGTH = 64;
|
|
14
|
+
/**
|
|
15
|
+
* `authz.fsAcl` of the Configuration in `container`, defaults filled; without a Configuration the defaults (the
|
|
16
|
+
* migration reads the connection before any is resolved). `owner` is always among the relations, first: owner
|
|
17
|
+
* stamping writes it whatever the config lists.
|
|
18
|
+
* @throws AuthzConfigError for a malformed value no schema checked
|
|
19
|
+
*/
|
|
20
|
+
export function fsAclConfig(container = DI.RootContainer) {
|
|
21
|
+
const configuration = container.get(Configuration);
|
|
22
|
+
const read = (key) => (configuration && typeof configuration.get === 'function' ? configuration.get(['authz', 'fsAcl', key]) : undefined);
|
|
23
|
+
const connection = read('connection') ?? FS_ACL_DEFAULT_CONNECTION;
|
|
24
|
+
if (typeof connection !== 'string' || connection === '')
|
|
25
|
+
throw new AuthzConfigError(`${FS_ACL_CONNECTION_KEY} must be a non-empty string, got ${show(connection)}`);
|
|
26
|
+
const relations = read('relations') ?? FS_ACL_DEFAULT_RELATIONS;
|
|
27
|
+
if (!isStringArray(relations, { nonEmpty: true }) || !relations.every((r) => r.length <= FS_ACL_RELATION_MAX_LENGTH)) {
|
|
28
|
+
throw new AuthzConfigError(`authz.fsAcl.relations must be a list of relation names of 1-${FS_ACL_RELATION_MAX_LENGTH} characters, got ${show(relations)}`);
|
|
29
|
+
}
|
|
30
|
+
return Object.freeze({ connection, relations: Object.freeze([...new Set([FS_ACL_OWNER, ...relations])]) });
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=acl-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acl-config.js","sourceRoot":"","sources":["../../../src/access-config/acl-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAEjC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC,gEAAgE;AAChE,MAAM,CAAC,MAAM,qBAAqB,GAAG,wBAAwB,CAAC;AAC9D,MAAM,CAAC,MAAM,yBAAyB,GAAG,SAAS,CAAC;AACnD,qDAAqD;AACrD,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AACpC,MAAM,CAAC,MAAM,wBAAwB,GAAsB,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC7G,kDAAkD;AAClD,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAC;AAU7C;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,SAAS,GAAe,EAAE,CAAC,aAAa;IAClE,MAAM,aAAa,GAAG,SAAS,CAAC,GAAG,CAAC,aAAa,CAA8B,CAAC;IAChF,MAAM,IAAI,GAAG,CAAC,GAAW,EAAW,EAAE,CAAC,CAAC,aAAa,IAAI,OAAO,aAAa,CAAC,GAAG,KAAK,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAU,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACpK,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,yBAAyB,CAAC;IACnE,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,EAAE;QAAE,MAAM,IAAI,gBAAgB,CAAC,GAAG,qBAAqB,oCAAoC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IACpK,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,wBAAwB,CAAC;IAChE,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,0BAA0B,CAAC,EAAE,CAAC;QACrH,MAAM,IAAI,gBAAgB,CAAC,+DAA+D,0BAA0B,oBAAoB,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC7J,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC7G,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { IContainer } from '@spinajs/di';
|
|
2
|
+
export * from './schema.js';
|
|
3
|
+
export * from './acl-config.js';
|
|
4
|
+
export type FsAccessMode = 'off' | 'audit' | 'enforce';
|
|
5
|
+
/** `authz.fs.<name>.signedUrl` (D9). */
|
|
6
|
+
export interface FsSignedUrlConfig {
|
|
7
|
+
/** Cap on every signed URL's lifetime. */
|
|
8
|
+
readonly maxTtlSeconds?: number;
|
|
9
|
+
/** Lifetime when the caller asks for no `until`; default 900 (the S3 signer's own default). */
|
|
10
|
+
readonly defaultTtlSeconds?: number;
|
|
11
|
+
}
|
|
12
|
+
/** `authz.fs.<name>` (fs middleware design §2). */
|
|
13
|
+
export interface FsAccessConfig {
|
|
14
|
+
readonly mode: FsAccessMode;
|
|
15
|
+
/** Authz domain the checks run in; default 'root'. Another domain must exist: authz-fs never creates one. */
|
|
16
|
+
readonly domain: string;
|
|
17
|
+
/** Record the first writer of a path an action creates as its `owner` ACL row. */
|
|
18
|
+
readonly stampOwner?: boolean;
|
|
19
|
+
readonly list?: 'dir' | 'each';
|
|
20
|
+
readonly signedUrl?: FsSignedUrlConfig;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* `authz.fs.<fsName>` of the Configuration resolved in `container`, read on every call. A filesystem without an
|
|
24
|
+
* entry is off.
|
|
25
|
+
*/
|
|
26
|
+
export declare function fsAccessConfig(fsName: string, container?: IContainer): FsAccessConfig;
|
|
27
|
+
/**
|
|
28
|
+
* One `authz.fs.<fsName>` entry; undefined is a missing entry (off). AUTHZ_FS_CONFIGURATION_SCHEMA checks the entry
|
|
29
|
+
* at boot; it may also come from a Configuration no schema checked, so every value is checked here too.
|
|
30
|
+
* @throws AuthzConfigError for a malformed value or an unknown key: a removed key such as `policies` must not be
|
|
31
|
+
* dropped silently, since a dropped deny policy would open files
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseFsAccessConfig(fsName: string, entry: unknown): FsAccessConfig;
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/access-config/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAEhC,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,OAAO,GAAG,SAAS,CAAC;AAEvD,wCAAwC;AACxC,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,+FAA+F;IAC/F,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,mDAAmD;AACnD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,6GAA6G;IAC7G,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kFAAkF;IAClF,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,iBAAiB,CAAC;CACxC;AAOD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,GAAE,UAA6B,GAAG,cAAc,CAGvG;AAcD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,cAAc,CAalF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { AuthzConfigError } from '@spinajs/authz';
|
|
2
|
+
import { Configuration } from '@spinajs/configuration';
|
|
3
|
+
import { DI } from '@spinajs/di';
|
|
4
|
+
import { isPlainObject } from '@spinajs/util';
|
|
5
|
+
import { show } from '../checks.js';
|
|
6
|
+
export * from './schema.js';
|
|
7
|
+
export * from './acl-config.js';
|
|
8
|
+
const MODES = ['off', 'audit', 'enforce'];
|
|
9
|
+
const KEYS = new Set(['mode', 'domain', 'stampOwner', 'list', 'signedUrl']);
|
|
10
|
+
const OFF = Object.freeze({ mode: 'off', domain: 'root' });
|
|
11
|
+
/**
|
|
12
|
+
* `authz.fs.<fsName>` of the Configuration resolved in `container`, read on every call. A filesystem without an
|
|
13
|
+
* entry is off.
|
|
14
|
+
*/
|
|
15
|
+
export function fsAccessConfig(fsName, container = DI.RootContainer) {
|
|
16
|
+
const all = fsSection(container);
|
|
17
|
+
return all ? parseFsAccessConfig(fsName, Object.hasOwn(all, fsName) ? all[fsName] : undefined) : OFF;
|
|
18
|
+
}
|
|
19
|
+
function fsSection(container) {
|
|
20
|
+
const configuration = container.get(Configuration);
|
|
21
|
+
if (!configuration || typeof configuration.get !== 'function') {
|
|
22
|
+
throw new AuthzConfigError('authz.fs: Configuration is not resolved; await DI.resolve(Configuration) first');
|
|
23
|
+
}
|
|
24
|
+
const all = configuration.get(['authz', 'fs']);
|
|
25
|
+
if (all === undefined || all === null)
|
|
26
|
+
return undefined;
|
|
27
|
+
// Fail-closed floor for a section no schema checked (Configuration.set, test configurations): it would read as every filesystem off.
|
|
28
|
+
if (!isPlainObject(all))
|
|
29
|
+
throw new AuthzConfigError(`authz.fs must be an object keyed by filesystem name, got ${show(all)}`);
|
|
30
|
+
return all;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* One `authz.fs.<fsName>` entry; undefined is a missing entry (off). AUTHZ_FS_CONFIGURATION_SCHEMA checks the entry
|
|
34
|
+
* at boot; it may also come from a Configuration no schema checked, so every value is checked here too.
|
|
35
|
+
* @throws AuthzConfigError for a malformed value or an unknown key: a removed key such as `policies` must not be
|
|
36
|
+
* dropped silently, since a dropped deny policy would open files
|
|
37
|
+
*/
|
|
38
|
+
export function parseFsAccessConfig(fsName, entry) {
|
|
39
|
+
if (entry === undefined)
|
|
40
|
+
return OFF;
|
|
41
|
+
const at = `authz.fs.${fsName}`;
|
|
42
|
+
const mode = isPlainObject(entry) ? entry.mode : undefined;
|
|
43
|
+
if (!MODES.includes(mode))
|
|
44
|
+
throw new AuthzConfigError(`${at}.mode must be one of ${MODES.join(', ')}, got ${show(isPlainObject(entry) ? mode : entry)}`);
|
|
45
|
+
const e = entry;
|
|
46
|
+
for (const key of Object.keys(e))
|
|
47
|
+
if (!KEYS.has(key))
|
|
48
|
+
throw new AuthzConfigError(`${at}.${key} is not an authz.fs option (${[...KEYS].join(', ')})`);
|
|
49
|
+
if (e.domain !== undefined && (typeof e.domain !== 'string' || e.domain === ''))
|
|
50
|
+
throw new AuthzConfigError(`${at}.domain must be a non-empty string, got ${show(e.domain)}`);
|
|
51
|
+
if (e.stampOwner !== undefined && typeof e.stampOwner !== 'boolean')
|
|
52
|
+
throw new AuthzConfigError(`${at}.stampOwner must be a boolean, got ${show(e.stampOwner)}`);
|
|
53
|
+
if (e.list !== undefined && e.list !== 'dir' && e.list !== 'each')
|
|
54
|
+
throw new AuthzConfigError(`${at}.list must be 'dir' or 'each', got ${show(e.list)}`);
|
|
55
|
+
const out = { ...e, domain: e.domain ?? 'root' };
|
|
56
|
+
if (e.signedUrl !== undefined)
|
|
57
|
+
out.signedUrl = signedUrlOf(e.signedUrl, `${at}.signedUrl`);
|
|
58
|
+
return Object.freeze(out);
|
|
59
|
+
}
|
|
60
|
+
function signedUrlOf(value, at) {
|
|
61
|
+
if (!isPlainObject(value))
|
|
62
|
+
throw new AuthzConfigError(`${at} must be an object, got ${show(value)}`);
|
|
63
|
+
for (const [key, ttl] of Object.entries(value)) {
|
|
64
|
+
if (key !== 'maxTtlSeconds' && key !== 'defaultTtlSeconds')
|
|
65
|
+
throw new AuthzConfigError(`${at}.${key} is not a signedUrl option`);
|
|
66
|
+
if (typeof ttl !== 'number' || !Number.isFinite(ttl) || ttl <= 0)
|
|
67
|
+
throw new AuthzConfigError(`${at}.${key} must be a positive finite number, got ${show(ttl)}`);
|
|
68
|
+
}
|
|
69
|
+
return Object.freeze({ ...value });
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/access-config/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Bootstrapper } from '@spinajs/di';
|
|
2
|
+
/** `authz.fs.<filesystem>`: one entry per filesystem name; a filesystem without one is off. */
|
|
3
|
+
export declare const AUTHZ_FS_CONFIGURATION_SCHEMA: {
|
|
4
|
+
$id: string;
|
|
5
|
+
$configurationModule: string;
|
|
6
|
+
description: string;
|
|
7
|
+
type: string;
|
|
8
|
+
additionalProperties: {
|
|
9
|
+
type: string;
|
|
10
|
+
properties: Record<string, unknown>;
|
|
11
|
+
propertyNames: {
|
|
12
|
+
enum: string[];
|
|
13
|
+
};
|
|
14
|
+
required?: string[] | undefined;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export declare const AUTHZ_FS_ACL_CONFIGURATION_SCHEMA: {
|
|
18
|
+
type: string;
|
|
19
|
+
properties: Record<string, unknown>;
|
|
20
|
+
propertyNames: {
|
|
21
|
+
enum: string[];
|
|
22
|
+
};
|
|
23
|
+
required?: string[] | undefined;
|
|
24
|
+
$id: string;
|
|
25
|
+
$configurationModule: string;
|
|
26
|
+
description: string;
|
|
27
|
+
};
|
|
28
|
+
export declare class AuthzFsConfigBootstrapper extends Bootstrapper {
|
|
29
|
+
bootstrap(): void;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/access-config/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAc,MAAM,aAAa,CAAC;AAqBvD,+FAA+F;AAC/F,eAAO,MAAM,6BAA6B;IACxC,GAAG;IACH,oBAAoB;IACpB,WAAW;IACX,IAAI;IACJ,oBAAoB;;;;YApBuG,IAAI;;;;CAqBhI,CAAC;AAEF,eAAO,MAAM,iCAAiC;;;;QAvB+E,IAAI;;;;;;CAgChI,CAAC;AAKF,qBACa,yBAA0B,SAAQ,YAAY;IAClD,SAAS,IAAI,IAAI,CAGvB;CACF"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { registerConfigurationSchema, registerConfigurationSchemaAtImport } from '@spinajs/configuration';
|
|
8
|
+
import { Bootstrapper, Injectable } from '@spinajs/di';
|
|
9
|
+
import { FS_ACL_DEFAULT_CONNECTION, FS_ACL_DEFAULT_RELATIONS, FS_ACL_RELATION_MAX_LENGTH } from './acl-config.js';
|
|
10
|
+
const name = { type: 'string', minLength: 1 };
|
|
11
|
+
// propertyNames refuses an unknown key; additionalProperties: false would let removeAdditional drop a typo silently.
|
|
12
|
+
const closed = (properties, required) => ({ type: 'object', properties, propertyNames: { enum: Object.keys(properties) }, ...(required ? { required } : {}) });
|
|
13
|
+
const entry = closed({
|
|
14
|
+
mode: { type: 'string', enum: ['off', 'audit', 'enforce'] },
|
|
15
|
+
domain: name,
|
|
16
|
+
stampOwner: { type: 'boolean' },
|
|
17
|
+
signedUrl: closed({ maxTtlSeconds: { type: 'number', exclusiveMinimum: 0 }, defaultTtlSeconds: { type: 'number', exclusiveMinimum: 0 } }),
|
|
18
|
+
list: { type: 'string', enum: ['dir', 'each'] },
|
|
19
|
+
},
|
|
20
|
+
// A present entry says its mode: an entry with other keys but no mode must not be silently off.
|
|
21
|
+
['mode']);
|
|
22
|
+
/** `authz.fs.<filesystem>`: one entry per filesystem name; a filesystem without one is off. */
|
|
23
|
+
export const AUTHZ_FS_CONFIGURATION_SCHEMA = {
|
|
24
|
+
$id: 'spinajs/authz-fs.configuration.schema.json',
|
|
25
|
+
$configurationModule: 'authz.fs',
|
|
26
|
+
description: 'Filesystem access configuration (authz.fs.<filesystem>)',
|
|
27
|
+
type: 'object',
|
|
28
|
+
additionalProperties: entry,
|
|
29
|
+
};
|
|
30
|
+
export const AUTHZ_FS_ACL_CONFIGURATION_SCHEMA = {
|
|
31
|
+
$id: 'spinajs/authz-fs-acl.configuration.schema.json',
|
|
32
|
+
// Not under authz.fs: that section is keyed by filesystem name.
|
|
33
|
+
$configurationModule: 'authz.fsAcl',
|
|
34
|
+
description: 'File ACL configuration (authz.fsAcl.*)',
|
|
35
|
+
...closed({
|
|
36
|
+
connection: { ...name, default: FS_ACL_DEFAULT_CONNECTION },
|
|
37
|
+
relations: { type: 'array', uniqueItems: true, items: { type: 'string', minLength: 1, maxLength: FS_ACL_RELATION_MAX_LENGTH }, default: [...FS_ACL_DEFAULT_RELATIONS] },
|
|
38
|
+
}),
|
|
39
|
+
};
|
|
40
|
+
registerConfigurationSchemaAtImport(AUTHZ_FS_CONFIGURATION_SCHEMA);
|
|
41
|
+
registerConfigurationSchemaAtImport(AUTHZ_FS_ACL_CONFIGURATION_SCHEMA);
|
|
42
|
+
let AuthzFsConfigBootstrapper = class AuthzFsConfigBootstrapper extends Bootstrapper {
|
|
43
|
+
bootstrap() {
|
|
44
|
+
registerConfigurationSchema(AUTHZ_FS_CONFIGURATION_SCHEMA);
|
|
45
|
+
registerConfigurationSchema(AUTHZ_FS_ACL_CONFIGURATION_SCHEMA);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
AuthzFsConfigBootstrapper = __decorate([
|
|
49
|
+
Injectable(Bootstrapper)
|
|
50
|
+
], AuthzFsConfigBootstrapper);
|
|
51
|
+
export { AuthzFsConfigBootstrapper };
|
|
52
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/access-config/schema.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,2BAA2B,EAAE,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;AAC1G,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAElH,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;AAE9C,qHAAqH;AACrH,MAAM,MAAM,GAAG,CAAC,UAAmC,EAAE,QAAmB,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAEnM,MAAM,KAAK,GAAG,MAAM,CAClB;IACE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE;IAC3D,MAAM,EAAE,IAAI;IACZ,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC/B,SAAS,EAAE,MAAM,CAAC,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,CAAC;IACzI,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE;CAChD;AACD,gGAAgG;AAChG,CAAC,MAAM,CAAC,CACT,CAAC;AAEF,+FAA+F;AAC/F,MAAM,CAAC,MAAM,6BAA6B,GAAG;IAC3C,GAAG,EAAE,4CAA4C;IACjD,oBAAoB,EAAE,UAAU;IAChC,WAAW,EAAE,yDAAyD;IACtE,IAAI,EAAE,QAAQ;IACd,oBAAoB,EAAE,KAAK;CAC5B,CAAC;AAEF,MAAM,CAAC,MAAM,iCAAiC,GAAG;IAC/C,GAAG,EAAE,gDAAgD;IACrD,gEAAgE;IAChE,oBAAoB,EAAE,aAAa;IACnC,WAAW,EAAE,wCAAwC;IACrD,GAAG,MAAM,CAAC;QACR,UAAU,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,yBAAyB,EAAE;QAC3D,SAAS,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,0BAA0B,EAAE,EAAE,OAAO,EAAE,CAAC,GAAG,wBAAwB,CAAC,EAAE;KACxK,CAAC;CACH,CAAC;AAEF,mCAAmC,CAAC,6BAA6B,CAAC,CAAC;AACnE,mCAAmC,CAAC,iCAAiC,CAAC,CAAC;AAGhE,IAAM,yBAAyB,GAA/B,MAAM,yBAA0B,SAAQ,YAAY;IAClD,SAAS;QACd,2BAA2B,CAAC,6BAA6B,CAAC,CAAC;QAC3D,2BAA2B,CAAC,iCAAiC,CAAC,CAAC;IACjE,CAAC;CACF,CAAA;AALY,yBAAyB;IADrC,UAAU,CAAC,YAAY,CAAC;GACZ,yBAAyB,CAKrC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { AssignmentSubject, Principal } from '@spinajs/authz';
|
|
2
|
+
import type { IContainer } from '@spinajs/di';
|
|
3
|
+
import type { FsDecideService, FsLog } from '../middleware/decide.js';
|
|
4
|
+
import type { FileAclStore, FsAclRow } from './store.js';
|
|
5
|
+
export interface FsAclOptions {
|
|
6
|
+
/** Where the Configuration, the published providers, AuthzService, AuthzDomains and the FileAclStore are resolved; default the root. */
|
|
7
|
+
readonly container?: IContainer;
|
|
8
|
+
/** The service that decides for a domain; default the root AuthzService, else `AuthzDomains.service(domain)`. */
|
|
9
|
+
readonly service?: (domain: string) => Promise<FsDecideService>;
|
|
10
|
+
/** Default: the ALS principal, else UNATTENDED. */
|
|
11
|
+
readonly principal?: () => Principal;
|
|
12
|
+
readonly log?: FsLog;
|
|
13
|
+
readonly store?: () => Promise<FileAclStore>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Changes the file ACL as the current principal. Every call asserts a definite
|
|
17
|
+
* `fs:manage` on both the file and the dir ref of the path (the fs ref for the root), whatever the filesystem's
|
|
18
|
+
* `authz.fs` mode; only SYSTEM is exempt. The checks run in the domain of `authz.fs.<fs>.domain`, 'root' without an
|
|
19
|
+
* entry. fs:manage lets the holder grant any configured relation, owner included. System code that needs unchecked
|
|
20
|
+
* writes uses the FileAclStore directly. A row granted on a path that does not exist yet is cleared as stale when
|
|
21
|
+
* that path is later created through the middleware.
|
|
22
|
+
*/
|
|
23
|
+
export declare class FsAcl {
|
|
24
|
+
protected readonly options: FsAclOptions;
|
|
25
|
+
private logger?;
|
|
26
|
+
constructor(options?: FsAclOptions);
|
|
27
|
+
grant(fs: string, path: string, subject: AssignmentSubject, relation: string, opts?: {
|
|
28
|
+
readonly expiresAt?: Date;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
revoke(fs: string, path: string, subject: AssignmentSubject, relation: string): Promise<void>;
|
|
31
|
+
list(fs: string, path: string): Promise<readonly FsAclRow[]>;
|
|
32
|
+
protected get container(): IContainer;
|
|
33
|
+
private get log();
|
|
34
|
+
private principal;
|
|
35
|
+
private store;
|
|
36
|
+
private known;
|
|
37
|
+
private authorize;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=facade.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facade.d.ts","sourceRoot":"","sources":["../../../src/acl/facade.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAItE,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC3B,wIAAwI;IACxI,QAAQ,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC;IAChC,iHAAiH;IACjH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAChE,mDAAmD;IACnD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,SAAS,CAAC;IACrC,QAAQ,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;CAC9C;AAED;;;;;;;GAOG;AACH,qBAAa,KAAK;IAGJ,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,YAAY;IAFpD,OAAO,CAAC,MAAM,CAAC,CAAQ;IAEvB,YAA+B,OAAO,GAAE,YAAiB,EAAI;IAEvD,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAK3I;IAEK,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKlG;IAEK,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,QAAQ,EAAE,CAAC,CAGjE;IAED,SAAS,KAAK,SAAS,IAAI,UAAU,CAEpC;IAED,OAAO,KAAK,GAAG,GAEd;IAED,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,KAAK;YAKC,SAAS;CAaxB"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { AuthzConfigError, SYSTEM, currentPrincipal, engineLog, principalKey } from '@spinajs/authz';
|
|
2
|
+
import { DI } from '@spinajs/di';
|
|
3
|
+
import { publishedFs } from '@spinajs/fs';
|
|
4
|
+
import { fsAccessConfig, fsAclConfig } from '../access-config/index.js';
|
|
5
|
+
import { decideFs, domainService, refOf } from '../middleware/decide.js';
|
|
6
|
+
import { fsRowOf, normalizeFsPath } from '../refs/index.js';
|
|
7
|
+
import { aclSubjectKey, fileAclStore } from './shared.js';
|
|
8
|
+
/**
|
|
9
|
+
* Changes the file ACL as the current principal. Every call asserts a definite
|
|
10
|
+
* `fs:manage` on both the file and the dir ref of the path (the fs ref for the root), whatever the filesystem's
|
|
11
|
+
* `authz.fs` mode; only SYSTEM is exempt. The checks run in the domain of `authz.fs.<fs>.domain`, 'root' without an
|
|
12
|
+
* entry. fs:manage lets the holder grant any configured relation, owner included. System code that needs unchecked
|
|
13
|
+
* writes uses the FileAclStore directly. A row granted on a path that does not exist yet is cleared as stale when
|
|
14
|
+
* that path is later created through the middleware.
|
|
15
|
+
*/
|
|
16
|
+
export class FsAcl {
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
this.options = options;
|
|
19
|
+
}
|
|
20
|
+
async grant(fs, path, subject, relation, opts = {}) {
|
|
21
|
+
this.known(relation);
|
|
22
|
+
const principal = this.principal();
|
|
23
|
+
const at = await this.authorize(fs, path, principal);
|
|
24
|
+
await (await this.store()).grant({ fs, path: at, subject, relation, grantedBy: principalKey(principal), ...(opts.expiresAt ? { expiresAt: opts.expiresAt } : {}) });
|
|
25
|
+
}
|
|
26
|
+
async revoke(fs, path, subject, relation) {
|
|
27
|
+
this.known(relation);
|
|
28
|
+
const key = aclSubjectKey(subject);
|
|
29
|
+
const at = await this.authorize(fs, path, this.principal());
|
|
30
|
+
await (await this.store()).revoke(fs, at, key, relation);
|
|
31
|
+
}
|
|
32
|
+
async list(fs, path) {
|
|
33
|
+
const at = await this.authorize(fs, path, this.principal());
|
|
34
|
+
return (await this.store()).list(fs, at);
|
|
35
|
+
}
|
|
36
|
+
get container() {
|
|
37
|
+
return this.options.container ?? DI.RootContainer;
|
|
38
|
+
}
|
|
39
|
+
get log() {
|
|
40
|
+
return (this.logger ??= this.options.log ?? engineLog('authz-fs'));
|
|
41
|
+
}
|
|
42
|
+
principal() {
|
|
43
|
+
return (this.options.principal ?? currentPrincipal)();
|
|
44
|
+
}
|
|
45
|
+
store() {
|
|
46
|
+
return this.options.store ? this.options.store() : fileAclStore(this.container);
|
|
47
|
+
}
|
|
48
|
+
known(relation) {
|
|
49
|
+
const { relations } = fsAclConfig(this.container);
|
|
50
|
+
if (!relations.includes(relation))
|
|
51
|
+
throw new AuthzConfigError(`FsAcl: relation ${JSON.stringify(relation)} is not in authz.fsAcl.relations (${relations.join(', ')})`);
|
|
52
|
+
}
|
|
53
|
+
async authorize(fs, path, principal) {
|
|
54
|
+
const provider = publishedFs(fs, this.container);
|
|
55
|
+
if (!provider)
|
|
56
|
+
throw new AuthzConfigError(`FsAcl: filesystem ${JSON.stringify(fs)} has no published provider`);
|
|
57
|
+
const normalised = normalizeFsPath(path, provider.BasePath);
|
|
58
|
+
if (principal === SYSTEM)
|
|
59
|
+
return normalised;
|
|
60
|
+
const { domain } = fsAccessConfig(fs, this.container);
|
|
61
|
+
const service = await (this.options.service ? this.options.service(domain) : domainService(this.container, domain));
|
|
62
|
+
const kinds = normalised === '' ? ['file'] : ['file', 'dir'];
|
|
63
|
+
for (const kind of kinds) {
|
|
64
|
+
await decideFs({ fsName: fs, mode: 'enforce', service, log: this.log, principal, permission: 'fs:manage', ref: refOf(fs, normalised, kind), subject: fsRowOf(fs, normalised, kind) });
|
|
65
|
+
}
|
|
66
|
+
return normalised;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=facade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facade.js","sourceRoot":"","sources":["../../../src/acl/facade.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/acl/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/acl/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { PrincipalRef } from '@spinajs/authz';
|
|
2
|
+
import type { IContainer } from '@spinajs/di';
|
|
3
|
+
import { FileAclStore } from './store.js';
|
|
4
|
+
import type { FsAclRow } from './store.js';
|
|
5
|
+
export interface OrmFileAclStoreOptions {
|
|
6
|
+
/** The ORM connection; default `authz.fsAcl.connection`, else 'default'. */
|
|
7
|
+
readonly connection?: string;
|
|
8
|
+
/** Where Configuration and Orm are resolved; default the DI root. */
|
|
9
|
+
readonly container?: IContainer;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* FileAclStore over `fs_acl` (migration AuthzFsAcl_2026_10_17_00_00_00). Reads are narrowed in SQL by `path_hash`
|
|
13
|
+
* (the indexed key) and decided by an exact comparison of `path` in code, and rows change by id, so a table created
|
|
14
|
+
* with a case-insensitive collation never merges two paths.
|
|
15
|
+
*/
|
|
16
|
+
export declare class OrmFileAclStore extends FileAclStore {
|
|
17
|
+
private readonly opts;
|
|
18
|
+
constructor(opts?: OrmFileAclStoreOptions);
|
|
19
|
+
holds(fs: string, paths: readonly string[], subjectKeys: readonly string[], relation: string, at: Date): Promise<boolean>;
|
|
20
|
+
list(fs: string, path: string): Promise<readonly FsAclRow[]>;
|
|
21
|
+
grant(row: FsAclRow): Promise<void>;
|
|
22
|
+
revoke(fs: string, path: string, subjectKey: string, relation: string): Promise<void>;
|
|
23
|
+
ownerOf(fs: string, path: string): Promise<PrincipalRef | null>;
|
|
24
|
+
setOwnerIfAbsent(fs: string, path: string, owner: PrincipalRef): Promise<void>;
|
|
25
|
+
deleteTree(fs: string, path: string): Promise<void>;
|
|
26
|
+
deletePath(fs: string, path: string): Promise<void>;
|
|
27
|
+
moveTree(fromFs: string, from: string, toFs: string, to: string): Promise<void>;
|
|
28
|
+
movePath(fromFs: string, from: string, toFs: string, to: string): Promise<void>;
|
|
29
|
+
private driver;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=orm-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orm-store.d.ts","sourceRoot":"","sources":["../../../src/acl/orm-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQ9C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAc3C,MAAM,WAAW,sBAAsB;IACrC,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,qEAAqE;IACrE,QAAQ,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC;CACjC;AAID;;;;GAIG;AACH,qBACa,eAAgB,SAAQ,YAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,GAAE,sBAA2B,EAE7D;IAEK,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAa9H;IAEK,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,QAAQ,EAAE,CAAC,CAIjE;IAEK,KAAK,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CASxC;IAEK,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW1F;IAEK,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAOpE;IAEK,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAOnF;IAEK,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKxD;IAEK,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKxD;IAEK,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBpF;IAEK,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAcpF;YAEa,MAAM;CAQrB"}
|