@holo-js/security 0.1.3 → 0.1.5
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/dist/{chunk-3J5QRTPZ.mjs → chunk-EWQKJSFA.mjs} +8 -11
- package/dist/chunk-FUOZWKHK.mjs +79 -0
- package/dist/chunk-Q3A7RJ67.mjs +1171 -0
- package/dist/client.d.ts +6 -11
- package/dist/client.mjs +10 -37
- package/dist/contracts.d.ts +17 -10
- package/dist/contracts.mjs +1 -1
- package/dist/drivers/redis-adapter.d.ts +2 -0
- package/dist/drivers/redis-adapter.mjs +32 -3
- package/dist/index.d.ts +62 -10
- package/dist/index.mjs +44 -866
- package/dist/next/server.d.ts +16 -0
- package/dist/next/server.mjs +84 -0
- package/dist/nuxt/server.d.ts +11 -0
- package/dist/nuxt/server.mjs +109 -0
- package/dist/sveltekit/server.d.ts +37 -0
- package/dist/sveltekit/server.mjs +68 -0
- package/package.json +31 -6
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// src/contracts.ts
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
normalizeCorsConfig,
|
|
4
|
+
normalizeSecurityConfig
|
|
5
|
+
} from "@holo-js/config";
|
|
3
6
|
var SecurityCsrfError = class extends Error {
|
|
4
7
|
status = 419;
|
|
5
8
|
constructor(message = "CSRF token mismatch.") {
|
|
@@ -46,23 +49,17 @@ function normalizeLimiterAttempts(value, label) {
|
|
|
46
49
|
}
|
|
47
50
|
return value;
|
|
48
51
|
}
|
|
49
|
-
function normalizeLimiterWindowSeconds(value, label) {
|
|
50
|
-
if (!Number.isInteger(value) || value < 1) {
|
|
51
|
-
throw new TypeError(`[@holo-js/security] ${label} must be an integer greater than or equal to 1.`);
|
|
52
|
-
}
|
|
53
|
-
return value;
|
|
54
|
-
}
|
|
55
52
|
var limit = Object.freeze({
|
|
56
53
|
perMinute(maxAttempts) {
|
|
57
54
|
return new PendingSecurityLimiterDefinition(
|
|
58
55
|
normalizeLimiterAttempts(maxAttempts, "Rate limiter maxAttempts"),
|
|
59
|
-
|
|
56
|
+
60
|
|
60
57
|
);
|
|
61
58
|
},
|
|
62
59
|
perHour(maxAttempts) {
|
|
63
60
|
return new PendingSecurityLimiterDefinition(
|
|
64
61
|
normalizeLimiterAttempts(maxAttempts, "Rate limiter maxAttempts"),
|
|
65
|
-
|
|
62
|
+
3600
|
|
66
63
|
);
|
|
67
64
|
}
|
|
68
65
|
});
|
|
@@ -116,6 +113,7 @@ function defineRateLimiter(definition) {
|
|
|
116
113
|
function defineSecurityRuntimeBindings(bindings) {
|
|
117
114
|
return Object.freeze({
|
|
118
115
|
config: normalizeSecurityConfig(bindings.config),
|
|
116
|
+
cors: normalizeCorsConfig(bindings.cors),
|
|
119
117
|
rateLimitStore: bindings.rateLimitStore,
|
|
120
118
|
csrfSigningKey: bindings.csrfSigningKey,
|
|
121
119
|
defaultKeyResolver: bindings.defaultKeyResolver
|
|
@@ -138,8 +136,7 @@ function createRedisRateLimitStoreConfig(config = {}) {
|
|
|
138
136
|
}
|
|
139
137
|
var securityInternals = {
|
|
140
138
|
PendingSecurityLimiterDefinition,
|
|
141
|
-
normalizeLimiterAttempts
|
|
142
|
-
normalizeLimiterWindowSeconds
|
|
139
|
+
normalizeLimiterAttempts
|
|
143
140
|
};
|
|
144
141
|
|
|
145
142
|
export {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// src/client-config.ts
|
|
2
|
+
var SECURITY_CLIENT_CONFIG_COOKIE = "HOLO-CSRF-CONFIG";
|
|
3
|
+
var DEFAULT_SECURITY_CLIENT_CONFIG = Object.freeze({
|
|
4
|
+
csrf: Object.freeze({
|
|
5
|
+
field: "_token",
|
|
6
|
+
cookie: "XSRF-TOKEN"
|
|
7
|
+
})
|
|
8
|
+
});
|
|
9
|
+
function safeDecodeCookieValue(value) {
|
|
10
|
+
try {
|
|
11
|
+
return decodeURIComponent(value);
|
|
12
|
+
} catch {
|
|
13
|
+
return void 0;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function parseCookieHeader(header) {
|
|
17
|
+
if (!header) {
|
|
18
|
+
return Object.freeze({});
|
|
19
|
+
}
|
|
20
|
+
const entries = header.split(";").map((segment) => segment.trim()).filter(Boolean).map((segment) => {
|
|
21
|
+
const separator = segment.indexOf("=");
|
|
22
|
+
if (separator <= 0) {
|
|
23
|
+
return void 0;
|
|
24
|
+
}
|
|
25
|
+
const name = safeDecodeCookieValue(segment.slice(0, separator));
|
|
26
|
+
const value = safeDecodeCookieValue(segment.slice(separator + 1));
|
|
27
|
+
return name && typeof value === "string" ? [name, value] : void 0;
|
|
28
|
+
}).filter((entry) => typeof entry !== "undefined");
|
|
29
|
+
return Object.freeze(Object.fromEntries(entries));
|
|
30
|
+
}
|
|
31
|
+
function isSecurityClientConfig(value) {
|
|
32
|
+
return !!value && typeof value === "object" && !!value.csrf && typeof value.csrf.field === "string" && typeof value.csrf.cookie === "string";
|
|
33
|
+
}
|
|
34
|
+
function getDefaultSecurityClientConfig() {
|
|
35
|
+
return DEFAULT_SECURITY_CLIENT_CONFIG;
|
|
36
|
+
}
|
|
37
|
+
function createSecurityClientConfig(config) {
|
|
38
|
+
return Object.freeze({
|
|
39
|
+
csrf: Object.freeze({
|
|
40
|
+
field: config.csrf.field,
|
|
41
|
+
cookie: config.csrf.cookie
|
|
42
|
+
})
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function serializeSecurityClientConfig(config) {
|
|
46
|
+
return JSON.stringify(config);
|
|
47
|
+
}
|
|
48
|
+
function readSecurityClientConfigFromCookies(cookieHeader) {
|
|
49
|
+
const raw = parseCookieHeader(cookieHeader)[SECURITY_CLIENT_CONFIG_COOKIE];
|
|
50
|
+
if (!raw) {
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const parsed = JSON.parse(raw);
|
|
55
|
+
if (!isSecurityClientConfig(parsed)) {
|
|
56
|
+
return void 0;
|
|
57
|
+
}
|
|
58
|
+
return Object.freeze({
|
|
59
|
+
csrf: Object.freeze({
|
|
60
|
+
field: parsed.csrf.field,
|
|
61
|
+
cookie: parsed.csrf.cookie
|
|
62
|
+
})
|
|
63
|
+
});
|
|
64
|
+
} catch {
|
|
65
|
+
return void 0;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
var securityClientConfigInternals = {
|
|
69
|
+
parseCookieHeader
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
SECURITY_CLIENT_CONFIG_COOKIE,
|
|
74
|
+
getDefaultSecurityClientConfig,
|
|
75
|
+
createSecurityClientConfig,
|
|
76
|
+
serializeSecurityClientConfig,
|
|
77
|
+
readSecurityClientConfigFromCookies,
|
|
78
|
+
securityClientConfigInternals
|
|
79
|
+
};
|