@blamejs/core 0.7.107 → 0.8.4
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 +41 -1
- package/NOTICE +17 -1
- package/README.md +4 -3
- package/index.js +15 -0
- package/lib/asyncapi-bindings.js +160 -0
- package/lib/asyncapi-traits.js +143 -0
- package/lib/asyncapi.js +531 -0
- package/lib/audit-sign.js +1 -1
- package/lib/audit.js +68 -2
- package/lib/auth/acr-vocabulary.js +265 -0
- package/lib/auth/auth-time-tracker.js +111 -0
- package/lib/auth/elevation-grant.js +306 -0
- package/lib/auth/jwt.js +13 -0
- package/lib/auth/lockout.js +16 -3
- package/lib/auth/oauth.js +15 -1
- package/lib/auth/password.js +22 -2
- package/lib/auth/sd-jwt-vc-issuer.js +2 -2
- package/lib/auth/sd-jwt-vc.js +7 -2
- package/lib/auth/step-up-policy.js +335 -0
- package/lib/auth/step-up.js +445 -0
- package/lib/break-glass.js +53 -14
- package/lib/cache-redis.js +1 -1
- package/lib/cache.js +6 -1
- package/lib/cli.js +3 -3
- package/lib/cluster.js +24 -1
- package/lib/compliance-ai-act-logging.js +190 -0
- package/lib/compliance-ai-act-prohibited.js +205 -0
- package/lib/compliance-ai-act-risk.js +189 -0
- package/lib/compliance-ai-act-transparency.js +200 -0
- package/lib/compliance-ai-act.js +558 -0
- package/lib/compliance.js +12 -2
- package/lib/config-drift.js +2 -2
- package/lib/crypto-field.js +21 -1
- package/lib/crypto.js +114 -1
- package/lib/db.js +35 -4
- package/lib/dev.js +30 -3
- package/lib/dual-control.js +19 -1
- package/lib/external-db.js +10 -0
- package/lib/file-upload.js +30 -3
- package/lib/flag-cache.js +136 -0
- package/lib/flag-evaluation-context.js +135 -0
- package/lib/flag-providers.js +279 -0
- package/lib/flag-targeting.js +210 -0
- package/lib/flag.js +284 -0
- package/lib/guard-all.js +33 -16
- package/lib/guard-csv.js +16 -2
- package/lib/guard-html.js +35 -0
- package/lib/guard-svg.js +20 -0
- package/lib/http-client.js +57 -11
- package/lib/inbox.js +391 -0
- package/lib/log-stream-syslog.js +8 -0
- package/lib/log-stream.js +1 -1
- package/lib/mail-arc-sign.js +372 -0
- package/lib/mail-auth.js +2 -0
- package/lib/mail.js +40 -0
- package/lib/middleware/ai-act-disclosure.js +166 -0
- package/lib/middleware/asyncapi-serve.js +136 -0
- package/lib/middleware/attach-user.js +25 -2
- package/lib/middleware/bearer-auth.js +71 -6
- package/lib/middleware/body-parser.js +13 -0
- package/lib/middleware/cors.js +10 -0
- package/lib/middleware/csrf-protect.js +34 -3
- package/lib/middleware/dpop.js +3 -3
- package/lib/middleware/flag-context.js +76 -0
- package/lib/middleware/host-allowlist.js +1 -1
- package/lib/middleware/index.js +15 -0
- package/lib/middleware/openapi-serve.js +143 -0
- package/lib/middleware/require-aal.js +2 -2
- package/lib/middleware/require-step-up.js +186 -0
- package/lib/middleware/trace-propagate.js +1 -1
- package/lib/mtls-ca.js +23 -29
- package/lib/mtls-engine-default.js +21 -1
- package/lib/network-tls.js +21 -6
- package/lib/object-store/sigv4-bucket-ops.js +41 -0
- package/lib/observability-otlp-exporter.js +35 -2
- package/lib/openapi-paths-builder.js +248 -0
- package/lib/openapi-schema-walk.js +192 -0
- package/lib/openapi-security.js +169 -0
- package/lib/openapi-yaml.js +154 -0
- package/lib/openapi.js +443 -0
- package/lib/outbox.js +3 -3
- package/lib/permissions.js +10 -1
- package/lib/pqc-agent.js +22 -1
- package/lib/pqc-software.js +195 -0
- package/lib/pubsub.js +8 -4
- package/lib/redact.js +26 -1
- package/lib/retention.js +26 -0
- package/lib/router.js +1 -0
- package/lib/scheduler.js +57 -1
- package/lib/session.js +3 -3
- package/lib/ssrf-guard.js +19 -4
- package/lib/static.js +12 -0
- package/lib/totp.js +16 -0
- package/lib/vault/index.js +3 -0
- package/lib/vault-aad.js +259 -0
- package/lib/vendor/MANIFEST.json +29 -0
- package/lib/vendor/noble-post-quantum.cjs +18 -0
- package/lib/ws-client.js +978 -0
- package/package.json +1 -1
- package/sbom.cyclonedx.json +6 -6
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* EU AI Act Article 50 — transparency obligations.
|
|
4
|
+
*
|
|
5
|
+
* Per Regulation (EU) 2024/1689 Art. 50, providers / deployers of
|
|
6
|
+
* certain AI systems must inform end-users that they are interacting
|
|
7
|
+
* with an AI system, OR that content was AI-generated, OR that AI
|
|
8
|
+
* detected emotions / biometric attributes. Effective 2026-08-02.
|
|
9
|
+
*
|
|
10
|
+
* Four obligations:
|
|
11
|
+
*
|
|
12
|
+
* §1 — AI systems intended to interact directly with natural
|
|
13
|
+
* persons MUST disclose to the user that they are interacting
|
|
14
|
+
* with AI (unless this is obvious from context).
|
|
15
|
+
*
|
|
16
|
+
* §2 — Providers of GPAI / generative AI systems generating synthetic
|
|
17
|
+
* audio / image / video / text MUST mark the output as
|
|
18
|
+
* artificially generated or manipulated, in a machine-readable
|
|
19
|
+
* format and detectable as such.
|
|
20
|
+
*
|
|
21
|
+
* §3 — Deployers of emotion-recognition or biometric categorisation
|
|
22
|
+
* systems MUST inform exposed natural persons.
|
|
23
|
+
*
|
|
24
|
+
* §4 — Deployers generating / manipulating image / audio / video
|
|
25
|
+
* constituting a deep fake MUST disclose that the content is
|
|
26
|
+
* artificially generated. Deployers generating / manipulating
|
|
27
|
+
* text published to inform on matters of public interest MUST
|
|
28
|
+
* disclose that the text is AI-generated, unless reviewed by a
|
|
29
|
+
* human editor with editorial responsibility.
|
|
30
|
+
*
|
|
31
|
+
* The framework provides:
|
|
32
|
+
*
|
|
33
|
+
* - banner({ kind }) → builder for the standard disclosure banner
|
|
34
|
+
* - watermark({ kind, ... }) → builder for content-marking tags
|
|
35
|
+
* - cspMetaTag({ ... }) → meta tag pair for HTML pages
|
|
36
|
+
* - jsonLdDisclosure({ ... }) → JSON-LD <script> for structured-data emit
|
|
37
|
+
* - C2pa-stub → operator-feeds-claims pattern for
|
|
38
|
+
* C2PA Content Credentials integration
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
var validateOpts = require("./validate-opts");
|
|
42
|
+
var { ComplianceError } = require("./framework-error");
|
|
43
|
+
|
|
44
|
+
var BANNER_KINDS = Object.freeze([
|
|
45
|
+
"ai-interaction", // Art. 50(1)
|
|
46
|
+
"ai-generated-content", // Art. 50(2) / 50(4)
|
|
47
|
+
"emotion-recognition", // Art. 50(3)
|
|
48
|
+
"biometric-categorisation", // Art. 50(3)
|
|
49
|
+
"deep-fake", // Art. 50(4)
|
|
50
|
+
"ai-text-public-interest", // Art. 50(4) text variant
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
var BANNER_TEXT_EN = Object.freeze({
|
|
54
|
+
"ai-interaction": "You are interacting with an AI system.",
|
|
55
|
+
"ai-generated-content": "This content was generated or modified by AI.",
|
|
56
|
+
"emotion-recognition": "This system uses AI to recognise emotional state.",
|
|
57
|
+
"biometric-categorisation": "This system uses AI biometric categorisation.",
|
|
58
|
+
"deep-fake": "This media was generated or modified by AI (deep-fake).",
|
|
59
|
+
"ai-text-public-interest": "This text was generated by AI on a matter of public interest.",
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
function banner(opts) {
|
|
63
|
+
opts = opts || {};
|
|
64
|
+
validateOpts(opts, [
|
|
65
|
+
"kind", "lang", "deployerName", "controllerContact",
|
|
66
|
+
"linkPolicy", "linkContact",
|
|
67
|
+
], "compliance.aiAct.transparency.banner");
|
|
68
|
+
if (BANNER_KINDS.indexOf(opts.kind) === -1) {
|
|
69
|
+
throw new ComplianceError("compliance-ai-act/bad-banner-kind",
|
|
70
|
+
"transparency.banner: kind must be one of " + BANNER_KINDS.join(", ") +
|
|
71
|
+
" — got " + JSON.stringify(opts.kind));
|
|
72
|
+
}
|
|
73
|
+
var lang = (typeof opts.lang === "string" && opts.lang.length > 0) ? opts.lang : "en";
|
|
74
|
+
var text = BANNER_TEXT_EN[opts.kind];
|
|
75
|
+
// Operators with a non-en lang supply their own translation via the
|
|
76
|
+
// returned object — the framework only ships en defaults for now.
|
|
77
|
+
var out = {
|
|
78
|
+
kind: opts.kind,
|
|
79
|
+
lang: lang,
|
|
80
|
+
text: text,
|
|
81
|
+
article: _articleFor(opts.kind),
|
|
82
|
+
};
|
|
83
|
+
if (typeof opts.deployerName === "string" && opts.deployerName.length > 0) {
|
|
84
|
+
out.deployerName = opts.deployerName;
|
|
85
|
+
}
|
|
86
|
+
if (typeof opts.controllerContact === "string" && opts.controllerContact.length > 0) {
|
|
87
|
+
out.controllerContact = opts.controllerContact;
|
|
88
|
+
}
|
|
89
|
+
if (typeof opts.linkPolicy === "string" && opts.linkPolicy.length > 0) {
|
|
90
|
+
out.linkPolicy = opts.linkPolicy;
|
|
91
|
+
}
|
|
92
|
+
if (typeof opts.linkContact === "string" && opts.linkContact.length > 0) {
|
|
93
|
+
out.linkContact = opts.linkContact;
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function _articleFor(kind) {
|
|
99
|
+
switch (kind) {
|
|
100
|
+
case "ai-interaction": return "Art. 50(1)";
|
|
101
|
+
case "ai-generated-content": return "Art. 50(2)";
|
|
102
|
+
case "emotion-recognition": return "Art. 50(3)";
|
|
103
|
+
case "biometric-categorisation": return "Art. 50(3)";
|
|
104
|
+
case "deep-fake": return "Art. 50(4)";
|
|
105
|
+
case "ai-text-public-interest": return "Art. 50(4)";
|
|
106
|
+
default: return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function htmlBanner(opts) {
|
|
111
|
+
var b = banner(opts);
|
|
112
|
+
var attrs =
|
|
113
|
+
'role="status" data-blamejs-aiAct="' + b.article +
|
|
114
|
+
'" data-blamejs-kind="' + b.kind +
|
|
115
|
+
'" lang="' + b.lang + '"';
|
|
116
|
+
return '<div ' + attrs + '>' + _escapeHtml(b.text) + '</div>';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function _escapeHtml(s) {
|
|
120
|
+
if (typeof s !== "string") return "";
|
|
121
|
+
return s.replace(/&/g, "&")
|
|
122
|
+
.replace(/</g, "<")
|
|
123
|
+
.replace(/>/g, ">")
|
|
124
|
+
.replace(/"/g, """);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Watermark builder for Art. 50(2). Operators integrate with C2PA /
|
|
128
|
+
// SynthID / SoundID / hidden-watermark schemes; the framework emits a
|
|
129
|
+
// machine-readable manifest fragment that downstream tooling can attach
|
|
130
|
+
// or hash into the asset.
|
|
131
|
+
function watermark(opts) {
|
|
132
|
+
opts = opts || {};
|
|
133
|
+
validateOpts(opts, [
|
|
134
|
+
"mediaKind", "modelId", "modelVersion", "createdAt", "promptHash",
|
|
135
|
+
"manipulation", "deployerName", "encoding",
|
|
136
|
+
], "compliance.aiAct.transparency.watermark");
|
|
137
|
+
if (typeof opts.mediaKind !== "string" ||
|
|
138
|
+
["image", "audio", "video", "text"].indexOf(opts.mediaKind) === -1) {
|
|
139
|
+
throw new ComplianceError("compliance-ai-act/bad-watermark",
|
|
140
|
+
"transparency.watermark: mediaKind must be one of image/audio/video/text — got " +
|
|
141
|
+
JSON.stringify(opts.mediaKind));
|
|
142
|
+
}
|
|
143
|
+
validateOpts.requireNonEmptyString(opts.modelId,
|
|
144
|
+
"transparency.watermark: modelId", ComplianceError, "compliance-ai-act/bad-watermark");
|
|
145
|
+
var manifest = {
|
|
146
|
+
"@context": "https://blamejs.com/schemas/ai-act-watermark/v1",
|
|
147
|
+
aiActArticle: "Art. 50(2)",
|
|
148
|
+
mediaKind: opts.mediaKind,
|
|
149
|
+
modelId: opts.modelId,
|
|
150
|
+
modelVersion: opts.modelVersion || null,
|
|
151
|
+
createdAt: opts.createdAt || new Date().toISOString(),
|
|
152
|
+
promptHash: opts.promptHash || null,
|
|
153
|
+
manipulation: opts.manipulation === true ? true : false,
|
|
154
|
+
deployerName: opts.deployerName || null,
|
|
155
|
+
encoding: opts.encoding || "json",
|
|
156
|
+
};
|
|
157
|
+
return manifest;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function jsonLdDisclosure(opts) {
|
|
161
|
+
var w = watermark(opts);
|
|
162
|
+
var script = '<script type="application/ld+json" ' +
|
|
163
|
+
'data-blamejs-aiAct="Art. 50(2)">' +
|
|
164
|
+
JSON.stringify(w) + '</script>';
|
|
165
|
+
return script;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// CSP-meta-tag pair for HTML pages — the disclosure-policy URI plus
|
|
169
|
+
// the AI-Act-Notice header are emitted as <meta> equivalents so static
|
|
170
|
+
// renderers can include them.
|
|
171
|
+
function metaTags(opts) {
|
|
172
|
+
opts = opts || {};
|
|
173
|
+
validateOpts(opts, [
|
|
174
|
+
"kind", "policyUri", "deployerName",
|
|
175
|
+
], "compliance.aiAct.transparency.metaTags");
|
|
176
|
+
if (BANNER_KINDS.indexOf(opts.kind) === -1) {
|
|
177
|
+
throw new ComplianceError("compliance-ai-act/bad-banner-kind",
|
|
178
|
+
"transparency.metaTags: kind must be one of " + BANNER_KINDS.join(", "));
|
|
179
|
+
}
|
|
180
|
+
var out = [];
|
|
181
|
+
out.push('<meta name="ai-act-notice" content="' + _escapeHtml(opts.kind) + '">');
|
|
182
|
+
out.push('<meta name="ai-act-article" content="' + _escapeHtml(_articleFor(opts.kind)) + '">');
|
|
183
|
+
if (typeof opts.policyUri === "string" && opts.policyUri.length > 0) {
|
|
184
|
+
out.push('<link rel="ai-act-policy" href="' + _escapeHtml(opts.policyUri) + '">');
|
|
185
|
+
}
|
|
186
|
+
if (typeof opts.deployerName === "string" && opts.deployerName.length > 0) {
|
|
187
|
+
out.push('<meta name="ai-act-deployer" content="' + _escapeHtml(opts.deployerName) + '">');
|
|
188
|
+
}
|
|
189
|
+
return out.join("\n");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
module.exports = {
|
|
193
|
+
BANNER_KINDS: BANNER_KINDS,
|
|
194
|
+
BANNER_TEXT_EN: BANNER_TEXT_EN,
|
|
195
|
+
banner: banner,
|
|
196
|
+
htmlBanner: htmlBanner,
|
|
197
|
+
watermark: watermark,
|
|
198
|
+
jsonLdDisclosure: jsonLdDisclosure,
|
|
199
|
+
metaTags: metaTags,
|
|
200
|
+
};
|