@voltro/plugin-storage 0.86.0 → 0.88.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/CHANGELOG.md +5484 -0
- package/README.md +27 -0
- package/THIRD-PARTY-NOTICES.md +2503 -690
- package/dist/access.js +26 -27
- package/dist/assetRef.js +1 -2
- package/dist/avatar.js +1 -2
- package/dist/byteSecurity.d.ts +3 -0
- package/dist/byteSecurity.js +6 -0
- package/dist/connection.js +98 -0
- package/dist/constraints.js +1 -2
- package/dist/custody.js +131 -0
- package/dist/derivatives.js +1 -2
- package/dist/env.js +8 -3
- package/dist/grant.js +90 -71
- package/dist/index.d.ts +453 -215
- package/dist/index.js +709 -537
- package/dist/ingest.js +7 -2
- package/dist/ingestPolicy.js +1 -1
- package/dist/metadataError.js +8 -9
- package/dist/objectAbandon.js +15 -0
- package/dist/objectLifecycle.js +135 -102
- package/dist/objectMetadata.js +253 -96
- package/dist/objectWriter.js +51 -23
- package/dist/pathDurability.js +1 -2
- package/dist/physicalReferences.js +53 -0
- package/dist/providers.js +451 -307
- package/dist/referenceCatalogue.js +1 -2
- package/dist/renditionProof.js +81 -0
- package/dist/retainedCapture.js +390 -0
- package/dist/retainedObjects.js +189 -0
- package/dist/rpc.d.ts +1 -15
- package/dist/rpc.js +1 -2
- package/dist/scanners.js +1 -2
- package/dist/server.d.ts +153 -0
- package/dist/server.js +4 -0
- package/dist/service.js +879 -546
- package/dist/sourceIdentity.js +13 -0
- package/dist/sourcePin.js +34 -0
- package/dist/storageNamespaces.js +52 -29
- package/dist/storageNumbers.js +1 -2
- package/dist/storageObjectNamespaces.js +170 -122
- package/dist/storageReferenceInstances.js +1 -2
- package/dist/storageRequest.js +9 -0
- package/dist/storageRouting.js +45 -0
- package/dist/streamBridge.js +5 -3
- package/dist/table.js +2 -2
- package/dist/transcodeVideo.js +85 -48
- package/dist/transform.js +30 -27
- package/dist/transformCache.js +1 -2
- package/dist/types.d.ts +115 -137
- package/dist/types.js +15 -16
- package/package.json +22 -11
package/dist/access.js
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
var i = (
|
|
5
|
-
let r =
|
|
6
|
-
return `${r}:${
|
|
7
|
-
}, a = (e,
|
|
8
|
-
if (!e || !
|
|
9
|
-
let [i, a] =
|
|
1
|
+
import { Effect as e } from "effect";
|
|
2
|
+
import { randomBytes as t, scryptSync as n, timingSafeEqual as r } from "node:crypto";
|
|
3
|
+
// src/access.ts
|
|
4
|
+
var i = (e) => {
|
|
5
|
+
let r = t(16).toString("hex");
|
|
6
|
+
return `${r}:${n(e, r, 32).toString("hex")}`;
|
|
7
|
+
}, a = (e, t) => {
|
|
8
|
+
if (!e || !t) return !1;
|
|
9
|
+
let [i, a] = t.split(":");
|
|
10
10
|
if (!i || !a) return !1;
|
|
11
|
-
let o = Buffer.from(a, "hex"), s =
|
|
12
|
-
return s.length === o.length &&
|
|
13
|
-
}, o = (e) => Array.isArray(e) ? e.filter((e) => typeof e == "string") : [], s = (e) => o(e.metadata?.roles), c = (e) => o(e.scopes), l = (e, t) => e.some((e) => t.includes(e)), u = (e) => o(e.metadata?.groups), d = (
|
|
14
|
-
if (
|
|
15
|
-
let i =
|
|
11
|
+
let o = Buffer.from(a, "hex"), s = n(e, i, o.length);
|
|
12
|
+
return s.length === o.length && r(s, o);
|
|
13
|
+
}, o = (e) => Array.isArray(e) ? e.filter((e) => typeof e == "string") : [], s = (e) => o(e.metadata?.roles), c = (e) => o(e.scopes), l = (e, t) => e.some((e) => t.includes(e)), u = (e) => o(e.metadata?.groups), d = (t) => typeof t == "boolean" ? e.succeed(t) : e.isEffect(t) ? t : e.promise(() => t), f = (t, n, r = {}) => e.gen(function* () {
|
|
14
|
+
if (n.id && t.ownerId && n.id === t.ownerId) return !0;
|
|
15
|
+
let i = t.accessPolicy ?? [];
|
|
16
16
|
if (i.length === 0) return !1;
|
|
17
|
-
let a =
|
|
18
|
-
for (let
|
|
17
|
+
let a = r.resolveGroups ? yield* e.promise(async () => await r.resolveGroups(n)) : u(n);
|
|
18
|
+
for (let e of i) if (yield* p(e, t, n, a, r)) return !0;
|
|
19
19
|
return !1;
|
|
20
|
-
}), p = (
|
|
21
|
-
let
|
|
22
|
-
if (
|
|
23
|
-
if (
|
|
24
|
-
let
|
|
25
|
-
if (!u(
|
|
26
|
-
subject:
|
|
27
|
-
ref:
|
|
20
|
+
}), p = (t, n, r, i, o) => e.gen(function* () {
|
|
21
|
+
let e = !1, u = (t) => (e = !0, t);
|
|
22
|
+
if (t.owner !== void 0 && t.owner && !u(!!r.id && !!n.ownerId && r.id === n.ownerId) || t.tenant !== void 0 && t.tenant && !u(!!r.tenantId && r.tenantId === n.tenantId) || t.apiKey !== void 0 && t.apiKey && !u(r.type === "apiKey") || t.roles && t.roles.length > 0 && !u(l(s(r), t.roles)) || t.groups && t.groups.length > 0 && !u(l(i, t.groups)) || t.scopes && t.scopes.length > 0 && !u(l(c(r), t.scopes)) || t.password !== void 0 && t.password && !u(a(o.password, n.passwordHash))) return !1;
|
|
23
|
+
if (t.guard) {
|
|
24
|
+
let e = o.guards?.[t.guard];
|
|
25
|
+
if (!u(e ? yield* d(e({
|
|
26
|
+
subject: r,
|
|
27
|
+
ref: n
|
|
28
28
|
})) : !1)) return !1;
|
|
29
29
|
}
|
|
30
|
-
return
|
|
30
|
+
return e;
|
|
31
31
|
}), m = (e, t) => {
|
|
32
32
|
let n = [];
|
|
33
33
|
e.id && n.push({
|
|
@@ -42,6 +42,5 @@ var i = (n) => {
|
|
|
42
42
|
}, h = (e, t, n, r, i) => {
|
|
43
43
|
let a = m(t, n);
|
|
44
44
|
return e.some((e) => e.expiresAt && e.expiresAt.getTime() < i || r === "write" && e.permission !== "write" ? !1 : a.some((t) => t.type === e.principalType && t.id === e.principalId));
|
|
45
|
-
}, g = (
|
|
46
|
-
//#endregion
|
|
45
|
+
}, g = (t, n) => n.resolveGroups ? e.promise(async () => await n.resolveGroups(t)) : e.succeed(u(t));
|
|
47
46
|
export { f as evaluatePolicy, h as grantsAllow, i as hashPassword, g as resolveSubjectGroups, m as subjectPrincipals, a as verifyPassword };
|
package/dist/assetRef.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { _voltroStorageRefsTable as e } from "./table.js";
|
|
2
2
|
import { mixin as t, reference as n, text as r } from "@voltro/database";
|
|
3
|
-
|
|
3
|
+
// src/assetRef.ts
|
|
4
4
|
function i(t = {}) {
|
|
5
5
|
let i = t.nullable ?? !0, a = t.fk === !1 ? r().externalId() : n(() => e, { onDelete: t.onDelete ?? "setNull" });
|
|
6
6
|
return i ? a.nullable() : a;
|
|
@@ -9,5 +9,4 @@ var a = () => t({
|
|
|
9
9
|
id: "@voltro/plugin-storage/withStorage",
|
|
10
10
|
fields: { asset: i() }
|
|
11
11
|
});
|
|
12
|
-
//#endregion
|
|
13
12
|
export { i as assetRef, a as withStorage };
|
package/dist/avatar.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StorageError as e } from "./types.js";
|
|
2
2
|
import { Effect as t } from "effect";
|
|
3
|
-
|
|
3
|
+
// src/avatar.ts
|
|
4
4
|
var n = {
|
|
5
5
|
"image/png": "png",
|
|
6
6
|
"image/jpeg": "jpg",
|
|
@@ -35,5 +35,4 @@ var n = {
|
|
|
35
35
|
key: `avatars/${a.userId}/avatar.${s}`
|
|
36
36
|
});
|
|
37
37
|
});
|
|
38
|
-
//#endregion
|
|
39
38
|
export { r as decodeDataUri, i as putAvatar };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// src/byteSecurity.ts
|
|
2
|
+
var e = /^(?:image\/(?!svg)|video\/|audio\/|application\/pdf(?:;|$)|text\/plain(?:;|$))/i, t = (t) => ({
|
|
3
|
+
"x-content-type-options": "nosniff",
|
|
4
|
+
"content-disposition": e.test(t) ? "inline" : "attachment"
|
|
5
|
+
});
|
|
6
|
+
export { t as storageByteSecurityHeaders };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { storageObjectNamespace as e } from "./storageNamespaces.js";
|
|
2
|
+
import { azureConnectionTransport as t, databaseProvider as n, filesystemProvider as r, memoryProviderWithState as i, s3ConnectionTransport as a } from "./providers.js";
|
|
3
|
+
import { StorageError as o } from "@voltro/kv/storage";
|
|
4
|
+
import { Effect as s } from "effect";
|
|
5
|
+
// src/connection.ts
|
|
6
|
+
var c = (t, n = "") => {
|
|
7
|
+
if (!n) return t;
|
|
8
|
+
let r = (e) => `${n}${e}`;
|
|
9
|
+
return {
|
|
10
|
+
...t,
|
|
11
|
+
objectNamespace: t.objectNamespace.pipe(s.map((t) => e([
|
|
12
|
+
"prefixed-object-namespace",
|
|
13
|
+
t,
|
|
14
|
+
n
|
|
15
|
+
]))),
|
|
16
|
+
...t.objectLocation === void 0 ? {} : { objectLocation: (e) => t.objectLocation(r(e)) },
|
|
17
|
+
put: (e, ...n) => t.put(r(e), ...n),
|
|
18
|
+
get: (e) => t.get(r(e)),
|
|
19
|
+
delete: (e) => t.delete(r(e)),
|
|
20
|
+
head: (e) => t.head(r(e)),
|
|
21
|
+
getUrl: (e, ...n) => t.getUrl(r(e), ...n),
|
|
22
|
+
...t.publicUrl === void 0 ? {} : { publicUrl: (e) => t.publicUrl(r(e)) },
|
|
23
|
+
...t.setObjectPublic === void 0 ? {} : { setObjectPublic: (e, n) => t.setObjectPublic(r(e), n) },
|
|
24
|
+
...t.getUploadUrl === void 0 ? {} : { getUploadUrl: (e, n, i) => t.getUploadUrl(r(e), n, i) },
|
|
25
|
+
...t.createMultipartUpload === void 0 ? {} : { createMultipartUpload: (e, n, i) => t.createMultipartUpload(r(e), n, i) },
|
|
26
|
+
...t.presignUploadPart === void 0 ? {} : { presignUploadPart: (e, n, i, a) => t.presignUploadPart(r(e), n, i, a) },
|
|
27
|
+
...t.completeMultipartUpload === void 0 ? {} : { completeMultipartUpload: (e, n, i) => t.completeMultipartUpload(r(e), n, i) },
|
|
28
|
+
...t.abortMultipartUpload === void 0 ? {} : { abortMultipartUpload: (e, n) => t.abortMultipartUpload(r(e), n) },
|
|
29
|
+
...t.getStream === void 0 ? {} : { getStream: (e) => t.getStream(r(e)) },
|
|
30
|
+
...t.putStream === void 0 ? {} : { putStream: (e, n, i) => t.putStream(r(e), n, i) },
|
|
31
|
+
...t.getRange === void 0 ? {} : { getRange: (e, n, i) => t.getRange(r(e), n, i) }
|
|
32
|
+
};
|
|
33
|
+
}, l = (e, l) => s.suspend(() => {
|
|
34
|
+
let u;
|
|
35
|
+
switch (e.provider) {
|
|
36
|
+
case "s3":
|
|
37
|
+
case "minio":
|
|
38
|
+
u = a({
|
|
39
|
+
bucket: e.bucket,
|
|
40
|
+
name: e.provider,
|
|
41
|
+
...e.region === void 0 ? {} : { region: e.region },
|
|
42
|
+
...e.endpoint === void 0 ? {} : { endpoint: e.endpoint },
|
|
43
|
+
...e.accessKeyId === void 0 ? {} : { accessKeyId: e.accessKeyId },
|
|
44
|
+
...e.secretAccessKey === void 0 ? {} : { secretAccessKey: e.secretAccessKey },
|
|
45
|
+
...e.cdnBaseUrl === void 0 ? {} : { cdnBaseUrl: e.cdnBaseUrl },
|
|
46
|
+
...e.publicAcl === void 0 ? {} : { publicAcl: e.publicAcl },
|
|
47
|
+
forcePathStyle: e.forcePathStyle ?? e.provider === "minio"
|
|
48
|
+
});
|
|
49
|
+
break;
|
|
50
|
+
case "filesystem":
|
|
51
|
+
u = {
|
|
52
|
+
provider: r({ root: e.root }),
|
|
53
|
+
close: s.void,
|
|
54
|
+
probe: s.tryPromise({
|
|
55
|
+
try: async () => {
|
|
56
|
+
let t = await import("node:fs/promises");
|
|
57
|
+
if (!(await t.stat(e.root)).isDirectory()) throw Error("Storage root must be a directory");
|
|
58
|
+
await t.access(e.root);
|
|
59
|
+
},
|
|
60
|
+
catch: () => new o({
|
|
61
|
+
provider: "filesystem",
|
|
62
|
+
message: "Storage root is not readable",
|
|
63
|
+
transient: !1
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
};
|
|
67
|
+
break;
|
|
68
|
+
case "memory":
|
|
69
|
+
u = {
|
|
70
|
+
provider: i(l.memory ?? /* @__PURE__ */ new Map()),
|
|
71
|
+
probe: s.void,
|
|
72
|
+
close: s.void
|
|
73
|
+
};
|
|
74
|
+
break;
|
|
75
|
+
case "database": {
|
|
76
|
+
let e = n();
|
|
77
|
+
u = {
|
|
78
|
+
provider: e,
|
|
79
|
+
probe: e.head("_connection_readiness").pipe(s.asVoid),
|
|
80
|
+
close: s.void
|
|
81
|
+
};
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case "azure": u = t({
|
|
85
|
+
container: e.bucket,
|
|
86
|
+
...e.accountName === void 0 ? {} : { accountName: e.accountName },
|
|
87
|
+
...e.accountKey === void 0 ? {} : { accountKey: e.accountKey },
|
|
88
|
+
...e.connectionString === void 0 ? {} : { connectionString: e.connectionString },
|
|
89
|
+
...e.endpoint === void 0 ? {} : { endpoint: e.endpoint },
|
|
90
|
+
...e.cdnBaseUrl === void 0 ? {} : { cdnBaseUrl: e.cdnBaseUrl }
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return s.succeed({
|
|
94
|
+
...u,
|
|
95
|
+
provider: c(u.provider, e.keyPrefix)
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
export { l as connectStorage, c as withStorageKeyPrefix };
|
package/dist/constraints.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/constraints.ts
|
|
2
2
|
var e = (e, t) => {
|
|
3
3
|
if (!t || t.length === 0) return !0;
|
|
4
4
|
let n = e.toLowerCase();
|
|
@@ -89,5 +89,4 @@ var e = (e, t) => {
|
|
|
89
89
|
reason: "content-type-not-allowed",
|
|
90
90
|
detail: `content type '${r}' is not in the allow-list`
|
|
91
91
|
} : null;
|
|
92
|
-
//#endregion
|
|
93
92
|
export { r as checkLimits, e as contentTypeAllowed, n as sniffMatches };
|
package/dist/custody.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { StorageError as e } from "./types.js";
|
|
2
|
+
import { storageMetadataError as t } from "./metadataError.js";
|
|
3
|
+
import { readRetainedStorageObject as n } from "./retainedObjects.js";
|
|
4
|
+
import { abandonRetainedCapture as r, admitRetainedCaptureObject as i, inspectRetainedSource as a, registerRetainedCapture as o, retainedCaptureItems as s, runRetainedCapture as c, sealRetainedCapture as l } from "./retainedCapture.js";
|
|
5
|
+
import { Context as u, Effect as d, Layer as f, Schema as p, Stream as m } from "effect";
|
|
6
|
+
import { canonicalJson as h, pluginInstanceName as g } from "@voltro/protocol";
|
|
7
|
+
// src/custody.ts
|
|
8
|
+
var _ = "@voltro/plugin-storage", v = (e) => g({
|
|
9
|
+
base: _,
|
|
10
|
+
alias: e.alias,
|
|
11
|
+
instance: e.name
|
|
12
|
+
}), y = (e) => `${_}/StorageCustody:${JSON.stringify(e)}`, b = class extends u.Service()(y(_)) {
|
|
13
|
+
static withSource(e) {
|
|
14
|
+
return d.suspend(() => {
|
|
15
|
+
let t = E.get(e.source), n = E.get(e.destination);
|
|
16
|
+
return t === void 0 || n === void 0 ? d.fail(x("Custody transfer requires configured storage services")) : t !== n && v(t.selection) === v(n.selection) ? d.fail(x("Custody source and destination need distinct configured instance identities")) : d.succeed(D(n, t));
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
static forInstance(e = {}) {
|
|
20
|
+
return u.Service(y(v(e)));
|
|
21
|
+
}
|
|
22
|
+
}, x = (t, n = 409) => new e({
|
|
23
|
+
provider: "custody",
|
|
24
|
+
message: t,
|
|
25
|
+
status: n,
|
|
26
|
+
transient: !1
|
|
27
|
+
}), S = (n) => p.is(e)(n) ? n : t(n, "custody"), C = (e) => d.tryPromise({
|
|
28
|
+
try: e,
|
|
29
|
+
catch: S
|
|
30
|
+
}), w = (e) => ({
|
|
31
|
+
id: e.id,
|
|
32
|
+
instance: e.instance,
|
|
33
|
+
objectNamespace: e.objectNamespace,
|
|
34
|
+
tenantId: e.tenantId,
|
|
35
|
+
bucket: e.bucket,
|
|
36
|
+
contextDigest: e.contextDigest,
|
|
37
|
+
...e.source === void 0 ? {} : { source: {
|
|
38
|
+
instance: e.source.instance,
|
|
39
|
+
objectNamespace: e.source.objectNamespace,
|
|
40
|
+
bucket: e.source.bucket
|
|
41
|
+
} }
|
|
42
|
+
}), T = (e) => ({
|
|
43
|
+
...w(e),
|
|
44
|
+
count: e.count,
|
|
45
|
+
digest: e.digest
|
|
46
|
+
}), E = /* @__PURE__ */ new WeakMap(), D = (e, t = e) => {
|
|
47
|
+
let u = v(t.selection), f = v(e.selection), p = e.bucket, g = e.provider, _ = (t) => d.gen(function* () {
|
|
48
|
+
let n = yield* g.objectNamespace;
|
|
49
|
+
if (t !== void 0 && (t.instance !== f || t.bucket !== p || t.objectNamespace !== n)) return yield* d.fail(x("Capture belongs to another storage instance or bucket", 403));
|
|
50
|
+
let r = e.store();
|
|
51
|
+
return yield* r === void 0 ? d.fail(x("Storage custody requires a bound database and the default reference and grant stores")) : d.succeed(r);
|
|
52
|
+
}), y = () => d.gen(function* () {
|
|
53
|
+
let e = yield* t.provider.objectNamespace;
|
|
54
|
+
return u === f && t.bucket === p ? void 0 : {
|
|
55
|
+
instance: u,
|
|
56
|
+
objectNamespace: e,
|
|
57
|
+
bucket: t.bucket
|
|
58
|
+
};
|
|
59
|
+
}), b = () => d.gen(function* () {
|
|
60
|
+
let e = yield* _();
|
|
61
|
+
return t.store() === e ? e : yield* d.fail(x("Custody source and destination must share the bound application database"));
|
|
62
|
+
}), D = {
|
|
63
|
+
inspect: (e, n) => d.gen(function* () {
|
|
64
|
+
let r = n.id, i = n.tenantId;
|
|
65
|
+
yield* b();
|
|
66
|
+
let o = yield* t.provider.objectNamespace;
|
|
67
|
+
return yield* C(() => a(e, {
|
|
68
|
+
instance: u,
|
|
69
|
+
objectNamespace: o,
|
|
70
|
+
bucket: t.bucket,
|
|
71
|
+
tenantId: i
|
|
72
|
+
}, r));
|
|
73
|
+
}),
|
|
74
|
+
register: (e, t) => d.gen(function* () {
|
|
75
|
+
let n = yield* y(), r = {
|
|
76
|
+
id: t.id,
|
|
77
|
+
instance: f,
|
|
78
|
+
objectNamespace: yield* g.objectNamespace,
|
|
79
|
+
tenantId: t.tenantId,
|
|
80
|
+
bucket: p,
|
|
81
|
+
contextDigest: t.contextDigest,
|
|
82
|
+
...n === void 0 ? {} : { source: n }
|
|
83
|
+
}, i = t.maxBytes, a = t.sources;
|
|
84
|
+
return yield* b(), {
|
|
85
|
+
key: r,
|
|
86
|
+
count: (yield* C(() => o(e, r, {
|
|
87
|
+
maxBytes: i,
|
|
88
|
+
sources: a
|
|
89
|
+
}))).count
|
|
90
|
+
};
|
|
91
|
+
}),
|
|
92
|
+
run: (n) => d.gen(function* () {
|
|
93
|
+
let r = w(n);
|
|
94
|
+
yield* _(r);
|
|
95
|
+
let i = yield* b();
|
|
96
|
+
yield* c(i, g, r, e.quota, {
|
|
97
|
+
instance: u,
|
|
98
|
+
bucket: t.bucket,
|
|
99
|
+
provider: t.provider
|
|
100
|
+
}).pipe(d.mapError(S));
|
|
101
|
+
}),
|
|
102
|
+
seal: (e, t) => d.gen(function* () {
|
|
103
|
+
let n = w(t);
|
|
104
|
+
return yield* _(n), yield* C(() => l(e, n));
|
|
105
|
+
}),
|
|
106
|
+
items: (e, t) => m.unwrap(d.gen(function* () {
|
|
107
|
+
let n = T(e), r = yield* _(n);
|
|
108
|
+
return m.fromAsyncIterable(s(t ?? r, n), S);
|
|
109
|
+
})),
|
|
110
|
+
read: (e, t, r) => d.gen(function* () {
|
|
111
|
+
let a = T(e), o = yield* d.try({
|
|
112
|
+
try: () => JSON.parse(h(t)),
|
|
113
|
+
catch: S
|
|
114
|
+
}), s = {
|
|
115
|
+
storageInstance: f,
|
|
116
|
+
tenantId: r.tenantId,
|
|
117
|
+
maxBytes: r.maxBytes,
|
|
118
|
+
bucket: p
|
|
119
|
+
};
|
|
120
|
+
if (a.tenantId !== s.tenantId || o.tenantId !== s.tenantId) return yield* d.fail(x("Capture tenant does not match admitted tenant", 403));
|
|
121
|
+
let c = yield* _(a);
|
|
122
|
+
return yield* C(() => i(c, a, o)), yield* n(c, g, o, s).pipe(d.mapError(S));
|
|
123
|
+
}),
|
|
124
|
+
abandon: (e) => d.gen(function* () {
|
|
125
|
+
let t = w(e), n = yield* _(t);
|
|
126
|
+
yield* r(n, g, t).pipe(d.mapError(S));
|
|
127
|
+
})
|
|
128
|
+
};
|
|
129
|
+
return E.set(D, e), D;
|
|
130
|
+
}, O = (e) => f.succeed(b.forInstance(e.selection), D(e));
|
|
131
|
+
export { b as StorageCustody, O as storageCustodyLayer };
|
package/dist/derivatives.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isTransformable as e, loadSharp as t } from "./transform.js";
|
|
2
|
-
|
|
2
|
+
// src/derivatives.ts
|
|
3
3
|
var n = async (n, r, i) => {
|
|
4
4
|
if (!e(r)) return { bytes: n };
|
|
5
5
|
let a = await t();
|
|
@@ -26,5 +26,4 @@ var n = async (n, r, i) => {
|
|
|
26
26
|
return { bytes: n };
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
|
-
//#endregion
|
|
30
29
|
export { n as extractImageMetadata };
|
package/dist/env.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { pluginEnv as e } from "@voltro/env";
|
|
2
|
-
|
|
2
|
+
// src/env.ts
|
|
3
3
|
var t = e([
|
|
4
4
|
{
|
|
5
5
|
name: "STORAGE_PROVIDER",
|
|
@@ -131,7 +131,13 @@ var t = e([
|
|
|
131
131
|
name: "VOLTRO_STORAGE_SECRET",
|
|
132
132
|
required: !1,
|
|
133
133
|
secret: !0,
|
|
134
|
-
description: "HMAC secret for signed
|
|
134
|
+
description: "HMAC secret for signed storage links and upload tickets. Falls back to the session secret (and its VOLTRO_SESSION_SECRET_PREVIOUS)."
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "VOLTRO_STORAGE_SECRET_PREVIOUS",
|
|
138
|
+
required: !1,
|
|
139
|
+
secret: !0,
|
|
140
|
+
description: "During a VOLTRO_STORAGE_SECRET rotation: the secret links and tickets were signed with until now. They keep verifying until they expire; then remove it."
|
|
135
141
|
},
|
|
136
142
|
{
|
|
137
143
|
name: "VOLTRO_SESSION_COOKIE",
|
|
@@ -152,5 +158,4 @@ var t = e([
|
|
|
152
158
|
description: "clamd port for the optional clamav virus scanner. Default 3310."
|
|
153
159
|
}
|
|
154
160
|
]);
|
|
155
|
-
//#endregion
|
|
156
161
|
export { t as storageEnv };
|
package/dist/grant.js
CHANGED
|
@@ -1,112 +1,131 @@
|
|
|
1
1
|
import { storageEnv as e } from "./env.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { Exit as t, Schema as n } from "effect";
|
|
3
|
+
import { createHmac as r, timingSafeEqual as i } from "node:crypto";
|
|
4
4
|
import { StorageAccessPolicySchema as a } from "@voltro/protocol";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
var
|
|
5
|
+
import { noteConfigured as o, noteSigned as s, noteSigningLifetime as c, previousAccepted as l, resolveSessionSecrets as u } from "@voltro/protocol/session";
|
|
6
|
+
// src/grant.ts
|
|
7
|
+
var d = () => {
|
|
8
|
+
let t = e.read("VOLTRO_STORAGE_SECRET");
|
|
9
|
+
if (t !== void 0 && t !== "") {
|
|
10
|
+
let n = e.read("VOLTRO_STORAGE_SECRET_PREVIOUS");
|
|
11
|
+
return o("storage", t, n), n === void 0 || n === "" || n === t || !l("storage", n) ? [t] : [t, n];
|
|
12
|
+
}
|
|
13
|
+
let n = u();
|
|
14
|
+
return n.previous === void 0 ? [n.current.secret] : [n.current.secret, n.previous.secret];
|
|
15
|
+
}, f = (t, n) => {
|
|
16
|
+
s(t === e.read("VOLTRO_STORAGE_SECRET") ? "storage" : "session", t, n * 1e3);
|
|
17
|
+
}, p = (t) => {
|
|
18
|
+
c(e.read("VOLTRO_STORAGE_SECRET") ? "storage" : "session", t * 1e3);
|
|
19
|
+
}, m = () => d()[0], h = (e, t, n) => {
|
|
20
|
+
let a = v(t), o = !1;
|
|
21
|
+
for (let t of typeof n == "string" ? [n] : n) {
|
|
22
|
+
if (!t) continue;
|
|
23
|
+
let n = r("sha256", t).update(e).digest();
|
|
24
|
+
a.length === n.length && i(a, n) && (o = !0);
|
|
25
|
+
}
|
|
26
|
+
return o;
|
|
27
|
+
}, g = (e) => typeof e == "string" ? e.length > 0 : e.some((e) => e.length > 0), _ = (e) => (typeof e == "string" ? Buffer.from(e, "utf8") : e).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""), v = (e) => {
|
|
8
28
|
let t = e.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat((4 - e.length % 4) % 4);
|
|
9
29
|
return Buffer.from(t, "base64");
|
|
10
|
-
},
|
|
11
|
-
if (!
|
|
30
|
+
}, y = (e, t, n = m(), i = "/_voltro/storage") => {
|
|
31
|
+
if (!n) throw Error("signGrant: secret must be a non-empty string");
|
|
12
32
|
let a = {
|
|
13
33
|
refId: e,
|
|
14
34
|
audience: i,
|
|
15
|
-
exp: Math.floor(Date.now() / 1e3) + Math.floor(
|
|
16
|
-
}, o =
|
|
17
|
-
return `${o}.${
|
|
18
|
-
},
|
|
19
|
-
if (!e || !
|
|
20
|
-
let
|
|
21
|
-
if (
|
|
22
|
-
let
|
|
23
|
-
if (
|
|
35
|
+
exp: Math.floor(Date.now() / 1e3) + Math.floor(t)
|
|
36
|
+
}, o = _(JSON.stringify(a)), s = _(r("sha256", n).update(o).digest());
|
|
37
|
+
return f(n, a.exp), `${o}.${s}`;
|
|
38
|
+
}, b = (e, t = d()) => {
|
|
39
|
+
if (!e || !g(t)) return null;
|
|
40
|
+
let n = e.indexOf(".");
|
|
41
|
+
if (n <= 0 || n === e.length - 1) return null;
|
|
42
|
+
let r = e.slice(0, n);
|
|
43
|
+
if (!h(r, e.slice(n + 1), t)) return null;
|
|
24
44
|
try {
|
|
25
|
-
let e = JSON.parse(
|
|
45
|
+
let e = JSON.parse(v(r).toString("utf8"));
|
|
26
46
|
return typeof e.audience != "string" || !e.audience || typeof e.refId != "string" || typeof e.exp != "number" || e.exp <= Math.floor(Date.now() / 1e3) ? null : e;
|
|
27
47
|
} catch {
|
|
28
48
|
return null;
|
|
29
49
|
}
|
|
30
|
-
},
|
|
31
|
-
if (!
|
|
50
|
+
}, x = (e) => e.version !== 2 || typeof e.writeScope != "string" || !/^[a-f0-9]{64}$/.test(e.writeScope) || Object.hasOwn(e, "replicaId") || e.issuerReplicaId !== void 0 && (typeof e.issuerReplicaId != "string" || !e.issuerReplicaId.trim()) ? !1 : e.access === void 0 || e.vis === "private" && t.isSuccess(n.decodeUnknownExit(a, { onExcessProperty: "error" })(e.access)), S = (e, t, n = m()) => {
|
|
51
|
+
if (!n) throw Error("signUploadTicket: secret must be a non-empty string");
|
|
32
52
|
let i = {
|
|
33
53
|
...e,
|
|
34
54
|
version: 2,
|
|
35
|
-
exp: Math.floor(Date.now() / 1e3) + Math.floor(
|
|
36
|
-
}, a =
|
|
37
|
-
return
|
|
38
|
-
},
|
|
39
|
-
if (!e || !
|
|
40
|
-
let
|
|
41
|
-
if (
|
|
42
|
-
let
|
|
43
|
-
if (
|
|
55
|
+
exp: Math.floor(Date.now() / 1e3) + Math.floor(t)
|
|
56
|
+
}, a = _(JSON.stringify(i)), o = _(r("sha256", n).update(`u:${a}`).digest());
|
|
57
|
+
return f(n, i.exp), `${a}.${o}`;
|
|
58
|
+
}, C = (e, t = d()) => {
|
|
59
|
+
if (!e || !g(t)) return null;
|
|
60
|
+
let n = e.indexOf(".");
|
|
61
|
+
if (n <= 0 || n === e.length - 1) return null;
|
|
62
|
+
let r = e.slice(0, n), i = e.slice(n + 1);
|
|
63
|
+
if (!h(`u:${r}`, i, t)) return null;
|
|
44
64
|
try {
|
|
45
|
-
let e = JSON.parse(
|
|
46
|
-
return !
|
|
65
|
+
let e = JSON.parse(v(r).toString("utf8"));
|
|
66
|
+
return !x(e) || e.operationId !== void 0 && (typeof e.operationId != "string" || !e.operationId.trim() || e.operationId.length > 200) || typeof e.instance != "string" || !e.instance || typeof e.ct != "string" || typeof e.exp != "number" || typeof e.destination != "string" || !e.destination || e.destination.includes("\0") || /[\uD800-\uDFFF]/u.test(e.destination) || e.vis !== "public" && e.vis !== "private" || e.exp <= Math.floor(Date.now() / 1e3) ? null : e;
|
|
47
67
|
} catch {
|
|
48
68
|
return null;
|
|
49
69
|
}
|
|
50
|
-
},
|
|
51
|
-
if (!
|
|
70
|
+
}, w = (e, t, n = m()) => {
|
|
71
|
+
if (!n) throw Error("signFinalizeTicket: secret must be a non-empty string");
|
|
52
72
|
let i = {
|
|
53
73
|
...e,
|
|
54
74
|
version: 2,
|
|
55
|
-
exp: Math.floor(Date.now() / 1e3) + Math.floor(
|
|
56
|
-
}, a =
|
|
57
|
-
return
|
|
58
|
-
},
|
|
59
|
-
if (!e || !
|
|
60
|
-
let
|
|
61
|
-
if (
|
|
62
|
-
let
|
|
63
|
-
if (
|
|
75
|
+
exp: Math.floor(Date.now() / 1e3) + Math.floor(t)
|
|
76
|
+
}, a = _(JSON.stringify(i)), o = _(r("sha256", n).update(`f:${a}`).digest());
|
|
77
|
+
return f(n, i.exp), `${a}.${o}`;
|
|
78
|
+
}, T = (e, t = d()) => {
|
|
79
|
+
if (!e || !g(t)) return null;
|
|
80
|
+
let n = e.indexOf(".");
|
|
81
|
+
if (n <= 0 || n === e.length - 1) return null;
|
|
82
|
+
let r = e.slice(0, n), i = e.slice(n + 1);
|
|
83
|
+
if (!h(`f:${r}`, i, t)) return null;
|
|
64
84
|
try {
|
|
65
|
-
let e = JSON.parse(
|
|
66
|
-
return !
|
|
85
|
+
let e = JSON.parse(v(r).toString("utf8"));
|
|
86
|
+
return !x(e) || typeof e.key != "string" || e.key.length === 0 || typeof e.instance != "string" || !e.instance || typeof e.ct != "string" || typeof e.exp != "number" || typeof e.destination != "string" || !e.destination || e.destination.includes("\0") || /[\uD800-\uDFFF]/u.test(e.destination) || e.vis !== "public" && e.vis !== "private" || e.exp <= Math.floor(Date.now() / 1e3) ? null : e;
|
|
67
87
|
} catch {
|
|
68
88
|
return null;
|
|
69
89
|
}
|
|
70
|
-
},
|
|
71
|
-
if (!
|
|
90
|
+
}, E = (e, t, n = m()) => {
|
|
91
|
+
if (!n) throw Error("signResumableTicket: secret must be a non-empty string");
|
|
72
92
|
let i = {
|
|
73
93
|
...e,
|
|
74
94
|
version: 2,
|
|
75
|
-
exp: Math.floor(Date.now() / 1e3) + Math.floor(
|
|
76
|
-
}, a =
|
|
77
|
-
return
|
|
78
|
-
},
|
|
79
|
-
if (!e || !
|
|
80
|
-
let
|
|
81
|
-
if (
|
|
82
|
-
let
|
|
83
|
-
if (
|
|
95
|
+
exp: Math.floor(Date.now() / 1e3) + Math.floor(t)
|
|
96
|
+
}, a = _(JSON.stringify(i)), o = _(r("sha256", n).update(`r:${a}`).digest());
|
|
97
|
+
return f(n, i.exp), `${a}.${o}`;
|
|
98
|
+
}, D = (e, t = d()) => {
|
|
99
|
+
if (!e || !g(t)) return null;
|
|
100
|
+
let n = e.indexOf(".");
|
|
101
|
+
if (n <= 0 || n === e.length - 1) return null;
|
|
102
|
+
let r = e.slice(0, n), i = e.slice(n + 1);
|
|
103
|
+
if (!h(`r:${r}`, i, t)) return null;
|
|
84
104
|
try {
|
|
85
|
-
let e = JSON.parse(
|
|
86
|
-
return !
|
|
105
|
+
let e = JSON.parse(v(r).toString("utf8"));
|
|
106
|
+
return !x(e) || typeof e.id != "string" || e.id.length === 0 || typeof e.size != "number" || e.size < 0 || typeof e.instance != "string" || !e.instance || typeof e.ct != "string" || typeof e.exp != "number" || typeof e.destination != "string" || !e.destination || e.destination.includes("\0") || /[\uD800-\uDFFF]/u.test(e.destination) || e.vis !== "public" && e.vis !== "private" || e.exp <= Math.floor(Date.now() / 1e3) ? null : e;
|
|
87
107
|
} catch {
|
|
88
108
|
return null;
|
|
89
109
|
}
|
|
90
|
-
},
|
|
91
|
-
if (!
|
|
110
|
+
}, O = (e, t, n = m()) => {
|
|
111
|
+
if (!n) throw Error("signMultipartTicket: secret must be a non-empty string");
|
|
92
112
|
let i = {
|
|
93
113
|
...e,
|
|
94
114
|
version: 2,
|
|
95
|
-
exp: Math.floor(Date.now() / 1e3) + Math.floor(
|
|
96
|
-
}, a =
|
|
97
|
-
return
|
|
98
|
-
},
|
|
99
|
-
if (!e || !
|
|
100
|
-
let
|
|
101
|
-
if (
|
|
102
|
-
let
|
|
103
|
-
if (
|
|
115
|
+
exp: Math.floor(Date.now() / 1e3) + Math.floor(t)
|
|
116
|
+
}, a = _(JSON.stringify(i)), o = _(r("sha256", n).update(`m:${a}`).digest());
|
|
117
|
+
return f(n, i.exp), `${a}.${o}`;
|
|
118
|
+
}, k = (e, t = d()) => {
|
|
119
|
+
if (!e || !g(t)) return null;
|
|
120
|
+
let n = e.indexOf(".");
|
|
121
|
+
if (n <= 0 || n === e.length - 1) return null;
|
|
122
|
+
let r = e.slice(0, n), i = e.slice(n + 1);
|
|
123
|
+
if (!h(`m:${r}`, i, t)) return null;
|
|
104
124
|
try {
|
|
105
|
-
let e = JSON.parse(
|
|
106
|
-
return !
|
|
125
|
+
let e = JSON.parse(v(r).toString("utf8"));
|
|
126
|
+
return !x(e) || typeof e.key != "string" || e.key.length === 0 || typeof e.uploadId != "string" || e.uploadId.length === 0 || typeof e.instance != "string" || !e.instance || typeof e.ct != "string" || typeof e.exp != "number" || typeof e.destination != "string" || !e.destination || e.destination.includes("\0") || /[\uD800-\uDFFF]/u.test(e.destination) || e.vis !== "public" && e.vis !== "private" || e.exp <= Math.floor(Date.now() / 1e3) ? null : e;
|
|
107
127
|
} catch {
|
|
108
128
|
return null;
|
|
109
129
|
}
|
|
110
130
|
};
|
|
111
|
-
|
|
112
|
-
export { s as resolveStorageSecret, h as signFinalizeTicket, u as signGrant, y as signMultipartTicket, _ as signResumableTicket, p as signUploadTicket, g as verifyFinalizeTicket, d as verifyGrant, b as verifyMultipartTicket, v as verifyResumableTicket, m as verifyUploadTicket };
|
|
131
|
+
export { p as declareStorageSigningLifetime, m as resolveStorageSecret, d as resolveStorageSecrets, w as signFinalizeTicket, y as signGrant, O as signMultipartTicket, E as signResumableTicket, S as signUploadTicket, T as verifyFinalizeTicket, b as verifyGrant, k as verifyMultipartTicket, D as verifyResumableTicket, C as verifyUploadTicket };
|