@blamejs/core 0.8.39 → 0.8.41
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 +2 -0
- package/index.js +4 -0
- package/lib/audit-tools.js +69 -0
- package/lib/audit.js +3 -0
- package/lib/auth/password.js +51 -7
- package/lib/backup/index.js +63 -0
- package/lib/canonical-json.js +35 -7
- package/lib/config.js +118 -7
- package/lib/constants.js +10 -1
- package/lib/crypto.js +51 -14
- package/lib/honeytoken.js +132 -0
- package/lib/mail-auth.js +16 -4
- package/lib/middleware/csp-report.js +133 -0
- package/lib/middleware/index.js +2 -0
- package/lib/network-smtp-policy.js +11 -4
- package/lib/network-tls.js +77 -0
- package/lib/pqc-software.js +42 -0
- package/lib/resource-access-lock.js +116 -0
- package/lib/vault/index.js +23 -0
- package/package.json +1 -1
- package/sbom.cyclonedx.json +6 -6
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* b.resourceAccessLock — three-mode access-lock for arbitrary
|
|
4
|
+
* resources (data exports, scheduled jobs, file paths, queue
|
|
5
|
+
* partitions). Different from b.auth.accessLock — that one gates
|
|
6
|
+
* HTTP request flow; this one gates non-HTTP-shaped operator
|
|
7
|
+
* actions. Both share the open / read-only / locked vocabulary.
|
|
8
|
+
*
|
|
9
|
+
* var exportLock = b.resourceAccessLock.create({
|
|
10
|
+
* resource: "data-export-jobs",
|
|
11
|
+
* startMode: "open",
|
|
12
|
+
* audit: b.audit,
|
|
13
|
+
* });
|
|
14
|
+
*
|
|
15
|
+
* if (!exportLock.permits("write")) {
|
|
16
|
+
* throw new b.resourceAccessLock.ResourceAccessLockError(
|
|
17
|
+
* "resource-access-lock/refused",
|
|
18
|
+
* "data export refused: lock mode is " + exportLock.mode());
|
|
19
|
+
* }
|
|
20
|
+
* await runExportJob();
|
|
21
|
+
*
|
|
22
|
+
* exportLock.set("locked", { actor: "alice", reason: "incident-42 freeze" });
|
|
23
|
+
*
|
|
24
|
+
* Mode semantics:
|
|
25
|
+
* open — every action permitted
|
|
26
|
+
* read-only — actions tagged "read" permitted; "write" refused
|
|
27
|
+
* locked — every action refused
|
|
28
|
+
*
|
|
29
|
+
* Audit shape:
|
|
30
|
+
* resourceaccesslock.mode_changed — {resource, from, to, actor, reason}
|
|
31
|
+
* resourceaccesslock.refused — {resource, action, mode, actor}
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
var lazyRequire = require("./lazy-require");
|
|
35
|
+
var validateOpts = require("./validate-opts");
|
|
36
|
+
var { defineClass } = require("./framework-error");
|
|
37
|
+
|
|
38
|
+
var audit = lazyRequire(function () { return require("./audit"); });
|
|
39
|
+
|
|
40
|
+
var ResourceAccessLockError = defineClass("ResourceAccessLockError",
|
|
41
|
+
{ alwaysPermanent: true });
|
|
42
|
+
|
|
43
|
+
var VALID_MODES = Object.freeze({ open: 1, "read-only": 1, locked: 1 });
|
|
44
|
+
var READ_ACTIONS = Object.freeze({ read: 1, list: 1, get: 1, query: 1, "read-only": 1 });
|
|
45
|
+
|
|
46
|
+
function create(opts) {
|
|
47
|
+
opts = opts || {};
|
|
48
|
+
validateOpts(opts, ["resource", "startMode", "audit"], "resourceAccessLock.create");
|
|
49
|
+
validateOpts.requireNonEmptyString(opts.resource, "resource",
|
|
50
|
+
ResourceAccessLockError, "resource-access-lock/no-resource");
|
|
51
|
+
var startMode = opts.startMode || "open";
|
|
52
|
+
if (!VALID_MODES[startMode]) {
|
|
53
|
+
throw new ResourceAccessLockError(
|
|
54
|
+
"resource-access-lock/bad-start-mode",
|
|
55
|
+
"startMode must be one of: " + Object.keys(VALID_MODES).join(" / "));
|
|
56
|
+
}
|
|
57
|
+
var auditOn = opts.audit !== false;
|
|
58
|
+
var resource = opts.resource;
|
|
59
|
+
var mode = startMode;
|
|
60
|
+
|
|
61
|
+
function _emit(action, outcome, meta) {
|
|
62
|
+
if (!auditOn) return;
|
|
63
|
+
try {
|
|
64
|
+
audit().safeEmit({
|
|
65
|
+
action: action, outcome: outcome,
|
|
66
|
+
metadata: Object.assign({ resource: resource }, meta || {}),
|
|
67
|
+
});
|
|
68
|
+
} catch (_e) { /* audit best-effort */ }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function permits(action) {
|
|
72
|
+
if (mode === "open") return true;
|
|
73
|
+
if (mode === "locked") return false;
|
|
74
|
+
return !!READ_ACTIONS[action];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function set(newMode, ctx) {
|
|
78
|
+
ctx = ctx || {};
|
|
79
|
+
if (!VALID_MODES[newMode]) {
|
|
80
|
+
throw new ResourceAccessLockError(
|
|
81
|
+
"resource-access-lock/bad-mode",
|
|
82
|
+
"set: mode must be one of: " + Object.keys(VALID_MODES).join(" / "));
|
|
83
|
+
}
|
|
84
|
+
var prev = mode;
|
|
85
|
+
mode = newMode;
|
|
86
|
+
_emit("resourceaccesslock.mode_changed", "success", {
|
|
87
|
+
from: prev, to: newMode,
|
|
88
|
+
actor: ctx.actor || null, reason: ctx.reason || null,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function assertPermits(action, ctx) {
|
|
93
|
+
if (permits(action)) return;
|
|
94
|
+
_emit("resourceaccesslock.refused", "failure", {
|
|
95
|
+
action: action, mode: mode,
|
|
96
|
+
actor: (ctx && ctx.actor) || null,
|
|
97
|
+
});
|
|
98
|
+
throw new ResourceAccessLockError(
|
|
99
|
+
"resource-access-lock/refused",
|
|
100
|
+
resource + " refuses '" + action + "': lock mode is '" + mode + "'");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
resource: resource,
|
|
105
|
+
mode: function () { return mode; },
|
|
106
|
+
set: set,
|
|
107
|
+
permits: permits,
|
|
108
|
+
assertPermits: assertPermits,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = {
|
|
113
|
+
create: create,
|
|
114
|
+
VALID_MODES: Object.freeze(Object.keys(VALID_MODES)),
|
|
115
|
+
ResourceAccessLockError: ResourceAccessLockError,
|
|
116
|
+
};
|
package/lib/vault/index.js
CHANGED
|
@@ -294,10 +294,33 @@ var vaultAad = require("../vault-aad");
|
|
|
294
294
|
|
|
295
295
|
var sealPemFileModule = require("./seal-pem-file");
|
|
296
296
|
|
|
297
|
+
// _zeroizeAndReplace — best-effort secureZero of prior in-memory keys
|
|
298
|
+
// before a swap. V8 strings can't be reliably overwritten (string
|
|
299
|
+
// interning + GC managed), so the pre-swap pass converts each PEM
|
|
300
|
+
// string to a Buffer, secureZeros the Buffer, and rebinds the
|
|
301
|
+
// property to "ZEROED" before the new keys land. The string copy
|
|
302
|
+
// inside V8 may still linger until GC; this just removes the
|
|
303
|
+
// largest-window heap copy (the ones held by `keys`).
|
|
304
|
+
function _zeroizeAndReplace(replacement) {
|
|
305
|
+
if (!keys) { keys = replacement; return; }
|
|
306
|
+
Object.keys(keys).forEach(function (k) {
|
|
307
|
+
var v = keys[k];
|
|
308
|
+
if (typeof v === "string" && v.length > 0) {
|
|
309
|
+
try {
|
|
310
|
+
var buf = Buffer.from(v, "utf8");
|
|
311
|
+
safeBuffer.secureZero(buf);
|
|
312
|
+
} catch (_e) { /* best-effort */ }
|
|
313
|
+
keys[k] = "ZEROED";
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
keys = replacement;
|
|
317
|
+
}
|
|
318
|
+
|
|
297
319
|
module.exports = {
|
|
298
320
|
init: init,
|
|
299
321
|
seal: seal,
|
|
300
322
|
unseal: unseal,
|
|
323
|
+
_zeroizeAndReplace: _zeroizeAndReplace,
|
|
301
324
|
aad: vaultAad,
|
|
302
325
|
getKeysJson: getKeysJson,
|
|
303
326
|
getCurrentPassphrase: getCurrentPassphrase,
|
package/package.json
CHANGED
package/sbom.cyclonedx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.5",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:a6849ba0-e669-440c-8a01-b08d37e28a1e",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-05-
|
|
8
|
+
"timestamp": "2026-05-07T17:22:17.744Z",
|
|
9
9
|
"lifecycles": [
|
|
10
10
|
{
|
|
11
11
|
"phase": "build"
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
}
|
|
20
20
|
],
|
|
21
21
|
"component": {
|
|
22
|
-
"bom-ref": "@blamejs/core@0.8.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.8.41",
|
|
23
23
|
"type": "library",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.8.
|
|
25
|
+
"version": "0.8.41",
|
|
26
26
|
"scope": "required",
|
|
27
27
|
"author": "blamejs contributors",
|
|
28
28
|
"description": "The Node framework that owns its stack.",
|
|
29
|
-
"purl": "pkg:npm/%40blamejs/core@0.8.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.8.41",
|
|
30
30
|
"properties": [],
|
|
31
31
|
"externalReferences": [
|
|
32
32
|
{
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"components": [],
|
|
55
55
|
"dependencies": [
|
|
56
56
|
{
|
|
57
|
-
"ref": "@blamejs/core@0.8.
|
|
57
|
+
"ref": "@blamejs/core@0.8.41",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|