fiberx-backend-toolkit 0.0.74 → 0.0.76

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.
@@ -16,7 +16,36 @@ export declare const DEVICE_ID_COOKIE_MAX_AGE: number;
16
16
  export declare const DEVICE_ID_COOKIE_NAME = "device_id";
17
17
  export declare const DEVICE_ID_HEADERS_NAME = "X-Device-Id";
18
18
  export declare const CORS_ALLOWED_METHODS: string[];
19
- export declare const CORS_ALLOWED_HEADERS: string[];
19
+ export declare const HEADERS_KEY_NAME: {
20
+ readonly content_type: "Content-Type";
21
+ readonly authorization: "Authorization";
22
+ readonly user_agent: "User-Agent";
23
+ readonly origin: "Origin";
24
+ readonly vary: "Vary";
25
+ readonly device_id: "X-Device-Id";
26
+ readonly device_name: "X-Device-Name";
27
+ readonly request_id: "X-Request-Id";
28
+ readonly rate_limit_limit: "X-RateLimit-Limit";
29
+ readonly rate_limit_remaining: "X-RateLimit-Remaining";
30
+ readonly rate_limit_reset: "X-RateLimit-Reset";
31
+ readonly rate_limit_retry_after: "X-RateLimit-Retry-After";
32
+ readonly login_challenge_token: "X-Login-Challenge-Token";
33
+ readonly csrf_token_header: "X-CSRF-Token";
34
+ readonly access_control_allow_origin: "Access-Control-Allow-Origin";
35
+ readonly access_control_allow_methods: "Access-Control-Allow-Methods";
36
+ readonly access_control_allow_headers: "Access-Control-Allow-Headers";
37
+ readonly access_control_allow_credentials: "Access-Control-Allow-Credentials";
38
+ readonly access_control_max_age: "Access-Control-Max-Age";
39
+ readonly xss_protection: "X-XSS-Protection";
40
+ readonly content_type_options: "X-Content-Type-Options";
41
+ readonly frame_options: "X-Frame-Options";
42
+ readonly referrer_policy: "Referrer-Policy";
43
+ readonly content_security_policy: "Content-Security-Policy";
44
+ readonly strict_transport_security: "Strict-Transport-Security";
45
+ readonly cross_origin_resource_policy: "Cross-Origin-Resource-Policy";
46
+ readonly cross_origin_opener_policy: "Cross-Origin-Opener-Policy";
47
+ };
48
+ export declare const CORS_ALLOWED_HEADERS: ("X-Request-Id" | "X-Device-Id" | "Content-Type" | "Authorization" | "User-Agent" | "Origin" | "Vary" | "X-Device-Name" | "X-RateLimit-Limit" | "X-RateLimit-Remaining" | "X-RateLimit-Reset" | "X-Login-Challenge-Token" | "X-CSRF-Token" | "Access-Control-Allow-Origin" | "Access-Control-Allow-Methods" | "Access-Control-Allow-Headers" | "Access-Control-Allow-Credentials" | "Access-Control-Max-Age")[];
20
49
  export declare const CORS_MAX_AGE_IN_SECONDS = 600;
21
50
  export declare const CORS_MAX_AGE_IN_MICRO_SECONDS: number;
22
51
  export declare const REQUEST_RATE_LIMITTER_OPTIONS: {
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DEFAULT_CONTENT_CACHE_TTL = exports.DEFAULT_CONTENT_LANG = exports.DEFAULT_CONTENT_URL = exports.CONTENT_LANG_KEY = exports.CONTENT_URL_KEY = exports.CONTENT_CACHE_TTL_KEY = exports.EMAIL_ENQUEUE_UTIL_FILE_NAME = exports.EMAIL_ENQUEUE_TYPES_FILE_NAME = exports.DEFAULT_RBAC_CACHE_TTL = exports.DEFAULT_RBAC_CACHE_KEY = exports.DEFAULT_TOTP_WINDOW = exports.DEFAULT_TOTP_DIGITS = exports.DEFAULT_TOTP_STEP = exports.ALPHABET_CORPUS = exports.CHARACTER_CORPUS = exports.REQUEST_RATE_LIMITTER_OPTIONS = exports.CORS_MAX_AGE_IN_MICRO_SECONDS = exports.CORS_MAX_AGE_IN_SECONDS = exports.CORS_ALLOWED_HEADERS = exports.CORS_ALLOWED_METHODS = exports.DEVICE_ID_HEADERS_NAME = exports.DEVICE_ID_COOKIE_NAME = exports.DEVICE_ID_COOKIE_MAX_AGE = exports.REQUEST_ID_HEADERS_NAME = exports.REQUEST_ID_COOKIE_NAME = exports.REQUEST_ID_COOKIE_MAX_AGE = exports.SEQUELIZE_SEEDER_META_TABLE_NAME = exports.SEQUELIZE_META_TABLE_NAME = exports.EMAIL_ENQUEUE_DIR = exports.SEEDERS_DIR = exports.MIGRATIONS_DIR = exports.MODELS_DIR = exports.SCHEMA_SNAPSHOTS_DIR = exports.SCHEMAS_DIR = exports.ENV_VAR_DIR = exports.LOG_DIR = exports.BASE_DIR = void 0;
6
+ exports.DEFAULT_CONTENT_CACHE_TTL = exports.DEFAULT_CONTENT_LANG = exports.DEFAULT_CONTENT_URL = exports.CONTENT_LANG_KEY = exports.CONTENT_URL_KEY = exports.CONTENT_CACHE_TTL_KEY = exports.EMAIL_ENQUEUE_UTIL_FILE_NAME = exports.EMAIL_ENQUEUE_TYPES_FILE_NAME = exports.DEFAULT_RBAC_CACHE_TTL = exports.DEFAULT_RBAC_CACHE_KEY = exports.DEFAULT_TOTP_WINDOW = exports.DEFAULT_TOTP_DIGITS = exports.DEFAULT_TOTP_STEP = exports.ALPHABET_CORPUS = exports.CHARACTER_CORPUS = exports.REQUEST_RATE_LIMITTER_OPTIONS = exports.CORS_MAX_AGE_IN_MICRO_SECONDS = exports.CORS_MAX_AGE_IN_SECONDS = exports.CORS_ALLOWED_HEADERS = exports.HEADERS_KEY_NAME = exports.CORS_ALLOWED_METHODS = exports.DEVICE_ID_HEADERS_NAME = exports.DEVICE_ID_COOKIE_NAME = exports.DEVICE_ID_COOKIE_MAX_AGE = exports.REQUEST_ID_HEADERS_NAME = exports.REQUEST_ID_COOKIE_NAME = exports.REQUEST_ID_COOKIE_MAX_AGE = exports.SEQUELIZE_SEEDER_META_TABLE_NAME = exports.SEQUELIZE_META_TABLE_NAME = exports.EMAIL_ENQUEUE_DIR = exports.SEEDERS_DIR = exports.MIGRATIONS_DIR = exports.MODELS_DIR = exports.SCHEMA_SNAPSHOTS_DIR = exports.SCHEMAS_DIR = exports.ENV_VAR_DIR = exports.LOG_DIR = exports.BASE_DIR = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  exports.BASE_DIR = process.cwd();
9
9
  exports.LOG_DIR = path_1.default.join(exports.BASE_DIR, "logs");
@@ -24,7 +24,76 @@ exports.DEVICE_ID_COOKIE_NAME = "device_id";
24
24
  exports.DEVICE_ID_HEADERS_NAME = "X-Device-Id";
25
25
  // CORS constants
26
26
  exports.CORS_ALLOWED_METHODS = ["GET", "POST", "PATCH", "DELETE", "OPTIONS"];
27
- exports.CORS_ALLOWED_HEADERS = ["Content-Type", "Authorization", exports.REQUEST_ID_HEADERS_NAME, exports.DEVICE_ID_HEADERS_NAME, "X-Device-Name", "User-Agent"];
27
+ exports.HEADERS_KEY_NAME = {
28
+ // ======================
29
+ // Standard Headers
30
+ // ======================
31
+ content_type: "Content-Type",
32
+ authorization: "Authorization",
33
+ user_agent: "User-Agent",
34
+ origin: "Origin",
35
+ vary: "Vary",
36
+ // ======================
37
+ // Device
38
+ // ======================
39
+ device_id: "X-Device-Id",
40
+ device_name: "X-Device-Name",
41
+ // ======================
42
+ // Request Tracking
43
+ // ======================
44
+ request_id: "X-Request-Id",
45
+ // ======================
46
+ // Rate limit
47
+ // ======================
48
+ rate_limit_limit: "X-RateLimit-Limit",
49
+ rate_limit_remaining: "X-RateLimit-Remaining",
50
+ rate_limit_reset: "X-RateLimit-Reset",
51
+ rate_limit_retry_after: "X-RateLimit-Retry-After",
52
+ // ======================
53
+ // Auth / Security
54
+ // ======================
55
+ login_challenge_token: "X-Login-Challenge-Token",
56
+ csrf_token_header: "X-CSRF-Token",
57
+ // ======================
58
+ // CORS Headers
59
+ // ======================
60
+ access_control_allow_origin: "Access-Control-Allow-Origin",
61
+ access_control_allow_methods: "Access-Control-Allow-Methods",
62
+ access_control_allow_headers: "Access-Control-Allow-Headers",
63
+ access_control_allow_credentials: "Access-Control-Allow-Credentials",
64
+ access_control_max_age: "Access-Control-Max-Age",
65
+ // ======================
66
+ // Secure Headers
67
+ // ======================
68
+ xss_protection: "X-XSS-Protection",
69
+ content_type_options: "X-Content-Type-Options",
70
+ frame_options: "X-Frame-Options",
71
+ referrer_policy: "Referrer-Policy",
72
+ content_security_policy: "Content-Security-Policy",
73
+ strict_transport_security: "Strict-Transport-Security",
74
+ cross_origin_resource_policy: "Cross-Origin-Resource-Policy",
75
+ cross_origin_opener_policy: "Cross-Origin-Opener-Policy",
76
+ };
77
+ exports.CORS_ALLOWED_HEADERS = [
78
+ exports.HEADERS_KEY_NAME.content_type,
79
+ exports.HEADERS_KEY_NAME.authorization,
80
+ exports.HEADERS_KEY_NAME.user_agent,
81
+ exports.HEADERS_KEY_NAME.origin,
82
+ exports.HEADERS_KEY_NAME.vary,
83
+ exports.HEADERS_KEY_NAME.device_id,
84
+ exports.HEADERS_KEY_NAME.device_name,
85
+ exports.HEADERS_KEY_NAME.request_id,
86
+ exports.HEADERS_KEY_NAME.rate_limit_limit,
87
+ exports.HEADERS_KEY_NAME.rate_limit_remaining,
88
+ exports.HEADERS_KEY_NAME.rate_limit_reset,
89
+ exports.HEADERS_KEY_NAME.login_challenge_token,
90
+ exports.HEADERS_KEY_NAME.csrf_token_header,
91
+ exports.HEADERS_KEY_NAME.access_control_allow_origin,
92
+ exports.HEADERS_KEY_NAME.access_control_allow_methods,
93
+ exports.HEADERS_KEY_NAME.access_control_allow_headers,
94
+ exports.HEADERS_KEY_NAME.access_control_allow_credentials,
95
+ exports.HEADERS_KEY_NAME.access_control_max_age,
96
+ ];
28
97
  exports.CORS_MAX_AGE_IN_SECONDS = (600); // default: 10 min
29
98
  exports.CORS_MAX_AGE_IN_MICRO_SECONDS = (1000 * 60 * 10); // 10 minutes
30
99
  // Rate limitter
@@ -12,7 +12,7 @@ declare class CookieManagerMiddleWare {
12
12
  private device_id_cookie_name;
13
13
  private device_id_header_name;
14
14
  private device_id_generator;
15
- constructor(options?: CookieManagerOptions);
15
+ constructor(options: CookieManagerOptions);
16
16
  private getDefaultCookieOptions;
17
17
  private handleRequestId;
18
18
  private handleDeviceId;
@@ -27,7 +27,7 @@ class CookieManagerMiddleWare {
27
27
  device_id_cookie_name;
28
28
  device_id_header_name;
29
29
  device_id_generator;
30
- constructor(options = {}) {
30
+ constructor(options) {
31
31
  this.request_id_max_age = options?.request_id_max_age || constants_1.REQUEST_ID_COOKIE_MAX_AGE;
32
32
  this.request_id_cookie_name = options.request_id_cookie_name || constants_1.REQUEST_ID_COOKIE_NAME;
33
33
  this.request_id_header_name = options.request_id_header_name || constants_1.REQUEST_ID_HEADERS_NAME;
@@ -50,7 +50,7 @@ class CookieManagerMiddleWare {
50
50
  }
51
51
  // Method to Ensure request_id exists + rolling expiration
52
52
  handleRequestId(req, res) {
53
- let request_id = this.get(req, "request_id");
53
+ let request_id = this.get(req, this.request_id_cookie_name);
54
54
  if (!request_id) {
55
55
  request_id = this.request_id_generator();
56
56
  this.logger.info(`Generated request_id: ${request_id}`);
@@ -59,7 +59,7 @@ class CookieManagerMiddleWare {
59
59
  this.set(res, "request_id", request_id, {
60
60
  max_age: this.request_id_max_age,
61
61
  });
62
- res.setHeader("X-Request-Id", request_id);
62
+ res.setHeader(this.request_id_header_name, request_id);
63
63
  return request_id;
64
64
  }
65
65
  // Method to Ensure device_id exists (long-lived)
@@ -6,6 +6,7 @@ declare class CorsMiddleWare {
6
6
  private origin_cache;
7
7
  private origins;
8
8
  private methods;
9
+ private headers_key_name;
9
10
  private headers;
10
11
  private credentials;
11
12
  private max_age;
@@ -17,57 +17,53 @@ class CorsMiddleWare {
17
17
  origin_cache = new main_1.InMemoryCacheUtil();
18
18
  origins;
19
19
  methods;
20
+ headers_key_name;
20
21
  headers;
21
22
  credentials;
22
23
  max_age;
23
24
  allow_null_origin;
24
25
  origin_resolver;
25
26
  constructor(options = {}) {
26
- this.origins = options.origins || [];
27
+ this.origins = options.origins ?? [];
27
28
  this.methods = options.methods ?? constants_1.CORS_ALLOWED_METHODS;
28
- this.headers = options.headers ?? constants_1.CORS_ALLOWED_HEADERS;
29
29
  this.credentials = options.credentials ?? true;
30
30
  this.max_age = options.max_age ?? constants_1.CORS_MAX_AGE_IN_SECONDS;
31
- this.allow_null_origin = options.allow_null_origin ?? false,
32
- this.origin_resolver = options?.origin_resolver || null;
31
+ this.headers_key_name = options.headers_key_name ?? constants_1.HEADERS_KEY_NAME;
32
+ this.allow_null_origin = options.allow_null_origin ?? false;
33
+ this.origin_resolver = options.origin_resolver ?? null;
34
+ // generate headers array dynamically from the key names
35
+ this.headers = Object.values(this.headers_key_name);
33
36
  main_1.SafeExecuteUtil.setNamedInstance(this.name, this);
34
37
  }
35
- // Method for Origin resolution logic
38
+ // -------------------------
39
+ // Origin resolution
40
+ // -------------------------
36
41
  async resolveAllowedOrigins() {
37
- if (Array.isArray(this.origins) && this.origins.length) {
42
+ if (Array.isArray(this.origins) && this.origins.length)
38
43
  return this.origins;
39
- }
40
- else if (this.origin_resolver && typeof this.origin_resolver === "function") {
44
+ if (this.origin_resolver) {
41
45
  const result = await this.origin_resolver();
42
46
  return Array.isArray(result) ? result : [];
43
47
  }
44
48
  return [];
45
49
  }
46
- // Method to validate origin
47
50
  async isValidOrigin(origin) {
48
- if (!origin) {
51
+ if (!origin)
49
52
  return this.allow_null_origin;
50
- }
51
- // Cached
52
- if (this.origin_cache.has(origin)) {
53
+ if (this.origin_cache.has(origin))
53
54
  return true;
54
- }
55
- // Function validator
56
- else if (this.origin_resolver && typeof this.origin_resolver === "function") {
55
+ if (this.origin_resolver) {
57
56
  const result = await this.origin_resolver(origin);
58
57
  if (typeof result === "boolean") {
59
- if (result) {
58
+ if (result)
60
59
  this.origin_cache.set(origin, true, constants_1.CORS_MAX_AGE_IN_MICRO_SECONDS);
61
- }
62
60
  return result;
63
61
  }
64
62
  }
65
- // List validator
66
63
  const allowed = await this.resolveAllowedOrigins();
67
64
  const is_valid = allowed.includes(origin);
68
- if (is_valid) {
65
+ if (is_valid)
69
66
  this.origin_cache.set(origin, true, constants_1.CORS_MAX_AGE_IN_MICRO_SECONDS);
70
- }
71
67
  return is_valid;
72
68
  }
73
69
  // -------------------------
@@ -75,13 +71,12 @@ class CorsMiddleWare {
75
71
  // -------------------------
76
72
  async getRequestOrigin(req) {
77
73
  const { headers, protocol } = req;
78
- if (headers?.origin) {
79
- return headers?.origin;
80
- }
81
- else if (headers?.referer) {
74
+ const originHeader = headers?.[this.headers_key_name.origin.toLowerCase()];
75
+ if (originHeader)
76
+ return originHeader;
77
+ if (headers?.referer)
82
78
  return new URL(headers.referer).origin;
83
- }
84
- return `${protocol}://${req?.get('host')}`;
79
+ return `${protocol}://${req.get("host")}`;
85
80
  }
86
81
  // -------------------------
87
82
  // Middleware
@@ -89,26 +84,25 @@ class CorsMiddleWare {
89
84
  async middleWare(req, res, next) {
90
85
  const origin = await this.getRequestOrigin(req);
91
86
  const is_allowed = await this.isValidOrigin(origin);
92
- res.setHeader("Vary", "Origin");
87
+ res.setHeader(this.headers_key_name.vary, this.headers_key_name.origin);
93
88
  if (!is_allowed) {
94
89
  this.logger.error(`Blocked CORS request from origin: ${origin}`);
95
90
  return res.status(403).json({ status: "error", code: 403, msg: "cors_blocked" });
96
91
  }
97
- res.setHeader("Access-Control-Allow-Origin", origin);
98
- res.setHeader("Access-Control-Allow-Methods", this.methods.join(","));
99
- res.setHeader("Access-Control-Allow-Headers", this.headers.join(","));
92
+ // Use constants from this.headers_key_name
93
+ res.setHeader(this.headers_key_name.access_control_allow_origin, origin);
94
+ res.setHeader(this.headers_key_name.access_control_allow_methods, this.methods.join(","));
95
+ res.setHeader(this.headers_key_name.access_control_allow_headers, this.headers.join(","));
100
96
  if (this.credentials) {
101
- res.setHeader("Access-Control-Allow-Credentials", "true");
97
+ res.setHeader(this.headers_key_name.access_control_allow_credentials, "true");
102
98
  }
103
99
  if (this.max_age) {
104
- res.setHeader("Access-Control-Max-Age", this.max_age.toString());
100
+ res.setHeader(this.headers_key_name.access_control_max_age, this.max_age.toString());
105
101
  }
106
- if (req.method === "OPTIONS") {
102
+ if (req.method === "OPTIONS")
107
103
  return res.sendStatus(204);
108
- }
109
104
  return next();
110
105
  }
111
- ;
112
106
  }
113
107
  __decorate([
114
108
  main_1.SafeExecuteUtil.safeExecuteReturn("cors_middle_ware", []),
@@ -8,6 +8,7 @@ declare class RateLimiterMiddleWare {
8
8
  private cache;
9
9
  private logger;
10
10
  private key_generator;
11
+ private headers_key_name;
11
12
  constructor(options?: RateLimiterOptions);
12
13
  private generateRequestIdentitfier;
13
14
  private getResetSeconds;
@@ -19,10 +19,12 @@ class RateLimiterMiddleWare {
19
19
  cache;
20
20
  logger;
21
21
  key_generator;
22
+ headers_key_name;
22
23
  constructor(options = {}) {
23
24
  this.window_ms = options?.window_ms ?? constants_1.REQUEST_RATE_LIMITTER_OPTIONS.window_ms;
24
25
  this.max_requests = options?.max_requests ?? constants_1.REQUEST_RATE_LIMITTER_OPTIONS.max_requests;
25
26
  this.message = options.message ?? constants_1.REQUEST_RATE_LIMITTER_OPTIONS.message;
27
+ this.headers_key_name = options.headers_key_name ?? constants_1.HEADERS_KEY_NAME;
26
28
  this.key_generator = options?.key_generator || this.generateRequestIdentitfier;
27
29
  this.cache = new main_1.InMemoryCacheUtil();
28
30
  this.logger = new main_1.LoggerUtil(this.name);
@@ -54,12 +56,12 @@ class RateLimiterMiddleWare {
54
56
  const remaining = Math.max(this.max_requests - record.count, 0);
55
57
  const reset_seconds = this.getResetSeconds(record.expires_at);
56
58
  // RFC-ish headers
57
- res.setHeader("X-RateLimit-Limit", this.max_requests);
58
- res.setHeader("X-RateLimit-Remaining", remaining);
59
- res.setHeader("X-RateLimit-Reset", reset_seconds);
59
+ res.setHeader(this.headers_key_name.rate_limit_limit, this.max_requests);
60
+ res.setHeader(this.headers_key_name.rate_limit_remaining, remaining);
61
+ res.setHeader(this.headers_key_name.rate_limit_reset, reset_seconds);
60
62
  if (record.count > this.max_requests) {
61
63
  this.logger.alert(`⚠️ Rate limit exceeded for key: ${key} (retry in ${reset_seconds}s)`);
62
- res.setHeader("Retry-After", reset_seconds);
64
+ res.setHeader(this.headers_key_name.rate_limit_retry_after, reset_seconds);
63
65
  return res.status(429).json({
64
66
  status: "error",
65
67
  code: 429,
@@ -3,17 +3,18 @@ import { SecureHeadersOptions } from "../types/middle_ware_type";
3
3
  declare class SecureHeadersMiddleWare {
4
4
  private name;
5
5
  private logger;
6
- private readonly enabled?;
7
- private readonly HSTS_enabled?;
8
- private readonly HSTS_max_age?;
6
+ private readonly enabled;
7
+ private readonly HSTS_enabled;
8
+ private readonly HSTS_max_age;
9
+ private readonly HSTS_Extras;
9
10
  private readonly frame_options;
10
- private readonly xss_protection?;
11
- private readonly content_type_options?;
11
+ private readonly xss_protection;
12
+ private readonly content_type_options;
12
13
  private readonly referrer_policy;
13
14
  private readonly content_security_policy;
14
- private readonly HSTS_Extras;
15
15
  private readonly cors_policy;
16
16
  private readonly cors_opener_policy;
17
+ private headers_key_name;
17
18
  constructor(options?: SecureHeadersOptions);
18
19
  private getDefaultContentSecurityPolicy;
19
20
  private getContentSecurityPolicyString;
@@ -10,35 +10,37 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const main_1 = require("../utils/main");
13
+ const constants_1 = require("../config/constants");
13
14
  class SecureHeadersMiddleWare {
14
15
  name = "secure_headers_middle_ware";
15
16
  logger = new main_1.LoggerUtil(this.name);
16
17
  enabled;
17
18
  HSTS_enabled;
18
19
  HSTS_max_age;
20
+ HSTS_Extras;
19
21
  frame_options;
20
22
  xss_protection;
21
23
  content_type_options;
22
24
  referrer_policy;
23
25
  content_security_policy;
24
- HSTS_Extras;
25
26
  cors_policy;
26
27
  cors_opener_policy;
28
+ headers_key_name;
27
29
  constructor(options = {}) {
28
30
  this.enabled = options.enabled ?? true;
29
- this.HSTS_enabled = options?.HSTS_enabled ?? main_1.InputValidatorUtil.isProduction();
30
- this.HSTS_max_age = options?.HSTS_max_age ?? 63072000;
31
- this.frame_options = options?.frame_options ?? "SAMEORIGIN";
32
- this.xss_protection = options?.xss_protection ?? true;
33
- this.content_type_options = options?.content_type_options ?? true;
34
- this.referrer_policy = options?.referrer_policy ?? "no-referrer-when-downgrade";
35
- this.content_security_policy = options?.content_security_policy ?? this.getDefaultContentSecurityPolicy(),
36
- this.HSTS_Extras = options?.HSTS_Extras ?? "includeSubDomains; preload;";
37
- this.cors_policy = options?.cors_policy ?? "same-origin";
38
- this.cors_opener_policy = options?.cors_opener_policy ?? "same-origin";
31
+ this.HSTS_enabled = options.HSTS_enabled ?? main_1.InputValidatorUtil.isProduction();
32
+ this.HSTS_max_age = options.HSTS_max_age ?? 63072000;
33
+ this.HSTS_Extras = options.HSTS_Extras ?? "includeSubDomains; preload;";
34
+ this.frame_options = options.frame_options ?? "SAMEORIGIN";
35
+ this.xss_protection = options.xss_protection ?? true;
36
+ this.content_type_options = options.content_type_options ?? true;
37
+ this.referrer_policy = options.referrer_policy ?? "no-referrer-when-downgrade";
38
+ this.content_security_policy = options.content_security_policy ?? this.getDefaultContentSecurityPolicy();
39
+ this.cors_policy = options.cors_policy ?? "same-origin";
40
+ this.cors_opener_policy = options.cors_opener_policy ?? "same-origin";
41
+ this.headers_key_name = options.headers_key_name ?? constants_1.HEADERS_KEY_NAME;
39
42
  main_1.SafeExecuteUtil.setNamedInstance(this.name, this);
40
43
  }
41
- // Method to get default content security policy
42
44
  getDefaultContentSecurityPolicy() {
43
45
  return {
44
46
  "default-src": ["'self'"],
@@ -52,46 +54,32 @@ class SecureHeadersMiddleWare {
52
54
  "frame-ancestors": ["'self'"],
53
55
  };
54
56
  }
55
- // Method to convert content security policy object to string
56
57
  getContentSecurityPolicyString(policy) {
57
58
  return Object.entries(policy)
58
59
  .map(([key, value]) => `${key} ${value.join(" ")}`)
59
60
  .join("; ");
60
61
  }
61
- // -------------------------
62
- // Middleware
63
- // -------------------------
64
62
  async middleWare(req, res, next) {
65
- if (!this.enabled) {
63
+ if (!this.enabled)
66
64
  return next();
67
- }
68
65
  // Prevent XSS
69
- if (this.xss_protection) {
70
- res.setHeader("X-XSS-Protection", "1; mode=block");
71
- }
72
- else {
73
- res.setHeader("X-XSS-Protection", "0");
74
- }
66
+ res.setHeader(this.headers_key_name.xss_protection ?? "X-XSS-Protection", this.xss_protection ? "1; mode=block" : "0");
75
67
  // Prevent MIME-type sniffing
76
- if (this.content_type_options) {
77
- res.setHeader("X-Content-Type-Options", "nosniff");
78
- }
79
- // Disable framing (clickjacking protection)
80
- res.setHeader("X-Frame-Options", this.frame_options);
81
- res.setHeader("Referrer-Policy", this.referrer_policy);
82
- if (this.cors_policy) {
83
- res.setHeader("Cross-Origin-Resource-Policy", this.cors_policy);
84
- }
85
- if (this.cors_opener_policy) {
86
- res.setHeader("Cross-Origin-Opener-Policy", this.cors_opener_policy);
87
- }
68
+ res.setHeader(this.headers_key_name.content_type_options ?? "X-Content-Type-Options", this.content_type_options ? "nosniff" : "0");
69
+ // Clickjacking protection
70
+ res.setHeader(this.headers_key_name.frame_options ?? "X-Frame-Options", this.frame_options);
71
+ // Referrer Policy
72
+ res.setHeader(this.headers_key_name.referrer_policy ?? "Referrer-Policy", this.referrer_policy);
73
+ // Cross-Origin Resource Policy
74
+ res.setHeader(this.headers_key_name.cross_origin_resource_policy ?? "Cross-Origin-Resource-Policy", this.cors_policy);
75
+ // Cross-Origin Opener Policy
76
+ res.setHeader(this.headers_key_name.cross_origin_opener_policy ?? "Cross-Origin-Opener-Policy", this.cors_opener_policy);
88
77
  // Content Security Policy
89
- if (this.content_security_policy) {
90
- const content_security_policy_string = this.getContentSecurityPolicyString(this.content_security_policy);
91
- res.setHeader("Content-Security-Policy", content_security_policy_string);
92
- }
78
+ const csp_string = this.getContentSecurityPolicyString(this.content_security_policy);
79
+ res.setHeader(this.headers_key_name.content_security_policy ?? "Content-Security-Policy", csp_string);
80
+ // HSTS
93
81
  if (this.HSTS_enabled) {
94
- res.setHeader("Strict-Transport-Security", `max-age=${this.HSTS_max_age}; ${this.HSTS_Extras}`);
82
+ res.setHeader(this.headers_key_name.strict_transport_security ?? "Strict-Transport-Security", `max-age=${this.HSTS_max_age}; ${this.HSTS_Extras}`);
95
83
  }
96
84
  return next();
97
85
  }
@@ -1,5 +1,6 @@
1
1
  import { Model } from "sequelize";
2
2
  import { Request, Response, NextFunction } from "express";
3
+ import { HEADERS_KEY_NAME } from "../config/constants";
3
4
  export type CorsOriginResolver = ((origin?: string) => boolean | Promise<boolean>) | (() => Promise<string[]>);
4
5
  export interface CorsOptions {
5
6
  origins?: string[];
@@ -9,11 +10,13 @@ export interface CorsOptions {
9
10
  credentials?: boolean;
10
11
  max_age?: number;
11
12
  allow_null_origin?: boolean;
13
+ headers_key_name?: typeof HEADERS_KEY_NAME;
12
14
  }
13
15
  export interface RateLimiterOptions {
14
16
  window_ms?: number;
15
17
  max_requests?: number;
16
18
  message?: string;
19
+ headers_key_name?: typeof HEADERS_KEY_NAME;
17
20
  key_generator?: (req: Request) => string;
18
21
  }
19
22
  export type RateLimitRecord = {
@@ -22,12 +25,12 @@ export type RateLimitRecord = {
22
25
  };
23
26
  export interface CookieManagerOptions {
24
27
  request_id_max_age?: number;
25
- request_id_cookie_name?: string;
26
- request_id_header_name?: string;
28
+ request_id_cookie_name: string;
29
+ request_id_header_name: string;
27
30
  request_id_generator?: () => string;
28
31
  device_id_max_age?: number;
29
- device_id_cookie_name?: string;
30
- device_id_header_name?: string;
32
+ device_id_cookie_name: string;
33
+ device_id_header_name: string;
31
34
  device_id_generator?: () => string;
32
35
  }
33
36
  export interface ForceHTTPSOptions {
@@ -47,6 +50,7 @@ export interface SecureHeadersOptions {
47
50
  HSTS_Extras?: string;
48
51
  cors_policy?: string;
49
52
  cors_opener_policy?: string;
53
+ headers_key_name?: typeof HEADERS_KEY_NAME;
50
54
  }
51
55
  export interface ResponseFormatterOptions {
52
56
  include_request_id?: boolean;
@@ -113,5 +113,6 @@ declare class InputTransformerUtil {
113
113
  static formatLinksObject(links: Record<string, string>): Record<string, string>;
114
114
  static buildNestedObject(paths: string[]): any;
115
115
  static minifyHtml(html: string): string;
116
+ static joinStringsBy(parts: string | string[], separator: string): string;
116
117
  }
117
118
  export default InputTransformerUtil;
@@ -349,5 +349,13 @@ class InputTransformerUtil {
349
349
  });
350
350
  return html;
351
351
  }
352
+ // Method to join strings by
353
+ static joinStringsBy(parts, separator) {
354
+ // Ensure parts is always a flat array of strings
355
+ const flat_parts = Array.isArray(parts) ? parts : [parts];
356
+ // Filter out empty/null/undefined strings to avoid extra separators
357
+ const valid_parts = flat_parts.filter(part => part !== null && part !== undefined && part !== "");
358
+ return valid_parts.join(separator);
359
+ }
352
360
  }
353
361
  exports.default = InputTransformerUtil;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fiberx-backend-toolkit",
3
- "version": "0.0.74",
3
+ "version": "0.0.76",
4
4
  "description": "A TypeScript backend toolkit providing shared domain logic, infrastructure helpers, and utilities for FiberX server-side applications and services.",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",