@holo-js/security 0.1.4 → 0.1.6

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.
@@ -1,5 +1,8 @@
1
1
  // src/contracts.ts
2
- import { normalizeSecurityConfig } from "@holo-js/config";
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
- normalizeLimiterWindowSeconds(60, "Rate limiter decaySeconds")
56
+ 60
60
57
  );
61
58
  },
62
59
  perHour(maxAttempts) {
63
60
  return new PendingSecurityLimiterDefinition(
64
61
  normalizeLimiterAttempts(maxAttempts, "Rate limiter maxAttempts"),
65
- normalizeLimiterWindowSeconds(3600, "Rate limiter decaySeconds")
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
+ };