@bloomneo/appkit 1.2.9

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.
Files changed (262) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +902 -0
  3. package/bin/appkit.js +71 -0
  4. package/bin/commands/generate.js +1050 -0
  5. package/bin/templates/backend/README.md.template +39 -0
  6. package/bin/templates/backend/api.http.template +0 -0
  7. package/bin/templates/backend/docs/APPKIT_CLI.md +507 -0
  8. package/bin/templates/backend/docs/APPKIT_COMMENTS_GUIDELINES.md +61 -0
  9. package/bin/templates/backend/docs/APPKIT_LLM_GUIDE.md +2539 -0
  10. package/bin/templates/backend/package.json.template +34 -0
  11. package/bin/templates/backend/src/api/features/welcome/welcome.http.template +29 -0
  12. package/bin/templates/backend/src/api/features/welcome/welcome.route.ts.template +36 -0
  13. package/bin/templates/backend/src/api/features/welcome/welcome.service.ts.template +88 -0
  14. package/bin/templates/backend/src/api/features/welcome/welcome.types.ts.template +18 -0
  15. package/bin/templates/backend/src/api/lib/api-router.ts.template +84 -0
  16. package/bin/templates/backend/src/api/server.ts.template +188 -0
  17. package/bin/templates/backend/tsconfig.api.json.template +24 -0
  18. package/bin/templates/backend/tsconfig.json.template +40 -0
  19. package/bin/templates/feature/feature.http.template +63 -0
  20. package/bin/templates/feature/feature.route.ts.template +36 -0
  21. package/bin/templates/feature/feature.service.ts.template +81 -0
  22. package/bin/templates/feature/feature.types.ts.template +23 -0
  23. package/bin/templates/feature-db/feature.http.template +63 -0
  24. package/bin/templates/feature-db/feature.model.ts.template +74 -0
  25. package/bin/templates/feature-db/feature.route.ts.template +58 -0
  26. package/bin/templates/feature-db/feature.service.ts.template +231 -0
  27. package/bin/templates/feature-db/feature.types.ts.template +25 -0
  28. package/bin/templates/feature-db/schema-addition.prisma.template +9 -0
  29. package/bin/templates/feature-db/seeding/README.md.template +57 -0
  30. package/bin/templates/feature-db/seeding/feature.seed.js.template +67 -0
  31. package/bin/templates/feature-user/schema-addition.prisma.template +19 -0
  32. package/bin/templates/feature-user/user.http.template +157 -0
  33. package/bin/templates/feature-user/user.model.ts.template +244 -0
  34. package/bin/templates/feature-user/user.route.ts.template +379 -0
  35. package/bin/templates/feature-user/user.seed.js.template +182 -0
  36. package/bin/templates/feature-user/user.service.ts.template +426 -0
  37. package/bin/templates/feature-user/user.types.ts.template +127 -0
  38. package/dist/auth/auth.d.ts +182 -0
  39. package/dist/auth/auth.d.ts.map +1 -0
  40. package/dist/auth/auth.js +477 -0
  41. package/dist/auth/auth.js.map +1 -0
  42. package/dist/auth/defaults.d.ts +104 -0
  43. package/dist/auth/defaults.d.ts.map +1 -0
  44. package/dist/auth/defaults.js +374 -0
  45. package/dist/auth/defaults.js.map +1 -0
  46. package/dist/auth/index.d.ts +70 -0
  47. package/dist/auth/index.d.ts.map +1 -0
  48. package/dist/auth/index.js +94 -0
  49. package/dist/auth/index.js.map +1 -0
  50. package/dist/cache/cache.d.ts +118 -0
  51. package/dist/cache/cache.d.ts.map +1 -0
  52. package/dist/cache/cache.js +249 -0
  53. package/dist/cache/cache.js.map +1 -0
  54. package/dist/cache/defaults.d.ts +63 -0
  55. package/dist/cache/defaults.d.ts.map +1 -0
  56. package/dist/cache/defaults.js +193 -0
  57. package/dist/cache/defaults.js.map +1 -0
  58. package/dist/cache/index.d.ts +101 -0
  59. package/dist/cache/index.d.ts.map +1 -0
  60. package/dist/cache/index.js +203 -0
  61. package/dist/cache/index.js.map +1 -0
  62. package/dist/cache/strategies/memory.d.ts +138 -0
  63. package/dist/cache/strategies/memory.d.ts.map +1 -0
  64. package/dist/cache/strategies/memory.js +348 -0
  65. package/dist/cache/strategies/memory.js.map +1 -0
  66. package/dist/cache/strategies/redis.d.ts +105 -0
  67. package/dist/cache/strategies/redis.d.ts.map +1 -0
  68. package/dist/cache/strategies/redis.js +318 -0
  69. package/dist/cache/strategies/redis.js.map +1 -0
  70. package/dist/config/config.d.ts +62 -0
  71. package/dist/config/config.d.ts.map +1 -0
  72. package/dist/config/config.js +107 -0
  73. package/dist/config/config.js.map +1 -0
  74. package/dist/config/defaults.d.ts +44 -0
  75. package/dist/config/defaults.d.ts.map +1 -0
  76. package/dist/config/defaults.js +217 -0
  77. package/dist/config/defaults.js.map +1 -0
  78. package/dist/config/index.d.ts +105 -0
  79. package/dist/config/index.d.ts.map +1 -0
  80. package/dist/config/index.js +163 -0
  81. package/dist/config/index.js.map +1 -0
  82. package/dist/database/adapters/mongoose.d.ts +106 -0
  83. package/dist/database/adapters/mongoose.d.ts.map +1 -0
  84. package/dist/database/adapters/mongoose.js +480 -0
  85. package/dist/database/adapters/mongoose.js.map +1 -0
  86. package/dist/database/adapters/prisma.d.ts +106 -0
  87. package/dist/database/adapters/prisma.d.ts.map +1 -0
  88. package/dist/database/adapters/prisma.js +494 -0
  89. package/dist/database/adapters/prisma.js.map +1 -0
  90. package/dist/database/defaults.d.ts +87 -0
  91. package/dist/database/defaults.d.ts.map +1 -0
  92. package/dist/database/defaults.js +271 -0
  93. package/dist/database/defaults.js.map +1 -0
  94. package/dist/database/index.d.ts +137 -0
  95. package/dist/database/index.d.ts.map +1 -0
  96. package/dist/database/index.js +490 -0
  97. package/dist/database/index.js.map +1 -0
  98. package/dist/email/defaults.d.ts +100 -0
  99. package/dist/email/defaults.d.ts.map +1 -0
  100. package/dist/email/defaults.js +400 -0
  101. package/dist/email/defaults.js.map +1 -0
  102. package/dist/email/email.d.ts +139 -0
  103. package/dist/email/email.d.ts.map +1 -0
  104. package/dist/email/email.js +316 -0
  105. package/dist/email/email.js.map +1 -0
  106. package/dist/email/index.d.ts +176 -0
  107. package/dist/email/index.d.ts.map +1 -0
  108. package/dist/email/index.js +251 -0
  109. package/dist/email/index.js.map +1 -0
  110. package/dist/email/strategies/console.d.ts +90 -0
  111. package/dist/email/strategies/console.d.ts.map +1 -0
  112. package/dist/email/strategies/console.js +268 -0
  113. package/dist/email/strategies/console.js.map +1 -0
  114. package/dist/email/strategies/resend.d.ts +84 -0
  115. package/dist/email/strategies/resend.d.ts.map +1 -0
  116. package/dist/email/strategies/resend.js +266 -0
  117. package/dist/email/strategies/resend.js.map +1 -0
  118. package/dist/email/strategies/smtp.d.ts +77 -0
  119. package/dist/email/strategies/smtp.d.ts.map +1 -0
  120. package/dist/email/strategies/smtp.js +286 -0
  121. package/dist/email/strategies/smtp.js.map +1 -0
  122. package/dist/error/defaults.d.ts +40 -0
  123. package/dist/error/defaults.d.ts.map +1 -0
  124. package/dist/error/defaults.js +75 -0
  125. package/dist/error/defaults.js.map +1 -0
  126. package/dist/error/error.d.ts +140 -0
  127. package/dist/error/error.d.ts.map +1 -0
  128. package/dist/error/error.js +200 -0
  129. package/dist/error/error.js.map +1 -0
  130. package/dist/error/index.d.ts +145 -0
  131. package/dist/error/index.d.ts.map +1 -0
  132. package/dist/error/index.js +145 -0
  133. package/dist/error/index.js.map +1 -0
  134. package/dist/event/defaults.d.ts +111 -0
  135. package/dist/event/defaults.d.ts.map +1 -0
  136. package/dist/event/defaults.js +378 -0
  137. package/dist/event/defaults.js.map +1 -0
  138. package/dist/event/event.d.ts +171 -0
  139. package/dist/event/event.d.ts.map +1 -0
  140. package/dist/event/event.js +391 -0
  141. package/dist/event/event.js.map +1 -0
  142. package/dist/event/index.d.ts +173 -0
  143. package/dist/event/index.d.ts.map +1 -0
  144. package/dist/event/index.js +302 -0
  145. package/dist/event/index.js.map +1 -0
  146. package/dist/event/strategies/memory.d.ts +122 -0
  147. package/dist/event/strategies/memory.d.ts.map +1 -0
  148. package/dist/event/strategies/memory.js +331 -0
  149. package/dist/event/strategies/memory.js.map +1 -0
  150. package/dist/event/strategies/redis.d.ts +115 -0
  151. package/dist/event/strategies/redis.d.ts.map +1 -0
  152. package/dist/event/strategies/redis.js +434 -0
  153. package/dist/event/strategies/redis.js.map +1 -0
  154. package/dist/index.d.ts +58 -0
  155. package/dist/index.d.ts.map +1 -0
  156. package/dist/index.js +72 -0
  157. package/dist/index.js.map +1 -0
  158. package/dist/logger/defaults.d.ts +67 -0
  159. package/dist/logger/defaults.d.ts.map +1 -0
  160. package/dist/logger/defaults.js +213 -0
  161. package/dist/logger/defaults.js.map +1 -0
  162. package/dist/logger/index.d.ts +84 -0
  163. package/dist/logger/index.d.ts.map +1 -0
  164. package/dist/logger/index.js +101 -0
  165. package/dist/logger/index.js.map +1 -0
  166. package/dist/logger/logger.d.ts +165 -0
  167. package/dist/logger/logger.d.ts.map +1 -0
  168. package/dist/logger/logger.js +843 -0
  169. package/dist/logger/logger.js.map +1 -0
  170. package/dist/logger/transports/console.d.ts +102 -0
  171. package/dist/logger/transports/console.d.ts.map +1 -0
  172. package/dist/logger/transports/console.js +276 -0
  173. package/dist/logger/transports/console.js.map +1 -0
  174. package/dist/logger/transports/database.d.ts +153 -0
  175. package/dist/logger/transports/database.d.ts.map +1 -0
  176. package/dist/logger/transports/database.js +539 -0
  177. package/dist/logger/transports/database.js.map +1 -0
  178. package/dist/logger/transports/file.d.ts +146 -0
  179. package/dist/logger/transports/file.d.ts.map +1 -0
  180. package/dist/logger/transports/file.js +464 -0
  181. package/dist/logger/transports/file.js.map +1 -0
  182. package/dist/logger/transports/http.d.ts +128 -0
  183. package/dist/logger/transports/http.d.ts.map +1 -0
  184. package/dist/logger/transports/http.js +401 -0
  185. package/dist/logger/transports/http.js.map +1 -0
  186. package/dist/logger/transports/webhook.d.ts +152 -0
  187. package/dist/logger/transports/webhook.d.ts.map +1 -0
  188. package/dist/logger/transports/webhook.js +485 -0
  189. package/dist/logger/transports/webhook.js.map +1 -0
  190. package/dist/queue/defaults.d.ts +66 -0
  191. package/dist/queue/defaults.d.ts.map +1 -0
  192. package/dist/queue/defaults.js +205 -0
  193. package/dist/queue/defaults.js.map +1 -0
  194. package/dist/queue/index.d.ts +124 -0
  195. package/dist/queue/index.d.ts.map +1 -0
  196. package/dist/queue/index.js +116 -0
  197. package/dist/queue/index.js.map +1 -0
  198. package/dist/queue/queue.d.ts +156 -0
  199. package/dist/queue/queue.d.ts.map +1 -0
  200. package/dist/queue/queue.js +387 -0
  201. package/dist/queue/queue.js.map +1 -0
  202. package/dist/queue/transports/database.d.ts +165 -0
  203. package/dist/queue/transports/database.d.ts.map +1 -0
  204. package/dist/queue/transports/database.js +595 -0
  205. package/dist/queue/transports/database.js.map +1 -0
  206. package/dist/queue/transports/memory.d.ts +143 -0
  207. package/dist/queue/transports/memory.d.ts.map +1 -0
  208. package/dist/queue/transports/memory.js +415 -0
  209. package/dist/queue/transports/memory.js.map +1 -0
  210. package/dist/queue/transports/redis.d.ts +203 -0
  211. package/dist/queue/transports/redis.d.ts.map +1 -0
  212. package/dist/queue/transports/redis.js +744 -0
  213. package/dist/queue/transports/redis.js.map +1 -0
  214. package/dist/security/defaults.d.ts +64 -0
  215. package/dist/security/defaults.d.ts.map +1 -0
  216. package/dist/security/defaults.js +159 -0
  217. package/dist/security/defaults.js.map +1 -0
  218. package/dist/security/index.d.ts +110 -0
  219. package/dist/security/index.d.ts.map +1 -0
  220. package/dist/security/index.js +160 -0
  221. package/dist/security/index.js.map +1 -0
  222. package/dist/security/security.d.ts +138 -0
  223. package/dist/security/security.d.ts.map +1 -0
  224. package/dist/security/security.js +419 -0
  225. package/dist/security/security.js.map +1 -0
  226. package/dist/storage/defaults.d.ts +79 -0
  227. package/dist/storage/defaults.d.ts.map +1 -0
  228. package/dist/storage/defaults.js +358 -0
  229. package/dist/storage/defaults.js.map +1 -0
  230. package/dist/storage/index.d.ts +153 -0
  231. package/dist/storage/index.d.ts.map +1 -0
  232. package/dist/storage/index.js +242 -0
  233. package/dist/storage/index.js.map +1 -0
  234. package/dist/storage/storage.d.ts +151 -0
  235. package/dist/storage/storage.d.ts.map +1 -0
  236. package/dist/storage/storage.js +439 -0
  237. package/dist/storage/storage.js.map +1 -0
  238. package/dist/storage/strategies/local.d.ts +117 -0
  239. package/dist/storage/strategies/local.d.ts.map +1 -0
  240. package/dist/storage/strategies/local.js +368 -0
  241. package/dist/storage/strategies/local.js.map +1 -0
  242. package/dist/storage/strategies/r2.d.ts +130 -0
  243. package/dist/storage/strategies/r2.d.ts.map +1 -0
  244. package/dist/storage/strategies/r2.js +470 -0
  245. package/dist/storage/strategies/r2.js.map +1 -0
  246. package/dist/storage/strategies/s3.d.ts +121 -0
  247. package/dist/storage/strategies/s3.d.ts.map +1 -0
  248. package/dist/storage/strategies/s3.js +461 -0
  249. package/dist/storage/strategies/s3.js.map +1 -0
  250. package/dist/util/defaults.d.ts +77 -0
  251. package/dist/util/defaults.d.ts.map +1 -0
  252. package/dist/util/defaults.js +193 -0
  253. package/dist/util/defaults.js.map +1 -0
  254. package/dist/util/index.d.ts +97 -0
  255. package/dist/util/index.d.ts.map +1 -0
  256. package/dist/util/index.js +165 -0
  257. package/dist/util/index.js.map +1 -0
  258. package/dist/util/util.d.ts +145 -0
  259. package/dist/util/util.d.ts.map +1 -0
  260. package/dist/util/util.js +481 -0
  261. package/dist/util/util.js.map +1 -0
  262. package/package.json +234 -0
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Core security class with CSRF, rate limiting, sanitization, and encryption
3
+ * @module @bloomneo/appkit/security
4
+ * @file src/security/security.ts
5
+ *
6
+ * @llm-rule WHEN: Building apps that need security protection (CSRF, rate limiting, input sanitization, encryption)
7
+ * @llm-rule AVOID: Using directly - always get instance via securityClass.get()
8
+ * @llm-rule NOTE: Provides enterprise-grade security with CSRF tokens, rate limiting, XSS prevention, and AES-256-GCM encryption
9
+ */
10
+ import type { SecurityConfig } from './defaults.js';
11
+ export interface ExpressRequest {
12
+ method: string;
13
+ session?: any;
14
+ body?: any;
15
+ headers?: Record<string, string | string[] | undefined>;
16
+ query?: any;
17
+ ip?: string;
18
+ connection?: {
19
+ remoteAddress?: string;
20
+ };
21
+ csrfToken?: () => string;
22
+ [key: string]: any;
23
+ }
24
+ export interface ExpressResponse {
25
+ setHeader?: (name: string, value: string | number) => void;
26
+ [key: string]: any;
27
+ }
28
+ export interface ExpressNextFunction {
29
+ (error?: any): void;
30
+ }
31
+ export type ExpressMiddleware = (req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => void;
32
+ export interface CSRFOptions {
33
+ secret?: string;
34
+ tokenField?: string;
35
+ headerField?: string;
36
+ expiryMinutes?: number;
37
+ }
38
+ export interface RateLimitOptions {
39
+ maxRequests?: number;
40
+ windowMs?: number;
41
+ message?: string;
42
+ keyGenerator?: (req: ExpressRequest) => string;
43
+ }
44
+ export interface InputOptions {
45
+ maxLength?: number;
46
+ trim?: boolean;
47
+ removeXSS?: boolean;
48
+ }
49
+ export interface HTMLOptions {
50
+ allowedTags?: string[];
51
+ stripAllTags?: boolean;
52
+ }
53
+ /**
54
+ * Security class with enterprise-grade protection functionality
55
+ */
56
+ export declare class SecurityClass {
57
+ config: SecurityConfig;
58
+ private requestStore;
59
+ private cleanupInitialized;
60
+ constructor(config: SecurityConfig);
61
+ /**
62
+ * Creates CSRF protection middleware for forms and AJAX requests
63
+ * @llm-rule WHEN: Protecting forms and state-changing requests from CSRF attacks
64
+ * @llm-rule AVOID: Using without session middleware - CSRF requires sessions for token storage
65
+ * @llm-rule NOTE: Automatically validates tokens on POST/PUT/DELETE/PATCH requests, adds req.csrfToken() method
66
+ */
67
+ forms(options?: CSRFOptions): ExpressMiddleware;
68
+ /**
69
+ * Creates rate limiting middleware with configurable limits and windows
70
+ * @llm-rule WHEN: Protecting endpoints from abuse and brute force attacks
71
+ * @llm-rule AVOID: Using same limits for all endpoints - auth should have stricter limits than API
72
+ * @llm-rule NOTE: Uses in-memory storage with automatic cleanup, sets standard rate limit headers
73
+ */
74
+ requests(maxRequests?: number, windowMs?: number, options?: RateLimitOptions): ExpressMiddleware;
75
+ /**
76
+ * Cleans text input with XSS prevention and length limiting
77
+ * @llm-rule WHEN: Processing any user text input before storage or display
78
+ * @llm-rule AVOID: Storing raw user input - always clean to prevent XSS attacks
79
+ * @llm-rule NOTE: Removes dangerous patterns like <script>, javascript:, event handlers
80
+ */
81
+ input(text: any, options?: InputOptions): string;
82
+ /**
83
+ * Cleans HTML content allowing only specified safe tags
84
+ * @llm-rule WHEN: Processing user HTML content like rich text editor input
85
+ * @llm-rule AVOID: Allowing all HTML tags - only whitelist safe formatting tags
86
+ * @llm-rule NOTE: Removes script, iframe, object tags and dangerous attributes like onclick
87
+ */
88
+ html(html: any, options?: HTMLOptions): string;
89
+ /**
90
+ * Escapes HTML special characters for safe display in HTML content
91
+ * @llm-rule WHEN: Displaying user text content in HTML without allowing any HTML tags
92
+ * @llm-rule AVOID: Direct interpolation of user content in HTML - always escape first
93
+ * @llm-rule NOTE: Converts &, <, >, quotes to HTML entities for safe display
94
+ */
95
+ escape(text: any): string;
96
+ /**
97
+ * Encrypts sensitive data using AES-256-GCM with authentication
98
+ * @llm-rule WHEN: Storing sensitive data like SSNs, credit cards, personal info
99
+ * @llm-rule AVOID: Storing sensitive data in plain text - always encrypt before database storage
100
+ * @llm-rule NOTE: Uses random IV per encryption, includes authentication tag to prevent tampering
101
+ */
102
+ encrypt(data: string | Buffer, key?: string | Buffer, associatedData?: Buffer): string;
103
+ /**
104
+ * Decrypts previously encrypted data with authentication verification
105
+ * @llm-rule WHEN: Retrieving sensitive data that was encrypted with encrypt() method
106
+ * @llm-rule AVOID: Using with data not encrypted by this module - will fail authentication
107
+ * @llm-rule NOTE: Automatically verifies authentication tag to detect tampering
108
+ */
109
+ decrypt(encryptedData: string, key?: string | Buffer, associatedData?: Buffer): string;
110
+ /**
111
+ * Generates a cryptographically secure 256-bit encryption key
112
+ * @llm-rule WHEN: Setting up encryption for the first time or rotating keys
113
+ * @llm-rule AVOID: Using weak or predictable keys - always use this method for key generation
114
+ * @llm-rule NOTE: Returns 64-character hex string suitable for VOILA_SECURITY_ENCRYPTION_KEY
115
+ */
116
+ generateKey(): string;
117
+ /**
118
+ * Generates a cryptographically secure CSRF token
119
+ */
120
+ private generateCSRFToken;
121
+ /**
122
+ * Verifies CSRF token using timing-safe comparison
123
+ */
124
+ private verifyCSRFToken;
125
+ /**
126
+ * Gets unique identifier for the client
127
+ */
128
+ private getClientKey;
129
+ /**
130
+ * Initializes cleanup interval for memory management
131
+ */
132
+ private initializeCleanup;
133
+ /**
134
+ * Validates encryption key format and length
135
+ */
136
+ private validateEncryptionKey;
137
+ }
138
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/security/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,419 @@
1
+ /**
2
+ * Core security class with CSRF, rate limiting, sanitization, and encryption
3
+ * @module @bloomneo/appkit/security
4
+ * @file src/security/security.ts
5
+ *
6
+ * @llm-rule WHEN: Building apps that need security protection (CSRF, rate limiting, input sanitization, encryption)
7
+ * @llm-rule AVOID: Using directly - always get instance via securityClass.get()
8
+ * @llm-rule NOTE: Provides enterprise-grade security with CSRF tokens, rate limiting, XSS prevention, and AES-256-GCM encryption
9
+ */
10
+ import crypto from 'crypto';
11
+ import { createSecurityError } from './defaults.js';
12
+ /**
13
+ * Security class with enterprise-grade protection functionality
14
+ */
15
+ export class SecurityClass {
16
+ config;
17
+ requestStore;
18
+ cleanupInitialized;
19
+ constructor(config) {
20
+ this.config = config;
21
+ this.requestStore = new Map();
22
+ this.cleanupInitialized = false;
23
+ }
24
+ /**
25
+ * Creates CSRF protection middleware for forms and AJAX requests
26
+ * @llm-rule WHEN: Protecting forms and state-changing requests from CSRF attacks
27
+ * @llm-rule AVOID: Using without session middleware - CSRF requires sessions for token storage
28
+ * @llm-rule NOTE: Automatically validates tokens on POST/PUT/DELETE/PATCH requests, adds req.csrfToken() method
29
+ */
30
+ forms(options = {}) {
31
+ const csrfSecret = options.secret || this.config.csrf.secret;
32
+ if (!csrfSecret) {
33
+ throw createSecurityError('CSRF secret required. Set VOILA_SECURITY_CSRF_SECRET or VOILA_AUTH_SECRET environment variable', 500);
34
+ }
35
+ const tokenField = options.tokenField || this.config.csrf.tokenField;
36
+ const headerField = options.headerField || this.config.csrf.headerField;
37
+ const expiryMinutes = options.expiryMinutes || this.config.csrf.expiryMinutes;
38
+ return (req, res, next) => {
39
+ // Ensure session exists
40
+ if (!req.session || typeof req.session !== 'object') {
41
+ const error = createSecurityError('Session required for CSRF protection', 500);
42
+ return next(error);
43
+ }
44
+ // Add token generation method to request
45
+ req.csrfToken = () => this.generateCSRFToken(req.session, expiryMinutes);
46
+ // Skip CSRF verification for safe HTTP methods
47
+ if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) {
48
+ return next();
49
+ }
50
+ // Extract token from request
51
+ const token = (req.body && req.body[tokenField]) ||
52
+ (req.headers && req.headers[headerField.toLowerCase()]) ||
53
+ (req.query && req.query[tokenField]);
54
+ // Verify token
55
+ if (!this.verifyCSRFToken(token, req.session)) {
56
+ const error = createSecurityError('Invalid or missing CSRF token', 403);
57
+ return next(error);
58
+ }
59
+ next();
60
+ };
61
+ }
62
+ /**
63
+ * Creates rate limiting middleware with configurable limits and windows
64
+ * @llm-rule WHEN: Protecting endpoints from abuse and brute force attacks
65
+ * @llm-rule AVOID: Using same limits for all endpoints - auth should have stricter limits than API
66
+ * @llm-rule NOTE: Uses in-memory storage with automatic cleanup, sets standard rate limit headers
67
+ */
68
+ requests(maxRequests, windowMs, options = {}) {
69
+ // Handle argument polymorphism
70
+ if (typeof maxRequests === 'object') {
71
+ options = maxRequests;
72
+ maxRequests = options.maxRequests;
73
+ windowMs = options.windowMs;
74
+ }
75
+ else if (typeof windowMs === 'object') {
76
+ options = windowMs;
77
+ windowMs = options.windowMs;
78
+ }
79
+ // Use provided values or config defaults
80
+ const max = maxRequests || this.config.rateLimit.maxRequests;
81
+ const window = windowMs || this.config.rateLimit.windowMs;
82
+ const message = options.message || this.config.rateLimit.message;
83
+ const keyGenerator = options.keyGenerator || this.getClientKey;
84
+ // Validate configuration
85
+ if (max < 0 || window <= 0) {
86
+ throw createSecurityError('Invalid rate limit configuration', 500);
87
+ }
88
+ // Initialize cleanup for memory management
89
+ this.initializeCleanup(window);
90
+ return (req, res, next) => {
91
+ const key = keyGenerator(req);
92
+ const now = Date.now();
93
+ // Get or create rate limit record
94
+ let record = this.requestStore.get(key);
95
+ if (!record) {
96
+ record = { count: 0, resetTime: now + window };
97
+ this.requestStore.set(key, record);
98
+ }
99
+ else if (now > record.resetTime) {
100
+ // Reset if window has passed
101
+ record.count = 0;
102
+ record.resetTime = now + window;
103
+ }
104
+ // Increment request count
105
+ record.count++;
106
+ // Set rate limit headers
107
+ if (res.setHeader) {
108
+ res.setHeader('X-RateLimit-Limit', max);
109
+ res.setHeader('X-RateLimit-Remaining', Math.max(0, max - record.count));
110
+ res.setHeader('X-RateLimit-Reset', Math.ceil(record.resetTime / 1000));
111
+ }
112
+ // Check if limit exceeded
113
+ if (record.count > max) {
114
+ const retryAfter = Math.ceil((record.resetTime - now) / 1000);
115
+ if (res.setHeader) {
116
+ res.setHeader('Retry-After', retryAfter);
117
+ }
118
+ const error = createSecurityError(message, 429, {
119
+ retryAfter,
120
+ limit: max,
121
+ remaining: 0,
122
+ resetTime: record.resetTime,
123
+ });
124
+ return next(error);
125
+ }
126
+ next();
127
+ };
128
+ }
129
+ /**
130
+ * Cleans text input with XSS prevention and length limiting
131
+ * @llm-rule WHEN: Processing any user text input before storage or display
132
+ * @llm-rule AVOID: Storing raw user input - always clean to prevent XSS attacks
133
+ * @llm-rule NOTE: Removes dangerous patterns like <script>, javascript:, event handlers
134
+ */
135
+ input(text, options = {}) {
136
+ if (typeof text !== 'string') {
137
+ return '';
138
+ }
139
+ const maxLength = options.maxLength || this.config.sanitization.maxLength;
140
+ const trim = options.trim !== false;
141
+ const removeXSS = options.removeXSS !== false;
142
+ let result = text;
143
+ // Trim whitespace
144
+ if (trim) {
145
+ result = result.trim();
146
+ }
147
+ // Basic XSS prevention
148
+ if (removeXSS) {
149
+ result = result
150
+ .replace(/[<>]/g, '') // Remove angle brackets
151
+ .replace(/javascript:/gi, '') // Remove javascript: protocol
152
+ .replace(/on\w+\s*=/gi, '') // Remove inline event handlers
153
+ .replace(/data:/gi, '') // Remove data: protocol
154
+ .replace(/vbscript:/gi, '') // Remove vbscript: protocol
155
+ .replace(/expression\s*\(/gi, '') // Remove CSS expressions
156
+ .replace(/url\s*\(/gi, ''); // Remove CSS url() functions
157
+ }
158
+ // Length limiting
159
+ if (result.length > maxLength) {
160
+ result = result.substring(0, maxLength);
161
+ }
162
+ return result;
163
+ }
164
+ /**
165
+ * Cleans HTML content allowing only specified safe tags
166
+ * @llm-rule WHEN: Processing user HTML content like rich text editor input
167
+ * @llm-rule AVOID: Allowing all HTML tags - only whitelist safe formatting tags
168
+ * @llm-rule NOTE: Removes script, iframe, object tags and dangerous attributes like onclick
169
+ */
170
+ html(html, options = {}) {
171
+ if (typeof html !== 'string') {
172
+ return '';
173
+ }
174
+ const allowedTags = options.allowedTags || this.config.sanitization.allowedTags;
175
+ const stripAllTags = options.stripAllTags !== undefined
176
+ ? options.stripAllTags
177
+ : this.config.sanitization.stripAllTags;
178
+ let result = html;
179
+ // Strip all tags if requested
180
+ if (stripAllTags) {
181
+ return result.replace(/<[^>]*>/g, '');
182
+ }
183
+ // Remove dangerous elements
184
+ result = result
185
+ .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '') // Remove script tags
186
+ .replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi, '') // Remove iframe tags
187
+ .replace(/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi, '') // Remove object tags
188
+ .replace(/<embed\b[^>]*>/gi, '') // Remove embed tags
189
+ .replace(/<form\b[^<]*(?:(?!<\/form>)<[^<]*)*<\/form>/gi, '') // Remove form tags
190
+ .replace(/\s+on\w+\s*=\s*["'][^"']*["']/gi, '') // Remove inline event handlers
191
+ .replace(/javascript\s*:/gi, '') // Remove javascript: protocol
192
+ .replace(/data\s*:/gi, '') // Remove data: protocol
193
+ .replace(/vbscript\s*:/gi, '') // Remove vbscript: protocol
194
+ .replace(/expression\s*\(/gi, ''); // Remove CSS expressions
195
+ // Filter allowed tags if specified
196
+ if (allowedTags.length > 0) {
197
+ try {
198
+ const allowedPattern = allowedTags
199
+ .map(tag => tag.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'))
200
+ .join('|');
201
+ const tagPattern = new RegExp(`<(?!\/?(?:${allowedPattern})\\b)[^>]+>`, 'gi');
202
+ result = result.replace(tagPattern, '');
203
+ }
204
+ catch (error) {
205
+ console.warn('HTML sanitization: Invalid allowed tags, stripping all tags');
206
+ result = result.replace(/<[^>]*>/g, '');
207
+ }
208
+ }
209
+ return result;
210
+ }
211
+ /**
212
+ * Escapes HTML special characters for safe display in HTML content
213
+ * @llm-rule WHEN: Displaying user text content in HTML without allowing any HTML tags
214
+ * @llm-rule AVOID: Direct interpolation of user content in HTML - always escape first
215
+ * @llm-rule NOTE: Converts &, <, >, quotes to HTML entities for safe display
216
+ */
217
+ escape(text) {
218
+ if (typeof text !== 'string') {
219
+ return '';
220
+ }
221
+ const HTML_ESCAPE_MAP = {
222
+ '&': '&amp;',
223
+ '<': '&lt;',
224
+ '>': '&gt;',
225
+ '"': '&quot;',
226
+ "'": '&#x27;',
227
+ '/': '&#x2F;',
228
+ '`': '&#x60;',
229
+ '=': '&#x3D;',
230
+ };
231
+ return text.replace(/[&<>"'/`=]/g, (char) => HTML_ESCAPE_MAP[char]);
232
+ }
233
+ /**
234
+ * Encrypts sensitive data using AES-256-GCM with authentication
235
+ * @llm-rule WHEN: Storing sensitive data like SSNs, credit cards, personal info
236
+ * @llm-rule AVOID: Storing sensitive data in plain text - always encrypt before database storage
237
+ * @llm-rule NOTE: Uses random IV per encryption, includes authentication tag to prevent tampering
238
+ */
239
+ encrypt(data, key, associatedData) {
240
+ if (!data) {
241
+ throw createSecurityError('Data to encrypt cannot be empty');
242
+ }
243
+ const encryptionKey = key || this.config.encryption.key;
244
+ if (!encryptionKey) {
245
+ throw createSecurityError('Encryption key required. Provide as argument or set VOILA_SECURITY_ENCRYPTION_KEY environment variable', 500);
246
+ }
247
+ this.validateEncryptionKey(encryptionKey);
248
+ const keyBuffer = typeof encryptionKey === 'string'
249
+ ? Buffer.from(encryptionKey, 'hex')
250
+ : encryptionKey;
251
+ try {
252
+ // Generate random IV for each encryption
253
+ const iv = crypto.randomBytes(this.config.encryption.ivLength);
254
+ const cipher = crypto.createCipheriv(this.config.encryption.algorithm, keyBuffer, iv);
255
+ // Set AAD if provided
256
+ if (associatedData) {
257
+ if (!Buffer.isBuffer(associatedData)) {
258
+ throw createSecurityError('Associated data must be a Buffer');
259
+ }
260
+ cipher.setAAD(associatedData);
261
+ }
262
+ // Encrypt data
263
+ const dataBuffer = Buffer.isBuffer(data) ? data : Buffer.from(data, 'utf8');
264
+ let encrypted = cipher.update(dataBuffer);
265
+ encrypted = Buffer.concat([encrypted, cipher.final()]);
266
+ // Get authentication tag
267
+ const authTag = cipher.getAuthTag();
268
+ // Combine IV, ciphertext, and auth tag
269
+ return `${iv.toString('hex')}:${encrypted.toString('hex')}:${authTag.toString('hex')}`;
270
+ }
271
+ catch (error) {
272
+ throw createSecurityError(`Encryption failed: ${error.message}`, 500);
273
+ }
274
+ }
275
+ /**
276
+ * Decrypts previously encrypted data with authentication verification
277
+ * @llm-rule WHEN: Retrieving sensitive data that was encrypted with encrypt() method
278
+ * @llm-rule AVOID: Using with data not encrypted by this module - will fail authentication
279
+ * @llm-rule NOTE: Automatically verifies authentication tag to detect tampering
280
+ */
281
+ decrypt(encryptedData, key, associatedData) {
282
+ if (!encryptedData || typeof encryptedData !== 'string') {
283
+ throw createSecurityError('Encrypted data must be a non-empty string');
284
+ }
285
+ const decryptionKey = key || this.config.encryption.key;
286
+ if (!decryptionKey) {
287
+ throw createSecurityError('Decryption key required. Provide as argument or set VOILA_SECURITY_ENCRYPTION_KEY environment variable', 500);
288
+ }
289
+ this.validateEncryptionKey(decryptionKey);
290
+ const keyBuffer = typeof decryptionKey === 'string'
291
+ ? Buffer.from(decryptionKey, 'hex')
292
+ : decryptionKey;
293
+ // Parse encrypted data format
294
+ const parts = encryptedData.split(':');
295
+ if (parts.length !== 3) {
296
+ throw createSecurityError('Invalid encrypted data format. Expected IV:ciphertext:authTag');
297
+ }
298
+ try {
299
+ const iv = Buffer.from(parts[0], 'hex');
300
+ const encrypted = Buffer.from(parts[1], 'hex');
301
+ const authTag = Buffer.from(parts[2], 'hex');
302
+ // Validate component lengths
303
+ if (iv.length !== this.config.encryption.ivLength ||
304
+ authTag.length !== this.config.encryption.tagLength) {
305
+ throw createSecurityError('Invalid IV or authentication tag length');
306
+ }
307
+ // Create decipher
308
+ const decipher = crypto.createDecipheriv(this.config.encryption.algorithm, keyBuffer, iv);
309
+ // Set AAD if provided
310
+ if (associatedData) {
311
+ if (!Buffer.isBuffer(associatedData)) {
312
+ throw createSecurityError('Associated data must be a Buffer');
313
+ }
314
+ decipher.setAAD(associatedData);
315
+ }
316
+ // Set authentication tag
317
+ decipher.setAuthTag(authTag);
318
+ // Decrypt data
319
+ let decrypted = decipher.update(encrypted);
320
+ decrypted = Buffer.concat([decrypted, decipher.final()]);
321
+ return decrypted.toString('utf8');
322
+ }
323
+ catch (error) {
324
+ if (error.code === 'EBADTAG') {
325
+ throw createSecurityError('Authentication failed: Data may be tampered with or incorrect key/AAD provided', 401);
326
+ }
327
+ throw createSecurityError(`Decryption failed: ${error.message}`, 500);
328
+ }
329
+ }
330
+ /**
331
+ * Generates a cryptographically secure 256-bit encryption key
332
+ * @llm-rule WHEN: Setting up encryption for the first time or rotating keys
333
+ * @llm-rule AVOID: Using weak or predictable keys - always use this method for key generation
334
+ * @llm-rule NOTE: Returns 64-character hex string suitable for VOILA_SECURITY_ENCRYPTION_KEY
335
+ */
336
+ generateKey() {
337
+ try {
338
+ return crypto.randomBytes(this.config.encryption.keyLength).toString('hex');
339
+ }
340
+ catch (error) {
341
+ throw createSecurityError(`Key generation failed: ${error.message}`, 500);
342
+ }
343
+ }
344
+ // Private helper methods
345
+ /**
346
+ * Generates a cryptographically secure CSRF token
347
+ */
348
+ generateCSRFToken(session, expiryMinutes) {
349
+ if (!session || typeof session !== 'object') {
350
+ throw createSecurityError('Session object required for CSRF token generation', 500);
351
+ }
352
+ const token = crypto.randomBytes(16).toString('hex');
353
+ session.csrfToken = token;
354
+ session.csrfTokenExpiry = Date.now() + expiryMinutes * 60 * 1000;
355
+ return token;
356
+ }
357
+ /**
358
+ * Verifies CSRF token using timing-safe comparison
359
+ */
360
+ verifyCSRFToken(token, session) {
361
+ if (!token || typeof token !== 'string' || !session?.csrfToken) {
362
+ return false;
363
+ }
364
+ // Check expiry
365
+ if (session.csrfTokenExpiry && Date.now() > session.csrfTokenExpiry) {
366
+ return false;
367
+ }
368
+ try {
369
+ const expectedBuffer = Buffer.from(session.csrfToken, 'hex');
370
+ const actualBuffer = Buffer.from(token, 'hex');
371
+ if (expectedBuffer.length !== actualBuffer.length) {
372
+ return false;
373
+ }
374
+ return crypto.timingSafeEqual(expectedBuffer, actualBuffer);
375
+ }
376
+ catch {
377
+ return false;
378
+ }
379
+ }
380
+ /**
381
+ * Gets unique identifier for the client
382
+ */
383
+ getClientKey = (req) => {
384
+ return req.ip ||
385
+ req.connection?.remoteAddress ||
386
+ (req.headers && req.headers['x-forwarded-for']?.split(',')[0]?.trim()) ||
387
+ 'unknown';
388
+ };
389
+ /**
390
+ * Initializes cleanup interval for memory management
391
+ */
392
+ initializeCleanup(windowMs) {
393
+ if (this.cleanupInitialized)
394
+ return;
395
+ const cleanupInterval = Math.min(windowMs, 60 * 1000);
396
+ setInterval(() => {
397
+ const now = Date.now();
398
+ for (const [key, record] of this.requestStore.entries()) {
399
+ if (now > record.resetTime) {
400
+ this.requestStore.delete(key);
401
+ }
402
+ }
403
+ }, cleanupInterval).unref();
404
+ this.cleanupInitialized = true;
405
+ }
406
+ /**
407
+ * Validates encryption key format and length
408
+ */
409
+ validateEncryptionKey(key) {
410
+ if (!key) {
411
+ throw createSecurityError('Encryption key is required', 500);
412
+ }
413
+ const keyBuffer = typeof key === 'string' ? Buffer.from(key, 'hex') : key;
414
+ if (keyBuffer.length !== this.config.encryption.keyLength) {
415
+ throw createSecurityError(`Invalid key length. Expected ${this.config.encryption.keyLength} bytes, got ${keyBuffer.length} bytes`, 500);
416
+ }
417
+ }
418
+ }
419
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/security/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Smart defaults and environment validation for file storage with auto-strategy detection
3
+ * @module @bloomneo/appkit/storage
4
+ * @file src/storage/defaults.ts
5
+ *
6
+ * @llm-rule WHEN: App startup - need to configure storage system and connection strategy
7
+ * @llm-rule AVOID: Calling multiple times - expensive environment parsing, use lazy loading in get()
8
+ * @llm-rule NOTE: Called once at startup, cached globally for performance
9
+ * @llm-rule NOTE: Auto-detects Local vs S3 vs R2 based on environment variables
10
+ */
11
+ export interface LocalConfig {
12
+ dir: string;
13
+ baseUrl: string;
14
+ maxFileSize: number;
15
+ allowedTypes: string[];
16
+ createDirs: boolean;
17
+ }
18
+ export interface S3Config {
19
+ bucket: string;
20
+ region: string;
21
+ endpoint?: string;
22
+ accessKeyId: string;
23
+ secretAccessKey: string;
24
+ forcePathStyle: boolean;
25
+ signedUrlExpiry: number;
26
+ cdnUrl?: string;
27
+ }
28
+ export interface R2Config {
29
+ bucket: string;
30
+ accountId: string;
31
+ accessKeyId: string;
32
+ secretAccessKey: string;
33
+ cdnUrl?: string;
34
+ signedUrlExpiry: number;
35
+ }
36
+ export interface StorageConfig {
37
+ strategy: 'local' | 's3' | 'r2';
38
+ local?: LocalConfig;
39
+ s3?: S3Config;
40
+ r2?: R2Config;
41
+ environment: {
42
+ isDevelopment: boolean;
43
+ isProduction: boolean;
44
+ isTest: boolean;
45
+ nodeEnv: string;
46
+ };
47
+ }
48
+ /**
49
+ * Gets smart defaults using environment variables with auto-strategy detection
50
+ * @llm-rule WHEN: App startup to get production-ready storage configuration
51
+ * @llm-rule AVOID: Calling repeatedly - expensive validation, cache the result
52
+ * @llm-rule NOTE: Auto-detects strategy: S3/R2 env vars → Cloud, nothing → Local
53
+ */
54
+ export declare function getSmartDefaults(): StorageConfig;
55
+ /**
56
+ * Gets storage configuration summary for debugging and health checks
57
+ * @llm-rule WHEN: Debugging storage configuration or building health check endpoints
58
+ * @llm-rule AVOID: Exposing sensitive connection details - this only shows safe info
59
+ */
60
+ export declare function getConfigSummary(): {
61
+ strategy: string;
62
+ local: boolean;
63
+ s3: boolean;
64
+ r2: boolean;
65
+ environment: string;
66
+ };
67
+ /**
68
+ * Checks if cloud storage is available and properly configured
69
+ * @llm-rule WHEN: Conditional logic based on storage capabilities
70
+ * @llm-rule AVOID: Complex storage detection - just use storage normally, strategy handles it
71
+ */
72
+ export declare function hasCloudStorage(): boolean;
73
+ /**
74
+ * Gets recommended configuration for different deployment types
75
+ * @llm-rule WHEN: Setting up storage for specific deployment scenarios
76
+ * @llm-rule AVOID: Default config for specialized deployments - needs specific tuning
77
+ */
78
+ export declare function getDeploymentConfig(type: 'development' | 'staging' | 'production'): Partial<StorageConfig>;
79
+ //# sourceMappingURL=defaults.d.ts.map