ts-prorm-orm 1.1.0

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 (310) hide show
  1. package/CHANGELOG.md +1111 -0
  2. package/LICENSE +21 -0
  3. package/README.md +573 -0
  4. package/dist/audit/history-query.js +180 -0
  5. package/dist/audit/index.js +23 -0
  6. package/dist/audit/logger.js +236 -0
  7. package/dist/cache/cache-manager.js +84 -0
  8. package/dist/cache/index.js +16 -0
  9. package/dist/cache/redis-cluster-cache.js +557 -0
  10. package/dist/cli.js +2200 -0
  11. package/dist/compliance/audit-trail.js +68 -0
  12. package/dist/compliance/backup-verification.js +685 -0
  13. package/dist/compliance/breach-detector.js +505 -0
  14. package/dist/compliance/consent-record.js +227 -0
  15. package/dist/compliance/consent-versioning.js +331 -0
  16. package/dist/compliance/cross-border-log.js +530 -0
  17. package/dist/compliance/data-classifier.js +258 -0
  18. package/dist/compliance/data-lineage.js +565 -0
  19. package/dist/compliance/data-masker.js +303 -0
  20. package/dist/compliance/data-portability.js +265 -0
  21. package/dist/compliance/data-retention.js +195 -0
  22. package/dist/compliance/dsar-workflow.js +342 -0
  23. package/dist/compliance/field-encryption.js +223 -0
  24. package/dist/compliance/immutable-record.js +148 -0
  25. package/dist/compliance/index.js +260 -0
  26. package/dist/compliance/privacy-impact-assessment.js +364 -0
  27. package/dist/compliance/pseudonymization.js +269 -0
  28. package/dist/compliance/query-firewall.js +1182 -0
  29. package/dist/compliance/rate-limiter.js +580 -0
  30. package/dist/compliance/right-to-erasure.js +117 -0
  31. package/dist/compliance/row-level-security.js +246 -0
  32. package/dist/compliance/security-decorator.js +574 -0
  33. package/dist/compliance/security-monitor.js +525 -0
  34. package/dist/compliance/sensitive-data-discovery.js +476 -0
  35. package/dist/compliance/session-isolation.js +472 -0
  36. package/dist/compliance/tls-enforcer.js +108 -0
  37. package/dist/compliance/worm-storage.js +712 -0
  38. package/dist/connection-manager.js +198 -0
  39. package/dist/connection-pool.js +519 -0
  40. package/dist/decorators/audit.js +136 -0
  41. package/dist/decorators/belongs-to-many.js +115 -0
  42. package/dist/decorators/belongs-to.js +115 -0
  43. package/dist/decorators/check.js +435 -0
  44. package/dist/decorators/collate.js +329 -0
  45. package/dist/decorators/comment.js +205 -0
  46. package/dist/decorators/database-settings.js +236 -0
  47. package/dist/decorators/default.js +244 -0
  48. package/dist/decorators/encryption.js +235 -0
  49. package/dist/decorators/engine.js +97 -0
  50. package/dist/decorators/fk-constraints.js +594 -0
  51. package/dist/decorators/foreign-table.js +136 -0
  52. package/dist/decorators/generated.js +274 -0
  53. package/dist/decorators/has-many.js +127 -0
  54. package/dist/decorators/has-one.js +116 -0
  55. package/dist/decorators/hstore.js +129 -0
  56. package/dist/decorators/index.js +355 -0
  57. package/dist/decorators/json-column.js +83 -0
  58. package/dist/decorators/jsonb.js +101 -0
  59. package/dist/decorators/orm-decorators.js +425 -0
  60. package/dist/decorators/permissions.js +294 -0
  61. package/dist/decorators/procedure.js +210 -0
  62. package/dist/decorators/query-options.js +556 -0
  63. package/dist/decorators/range.js +167 -0
  64. package/dist/decorators/set-column.js +83 -0
  65. package/dist/decorators/spatial.js +114 -0
  66. package/dist/decorators/storage.js +580 -0
  67. package/dist/decorators/timezone.js +512 -0
  68. package/dist/decorators/trigger.js +90 -0
  69. package/dist/decorators/uuid.js +135 -0
  70. package/dist/decorators/view.js +258 -0
  71. package/dist/diagrams/chen-diagram.js +354 -0
  72. package/dist/diagrams/class-diagram.js +384 -0
  73. package/dist/diagrams/dependency-diagram.js +432 -0
  74. package/dist/diagrams/er-diagram.js +605 -0
  75. package/dist/diagrams/flow-diagram.js +394 -0
  76. package/dist/diagrams/gantt-diagram.js +411 -0
  77. package/dist/diagrams/index-diagram.js +353 -0
  78. package/dist/diagrams/index.js +184 -0
  79. package/dist/diagrams/migration-diagram.js +316 -0
  80. package/dist/diagrams/model-diagram.js +616 -0
  81. package/dist/diagrams/package-diagram.js +376 -0
  82. package/dist/diagrams/palette.js +85 -0
  83. package/dist/diagrams/relational-diagram.js +455 -0
  84. package/dist/diagrams/schemadoc-diagram.js +309 -0
  85. package/dist/diagrams/sequence-diagram.js +307 -0
  86. package/dist/diagrams/state-diagram.js +344 -0
  87. package/dist/diagrams/svg-dom.js +111 -0
  88. package/dist/diagrams/tree-diagram.js +250 -0
  89. package/dist/dialects/clickhouse/index.js +1742 -0
  90. package/dist/dialects/cockroachdb/index.js +4677 -0
  91. package/dist/dialects/cratedb/index.js +441 -0
  92. package/dist/dialects/databricks/index.js +517 -0
  93. package/dist/dialects/db2/index.js +2225 -0
  94. package/dist/dialects/dialect.js +720 -0
  95. package/dist/dialects/duckdb/index.js +2014 -0
  96. package/dist/dialects/exasol/index.js +357 -0
  97. package/dist/dialects/firebird/index.js +495 -0
  98. package/dist/dialects/greenplum/index.js +457 -0
  99. package/dist/dialects/hana/index.js +1741 -0
  100. package/dist/dialects/mariadb/index.js +3590 -0
  101. package/dist/dialects/mssql/index.js +2296 -0
  102. package/dist/dialects/mysql/index.js +4058 -0
  103. package/dist/dialects/oracle/index.js +2999 -0
  104. package/dist/dialects/postgres/index.js +5319 -0
  105. package/dist/dialects/query-stream-helper.js +152 -0
  106. package/dist/dialects/questdb/index.js +433 -0
  107. package/dist/dialects/redshift/index.js +2277 -0
  108. package/dist/dialects/singlestore/index.js +354 -0
  109. package/dist/dialects/snowflake/index.js +2082 -0
  110. package/dist/dialects/spanner/index.js +1768 -0
  111. package/dist/dialects/sqlite/index.js +3382 -0
  112. package/dist/dialects/tidb/index.js +377 -0
  113. package/dist/dialects/timescaledb/index.js +164 -0
  114. package/dist/dialects/trino/index.js +420 -0
  115. package/dist/dialects/turso/index.js +227 -0
  116. package/dist/dialects/vertica/index.js +317 -0
  117. package/dist/dialects/yugabytedb/index.js +424 -0
  118. package/dist/errors/index.js +472 -0
  119. package/dist/errors/utils.js +340 -0
  120. package/dist/errors.js +21 -0
  121. package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
  122. package/dist/extensions/catalog/mssql-features.js +147 -0
  123. package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
  124. package/dist/extensions/catalog/oracle-db2-features.js +196 -0
  125. package/dist/extensions/catalog/postgres-extensions.js +516 -0
  126. package/dist/extensions/index.js +71 -0
  127. package/dist/extensions/types.js +13 -0
  128. package/dist/foreign-data.js +173 -0
  129. package/dist/hooks/hooks-manager.js +350 -0
  130. package/dist/hooks/index.js +37 -0
  131. package/dist/index.js +463 -0
  132. package/dist/logging.js +335 -0
  133. package/dist/migrations/index.js +40 -0
  134. package/dist/migrations/migration.js +196 -0
  135. package/dist/migrations/migrator.js +411 -0
  136. package/dist/migrations/prormmigration.js +275 -0
  137. package/dist/migrations/query-interface.js +435 -0
  138. package/dist/migrations/seeder.js +353 -0
  139. package/dist/models/associations.js +852 -0
  140. package/dist/models/constraints.js +288 -0
  141. package/dist/models/data-types.js +2518 -0
  142. package/dist/models/decorators.js +445 -0
  143. package/dist/models/index.js +33 -0
  144. package/dist/models/indexes.js +531 -0
  145. package/dist/models/methods.js +382 -0
  146. package/dist/models/model-manager.js +103 -0
  147. package/dist/models/model.js +5349 -0
  148. package/dist/models/operators.js +67 -0
  149. package/dist/models/scopes.js +189 -0
  150. package/dist/models/typescript-types.js +26 -0
  151. package/dist/nosql/aerospike/index.js +205 -0
  152. package/dist/nosql/allegrograph/index.js +169 -0
  153. package/dist/nosql/arangodb/index.js +364 -0
  154. package/dist/nosql/azure-blob/index.js +206 -0
  155. package/dist/nosql/beanstalkd/index.js +231 -0
  156. package/dist/nosql/beequeue/index.js +210 -0
  157. package/dist/nosql/bigchaindb/index.js +195 -0
  158. package/dist/nosql/bigtable/index.js +224 -0
  159. package/dist/nosql/blazegraph/index.js +173 -0
  160. package/dist/nosql/bullmq/index.js +191 -0
  161. package/dist/nosql/cassandra/index.js +174 -0
  162. package/dist/nosql/chroma/index.js +190 -0
  163. package/dist/nosql/cloudflare-kv/index.js +220 -0
  164. package/dist/nosql/coherence/index.js +200 -0
  165. package/dist/nosql/cosmosdb/index.js +157 -0
  166. package/dist/nosql/couchbase/index.js +213 -0
  167. package/dist/nosql/dax/index.js +212 -0
  168. package/dist/nosql/deno-kv/index.js +206 -0
  169. package/dist/nosql/dgraph/index.js +171 -0
  170. package/dist/nosql/doris/index.js +169 -0
  171. package/dist/nosql/druid/index.js +162 -0
  172. package/dist/nosql/dynamodb/index.js +937 -0
  173. package/dist/nosql/elasticsearch/index.js +377 -0
  174. package/dist/nosql/etcd/index.js +502 -0
  175. package/dist/nosql/eventhubs/index.js +213 -0
  176. package/dist/nosql/eventstore/index.js +254 -0
  177. package/dist/nosql/faunadb/index.js +188 -0
  178. package/dist/nosql/firestore/index.js +177 -0
  179. package/dist/nosql/fluree/index.js +148 -0
  180. package/dist/nosql/fuseki/index.js +170 -0
  181. package/dist/nosql/gcs/index.js +172 -0
  182. package/dist/nosql/gearman/index.js +160 -0
  183. package/dist/nosql/geode/index.js +196 -0
  184. package/dist/nosql/graphdb/index.js +169 -0
  185. package/dist/nosql/graylog/index.js +188 -0
  186. package/dist/nosql/gridgain/index.js +171 -0
  187. package/dist/nosql/hazelcast/index.js +162 -0
  188. package/dist/nosql/hbase/index.js +230 -0
  189. package/dist/nosql/ignite/index.js +173 -0
  190. package/dist/nosql/immudb/index.js +184 -0
  191. package/dist/nosql/index.js +232 -0
  192. package/dist/nosql/infinispan/index.js +200 -0
  193. package/dist/nosql/influxdb/index.js +0 -0
  194. package/dist/nosql/kafka/index.js +234 -0
  195. package/dist/nosql/keyspaces/index.js +189 -0
  196. package/dist/nosql/kinesis/index.js +253 -0
  197. package/dist/nosql/leveldb/index.js +153 -0
  198. package/dist/nosql/lmdb/index.js +160 -0
  199. package/dist/nosql/loki/index.js +201 -0
  200. package/dist/nosql/marklogic/index.js +204 -0
  201. package/dist/nosql/materialize/index.js +145 -0
  202. package/dist/nosql/meilisearch/index.js +154 -0
  203. package/dist/nosql/memcached/index.js +223 -0
  204. package/dist/nosql/milvus/index.js +410 -0
  205. package/dist/nosql/minio/index.js +265 -0
  206. package/dist/nosql/momento/index.js +179 -0
  207. package/dist/nosql/mongodb/index.js +461 -0
  208. package/dist/nosql/nats/index.js +247 -0
  209. package/dist/nosql/nedb/index.js +164 -0
  210. package/dist/nosql/neo4j/index.js +450 -0
  211. package/dist/nosql/neptune/index.js +470 -0
  212. package/dist/nosql/nsq/index.js +200 -0
  213. package/dist/nosql/opensearch/index.js +186 -0
  214. package/dist/nosql/orientdb/index.js +175 -0
  215. package/dist/nosql/papertrail/index.js +200 -0
  216. package/dist/nosql/pinecone/index.js +0 -0
  217. package/dist/nosql/pinot/index.js +133 -0
  218. package/dist/nosql/pouchdb/index.js +172 -0
  219. package/dist/nosql/prometheus/index.js +174 -0
  220. package/dist/nosql/provendb/index.js +147 -0
  221. package/dist/nosql/pubsub/index.js +187 -0
  222. package/dist/nosql/pulsar/index.js +232 -0
  223. package/dist/nosql/qdrant/index.js +295 -0
  224. package/dist/nosql/qldb/index.js +192 -0
  225. package/dist/nosql/r2/index.js +281 -0
  226. package/dist/nosql/rabbitmq/index.js +237 -0
  227. package/dist/nosql/ravendb/index.js +175 -0
  228. package/dist/nosql/redis/index.js +607 -0
  229. package/dist/nosql/redpanda/index.js +237 -0
  230. package/dist/nosql/resque/index.js +203 -0
  231. package/dist/nosql/rethinkdb/index.js +232 -0
  232. package/dist/nosql/rocksdb/index.js +152 -0
  233. package/dist/nosql/rockset/index.js +126 -0
  234. package/dist/nosql/s3/index.js +298 -0
  235. package/dist/nosql/scylladb/index.js +178 -0
  236. package/dist/nosql/signoz/index.js +227 -0
  237. package/dist/nosql/sns/index.js +201 -0
  238. package/dist/nosql/solr/index.js +231 -0
  239. package/dist/nosql/splunk/index.js +227 -0
  240. package/dist/nosql/sqs/index.js +246 -0
  241. package/dist/nosql/stardog/index.js +169 -0
  242. package/dist/nosql/starrocks/index.js +170 -0
  243. package/dist/nosql/store.js +2 -0
  244. package/dist/nosql/sumologic/index.js +213 -0
  245. package/dist/nosql/surrealdb/index.js +179 -0
  246. package/dist/nosql/terminusdb/index.js +151 -0
  247. package/dist/nosql/tigergraph/index.js +469 -0
  248. package/dist/nosql/typesense/index.js +148 -0
  249. package/dist/nosql/unqlite/index.js +157 -0
  250. package/dist/nosql/upstash/index.js +167 -0
  251. package/dist/nosql/vercel-kv/index.js +166 -0
  252. package/dist/nosql/victoriametrics/index.js +213 -0
  253. package/dist/nosql/virtuoso/index.js +169 -0
  254. package/dist/nosql/weaviate/index.js +276 -0
  255. package/dist/operators/index.js +108 -0
  256. package/dist/operators.js +2690 -0
  257. package/dist/prisma-migrate/index.js +38 -0
  258. package/dist/prisma-migrate/migration-generator.js +125 -0
  259. package/dist/prisma-migrate/model-generator.js +172 -0
  260. package/dist/prisma-migrate/relations.js +100 -0
  261. package/dist/prisma-migrate/schema-parser.js +167 -0
  262. package/dist/prisma-migrate/type-mapper.js +40 -0
  263. package/dist/prorm.js +6832 -0
  264. package/dist/query-builders/cte-builder.js +80 -0
  265. package/dist/query-builders/functions/aggregate.js +390 -0
  266. package/dist/query-builders/functions/conditional.js +503 -0
  267. package/dist/query-builders/functions/datetime.js +695 -0
  268. package/dist/query-builders/functions/fulltext.js +439 -0
  269. package/dist/query-builders/functions/index.js +93 -0
  270. package/dist/query-builders/functions/json.js +427 -0
  271. package/dist/query-builders/functions/math.js +399 -0
  272. package/dist/query-builders/functions/string.js +518 -0
  273. package/dist/query-builders/functions/window.js +328 -0
  274. package/dist/query-builders/include-builder.js +323 -0
  275. package/dist/query-builders/index-expression-builder.js +242 -0
  276. package/dist/query-builders/index.js +161 -0
  277. package/dist/query-builders/insert-builder.js +164 -0
  278. package/dist/query-builders/model-helpers.js +38 -0
  279. package/dist/query-builders/order-limit-builder.js +239 -0
  280. package/dist/query-builders/sql-compiler.js +2040 -0
  281. package/dist/query-builders/subquery-builder.js +152 -0
  282. package/dist/query-builders/update-builder.js +182 -0
  283. package/dist/query-builders/view-builder.js +218 -0
  284. package/dist/query-builders/where-builder.js +1532 -0
  285. package/dist/query-interface.js +622 -0
  286. package/dist/query-optimizers/batch-optimizer.js +426 -0
  287. package/dist/query-optimizers/explain-plans.js +415 -0
  288. package/dist/query-optimizers/index.js +51 -0
  289. package/dist/query-optimizers/prepared-statement-cache.js +423 -0
  290. package/dist/query-optimizers/query-hints.js +438 -0
  291. package/dist/query-optimizers/query-optimizer.js +278 -0
  292. package/dist/query-optimizers/slow-query-logger.js +271 -0
  293. package/dist/replica-manager.js +507 -0
  294. package/dist/schema/index.js +15 -0
  295. package/dist/schema/migration-generator.js +374 -0
  296. package/dist/schema/schema-differ.js +549 -0
  297. package/dist/schema/types.js +6 -0
  298. package/dist/sql-constants.js +300 -0
  299. package/dist/sqlite-advanced.js +1047 -0
  300. package/dist/streams/index.js +12 -0
  301. package/dist/streams/transforms.js +178 -0
  302. package/dist/transaction.js +456 -0
  303. package/dist/types/index.js +180 -0
  304. package/dist/user-management.js +127 -0
  305. package/dist/utils/date.js +300 -0
  306. package/dist/utils/index.js +1079 -0
  307. package/dist/utils/string.js +161 -0
  308. package/dist/validators/index.js +19 -0
  309. package/dist/validators/validator.js +911 -0
  310. package/package.json +190 -0
@@ -0,0 +1,1182 @@
1
+ "use strict";
2
+ /**
3
+ * Database Firewall / Query Allowlist
4
+ *
5
+ * A security layer that:
6
+ * - Blocks dangerous queries or commands
7
+ * - Allows only approved query patterns
8
+ * - Logs and alerts on blocked queries
9
+ * - Required for: OWASP, CIS Benchmarks compliance
10
+ *
11
+ * Usage:
12
+ * // Create firewall instance
13
+ * const firewall = QueryFirewall.create(prorm, {
14
+ * mode: 'allowlist',
15
+ * onBlock: (block) => console.log('Blocked:', block.query),
16
+ * });
17
+ *
18
+ * // Add allowed patterns
19
+ * firewall.allow('^SELECT \\* FROM users WHERE');
20
+ * firewall.allow('^INSERT INTO orders');
21
+ *
22
+ * // Add blocked patterns (dangerous commands)
23
+ * firewall.block('^DROP (TABLE|DATABASE)');
24
+ * firewall.block('^TRUNCATE');
25
+ *
26
+ * // Check if query is allowed
27
+ * const result = firewall.checkQuery('SELECT * FROM users WHERE id = 1');
28
+ * if (!result.allowed) {
29
+ * console.log('Query blocked:', result.reason);
30
+ * }
31
+ *
32
+ * // Get blocked history
33
+ * const history = firewall.getBlockedHistory();
34
+ */
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.QueryFirewall = exports.DATABASE_RULES = exports.SQLITE_RULES = exports.ORACLE_RULES = exports.MSSQL_RULES = exports.MARIADB_RULES = exports.MYSQL_RULES = exports.POSTGRESQL_RULES = exports.NIST_CSF_RULES = exports.SOX_RULES = exports.HIPAA_RULES = exports.PCI_DSS_RULES = exports.CIS_BENCHMARK_RULES = exports.OWASP_SQL_INJECTION_PATTERNS = exports.FIREWALL_RULES = exports.FirewallModeEnum = void 0;
37
+ exports.analyzeQuerySecurity = analyzeQuerySecurity;
38
+ exports.getRecommendedRules = getRecommendedRules;
39
+ exports.FirewallRules = FirewallRules;
40
+ exports.PostgreSQLFirewall = PostgreSQLFirewall;
41
+ exports.MySQLFirewall = MySQLFirewall;
42
+ exports.MariaDBFirewall = MariaDBFirewall;
43
+ exports.MSSQLFirewall = MSSQLFirewall;
44
+ exports.OracleFirewall = OracleFirewall;
45
+ exports.SQLiteFirewall = SQLiteFirewall;
46
+ exports.applyFirewallRulesToModel = applyFirewallRulesToModel;
47
+ /**
48
+ * Companion enum for {@link FirewallMode}. Provided for callers who prefer
49
+ * enum-based ergonomics (autocomplete, refactor-safety) over raw string
50
+ * literals. The underlying values are identical to the `FirewallMode`
51
+ * string literals, so either form may be used interchangeably.
52
+ */
53
+ var FirewallModeEnum;
54
+ (function (FirewallModeEnum) {
55
+ FirewallModeEnum["Allowlist"] = "allowlist";
56
+ FirewallModeEnum["Blocklist"] = "blocklist";
57
+ FirewallModeEnum["Strict"] = "strict";
58
+ })(FirewallModeEnum || (exports.FirewallModeEnum = FirewallModeEnum = {}));
59
+ // ==================== Firewall Rule Categories ====================
60
+ /** Exportable rule constants for custom configurations */
61
+ exports.FIREWALL_RULES = {
62
+ // Destructive Operations
63
+ DESTRUCTIVE: [
64
+ { pattern: /^DROP\s+(TABLE|DATABASE|SCHEMA|INDEX|PROCEDURE|FUNCTION|VIEW|MATERIALIZED)/i, description: 'DROP object' },
65
+ { pattern: /^TRUNCATE\s+(TABLE)?/i, description: 'TRUNCATE table' },
66
+ { pattern: /^DELETE\s+FROM\s+\w+\s*$/i, description: 'DELETE without WHERE clause' },
67
+ { pattern: /^ALTER\s+TABLE\s+\w+\s+DROP/i, description: 'ALTER TABLE DROP' },
68
+ { pattern: /^ALTER\s+TABLE\s+\w+\s+RENAME/i, description: 'ALTER TABLE RENAME' },
69
+ { pattern: /^DROP\s+INDEX/i, description: 'DROP index' },
70
+ { pattern: /^DROP\s+TRIGGER/i, description: 'DROP trigger' },
71
+ { pattern: /^DROP\s+SEQUENCE/i, description: 'DROP sequence' },
72
+ ],
73
+ // Schema Modification
74
+ SCHEMA_MODIFICATION: [
75
+ { pattern: /^CREATE\s+(TABLE|DATABASE|SCHEMA)/i, description: 'CREATE table/database/schema' },
76
+ { pattern: /^ALTER\s+TABLE\s+\w+\s+ADD\s+COLUMN/i, description: 'ADD column' },
77
+ { pattern: /^ALTER\s+TABLE\s+\w+\s+MODIFY/i, description: 'MODIFY column' },
78
+ { pattern: /^ALTER\s+TABLE\s+\w+\s+CHANGE/i, description: 'CHANGE column' },
79
+ { pattern: /^ALTER\s+TABLE\s+\w+\s+ADD\s+INDEX/i, description: 'ADD index' },
80
+ { pattern: /^CREATE\s+INDEX/i, description: 'CREATE index' },
81
+ { pattern: /^CREATE\s+(UNIQUE\s+)?INDEX/i, description: 'CREATE index' },
82
+ ],
83
+ // Permission Changes
84
+ PERMISSIONS: [
85
+ { pattern: /^GRANT\s+/i, description: 'GRANT permissions' },
86
+ { pattern: /^REVOKE\s+/i, description: 'REVOKE permissions' },
87
+ { pattern: /^CREATE\s+USER/i, description: 'CREATE user' },
88
+ { pattern: /^DROP\s+USER/i, description: 'DROP user' },
89
+ { pattern: /^ALTER\s+USER/i, description: 'ALTER user' },
90
+ { pattern: /^SET\s+PASSWORD/i, description: 'SET password' },
91
+ ],
92
+ // Execution / Code Execution
93
+ CODE_EXECUTION: [
94
+ { pattern: /^EXEC\s*\(/i, description: 'EXEC stored procedure' },
95
+ { pattern: /^EXECUTE\s*\(/i, description: 'EXECUTE stored procedure' },
96
+ { pattern: /^CALL\s+\w+\s*\(/i, description: 'CALL procedure/function' },
97
+ { pattern: /^xp_cmdshell/i, description: 'xp_cmdshell (SQL Server)' },
98
+ { pattern: /^sp_executesql/i, description: 'sp_executesql (SQL Server)' },
99
+ { pattern: /^CREATE\s+(FUNCTION|PROCEDURE)/i, description: 'CREATE function/procedure' },
100
+ { pattern: /^DROP\s+(FUNCTION|PROCEDURE)/i, description: 'DROP function/procedure' },
101
+ ],
102
+ // File Operations
103
+ FILE_OPERATIONS: [
104
+ { pattern: /^load_file\s*\(/i, description: 'LOAD_FILE() - read file' },
105
+ { pattern: /^into\s+outfile/i, description: 'INTO OUTFILE - write file' },
106
+ { pattern: /^into\s+dumpfile/i, description: 'INTO DUMPFILE - write binary file' },
107
+ { pattern: /^SELECT\s+.+\s+FROM\s+\w+\s+WHERE\s+.+\s+like\s+['"]%[\/\\]/i, description: 'Path traversal attempt' },
108
+ { pattern: /\/etc\/passwd/i, description: 'Access /etc/passwd' },
109
+ { pattern: /windows[\/\\]system32/i, description: 'Access Windows system32' },
110
+ ],
111
+ // Information Gathering
112
+ INFORMATION_GATHERING: [
113
+ { pattern: /^SHOW\s+(DATABASES|TABLES|COLUMNS|INDEXES)/i, description: 'SHOW databases/tables/columns' },
114
+ { pattern: /^DESCRIBE\s+\w+/i, description: 'DESCRIBE table' },
115
+ { pattern: /^EXPLAIN\s+/i, description: 'EXPLAIN query' },
116
+ { pattern: /^SELECT\s+@@version/i, description: 'Get database version' },
117
+ { pattern: /^SELECT\s+user\s*\(\s*\)/i, description: 'Get current user' },
118
+ { pattern: /^SELECT\s+current_user/i, description: 'Get current user' },
119
+ { pattern: /^SELECT\s+@@datadir/i, description: 'Get data directory' },
120
+ { pattern: /^SELECT\s+information_schema/i, description: 'Access information_schema' },
121
+ ],
122
+ // Transaction Control
123
+ TRANSACTION_CONTROL: [
124
+ { pattern: /^BEGIN\s*;?\s*$/i, description: 'BEGIN transaction' },
125
+ { pattern: /^START\s+TRANSACTION/i, description: 'START TRANSACTION' },
126
+ { pattern: /^COMMIT\s*;?\s*$/i, description: 'COMMIT transaction' },
127
+ { pattern: /^ROLLBACK\s*;?\s*$/i, description: 'ROLLBACK transaction' },
128
+ { pattern: /^SET\s+TRANSACTION\s+ISOLATION/i, description: 'SET TRANSACTION ISOLATION' },
129
+ ],
130
+ // Bulk Operations
131
+ BULK_OPERATIONS: [
132
+ { pattern: /^BULK\s+INSERT/i, description: 'BULK INSERT' },
133
+ { pattern: /^INSERT\s+INTO\s+\w+\s+SELECT\s+.*\s+FROM\s+\w+\s+WHERE\s+['"]%.*['"]/i, description: 'Bulk insert with wildcard' },
134
+ ],
135
+ // Database Links / Remote Operations
136
+ REMOTE_OPERATIONS: [
137
+ { pattern: /^SELECT\s+.*\s+FROM\s+\w+\.\w+/i, description: 'Cross-database query' },
138
+ { pattern: /^EXEC\s+at\s+\w+/i, description: 'Remote execution (Oracle)' },
139
+ { pattern: /^openquery\s*\(/i, description: 'OPENQUERY - linked server' },
140
+ { pattern: /^opendatasource\s*\(/i, description: 'OPENDATASOURCE' },
141
+ ],
142
+ // Encryption/Decryption
143
+ CRYPTO_OPERATIONS: [
144
+ { pattern: /^CREATE\s+ASYMMETRIC\s+KEY/i, description: 'CREATE asymmetric key' },
145
+ { pattern: /^CREATE\s+SYMMETRIC\s+KEY/i, description: 'CREATE symmetric key' },
146
+ { pattern: /^CREATE\s+CERTIFICATE/i, description: 'CREATE certificate' },
147
+ ],
148
+ // Backup Operations
149
+ BACKUP_OPERATIONS: [
150
+ { pattern: /^BACKUP\s+(DATABASE|LOG)/i, description: 'BACKUP database/log' },
151
+ { pattern: /^RESTORE\s+(DATABASE|LOG)/i, description: 'RESTORE database/log' },
152
+ { pattern: /^mysqldump/i, description: 'mysqldump command' },
153
+ { pattern: /^pg_dump/i, description: 'pg_dump command' },
154
+ ],
155
+ };
156
+ /** OWASP Top 10 SQL Injection patterns */
157
+ exports.OWASP_SQL_INJECTION_PATTERNS = [
158
+ /('\s*or\s*'1'\s*=\s*'1)/i,
159
+ /('\s*or\s*1\s*=\s*1)/i,
160
+ /(union\s+select)/i,
161
+ /(union\s+all\s+select)/i,
162
+ /(\bor\b.*\b=\b)/,
163
+ /(exec\s*\()/i,
164
+ /(;\s*drop\s+table)/i,
165
+ /(\/\*.*\*\/)/,
166
+ /(--\s*)/,
167
+ /(char\s*\(\s*\d+)/,
168
+ /(0x[\da-f]+)/i,
169
+ /(\bor\b\s+\d+\s*=\s*\d+)/,
170
+ /('\s+and\s+'\s*=\s*')/i,
171
+ /(having\s+\d+\s*=\s*\d+)/i,
172
+ /(order\s+by\s+\d+)/i,
173
+ /(benchmark\s*\()/i,
174
+ /(sleep\s*\()/i,
175
+ ];
176
+ /** CIS Benchmarks database security rules */
177
+ exports.CIS_BENCHMARK_RULES = [
178
+ { pattern: /^DROP\s+(TABLE|DATABASE|SCHEMA)/i, description: 'CIS: Block DROP TABLE/DATABASE' },
179
+ { pattern: /^DELETE\s+FROM\s+\w+\s*$/i, description: 'CIS: Block DELETE without WHERE' },
180
+ { pattern: /^GRANT\s+ALL/i, description: 'CIS: Block GRANT ALL' },
181
+ { pattern: /^CREATE\s+(FUNCTION|PROCEDURE)\s+.*\s+RETURNS\s+void/i, description: 'CIS: Block void-returning functions' },
182
+ ];
183
+ /** PCI DSS compliance rules */
184
+ exports.PCI_DSS_RULES = [
185
+ { pattern: /^SELECT\s+.*\s+FROM\s+credit_cards/i, description: 'PCI: Direct SELECT on credit_cards table' },
186
+ { pattern: /^SELECT\s+.*\s+FROM\s+payments\s+WHERE\s+card_number/i, description: 'PCI: Query card numbers' },
187
+ { pattern: /^INSERT\s+INTO\s+audit_log/i, description: 'PCI: All queries must be logged' },
188
+ { pattern: /^DELETE\s+FROM\s+audit_log/i, description: 'PCI: Cannot delete audit logs' },
189
+ ];
190
+ /** HIPAA compliance rules */
191
+ exports.HIPAA_RULES = [
192
+ { pattern: /^SELECT\s+.*\s+FROM\s+patients\s+WHERE\s+ssn/i, description: 'HIPAA: Direct SSN query' },
193
+ { pattern: /^SELECT\s+.*\s+FROM\s+medical_records\s+WHERE\s+diagnosis/i, description: 'HIPAA: Direct diagnosis query' },
194
+ { pattern: /^SELECT\s+.*\s+FROM\s+phi\s+WHERE/i, description: 'HIPAA: PHI access without audit' },
195
+ { pattern: /^DROP\s+(TABLE|DATABASE)\s+\w*patient/i, description: 'HIPAA: Cannot drop patient tables' },
196
+ ];
197
+ /** SOX compliance rules */
198
+ exports.SOX_RULES = [
199
+ { pattern: /^DELETE\s+FROM\s+.*\s+WHERE\s+.*\s+<\s+NOW/i, description: 'SOX: Cannot delete old records' },
200
+ { pattern: /^DROP\s+(TABLE|DATABASE)\s+\w*financial/i, description: 'SOX: Cannot drop financial tables' },
201
+ { pattern: /^TRUNCATE\s+.*\s+financial/i, description: 'SOX: Cannot truncate financial tables' },
202
+ ];
203
+ /** NIST CSF rules */
204
+ exports.NIST_CSF_RULES = [
205
+ { pattern: /^DROP\s+(TABLE|DATABASE)/i, description: 'NIST: Block DROP operations' },
206
+ { pattern: /^DELETE\s+FROM\s+\w+\s*$/i, description: 'NIST: Block bulk DELETE' },
207
+ { pattern: /^GRANT\s+/i, description: 'NIST: Require approval for GRANT' },
208
+ { pattern: /^REVOKE\s+/i, description: 'NIST: Require approval for REVOKE' },
209
+ ];
210
+ /** Default dangerous patterns for general use */
211
+ const DEFAULT_DANGEROUS_PATTERNS = [
212
+ ...exports.FIREWALL_RULES.DESTRUCTIVE,
213
+ ...exports.FIREWALL_RULES.CODE_EXECUTION,
214
+ ...exports.FIREWALL_RULES.FILE_OPERATIONS,
215
+ { pattern: /^xp_cmdshell/i, description: 'xp_cmdshell (SQL Server)' },
216
+ { pattern: /^load_file\s*\(/i, description: 'LOAD_FILE()' },
217
+ { pattern: /^into\s+outfile/i, description: 'INTO OUTFILE' },
218
+ { pattern: /^grant\s+/i, description: 'GRANT' },
219
+ { pattern: /^revoke\s+/i, description: 'REVOKE' },
220
+ ];
221
+ // ==================== Database-Specific Rules ====================
222
+ /** PostgreSQL-specific dangerous patterns */
223
+ exports.POSTGRESQL_RULES = [
224
+ { pattern: /^DROP\s+IF\s+EXISTS\s+(TABLE|DATABASE|SCHEMA)/i, description: 'PostgreSQL: DROP IF EXISTS' },
225
+ { pattern: /^DROP\s+OWNED\s+BY/i, description: 'PostgreSQL: DROP OWNED BY' },
226
+ { pattern: /^DROP\s+ROLE/i, description: 'PostgreSQL: DROP ROLE' },
227
+ { pattern: /^DROP\s+CONVERSION/i, description: 'PostgreSQL: DROP CONVERSION' },
228
+ { pattern: /^DROP\s+LANGUAGE/i, description: 'PostgreSQL: DROP LANGUAGE' },
229
+ { pattern: /^DROP\s+EXTENSION/i, description: 'PostgreSQL: DROP EXTENSION' },
230
+ { pattern: /^CREATE\s+LANGUAGE/i, description: 'PostgreSQL: CREATE LANGUAGE' },
231
+ { pattern: /^CREATE\s+OR\s+REPLACE\s+(FUNCTION|PROCEDURE)/i, description: 'PostgreSQL: CREATE OR REPLACE' },
232
+ { pattern: /^ALTER\s+DEFAULT\s+PRIVILEGES/i, description: 'PostgreSQL: ALTER DEFAULT PRIVILEGES' },
233
+ { pattern: /^COPY\s+/i, description: 'PostgreSQL: COPY command' },
234
+ { pattern: /^pg_read_file/i, description: 'PostgreSQL: pg_read_file()' },
235
+ { pattern: /^pg_write_file/i, description: 'PostgreSQL: pg_write_file()' },
236
+ { pattern: /^pg_execute_server_program/i, description: 'PostgreSQL: pg_execute_server_program' },
237
+ { pattern: /^lo_import/i, description: 'PostgreSQL: lo_import()' },
238
+ { pattern: /^lo_export/i, description: 'PostgreSQL: lo_export()' },
239
+ { pattern: /^SET\s+session\s+authorization/i, description: 'PostgreSQL: SET SESSION AUTHORIZATION' },
240
+ { pattern: /^RESET\s+(session\s+)?authorization/i, description: 'PostgreSQL: RESET AUTHORIZATION' },
241
+ ];
242
+ /** MySQL-specific dangerous patterns */
243
+ exports.MYSQL_RULES = [
244
+ { pattern: /^DROP\s+IF\s+EXISTS/i, description: 'MySQL: DROP IF EXISTS' },
245
+ { pattern: /^DROP\s+PROCEDURE/i, description: 'MySQL: DROP PROCEDURE' },
246
+ { pattern: /^DROP\s+FUNCTION/i, description: 'MySQL: DROP FUNCTION' },
247
+ { pattern: /^DROP\s+TRIGGER/i, description: 'MySQL: DROP TRIGGER' },
248
+ { pattern: /^CREATE\s+PROCEDURE/i, description: 'MySQL: CREATE PROCEDURE' },
249
+ { pattern: /^CREATE\s+FUNCTION/i, description: 'MySQL: CREATE FUNCTION' },
250
+ { pattern: /^CREATE\s+TRIGGER/i, description: 'MySQL: CREATE TRIGGER' },
251
+ { pattern: /^HANDLER\s+\w+\s+OPEN/i, description: 'MySQL: HANDLER OPEN' },
252
+ { pattern: /^LOAD\s+DATA\s+INFILE/i, description: 'MySQL: LOAD DATA INFILE' },
253
+ { pattern: /^SELECT\s+.*\s+INTO\s+OUTFILE/i, description: 'MySQL: SELECT INTO OUTFILE' },
254
+ { pattern: /^SET\s+GLOBAL\s+\w+/i, description: 'MySQL: SET GLOBAL' },
255
+ { pattern: /^SET\s+@@global\./i, description: 'MySQL: SET @@global' },
256
+ { pattern: /^KILL\s+(CONNECTION|QUERY)?/i, description: 'MySQL: KILL' },
257
+ { pattern: /^SHUTDOWN/i, description: 'MySQL: SHUTDOWN' },
258
+ { pattern: /^BINLOG\s+/i, description: 'MySQL: BINLOG' },
259
+ { pattern: /^SHOW\s+BINLOG/i, description: 'MySQL: SHOW BINLOG' },
260
+ ];
261
+ /** MariaDB-specific dangerous patterns */
262
+ exports.MARIADB_RULES = [
263
+ ...exports.MYSQL_RULES,
264
+ { pattern: /^CREATE\s+OR\s+REPLACE\s+VIEW/i, description: 'MariaDB: CREATE OR REPLACE VIEW' },
265
+ { pattern: /^CREATE\s+EVENT/i, description: 'MariaDB: CREATE EVENT' },
266
+ { pattern: /^DROP\s+EVENT/i, description: 'MariaDB: DROP EVENT' },
267
+ { pattern: /^SET\s+GLOBAL\s+sql_mode/i, description: 'MariaDB: SET GLOBAL sql_mode' },
268
+ { pattern: /^SET\s+@@session\.\w+/i, description: 'MariaDB: SET SESSION' },
269
+ ];
270
+ /** Microsoft SQL Server-specific dangerous patterns */
271
+ exports.MSSQL_RULES = [
272
+ { pattern: /^DROP\s+IF\s+EXISTS/i, description: 'MSSQL: DROP IF EXISTS' },
273
+ { pattern: /^DROP\s+PROCEDURE/i, description: 'MSSQL: DROP PROCEDURE' },
274
+ { pattern: /^DROP\s+FUNCTION/i, description: 'MSSQL: DROP FUNCTION' },
275
+ { pattern: /^DROP\s+TRIGGER/i, description: 'MSSQL: DROP TRIGGER' },
276
+ { pattern: /^CREATE\s+PROCEDURE/i, description: 'MSSQL: CREATE PROCEDURE' },
277
+ { pattern: /^CREATE\s+FUNCTION/i, description: 'MSSQL: CREATE FUNCTION' },
278
+ { pattern: /^CREATE\s+TRIGGER/i, description: 'MSSQL: CREATE TRIGGER' },
279
+ { pattern: /^xp_cmdshell/i, description: 'MSSQL: xp_cmdshell' },
280
+ { pattern: /^sp_executesql/i, description: 'MSSQL: sp_executesql' },
281
+ { pattern: /^sp_addjob/i, description: 'MSSQL: sp_addjob' },
282
+ { pattern: /^sp_oacreate/i, description: 'MSSQL: sp_oacreate' },
283
+ { pattern: /^sp_oamethod/i, description: 'MSSQL: sp_oamethod' },
284
+ { pattern: /^OPENROWSET/i, description: 'MSSQL: OPENROWSET' },
285
+ { pattern: /^OPENDATASOURCE/i, description: 'MSSQL: OPENDATASOURCE' },
286
+ { pattern: /^BACKUP\s+LOG/i, description: 'MSSQL: BACKUP LOG' },
287
+ { pattern: /^RESTORE\s+LOG/i, description: 'MSSQL: RESTORE LOG' },
288
+ { pattern: /^ALTER\s+LOGIN/i, description: 'MSSQL: ALTER LOGIN' },
289
+ { pattern: /^CREATE\s+LOGIN/i, description: 'MSSQL: CREATE LOGIN' },
290
+ { pattern: /^DROP\s+LOGIN/i, description: 'MSSQL: DROP LOGIN' },
291
+ { pattern: /^EXEC\s+at\s+\w+/i, description: 'MSSQL: Linked server execution' },
292
+ { pattern: /^EXEC\s+sp_executesql/i, description: 'MSSQL: sp_executesql' },
293
+ ];
294
+ /** Oracle-specific dangerous patterns */
295
+ exports.ORACLE_RULES = [
296
+ { pattern: /^DROP\s+(TABLE|DATABASE|SCHEMA)\s+\w+/i, description: 'Oracle: DROP object' },
297
+ { pattern: /^DROP\s+(PROCEDURE|FUNCTION|PACKAGE|TRIGGER|VIEW|SYNONYM)/i, description: 'Oracle: DROP object' },
298
+ { pattern: /^CREATE\s+(OR\s+REPLACE\s+)?(PROCEDURE|FUNCTION|PACKAGE|TRIGGER|VIEW)/i, description: 'Oracle: CREATE object' },
299
+ { pattern: /^DROP\s+USER\s+CASCADE/i, description: 'Oracle: DROP USER CASCADE' },
300
+ { pattern: /^DROP\s+INDEX/i, description: 'Oracle: DROP INDEX' },
301
+ { pattern: /^GRANT\s+\w+\s+TO\s+\w+/i, description: 'Oracle: GRANT' },
302
+ { pattern: /^REVOKE\s+\w+\s+FROM\s+\w+/i, description: 'Oracle: REVOKE' },
303
+ { pattern: /^BEGIN\s+.*\s+EXECUTE\s+IMMEDIATE/i, description: 'Oracle: EXECUTE IMMEDIATE' },
304
+ { pattern: /^SELECT\s+ANY\s+TABLE/i, description: 'Oracle: SELECT ANY TABLE' },
305
+ { pattern: /^SELECT\s+INTO\s+\w+\s+FROM\s+v\$/i, description: 'Oracle: V$ tables access' },
306
+ { pattern: /^DBMS_JAVA/i, description: 'Oracle: DBMS_JAVA' },
307
+ { pattern: /^DBMS_SCHEDULER/i, description: 'Oracle: DBMS_SCHEDULER' },
308
+ { pattern: /^DBMS_OUTPUT/i, description: 'Oracle: DBMS_OUTPUT' },
309
+ { pattern: /^UTL_FILE/i, description: 'Oracle: UTL_FILE' },
310
+ { pattern: /^UTL_HTTP/i, description: 'Oracle: UTL_HTTP' },
311
+ { pattern: /^DBMS_XMLGEN/i, description: 'Oracle: DBMS_XMLGEN' },
312
+ { pattern: /^CREATE\s+PROFILE/i, description: 'Oracle: CREATE PROFILE' },
313
+ { pattern: /^ALTER\s+PROFILE/i, description: 'Oracle: ALTER PROFILE' },
314
+ { pattern: /^DROP\s+PROFILE/i, description: 'Oracle: DROP PROFILE' },
315
+ ];
316
+ /** SQLite-specific dangerous patterns */
317
+ exports.SQLITE_RULES = [
318
+ { pattern: /^DROP\s+(TABLE|DATABASE|INDEX|TRIGGER|VIEW)\s+\w+/i, description: 'SQLite: DROP object' },
319
+ { pattern: /^DETACH\s+DATABASE/i, description: 'SQLite: DETACH DATABASE' },
320
+ { pattern: /^ATTACH\s+DATABASE/i, description: 'SQLite: ATTACH DATABASE' },
321
+ { pattern: /\.mode\s+\w+/i, description: 'SQLite: .mode command' },
322
+ { pattern: /\.import\s+/i, description: 'SQLite: .import command' },
323
+ { pattern: /\.dump\s+/i, description: 'SQLite: .dump command' },
324
+ ];
325
+ /** All database-specific rules */
326
+ exports.DATABASE_RULES = {
327
+ postgresql: exports.POSTGRESQL_RULES,
328
+ mysql: exports.MYSQL_RULES,
329
+ mariadb: exports.MARIADB_RULES,
330
+ mssql: exports.MSSQL_RULES,
331
+ oracle: exports.ORACLE_RULES,
332
+ sqlite: exports.SQLITE_RULES,
333
+ };
334
+ // ==================== Query Firewall Class ====================
335
+ class QueryFirewall {
336
+ constructor(prorm, options = {}) {
337
+ this.allowRules = [];
338
+ this.blockRules = [];
339
+ this.blockedHistory = [];
340
+ this.queryLog = [];
341
+ this.originalQuery = null;
342
+ this.isActive = false;
343
+ this.prorm = prorm;
344
+ this.options = {
345
+ mode: options.mode ?? 'allowlist',
346
+ blockDangerousByDefault: options.blockDangerousByDefault ?? true,
347
+ onBlock: options.onBlock ?? (() => { }),
348
+ onAllow: options.onAllow ?? (() => { }),
349
+ maxHistory: options.maxHistory ?? 1000,
350
+ logAllQueries: options.logAllQueries ?? false,
351
+ caseInsensitive: options.caseInsensitive ?? true,
352
+ rules: options.rules ?? [],
353
+ frameworks: options.frameworks ?? [],
354
+ };
355
+ // Initialize with default rules
356
+ this.initializeRules();
357
+ }
358
+ /**
359
+ * Create a new firewall instance (factory method)
360
+ */
361
+ static create(prorm, options) {
362
+ const instance = new QueryFirewall(prorm, options);
363
+ QueryFirewall.instances.set(prorm, instance);
364
+ return instance;
365
+ }
366
+ /**
367
+ * Get existing instance for a Prorm instance
368
+ */
369
+ static getInstance(prorm) {
370
+ return QueryFirewall.instances.get(prorm);
371
+ }
372
+ /**
373
+ * Initialize default rules
374
+ */
375
+ initializeRules() {
376
+ // Add dangerous patterns if configured
377
+ if (this.options.blockDangerousByDefault) {
378
+ for (const rule of DEFAULT_DANGEROUS_PATTERNS) {
379
+ this.blockRules.push({
380
+ id: `default-block-${this.blockRules.length}`,
381
+ type: 'block',
382
+ pattern: rule.pattern,
383
+ description: rule.description,
384
+ createdAt: new Date(),
385
+ });
386
+ }
387
+ }
388
+ // Add OWASP SQL injection patterns
389
+ if (this.options.frameworks.includes('OWASP') || this.options.blockDangerousByDefault) {
390
+ for (const pattern of exports.OWASP_SQL_INJECTION_PATTERNS) {
391
+ this.blockRules.push({
392
+ id: `owasp-sql-injection-${this.blockRules.length}`,
393
+ type: 'block',
394
+ pattern,
395
+ description: 'OWASP SQL Injection pattern',
396
+ createdAt: new Date(),
397
+ });
398
+ }
399
+ }
400
+ // CIS Benchmarks - require explicit allow for data modification
401
+ if (this.options.frameworks.includes('CIS')) {
402
+ // Add strict block rules for CIS compliance
403
+ this.blockRules.push({
404
+ id: 'cis-drop-all',
405
+ type: 'block',
406
+ pattern: /^DROP\s+(TABLE|DATABASE)/i,
407
+ description: 'CIS: Block DROP DATABASE/TABLE',
408
+ createdAt: new Date(),
409
+ });
410
+ }
411
+ // Add custom rules
412
+ for (const rule of this.options.rules) {
413
+ if (rule.type === 'allow') {
414
+ this.allow(rule.pattern, rule.description);
415
+ }
416
+ else {
417
+ this.block(rule.pattern, rule.description);
418
+ }
419
+ }
420
+ }
421
+ /**
422
+ * Add an allowed pattern
423
+ */
424
+ allow(pattern, description) {
425
+ const rule = {
426
+ id: `allow-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
427
+ type: 'allow',
428
+ pattern,
429
+ description,
430
+ createdAt: new Date(),
431
+ };
432
+ this.allowRules.push(rule);
433
+ return rule;
434
+ }
435
+ /**
436
+ * Add a blocked pattern
437
+ */
438
+ block(pattern, description) {
439
+ const rule = {
440
+ id: `block-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
441
+ type: 'block',
442
+ pattern,
443
+ description,
444
+ createdAt: new Date(),
445
+ };
446
+ this.blockRules.push(rule);
447
+ return rule;
448
+ }
449
+ /**
450
+ * Remove a rule by ID
451
+ */
452
+ removeRule(ruleId) {
453
+ const allowIndex = this.allowRules.findIndex(r => r.id === ruleId);
454
+ if (allowIndex !== -1) {
455
+ this.allowRules.splice(allowIndex, 1);
456
+ return true;
457
+ }
458
+ const blockIndex = this.blockRules.findIndex(r => r.id === ruleId);
459
+ if (blockIndex !== -1) {
460
+ this.blockRules.splice(blockIndex, 1);
461
+ return true;
462
+ }
463
+ return false;
464
+ }
465
+ /**
466
+ * Check if a query is allowed
467
+ */
468
+ checkQuery(sql) {
469
+ const analysis = this.analyzeQuery(sql);
470
+ // Apply firewall mode logic
471
+ let allowed = true;
472
+ let reason;
473
+ let matchedRule;
474
+ // Block rules (populated by blockDangerousByDefault / explicit addBlockRule calls)
475
+ // are a safety net that applies regardless of mode - including 'allowlist' mode.
476
+ // Previously this check only ran for 'blocklist'/'strict', so 'allowlist' mode
477
+ // with zero configured allow rules (the out-of-the-box default) silently allowed
478
+ // every query, dangerous or not.
479
+ const matchedBlock = this.blockRules.find(rule => this.matchPattern(sql, rule.pattern));
480
+ if (matchedBlock) {
481
+ allowed = false;
482
+ reason = `Query matches blocked pattern: ${matchedBlock.description || matchedBlock.pattern}`;
483
+ matchedRule = matchedBlock.id;
484
+ }
485
+ if (allowed && (this.options.mode === 'allowlist' || this.options.mode === 'strict')) {
486
+ // In allowlist/strict mode, an explicitly-configured allowlist means the query
487
+ // must match at least one allow rule. With zero allow rules configured, fail
488
+ // closed (deny) rather than silently allowing everything - a firewall that
489
+ // allows all traffic when unconfigured isn't a firewall.
490
+ const matchesAllow = this.allowRules.some(rule => this.matchPattern(sql, rule.pattern));
491
+ if (!matchesAllow) {
492
+ allowed = false;
493
+ reason =
494
+ this.allowRules.length > 0
495
+ ? 'Query does not match any allowed pattern'
496
+ : 'No allow rules configured - denying by default (fail closed)';
497
+ matchedRule = this.options.mode === 'strict' ? 'strict-allow' : 'allowlist';
498
+ }
499
+ }
500
+ // Update analysis result
501
+ analysis.allowed = allowed;
502
+ analysis.reason = reason;
503
+ analysis.matchedRule = matchedRule;
504
+ // Handle blocked query
505
+ if (!allowed) {
506
+ const blocked = {
507
+ id: `blocked-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
508
+ timestamp: new Date(),
509
+ query: sql,
510
+ reason: reason || 'Query blocked',
511
+ matchedRule: matchedRule || 'unknown',
512
+ operation: analysis.operation,
513
+ };
514
+ this.blockedHistory.push(blocked);
515
+ // Trim history
516
+ if (this.blockedHistory.length > this.options.maxHistory) {
517
+ this.blockedHistory = this.blockedHistory.slice(-this.options.maxHistory);
518
+ }
519
+ // Callback
520
+ this.options.onBlock(blocked);
521
+ }
522
+ else {
523
+ // Callback for allowed query
524
+ this.options.onAllow(analysis);
525
+ }
526
+ // Log if enabled
527
+ if (this.options.logAllQueries) {
528
+ this.queryLog.push(analysis);
529
+ if (this.queryLog.length > this.options.maxHistory) {
530
+ this.queryLog = this.queryLog.slice(-this.options.maxHistory);
531
+ }
532
+ }
533
+ return analysis;
534
+ }
535
+ /**
536
+ * Analyze a query without applying firewall rules
537
+ */
538
+ analyzeQuery(sql) {
539
+ const upperQuery = sql.toUpperCase();
540
+ let operation = 'UNKNOWN';
541
+ if (upperQuery.includes('SELECT'))
542
+ operation = 'SELECT';
543
+ else if (upperQuery.includes('INSERT'))
544
+ operation = 'INSERT';
545
+ else if (upperQuery.includes('UPDATE'))
546
+ operation = 'UPDATE';
547
+ else if (upperQuery.includes('DELETE'))
548
+ operation = 'DELETE';
549
+ else if (upperQuery.includes('DROP'))
550
+ operation = 'DROP';
551
+ else if (upperQuery.includes('TRUNCATE'))
552
+ operation = 'TRUNCATE';
553
+ else if (upperQuery.includes('ALTER'))
554
+ operation = 'ALTER';
555
+ else if (upperQuery.includes('CREATE'))
556
+ operation = 'CREATE';
557
+ else if (upperQuery.includes('EXEC') || upperQuery.includes('CALL'))
558
+ operation = 'EXECUTE';
559
+ // Extract table names
560
+ const tableMatches = sql.match(/(?:from|into|update|table)\s+`?(\w+)`?/gi) || [];
561
+ const tables = tableMatches
562
+ .map(m => m.replace(/`/g, '').split(' ').pop() || '')
563
+ .filter(Boolean);
564
+ // Check for sensitive data patterns
565
+ const sensitivePatterns = [
566
+ { name: 'SSN', pattern: /\b\d{3}-\d{2}-\d{4}\b/ },
567
+ { name: 'Credit Card', pattern: /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/ },
568
+ { name: 'Email', pattern: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/ },
569
+ ];
570
+ const containsSensitiveData = sensitivePatterns.some(s => s.pattern.test(sql));
571
+ // Calculate risk score
572
+ let riskScore = 0;
573
+ if (operation === 'DROP' || operation === 'TRUNCATE')
574
+ riskScore += 80;
575
+ if (operation === 'DELETE')
576
+ riskScore += 50;
577
+ if (operation === 'UPDATE')
578
+ riskScore += 30;
579
+ if (containsSensitiveData)
580
+ riskScore += 20;
581
+ if (sql.length > 1000)
582
+ riskScore += 10;
583
+ // Check for SQL injection patterns
584
+ for (const pattern of exports.OWASP_SQL_INJECTION_PATTERNS) {
585
+ if (pattern.test(sql)) {
586
+ riskScore += 50;
587
+ break;
588
+ }
589
+ }
590
+ return {
591
+ query: sql,
592
+ allowed: true,
593
+ operation,
594
+ tables,
595
+ containsSensitiveData,
596
+ riskScore,
597
+ };
598
+ }
599
+ /**
600
+ * Match a pattern against a query
601
+ */
602
+ matchPattern(query, pattern) {
603
+ try {
604
+ if (pattern instanceof RegExp) {
605
+ return this.options.caseInsensitive
606
+ ? pattern.test(query)
607
+ : new RegExp(pattern.source, pattern.flags.replace('i', '') + (this.options.caseInsensitive ? 'i' : '')).test(query);
608
+ }
609
+ // Convert string to regex
610
+ const flags = this.options.caseInsensitive ? 'i' : '';
611
+ const regex = new RegExp(pattern, flags);
612
+ return regex.test(query);
613
+ }
614
+ catch {
615
+ return false;
616
+ }
617
+ }
618
+ /**
619
+ * Get blocked query history
620
+ */
621
+ getBlockedHistory(options) {
622
+ let filtered = [...this.blockedHistory];
623
+ if (options?.since) {
624
+ filtered = filtered.filter(b => b.timestamp >= options.since);
625
+ }
626
+ if (options?.operation) {
627
+ filtered = filtered.filter(b => b.operation === options.operation);
628
+ }
629
+ if (options?.limit) {
630
+ filtered = filtered.slice(-options.limit);
631
+ }
632
+ return filtered;
633
+ }
634
+ /**
635
+ * Get query log (if logging enabled)
636
+ */
637
+ getQueryLog(limit) {
638
+ const log = [...this.queryLog];
639
+ return limit ? log.slice(-limit) : log;
640
+ }
641
+ /**
642
+ * Get all rules
643
+ */
644
+ getRules() {
645
+ return {
646
+ allowRules: [...this.allowRules],
647
+ blockRules: [...this.blockRules],
648
+ };
649
+ }
650
+ /**
651
+ * Get statistics
652
+ */
653
+ getStats() {
654
+ const blockedByOperation = {
655
+ SELECT: 0,
656
+ INSERT: 0,
657
+ UPDATE: 0,
658
+ DELETE: 0,
659
+ DROP: 0,
660
+ TRUNCATE: 0,
661
+ ALTER: 0,
662
+ CREATE: 0,
663
+ EXECUTE: 0,
664
+ UNKNOWN: 0,
665
+ };
666
+ for (const blocked of this.blockedHistory) {
667
+ blockedByOperation[blocked.operation]++;
668
+ }
669
+ return {
670
+ totalBlocked: this.blockedHistory.length,
671
+ totalAllowed: this.queryLog.filter(q => q.allowed).length,
672
+ blockedByOperation,
673
+ allowRulesCount: this.allowRules.length,
674
+ blockRulesCount: this.blockRules.length,
675
+ isActive: this.isActive,
676
+ };
677
+ }
678
+ /**
679
+ * Apply CIS Benchmarks rules
680
+ */
681
+ applyCisRules() {
682
+ for (const rule of exports.CIS_BENCHMARK_RULES) {
683
+ this.block(rule.pattern, rule.description);
684
+ }
685
+ }
686
+ /**
687
+ * Apply PCI DSS rules
688
+ */
689
+ applyPciRules() {
690
+ for (const rule of exports.PCI_DSS_RULES) {
691
+ this.block(rule.pattern, rule.description);
692
+ }
693
+ }
694
+ /**
695
+ * Apply HIPAA rules
696
+ */
697
+ applyHipaaRules() {
698
+ for (const rule of exports.HIPAA_RULES) {
699
+ this.block(rule.pattern, rule.description);
700
+ }
701
+ }
702
+ /**
703
+ * Apply SOX rules
704
+ */
705
+ applySoxRules() {
706
+ for (const rule of exports.SOX_RULES) {
707
+ this.block(rule.pattern, rule.description);
708
+ }
709
+ }
710
+ /**
711
+ * Apply NIST CSF rules
712
+ */
713
+ applyNistRules() {
714
+ for (const rule of exports.NIST_CSF_RULES) {
715
+ this.block(rule.pattern, rule.description);
716
+ }
717
+ }
718
+ /**
719
+ * Apply OWASP SQL Injection patterns
720
+ */
721
+ applyOwaspRules() {
722
+ for (const pattern of exports.OWASP_SQL_INJECTION_PATTERNS) {
723
+ this.block(pattern, 'OWASP SQL Injection pattern');
724
+ }
725
+ }
726
+ /**
727
+ * Apply all destructive operation rules
728
+ */
729
+ applyDestructiveRules() {
730
+ for (const rule of exports.FIREWALL_RULES.DESTRUCTIVE) {
731
+ this.block(rule.pattern, rule.description);
732
+ }
733
+ }
734
+ /**
735
+ * Apply all schema modification rules
736
+ */
737
+ applySchemaRules() {
738
+ for (const rule of exports.FIREWALL_RULES.SCHEMA_MODIFICATION) {
739
+ this.block(rule.pattern, rule.description);
740
+ }
741
+ }
742
+ /**
743
+ * Apply all permission rules
744
+ */
745
+ applyPermissionRules() {
746
+ for (const rule of exports.FIREWALL_RULES.PERMISSIONS) {
747
+ this.block(rule.pattern, rule.description);
748
+ }
749
+ }
750
+ /**
751
+ * Apply all file operation rules
752
+ */
753
+ applyFileRules() {
754
+ for (const rule of exports.FIREWALL_RULES.FILE_OPERATIONS) {
755
+ this.block(rule.pattern, rule.description);
756
+ }
757
+ }
758
+ /**
759
+ * Apply all information gathering rules
760
+ */
761
+ applyInfoGatheringRules() {
762
+ for (const rule of exports.FIREWALL_RULES.INFORMATION_GATHERING) {
763
+ this.block(rule.pattern, rule.description);
764
+ }
765
+ }
766
+ /**
767
+ * Apply all code execution rules
768
+ */
769
+ applyCodeExecutionRules() {
770
+ for (const rule of exports.FIREWALL_RULES.CODE_EXECUTION) {
771
+ this.block(rule.pattern, rule.description);
772
+ }
773
+ }
774
+ /**
775
+ * Apply all transaction control rules
776
+ */
777
+ applyTransactionRules() {
778
+ for (const rule of exports.FIREWALL_RULES.TRANSACTION_CONTROL) {
779
+ this.block(rule.pattern, rule.description);
780
+ }
781
+ }
782
+ /**
783
+ * Apply all remote operation rules
784
+ */
785
+ applyRemoteOperationRules() {
786
+ for (const rule of exports.FIREWALL_RULES.REMOTE_OPERATIONS) {
787
+ this.block(rule.pattern, rule.description);
788
+ }
789
+ }
790
+ /**
791
+ * Apply all crypto operation rules
792
+ */
793
+ applyCryptoRules() {
794
+ for (const rule of exports.FIREWALL_RULES.CRYPTO_OPERATIONS) {
795
+ this.block(rule.pattern, rule.description);
796
+ }
797
+ }
798
+ /**
799
+ * Apply all backup operation rules
800
+ */
801
+ applyBackupRules() {
802
+ for (const rule of exports.FIREWALL_RULES.BACKUP_OPERATIONS) {
803
+ this.block(rule.pattern, rule.description);
804
+ }
805
+ }
806
+ /**
807
+ * Apply database-specific rules
808
+ * @param database - 'postgresql' | 'mysql' | 'mariadb' | 'mssql' | 'oracle' | 'sqlite'
809
+ */
810
+ applyDatabaseRules(database) {
811
+ const rules = exports.DATABASE_RULES[database];
812
+ if (rules) {
813
+ for (const rule of rules) {
814
+ this.block(rule.pattern, `${database.toUpperCase()}: ${rule.description}`);
815
+ }
816
+ }
817
+ }
818
+ /**
819
+ * Apply all predefined security rules
820
+ */
821
+ applyAllSecurityRules() {
822
+ this.applyDestructiveRules();
823
+ this.applySchemaRules();
824
+ this.applyPermissionRules();
825
+ this.applyFileRules();
826
+ this.applyInfoGatheringRules();
827
+ this.applyCodeExecutionRules();
828
+ this.applyTransactionRules();
829
+ this.applyRemoteOperationRules();
830
+ this.applyCryptoRules();
831
+ this.applyBackupRules();
832
+ this.applyOwaspRules();
833
+ }
834
+ /**
835
+ * Apply predefined compliance framework rules
836
+ * @param framework - 'CIS', 'PCI', 'HIPAA', 'SOX', 'NIST', 'OWASP'
837
+ */
838
+ applyFrameworkRules(framework) {
839
+ switch (framework) {
840
+ case 'CIS':
841
+ this.applyCisRules();
842
+ break;
843
+ case 'PCI':
844
+ this.applyPciRules();
845
+ break;
846
+ case 'HIPAA':
847
+ this.applyHipaaRules();
848
+ break;
849
+ case 'SOX':
850
+ this.applySoxRules();
851
+ break;
852
+ case 'NIST':
853
+ this.applyNistRules();
854
+ break;
855
+ case 'OWASP':
856
+ this.applyOwaspRules();
857
+ break;
858
+ }
859
+ }
860
+ /**
861
+ * Start the firewall - intercept queries
862
+ */
863
+ start() {
864
+ if (this.isActive)
865
+ return;
866
+ this.isActive = true;
867
+ this.originalQuery = this.prorm.query;
868
+ this.prorm.query = async (...args) => {
869
+ const query = typeof args[0] === 'string' ? args[0] : args[0]?.sql ?? '';
870
+ if (query.trim()) {
871
+ const analysis = this.checkQuery(query);
872
+ if (!analysis.allowed) {
873
+ throw new Error(`Query blocked by firewall: ${analysis.reason}`);
874
+ }
875
+ }
876
+ return this.originalQuery.apply(this.prorm, args);
877
+ };
878
+ }
879
+ /**
880
+ * Stop the firewall - restore original query method
881
+ */
882
+ stop() {
883
+ if (!this.isActive)
884
+ return;
885
+ this.isActive = false;
886
+ if (this.originalQuery) {
887
+ this.prorm.query = this.originalQuery;
888
+ this.originalQuery = null;
889
+ }
890
+ }
891
+ /**
892
+ * Check if firewall is active
893
+ */
894
+ isFirewallActive() {
895
+ return this.isActive;
896
+ }
897
+ /**
898
+ * Clear blocked history
899
+ */
900
+ clearHistory() {
901
+ this.blockedHistory = [];
902
+ }
903
+ /**
904
+ * Clear query log
905
+ */
906
+ clearLog() {
907
+ this.queryLog = [];
908
+ }
909
+ /**
910
+ * Export rules for audit purposes
911
+ */
912
+ exportRules() {
913
+ return JSON.stringify({
914
+ allowRules: this.allowRules.map(r => ({
915
+ ...r,
916
+ pattern: r.pattern instanceof RegExp ? r.pattern.source : r.pattern,
917
+ })),
918
+ blockRules: this.blockRules.map(r => ({
919
+ ...r,
920
+ pattern: r.pattern instanceof RegExp ? r.pattern.source : r.pattern,
921
+ })),
922
+ }, null, 2);
923
+ }
924
+ /**
925
+ * Import rules from JSON
926
+ */
927
+ importRules(json) {
928
+ const data = JSON.parse(json);
929
+ if (data.allowRules) {
930
+ for (const rule of data.allowRules) {
931
+ this.allow(rule.pattern instanceof RegExp ? rule.pattern.source : rule.pattern, rule.description);
932
+ }
933
+ }
934
+ if (data.blockRules) {
935
+ for (const rule of data.blockRules) {
936
+ this.block(rule.pattern instanceof RegExp ? rule.pattern.source : rule.pattern, rule.description);
937
+ }
938
+ }
939
+ }
940
+ }
941
+ exports.QueryFirewall = QueryFirewall;
942
+ QueryFirewall.instances = new Map();
943
+ // ==================== Static Helper Functions ====================
944
+ /**
945
+ * Analyze a query for security issues (static method)
946
+ */
947
+ function analyzeQuerySecurity(query) {
948
+ const detectedPatterns = [];
949
+ // Check SQL injection patterns
950
+ for (const pattern of exports.OWASP_SQL_INJECTION_PATTERNS) {
951
+ if (pattern.test(query)) {
952
+ detectedPatterns.push(`SQL_INJECTION:${pattern.source}`);
953
+ }
954
+ }
955
+ // Check for dangerous operations
956
+ let isDangerousOperation = false;
957
+ const upperQuery = query.toUpperCase();
958
+ if (/^DROP\s+/i.test(upperQuery) || /^TRUNCATE/i.test(upperQuery)) {
959
+ isDangerousOperation = true;
960
+ detectedPatterns.push('DANGEROUS_OPERATION:DROP_OR_TRUNCATE');
961
+ }
962
+ if (/^DELETE\s+FROM\s+\w+\s*$/i.test(upperQuery)) {
963
+ isDangerousOperation = true;
964
+ detectedPatterns.push('DANGEROUS_OPERATION:DELETE_ALL');
965
+ }
966
+ // Determine risk level
967
+ let riskLevel = 'low';
968
+ if (detectedPatterns.some(p => p.startsWith('SQL_INJECTION'))) {
969
+ riskLevel = 'critical';
970
+ }
971
+ else if (detectedPatterns.some(p => p.startsWith('DANGEROUS_OPERATION'))) {
972
+ riskLevel = 'high';
973
+ }
974
+ else if (isDangerousOperation) {
975
+ riskLevel = 'medium';
976
+ }
977
+ return {
978
+ isSQLInjection: detectedPatterns.some(p => p.startsWith('SQL_INJECTION')),
979
+ isDangerousOperation,
980
+ riskLevel,
981
+ detectedPatterns,
982
+ };
983
+ }
984
+ /**
985
+ * Get recommended firewall rules for compliance frameworks
986
+ */
987
+ function getRecommendedRules(frameworks) {
988
+ const rules = [];
989
+ // OWASP recommendations
990
+ if (frameworks.includes('OWASP')) {
991
+ rules.push({ type: 'block', pattern: "('|(\\'))", description: 'OWASP: Quote escaping' }, { type: 'block', pattern: '(union\\s+select)', description: 'OWASP: UNION SELECT' }, { type: 'block', pattern: '(--)', description: 'OWASP: Comment injection' });
992
+ }
993
+ // CIS Benchmarks
994
+ if (frameworks.includes('CIS')) {
995
+ rules.push({ type: 'block', pattern: '^DROP\\s+DATABASE', description: 'CIS: Block DROP DATABASE' }, { type: 'block', pattern: '^DROP\\s+TABLE', description: 'CIS: Block DROP TABLE' }, { type: 'allow', pattern: '^SELECT', description: 'CIS: Allow SELECT queries' });
996
+ }
997
+ // GDPR specific
998
+ if (frameworks.includes('GDPR')) {
999
+ rules.push({ type: 'block', pattern: '(select\\s+.*\\s+from\\s+users)', description: 'GDPR: Limit user data queries' });
1000
+ }
1001
+ return rules;
1002
+ }
1003
+ // ==================== Class Decorators ====================
1004
+ /** Metadata key for firewall rules on classes */
1005
+ const FIREWALL_RULES_KEY = Symbol('__orm_firewall_rules__');
1006
+ const FIREWALL_DATABASE_KEY = Symbol('__orm_firewall_database__');
1007
+ /**
1008
+ * Decorator to apply firewall rules to a model class
1009
+ *
1010
+ * @example
1011
+ * // Block destructive operations and file operations on a model
1012
+ * @FirewallRules({
1013
+ * blockDestructive: true,
1014
+ * blockFileOperations: true,
1015
+ * })
1016
+ * class SensitiveData extends Model { ... }
1017
+ *
1018
+ * // Apply database-specific rules
1019
+ * @FirewallRules({
1020
+ * database: 'postgresql',
1021
+ * blockCodeExecution: true,
1022
+ * })
1023
+ * class UserDefinedFunction extends Model { ... }
1024
+ *
1025
+ * // Custom rules
1026
+ * @FirewallRules({
1027
+ * rules: [
1028
+ * { pattern: /^SELECT\s+FROM\s+logs/i, description: 'Block log access' },
1029
+ * ],
1030
+ * })
1031
+ * class AuditLog extends Model { ... }
1032
+ */
1033
+ function FirewallRules(options = {}) {
1034
+ return function (target) {
1035
+ const rules = [];
1036
+ // Apply database-specific rules
1037
+ if (options.database) {
1038
+ rules.push(`database:${options.database}`);
1039
+ target[FIREWALL_DATABASE_KEY] = options.database;
1040
+ }
1041
+ // Apply category rules
1042
+ if (options.blockDestructive) {
1043
+ rules.push('DESTRUCTIVE');
1044
+ }
1045
+ if (options.blockSchemaModification) {
1046
+ rules.push('SCHEMA_MODIFICATION');
1047
+ }
1048
+ if (options.blockPermissions) {
1049
+ rules.push('PERMISSIONS');
1050
+ }
1051
+ if (options.blockFileOperations) {
1052
+ rules.push('FILE_OPERATIONS');
1053
+ }
1054
+ if (options.blockInfoGathering) {
1055
+ rules.push('INFORMATION_GATHERING');
1056
+ }
1057
+ if (options.blockCodeExecution) {
1058
+ rules.push('CODE_EXECUTION');
1059
+ }
1060
+ if (options.blockTransactions) {
1061
+ rules.push('TRANSACTION_CONTROL');
1062
+ }
1063
+ if (options.blockRemoteOperations) {
1064
+ rules.push('REMOTE_OPERATIONS');
1065
+ }
1066
+ // Store custom rules
1067
+ if (options.rules && options.rules.length > 0) {
1068
+ rules.push('custom');
1069
+ target[FIREWALL_RULES_KEY] = options.rules;
1070
+ }
1071
+ target[FIREWALL_RULES_KEY] = rules;
1072
+ };
1073
+ }
1074
+ /**
1075
+ * Decorator for PostgreSQL-specific firewall rules
1076
+ *
1077
+ * @example
1078
+ * @PostgreSQLFirewall()
1079
+ * class PostgresSensitive extends Model { ... }
1080
+ */
1081
+ function PostgreSQLFirewall() {
1082
+ return FirewallRules({ database: 'postgresql' });
1083
+ }
1084
+ /**
1085
+ * Decorator for MySQL-specific firewall rules
1086
+ *
1087
+ * @example
1088
+ * @MySQLFirewall()
1089
+ * class MySQLSensitive extends Model { ... }
1090
+ */
1091
+ function MySQLFirewall() {
1092
+ return FirewallRules({ database: 'mysql' });
1093
+ }
1094
+ /**
1095
+ * Decorator for MariaDB-specific firewall rules
1096
+ *
1097
+ * @example
1098
+ * @MariaDBFirewall()
1099
+ * class MariaDBSensitive extends Model { ... }
1100
+ */
1101
+ function MariaDBFirewall() {
1102
+ return FirewallRules({ database: 'mariadb' });
1103
+ }
1104
+ /**
1105
+ * Decorator for SQL Server-specific firewall rules
1106
+ *
1107
+ * @example
1108
+ * @MSSQLFirewall()
1109
+ * class MSSQLSensitive extends Model { ... }
1110
+ */
1111
+ function MSSQLFirewall() {
1112
+ return FirewallRules({ database: 'mssql' });
1113
+ }
1114
+ /**
1115
+ * Decorator for Oracle-specific firewall rules
1116
+ *
1117
+ * @example
1118
+ * @OracleFirewall()
1119
+ * class OracleSensitive extends Model { ... }
1120
+ */
1121
+ function OracleFirewall() {
1122
+ return FirewallRules({ database: 'oracle' });
1123
+ }
1124
+ /**
1125
+ * Decorator for SQLite-specific firewall rules
1126
+ *
1127
+ * @example
1128
+ * @SQLiteFirewall()
1129
+ * class SQLiteSensitive extends Model { ... }
1130
+ */
1131
+ function SQLiteFirewall() {
1132
+ return FirewallRules({ database: 'sqlite' });
1133
+ }
1134
+ /**
1135
+ * Apply firewall rules from a decorated model to a firewall instance
1136
+ */
1137
+ function applyFirewallRulesToModel(model, firewall) {
1138
+ const rules = model[FIREWALL_RULES_KEY];
1139
+ const database = model[FIREWALL_DATABASE_KEY];
1140
+ if (!rules && !database)
1141
+ return;
1142
+ // Apply database-specific rules
1143
+ if (database && exports.DATABASE_RULES[database]) {
1144
+ for (const rule of exports.DATABASE_RULES[database]) {
1145
+ firewall.block(rule.pattern, `${database.toUpperCase()}: ${rule.description}`);
1146
+ }
1147
+ }
1148
+ // Apply category rules
1149
+ if (rules && rules.includes('DESTRUCTIVE')) {
1150
+ firewall.applyDestructiveRules();
1151
+ }
1152
+ if (rules && rules.includes('SCHEMA_MODIFICATION')) {
1153
+ firewall.applySchemaRules();
1154
+ }
1155
+ if (rules && rules.includes('PERMISSIONS')) {
1156
+ firewall.applyPermissionRules();
1157
+ }
1158
+ if (rules && rules.includes('FILE_OPERATIONS')) {
1159
+ firewall.applyFileRules();
1160
+ }
1161
+ if (rules && rules.includes('INFORMATION_GATHERING')) {
1162
+ firewall.applyInfoGatheringRules();
1163
+ }
1164
+ if (rules && rules.includes('CODE_EXECUTION')) {
1165
+ firewall.applyCodeExecutionRules?.(); // Need to add this method
1166
+ }
1167
+ if (rules && rules.includes('TRANSACTION_CONTROL')) {
1168
+ firewall.applyTransactionRules?.(); // Need to add this method
1169
+ }
1170
+ if (rules && rules.includes('REMOTE_OPERATIONS')) {
1171
+ firewall.applyRemoteOperationRules?.(); // Need to add this method
1172
+ }
1173
+ // Apply custom rules
1174
+ const customRules = model[FIREWALL_RULES_KEY];
1175
+ if (Array.isArray(customRules)) {
1176
+ for (const rule of customRules) {
1177
+ if (rule.pattern) {
1178
+ firewall.block(rule.pattern, rule.description);
1179
+ }
1180
+ }
1181
+ }
1182
+ }