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.
- package/CHANGELOG.md +1111 -0
- package/LICENSE +21 -0
- package/README.md +573 -0
- package/dist/audit/history-query.js +180 -0
- package/dist/audit/index.js +23 -0
- package/dist/audit/logger.js +236 -0
- package/dist/cache/cache-manager.js +84 -0
- package/dist/cache/index.js +16 -0
- package/dist/cache/redis-cluster-cache.js +557 -0
- package/dist/cli.js +2200 -0
- package/dist/compliance/audit-trail.js +68 -0
- package/dist/compliance/backup-verification.js +685 -0
- package/dist/compliance/breach-detector.js +505 -0
- package/dist/compliance/consent-record.js +227 -0
- package/dist/compliance/consent-versioning.js +331 -0
- package/dist/compliance/cross-border-log.js +530 -0
- package/dist/compliance/data-classifier.js +258 -0
- package/dist/compliance/data-lineage.js +565 -0
- package/dist/compliance/data-masker.js +303 -0
- package/dist/compliance/data-portability.js +265 -0
- package/dist/compliance/data-retention.js +195 -0
- package/dist/compliance/dsar-workflow.js +342 -0
- package/dist/compliance/field-encryption.js +223 -0
- package/dist/compliance/immutable-record.js +148 -0
- package/dist/compliance/index.js +260 -0
- package/dist/compliance/privacy-impact-assessment.js +364 -0
- package/dist/compliance/pseudonymization.js +269 -0
- package/dist/compliance/query-firewall.js +1182 -0
- package/dist/compliance/rate-limiter.js +580 -0
- package/dist/compliance/right-to-erasure.js +117 -0
- package/dist/compliance/row-level-security.js +246 -0
- package/dist/compliance/security-decorator.js +574 -0
- package/dist/compliance/security-monitor.js +525 -0
- package/dist/compliance/sensitive-data-discovery.js +476 -0
- package/dist/compliance/session-isolation.js +472 -0
- package/dist/compliance/tls-enforcer.js +108 -0
- package/dist/compliance/worm-storage.js +712 -0
- package/dist/connection-manager.js +198 -0
- package/dist/connection-pool.js +519 -0
- package/dist/decorators/audit.js +136 -0
- package/dist/decorators/belongs-to-many.js +115 -0
- package/dist/decorators/belongs-to.js +115 -0
- package/dist/decorators/check.js +435 -0
- package/dist/decorators/collate.js +329 -0
- package/dist/decorators/comment.js +205 -0
- package/dist/decorators/database-settings.js +236 -0
- package/dist/decorators/default.js +244 -0
- package/dist/decorators/encryption.js +235 -0
- package/dist/decorators/engine.js +97 -0
- package/dist/decorators/fk-constraints.js +594 -0
- package/dist/decorators/foreign-table.js +136 -0
- package/dist/decorators/generated.js +274 -0
- package/dist/decorators/has-many.js +127 -0
- package/dist/decorators/has-one.js +116 -0
- package/dist/decorators/hstore.js +129 -0
- package/dist/decorators/index.js +355 -0
- package/dist/decorators/json-column.js +83 -0
- package/dist/decorators/jsonb.js +101 -0
- package/dist/decorators/orm-decorators.js +425 -0
- package/dist/decorators/permissions.js +294 -0
- package/dist/decorators/procedure.js +210 -0
- package/dist/decorators/query-options.js +556 -0
- package/dist/decorators/range.js +167 -0
- package/dist/decorators/set-column.js +83 -0
- package/dist/decorators/spatial.js +114 -0
- package/dist/decorators/storage.js +580 -0
- package/dist/decorators/timezone.js +512 -0
- package/dist/decorators/trigger.js +90 -0
- package/dist/decorators/uuid.js +135 -0
- package/dist/decorators/view.js +258 -0
- package/dist/diagrams/chen-diagram.js +354 -0
- package/dist/diagrams/class-diagram.js +384 -0
- package/dist/diagrams/dependency-diagram.js +432 -0
- package/dist/diagrams/er-diagram.js +605 -0
- package/dist/diagrams/flow-diagram.js +394 -0
- package/dist/diagrams/gantt-diagram.js +411 -0
- package/dist/diagrams/index-diagram.js +353 -0
- package/dist/diagrams/index.js +184 -0
- package/dist/diagrams/migration-diagram.js +316 -0
- package/dist/diagrams/model-diagram.js +616 -0
- package/dist/diagrams/package-diagram.js +376 -0
- package/dist/diagrams/palette.js +85 -0
- package/dist/diagrams/relational-diagram.js +455 -0
- package/dist/diagrams/schemadoc-diagram.js +309 -0
- package/dist/diagrams/sequence-diagram.js +307 -0
- package/dist/diagrams/state-diagram.js +344 -0
- package/dist/diagrams/svg-dom.js +111 -0
- package/dist/diagrams/tree-diagram.js +250 -0
- package/dist/dialects/clickhouse/index.js +1742 -0
- package/dist/dialects/cockroachdb/index.js +4677 -0
- package/dist/dialects/cratedb/index.js +441 -0
- package/dist/dialects/databricks/index.js +517 -0
- package/dist/dialects/db2/index.js +2225 -0
- package/dist/dialects/dialect.js +720 -0
- package/dist/dialects/duckdb/index.js +2014 -0
- package/dist/dialects/exasol/index.js +357 -0
- package/dist/dialects/firebird/index.js +495 -0
- package/dist/dialects/greenplum/index.js +457 -0
- package/dist/dialects/hana/index.js +1741 -0
- package/dist/dialects/mariadb/index.js +3590 -0
- package/dist/dialects/mssql/index.js +2296 -0
- package/dist/dialects/mysql/index.js +4058 -0
- package/dist/dialects/oracle/index.js +2999 -0
- package/dist/dialects/postgres/index.js +5319 -0
- package/dist/dialects/query-stream-helper.js +152 -0
- package/dist/dialects/questdb/index.js +433 -0
- package/dist/dialects/redshift/index.js +2277 -0
- package/dist/dialects/singlestore/index.js +354 -0
- package/dist/dialects/snowflake/index.js +2082 -0
- package/dist/dialects/spanner/index.js +1768 -0
- package/dist/dialects/sqlite/index.js +3382 -0
- package/dist/dialects/tidb/index.js +377 -0
- package/dist/dialects/timescaledb/index.js +164 -0
- package/dist/dialects/trino/index.js +420 -0
- package/dist/dialects/turso/index.js +227 -0
- package/dist/dialects/vertica/index.js +317 -0
- package/dist/dialects/yugabytedb/index.js +424 -0
- package/dist/errors/index.js +472 -0
- package/dist/errors/utils.js +340 -0
- package/dist/errors.js +21 -0
- package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
- package/dist/extensions/catalog/mssql-features.js +147 -0
- package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
- package/dist/extensions/catalog/oracle-db2-features.js +196 -0
- package/dist/extensions/catalog/postgres-extensions.js +516 -0
- package/dist/extensions/index.js +71 -0
- package/dist/extensions/types.js +13 -0
- package/dist/foreign-data.js +173 -0
- package/dist/hooks/hooks-manager.js +350 -0
- package/dist/hooks/index.js +37 -0
- package/dist/index.js +463 -0
- package/dist/logging.js +335 -0
- package/dist/migrations/index.js +40 -0
- package/dist/migrations/migration.js +196 -0
- package/dist/migrations/migrator.js +411 -0
- package/dist/migrations/prormmigration.js +275 -0
- package/dist/migrations/query-interface.js +435 -0
- package/dist/migrations/seeder.js +353 -0
- package/dist/models/associations.js +852 -0
- package/dist/models/constraints.js +288 -0
- package/dist/models/data-types.js +2518 -0
- package/dist/models/decorators.js +445 -0
- package/dist/models/index.js +33 -0
- package/dist/models/indexes.js +531 -0
- package/dist/models/methods.js +382 -0
- package/dist/models/model-manager.js +103 -0
- package/dist/models/model.js +5349 -0
- package/dist/models/operators.js +67 -0
- package/dist/models/scopes.js +189 -0
- package/dist/models/typescript-types.js +26 -0
- package/dist/nosql/aerospike/index.js +205 -0
- package/dist/nosql/allegrograph/index.js +169 -0
- package/dist/nosql/arangodb/index.js +364 -0
- package/dist/nosql/azure-blob/index.js +206 -0
- package/dist/nosql/beanstalkd/index.js +231 -0
- package/dist/nosql/beequeue/index.js +210 -0
- package/dist/nosql/bigchaindb/index.js +195 -0
- package/dist/nosql/bigtable/index.js +224 -0
- package/dist/nosql/blazegraph/index.js +173 -0
- package/dist/nosql/bullmq/index.js +191 -0
- package/dist/nosql/cassandra/index.js +174 -0
- package/dist/nosql/chroma/index.js +190 -0
- package/dist/nosql/cloudflare-kv/index.js +220 -0
- package/dist/nosql/coherence/index.js +200 -0
- package/dist/nosql/cosmosdb/index.js +157 -0
- package/dist/nosql/couchbase/index.js +213 -0
- package/dist/nosql/dax/index.js +212 -0
- package/dist/nosql/deno-kv/index.js +206 -0
- package/dist/nosql/dgraph/index.js +171 -0
- package/dist/nosql/doris/index.js +169 -0
- package/dist/nosql/druid/index.js +162 -0
- package/dist/nosql/dynamodb/index.js +937 -0
- package/dist/nosql/elasticsearch/index.js +377 -0
- package/dist/nosql/etcd/index.js +502 -0
- package/dist/nosql/eventhubs/index.js +213 -0
- package/dist/nosql/eventstore/index.js +254 -0
- package/dist/nosql/faunadb/index.js +188 -0
- package/dist/nosql/firestore/index.js +177 -0
- package/dist/nosql/fluree/index.js +148 -0
- package/dist/nosql/fuseki/index.js +170 -0
- package/dist/nosql/gcs/index.js +172 -0
- package/dist/nosql/gearman/index.js +160 -0
- package/dist/nosql/geode/index.js +196 -0
- package/dist/nosql/graphdb/index.js +169 -0
- package/dist/nosql/graylog/index.js +188 -0
- package/dist/nosql/gridgain/index.js +171 -0
- package/dist/nosql/hazelcast/index.js +162 -0
- package/dist/nosql/hbase/index.js +230 -0
- package/dist/nosql/ignite/index.js +173 -0
- package/dist/nosql/immudb/index.js +184 -0
- package/dist/nosql/index.js +232 -0
- package/dist/nosql/infinispan/index.js +200 -0
- package/dist/nosql/influxdb/index.js +0 -0
- package/dist/nosql/kafka/index.js +234 -0
- package/dist/nosql/keyspaces/index.js +189 -0
- package/dist/nosql/kinesis/index.js +253 -0
- package/dist/nosql/leveldb/index.js +153 -0
- package/dist/nosql/lmdb/index.js +160 -0
- package/dist/nosql/loki/index.js +201 -0
- package/dist/nosql/marklogic/index.js +204 -0
- package/dist/nosql/materialize/index.js +145 -0
- package/dist/nosql/meilisearch/index.js +154 -0
- package/dist/nosql/memcached/index.js +223 -0
- package/dist/nosql/milvus/index.js +410 -0
- package/dist/nosql/minio/index.js +265 -0
- package/dist/nosql/momento/index.js +179 -0
- package/dist/nosql/mongodb/index.js +461 -0
- package/dist/nosql/nats/index.js +247 -0
- package/dist/nosql/nedb/index.js +164 -0
- package/dist/nosql/neo4j/index.js +450 -0
- package/dist/nosql/neptune/index.js +470 -0
- package/dist/nosql/nsq/index.js +200 -0
- package/dist/nosql/opensearch/index.js +186 -0
- package/dist/nosql/orientdb/index.js +175 -0
- package/dist/nosql/papertrail/index.js +200 -0
- package/dist/nosql/pinecone/index.js +0 -0
- package/dist/nosql/pinot/index.js +133 -0
- package/dist/nosql/pouchdb/index.js +172 -0
- package/dist/nosql/prometheus/index.js +174 -0
- package/dist/nosql/provendb/index.js +147 -0
- package/dist/nosql/pubsub/index.js +187 -0
- package/dist/nosql/pulsar/index.js +232 -0
- package/dist/nosql/qdrant/index.js +295 -0
- package/dist/nosql/qldb/index.js +192 -0
- package/dist/nosql/r2/index.js +281 -0
- package/dist/nosql/rabbitmq/index.js +237 -0
- package/dist/nosql/ravendb/index.js +175 -0
- package/dist/nosql/redis/index.js +607 -0
- package/dist/nosql/redpanda/index.js +237 -0
- package/dist/nosql/resque/index.js +203 -0
- package/dist/nosql/rethinkdb/index.js +232 -0
- package/dist/nosql/rocksdb/index.js +152 -0
- package/dist/nosql/rockset/index.js +126 -0
- package/dist/nosql/s3/index.js +298 -0
- package/dist/nosql/scylladb/index.js +178 -0
- package/dist/nosql/signoz/index.js +227 -0
- package/dist/nosql/sns/index.js +201 -0
- package/dist/nosql/solr/index.js +231 -0
- package/dist/nosql/splunk/index.js +227 -0
- package/dist/nosql/sqs/index.js +246 -0
- package/dist/nosql/stardog/index.js +169 -0
- package/dist/nosql/starrocks/index.js +170 -0
- package/dist/nosql/store.js +2 -0
- package/dist/nosql/sumologic/index.js +213 -0
- package/dist/nosql/surrealdb/index.js +179 -0
- package/dist/nosql/terminusdb/index.js +151 -0
- package/dist/nosql/tigergraph/index.js +469 -0
- package/dist/nosql/typesense/index.js +148 -0
- package/dist/nosql/unqlite/index.js +157 -0
- package/dist/nosql/upstash/index.js +167 -0
- package/dist/nosql/vercel-kv/index.js +166 -0
- package/dist/nosql/victoriametrics/index.js +213 -0
- package/dist/nosql/virtuoso/index.js +169 -0
- package/dist/nosql/weaviate/index.js +276 -0
- package/dist/operators/index.js +108 -0
- package/dist/operators.js +2690 -0
- package/dist/prisma-migrate/index.js +38 -0
- package/dist/prisma-migrate/migration-generator.js +125 -0
- package/dist/prisma-migrate/model-generator.js +172 -0
- package/dist/prisma-migrate/relations.js +100 -0
- package/dist/prisma-migrate/schema-parser.js +167 -0
- package/dist/prisma-migrate/type-mapper.js +40 -0
- package/dist/prorm.js +6832 -0
- package/dist/query-builders/cte-builder.js +80 -0
- package/dist/query-builders/functions/aggregate.js +390 -0
- package/dist/query-builders/functions/conditional.js +503 -0
- package/dist/query-builders/functions/datetime.js +695 -0
- package/dist/query-builders/functions/fulltext.js +439 -0
- package/dist/query-builders/functions/index.js +93 -0
- package/dist/query-builders/functions/json.js +427 -0
- package/dist/query-builders/functions/math.js +399 -0
- package/dist/query-builders/functions/string.js +518 -0
- package/dist/query-builders/functions/window.js +328 -0
- package/dist/query-builders/include-builder.js +323 -0
- package/dist/query-builders/index-expression-builder.js +242 -0
- package/dist/query-builders/index.js +161 -0
- package/dist/query-builders/insert-builder.js +164 -0
- package/dist/query-builders/model-helpers.js +38 -0
- package/dist/query-builders/order-limit-builder.js +239 -0
- package/dist/query-builders/sql-compiler.js +2040 -0
- package/dist/query-builders/subquery-builder.js +152 -0
- package/dist/query-builders/update-builder.js +182 -0
- package/dist/query-builders/view-builder.js +218 -0
- package/dist/query-builders/where-builder.js +1532 -0
- package/dist/query-interface.js +622 -0
- package/dist/query-optimizers/batch-optimizer.js +426 -0
- package/dist/query-optimizers/explain-plans.js +415 -0
- package/dist/query-optimizers/index.js +51 -0
- package/dist/query-optimizers/prepared-statement-cache.js +423 -0
- package/dist/query-optimizers/query-hints.js +438 -0
- package/dist/query-optimizers/query-optimizer.js +278 -0
- package/dist/query-optimizers/slow-query-logger.js +271 -0
- package/dist/replica-manager.js +507 -0
- package/dist/schema/index.js +15 -0
- package/dist/schema/migration-generator.js +374 -0
- package/dist/schema/schema-differ.js +549 -0
- package/dist/schema/types.js +6 -0
- package/dist/sql-constants.js +300 -0
- package/dist/sqlite-advanced.js +1047 -0
- package/dist/streams/index.js +12 -0
- package/dist/streams/transforms.js +178 -0
- package/dist/transaction.js +456 -0
- package/dist/types/index.js +180 -0
- package/dist/user-management.js +127 -0
- package/dist/utils/date.js +300 -0
- package/dist/utils/index.js +1079 -0
- package/dist/utils/string.js +161 -0
- package/dist/validators/index.js +19 -0
- package/dist/validators/validator.js +911 -0
- package/package.json +190 -0
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MTAT - Monitoring and Threat Assessment Tool
|
|
4
|
+
*
|
|
5
|
+
* A comprehensive security monitoring system that:
|
|
6
|
+
* - Screens SQL logs for suspicious patterns
|
|
7
|
+
* - Flags security-relevant events
|
|
8
|
+
* - Monitors compliance violations (invalid data movement)
|
|
9
|
+
* - Tracks slow/invalid queries
|
|
10
|
+
* - Provides real-time alerts
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* // Initialize with the MTAT monitor
|
|
14
|
+
* const monitor = new SecurityMonitor(prorm, {
|
|
15
|
+
* frameworks: ['GDPR', 'HIPAA'],
|
|
16
|
+
* alertLevel: 'high',
|
|
17
|
+
* onAlert: (alert) => console.log('Security Alert:', alert),
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* // Start monitoring
|
|
21
|
+
* await monitor.start();
|
|
22
|
+
*
|
|
23
|
+
* // Query the dashboard
|
|
24
|
+
* const stats = monitor.getStats();
|
|
25
|
+
* const alerts = monitor.getAlerts();
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.ComplianceSecurityMonitor = exports.SecurityMonitor = void 0;
|
|
29
|
+
exports.getGlobalMonitor = getGlobalMonitor;
|
|
30
|
+
exports.initSecurityMonitor = initSecurityMonitor;
|
|
31
|
+
exports.analyzeQuerySecurity = analyzeQuerySecurity;
|
|
32
|
+
// SQL Injection patterns
|
|
33
|
+
const SQL_INJECTION_PATTERNS = [
|
|
34
|
+
/('\s*or\s*'1'\s*=\s*'1)/i,
|
|
35
|
+
/('\s*or\s*1\s*=\s*1)/i,
|
|
36
|
+
/(union\s+select)/i,
|
|
37
|
+
/(union\s+all\s+select)/i,
|
|
38
|
+
/(\bor\b.*\b=\b)/,
|
|
39
|
+
/(exec\s*\()/i,
|
|
40
|
+
/(execute\s*\()/i,
|
|
41
|
+
/(xp_cmdshell)/i,
|
|
42
|
+
/(load_file\s*\()/i,
|
|
43
|
+
/(into\s+outfile)/i,
|
|
44
|
+
/(sleep\s*\()/i,
|
|
45
|
+
/(waitfor\s+delay)/i,
|
|
46
|
+
/('\s*;\s*drop\s+table)/i,
|
|
47
|
+
/(;\s*drop\s+table)/i,
|
|
48
|
+
/(\/\*.*\*\/)/,
|
|
49
|
+
/(--\s*)/,
|
|
50
|
+
/(char\s*\(\s*\d+)/,
|
|
51
|
+
/(0x[0-9a-f]+)/i,
|
|
52
|
+
/(\bunion\b.*\bselect\b)/i,
|
|
53
|
+
/(\bselect\b.*\bfrom\b)/i,
|
|
54
|
+
/(having\s+.*\b=\b)/i,
|
|
55
|
+
/(\border\s+by\s+\d+)/i,
|
|
56
|
+
];
|
|
57
|
+
// Sensitive data patterns
|
|
58
|
+
const PII_PATTERNS = {
|
|
59
|
+
email: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
|
|
60
|
+
ssn: /\b\d{3}-\d{2}-\d{4}\b/g,
|
|
61
|
+
phone: /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g,
|
|
62
|
+
creditCard: /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g,
|
|
63
|
+
ipAddress: /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g,
|
|
64
|
+
};
|
|
65
|
+
// High-risk operations
|
|
66
|
+
const RISKY_OPERATIONS = [
|
|
67
|
+
'DROP TABLE',
|
|
68
|
+
'DROP DATABASE',
|
|
69
|
+
'TRUNCATE',
|
|
70
|
+
'DELETE FROM',
|
|
71
|
+
'ALTER TABLE',
|
|
72
|
+
'DROP COLUMN',
|
|
73
|
+
'DROP INDEX',
|
|
74
|
+
];
|
|
75
|
+
// ==================== Security Monitor Class ====================
|
|
76
|
+
class SecurityMonitor {
|
|
77
|
+
constructor(prorm, options = {}) {
|
|
78
|
+
this.alerts = [];
|
|
79
|
+
this.queryCount = 0;
|
|
80
|
+
this.slowQueryCount = 0;
|
|
81
|
+
this.blockedCount = 0;
|
|
82
|
+
this.isRunning = false;
|
|
83
|
+
this.prorm = prorm;
|
|
84
|
+
this.options = {
|
|
85
|
+
frameworks: options.frameworks ?? [],
|
|
86
|
+
alertLevel: options.alertLevel ?? 'medium',
|
|
87
|
+
onAlert: options.onAlert ?? (() => { }),
|
|
88
|
+
detectSQLInjection: options.detectSQLInjection ?? true,
|
|
89
|
+
monitorSlowQueries: options.monitorSlowQueries ?? true,
|
|
90
|
+
slowQueryThreshold: options.slowQueryThreshold ?? 1000,
|
|
91
|
+
detectExfiltration: options.detectExfiltration ?? true,
|
|
92
|
+
detectComplianceViolations: options.detectComplianceViolations ?? true,
|
|
93
|
+
maxAlerts: options.maxAlerts ?? 1000,
|
|
94
|
+
rateLimitThreshold: options.rateLimitThreshold ?? 100,
|
|
95
|
+
detectAnomalies: options.detectAnomalies ?? true,
|
|
96
|
+
bulkOperationThreshold: options.bulkOperationThreshold ?? 100,
|
|
97
|
+
};
|
|
98
|
+
this.startTime = new Date();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Start monitoring queries
|
|
102
|
+
*/
|
|
103
|
+
async start() {
|
|
104
|
+
if (this.isRunning)
|
|
105
|
+
return;
|
|
106
|
+
this.isRunning = true;
|
|
107
|
+
// Hook into Prorm query events
|
|
108
|
+
this.originalQuery = this.prorm.query;
|
|
109
|
+
this.prorm.query = async (...args) => {
|
|
110
|
+
const startTime = Date.now();
|
|
111
|
+
const query = typeof args[0] === 'string' ? args[0] : args[0]?.sql ?? '';
|
|
112
|
+
try {
|
|
113
|
+
const result = await this.originalQuery.apply(this.prorm, args);
|
|
114
|
+
const duration = Date.now() - startTime;
|
|
115
|
+
this.queryCount++;
|
|
116
|
+
this.analyzeQuery(query, duration);
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
this.analyzeError(query, error);
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
// Also hook into model operations via hooks
|
|
125
|
+
this.setupHooks();
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Stop monitoring
|
|
129
|
+
*/
|
|
130
|
+
stop() {
|
|
131
|
+
if (!this.isRunning)
|
|
132
|
+
return;
|
|
133
|
+
this.isRunning = false;
|
|
134
|
+
if (this.originalQuery) {
|
|
135
|
+
this.prorm.query = this.originalQuery;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Setup hooks for model-level monitoring
|
|
140
|
+
*/
|
|
141
|
+
setupHooks() {
|
|
142
|
+
const models = this.prorm.getModels?.() ?? [];
|
|
143
|
+
for (const [, Model] of models) {
|
|
144
|
+
// Monitor bulk operations
|
|
145
|
+
Model.hook('beforeBulkCreate', 'mtat:bulkCreate', (instances) => {
|
|
146
|
+
if (instances.length > this.options.bulkOperationThreshold) {
|
|
147
|
+
this.addAlert({
|
|
148
|
+
severity: 'medium',
|
|
149
|
+
category: 'bulk_operation',
|
|
150
|
+
message: `Bulk create operation detected: ${instances.length} records`,
|
|
151
|
+
details: { count: instances.length, model: Model.name },
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
Model.hook('beforeBulkUpdate', 'mtat:bulkUpdate', (opts) => {
|
|
156
|
+
// Check if this looks like a dangerous bulk update
|
|
157
|
+
if (!opts.where || Object.keys(opts.where).length === 0) {
|
|
158
|
+
this.addAlert({
|
|
159
|
+
severity: 'critical',
|
|
160
|
+
category: 'bulk_operation',
|
|
161
|
+
message: 'Dangerous bulk update without where clause',
|
|
162
|
+
details: { model: Model.name, attributes: opts.attributes },
|
|
163
|
+
query: JSON.stringify(opts),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
Model.hook('beforeBulkDestroy', 'mtat:bulkDestroy', (opts) => {
|
|
168
|
+
if (!opts.where || Object.keys(opts.where).length === 0) {
|
|
169
|
+
this.addAlert({
|
|
170
|
+
severity: 'critical',
|
|
171
|
+
category: 'data_exfiltration',
|
|
172
|
+
message: 'Dangerous bulk delete without where clause',
|
|
173
|
+
details: { model: Model.name },
|
|
174
|
+
query: JSON.stringify(opts),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Analyze a query for security issues
|
|
182
|
+
*/
|
|
183
|
+
analyzeQuery(query, duration) {
|
|
184
|
+
const analysis = this.analyzeQueryInternal(query);
|
|
185
|
+
// SQL Injection detection
|
|
186
|
+
if (this.options.detectSQLInjection) {
|
|
187
|
+
for (const pattern of SQL_INJECTION_PATTERNS) {
|
|
188
|
+
if (pattern.test(query)) {
|
|
189
|
+
this.addAlert({
|
|
190
|
+
severity: 'critical',
|
|
191
|
+
category: 'sql_injection',
|
|
192
|
+
message: 'Potential SQL injection detected',
|
|
193
|
+
details: { pattern: pattern.source, riskScore: analysis.riskScore },
|
|
194
|
+
query,
|
|
195
|
+
});
|
|
196
|
+
this.blockedCount++;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Slow query monitoring
|
|
202
|
+
if (this.options.monitorSlowQueries && duration > this.options.slowQueryThreshold) {
|
|
203
|
+
this.slowQueryCount++;
|
|
204
|
+
this.addAlert({
|
|
205
|
+
severity: 'medium',
|
|
206
|
+
category: 'slow_query',
|
|
207
|
+
message: `Slow query detected: ${duration}ms`,
|
|
208
|
+
details: { duration, threshold: this.options.slowQueryThreshold },
|
|
209
|
+
query,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
// High-risk operations
|
|
213
|
+
for (const op of RISKY_OPERATIONS) {
|
|
214
|
+
if (query.toUpperCase().includes(op)) {
|
|
215
|
+
this.addAlert({
|
|
216
|
+
severity: 'high',
|
|
217
|
+
category: 'unauthorized_access',
|
|
218
|
+
message: `High-risk operation: ${op}`,
|
|
219
|
+
details: { operation: op },
|
|
220
|
+
query,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Data exfiltration detection
|
|
225
|
+
if (this.options.detectExfiltration && analysis.isBulkOperation) {
|
|
226
|
+
this.addAlert({
|
|
227
|
+
severity: 'medium',
|
|
228
|
+
category: 'data_exfiltration',
|
|
229
|
+
message: 'Potential data exfiltration: bulk SELECT operation',
|
|
230
|
+
details: { tables: analysis.tables },
|
|
231
|
+
query,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
// Compliance violation detection
|
|
235
|
+
if (this.options.detectComplianceViolations && this.options.frameworks.length > 0) {
|
|
236
|
+
this.checkComplianceViolationDetection(query, analysis);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Analyze errors for security issues
|
|
241
|
+
*/
|
|
242
|
+
analyzeError(query, error) {
|
|
243
|
+
const message = error?.message ?? '';
|
|
244
|
+
// Detect injection errors
|
|
245
|
+
if (message.includes('syntax error') || message.includes('SQL syntax')) {
|
|
246
|
+
this.addAlert({
|
|
247
|
+
severity: 'low',
|
|
248
|
+
category: 'invalid_query',
|
|
249
|
+
message: 'Invalid SQL query detected',
|
|
250
|
+
details: { error: message.substring(0, 100) },
|
|
251
|
+
query,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
// Access denied patterns
|
|
255
|
+
if (message.includes('permission denied') || message.includes('access denied')) {
|
|
256
|
+
this.addAlert({
|
|
257
|
+
severity: 'high',
|
|
258
|
+
category: 'unauthorized_access',
|
|
259
|
+
message: 'Unauthorized access attempt',
|
|
260
|
+
details: { error: message.substring(0, 100) },
|
|
261
|
+
query,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Internal query analysis
|
|
267
|
+
*/
|
|
268
|
+
analyzeQueryInternal(query) {
|
|
269
|
+
const upperQuery = query.toUpperCase();
|
|
270
|
+
let operation = 'UNKNOWN';
|
|
271
|
+
if (upperQuery.includes('SELECT'))
|
|
272
|
+
operation = 'SELECT';
|
|
273
|
+
else if (upperQuery.includes('INSERT'))
|
|
274
|
+
operation = 'INSERT';
|
|
275
|
+
else if (upperQuery.includes('UPDATE'))
|
|
276
|
+
operation = 'UPDATE';
|
|
277
|
+
else if (upperQuery.includes('DELETE'))
|
|
278
|
+
operation = 'DELETE';
|
|
279
|
+
else if (upperQuery.includes('DROP'))
|
|
280
|
+
operation = 'DROP';
|
|
281
|
+
else if (upperQuery.includes('TRUNCATE'))
|
|
282
|
+
operation = 'TRUNCATE';
|
|
283
|
+
else if (upperQuery.includes('ALTER'))
|
|
284
|
+
operation = 'ALTER';
|
|
285
|
+
// Extract table names (simple regex)
|
|
286
|
+
const tableMatches = query.match(/(?:from|into|update|table)\s+`?(\w+)`?/gi) || [];
|
|
287
|
+
const tables = tableMatches.map(m => m.replace(/`/g, '').split(' ').pop() || '');
|
|
288
|
+
// Check for PII in query
|
|
289
|
+
let involvesPII = false;
|
|
290
|
+
for (const pattern of Object.values(PII_PATTERNS)) {
|
|
291
|
+
if (pattern.test(query)) {
|
|
292
|
+
involvesPII = true;
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
// Calculate risk score
|
|
297
|
+
let riskScore = 0;
|
|
298
|
+
if (operation === 'SELECT' && involvesPII)
|
|
299
|
+
riskScore += 30;
|
|
300
|
+
if (RISKY_OPERATIONS.some(op => upperQuery.includes(op)))
|
|
301
|
+
riskScore += 50;
|
|
302
|
+
if (query.length > 1000)
|
|
303
|
+
riskScore += 10;
|
|
304
|
+
return {
|
|
305
|
+
query,
|
|
306
|
+
tables,
|
|
307
|
+
operation,
|
|
308
|
+
isSensitive: involvesPII,
|
|
309
|
+
involvesPII,
|
|
310
|
+
isBulkOperation: false, // Determined by hook
|
|
311
|
+
riskScore,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Check for compliance violations
|
|
316
|
+
*/
|
|
317
|
+
checkComplianceViolationDetection(query, analysis) {
|
|
318
|
+
const frameworks = this.options.frameworks;
|
|
319
|
+
// GDPR-specific checks
|
|
320
|
+
if (frameworks.includes('GDPR') || frameworks.includes('UK_GDPR')) {
|
|
321
|
+
// Check for unauthorized personal data access
|
|
322
|
+
if (analysis.involvesPII && analysis.operation === 'SELECT') {
|
|
323
|
+
this.addAlert({
|
|
324
|
+
severity: 'medium',
|
|
325
|
+
category: 'compliance_violation',
|
|
326
|
+
message: 'GDPR: Personal data access detected',
|
|
327
|
+
details: { framework: 'GDPR', dataType: 'PII' },
|
|
328
|
+
query,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
// HIPAA-specific checks
|
|
333
|
+
if (frameworks.includes('HIPAA')) {
|
|
334
|
+
// Check for PHI access
|
|
335
|
+
if (query.toLowerCase().includes('medical') ||
|
|
336
|
+
query.toLowerCase().includes('diagnosis') ||
|
|
337
|
+
query.toLowerCase().includes('prescription')) {
|
|
338
|
+
this.addAlert({
|
|
339
|
+
severity: 'high',
|
|
340
|
+
category: 'compliance_violation',
|
|
341
|
+
message: 'HIPAA: Protected Health Information access',
|
|
342
|
+
details: { framework: 'HIPAA', dataType: 'PHI' },
|
|
343
|
+
query,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
// PCI DSS checks
|
|
348
|
+
if (frameworks.includes('PCI_DSS')) {
|
|
349
|
+
if (query.toLowerCase().includes('credit') ||
|
|
350
|
+
query.toLowerCase().includes('card') ||
|
|
351
|
+
query.toLowerCase().includes('payment')) {
|
|
352
|
+
this.addAlert({
|
|
353
|
+
severity: 'critical',
|
|
354
|
+
category: 'compliance_violation',
|
|
355
|
+
message: 'PCI DSS: Cardholder data access',
|
|
356
|
+
details: { framework: 'PCI_DSS', dataType: 'PCI' },
|
|
357
|
+
query,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Add an alert
|
|
364
|
+
*/
|
|
365
|
+
addAlert(alert) {
|
|
366
|
+
const fullAlert = {
|
|
367
|
+
...alert,
|
|
368
|
+
id: `alert-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
|
|
369
|
+
timestamp: new Date(),
|
|
370
|
+
};
|
|
371
|
+
// Check severity threshold
|
|
372
|
+
const severityOrder = ['low', 'medium', 'high', 'critical'];
|
|
373
|
+
if (severityOrder.indexOf(fullAlert.severity) < severityOrder.indexOf(this.options.alertLevel)) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
this.alerts.push(fullAlert);
|
|
377
|
+
// Trim old alerts
|
|
378
|
+
if (this.alerts.length > this.options.maxAlerts) {
|
|
379
|
+
this.alerts = this.alerts.slice(-this.options.maxAlerts);
|
|
380
|
+
}
|
|
381
|
+
// Callback
|
|
382
|
+
if (this.options.onAlert) {
|
|
383
|
+
this.options.onAlert(fullAlert);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
// ==================== Public API ====================
|
|
387
|
+
/**
|
|
388
|
+
* Get current statistics
|
|
389
|
+
*/
|
|
390
|
+
getStats() {
|
|
391
|
+
const alertsBySeverity = {
|
|
392
|
+
low: 0, medium: 0, high: 0, critical: 0,
|
|
393
|
+
};
|
|
394
|
+
const alertsByCategory = {
|
|
395
|
+
sql_injection: 0,
|
|
396
|
+
data_exfiltration: 0,
|
|
397
|
+
unauthorized_access: 0,
|
|
398
|
+
compliance_violation: 0,
|
|
399
|
+
slow_query: 0,
|
|
400
|
+
invalid_query: 0,
|
|
401
|
+
anomaly: 0,
|
|
402
|
+
rate_limit: 0,
|
|
403
|
+
bulk_operation: 0,
|
|
404
|
+
sensitive_access: 0,
|
|
405
|
+
};
|
|
406
|
+
for (const alert of this.alerts) {
|
|
407
|
+
alertsBySeverity[alert.severity]++;
|
|
408
|
+
alertsByCategory[alert.category]++;
|
|
409
|
+
}
|
|
410
|
+
return {
|
|
411
|
+
uptime: Date.now() - this.startTime.getTime(),
|
|
412
|
+
totalQueries: this.queryCount,
|
|
413
|
+
slowQueries: this.slowQueryCount,
|
|
414
|
+
blockedQueries: this.blockedCount,
|
|
415
|
+
totalAlerts: this.alerts.length,
|
|
416
|
+
alertsBySeverity,
|
|
417
|
+
alertsByCategory,
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Get all alerts
|
|
422
|
+
*/
|
|
423
|
+
getAlerts(options) {
|
|
424
|
+
let filtered = [...this.alerts];
|
|
425
|
+
if (options?.severity) {
|
|
426
|
+
filtered = filtered.filter(a => a.severity === options.severity);
|
|
427
|
+
}
|
|
428
|
+
if (options?.category) {
|
|
429
|
+
filtered = filtered.filter(a => a.category === options.category);
|
|
430
|
+
}
|
|
431
|
+
if (options?.limit) {
|
|
432
|
+
filtered = filtered.slice(-options.limit);
|
|
433
|
+
}
|
|
434
|
+
return filtered;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Get critical alerts
|
|
438
|
+
*/
|
|
439
|
+
getCriticalAlerts() {
|
|
440
|
+
return this.getAlerts({ severity: 'critical' });
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Clear all alerts
|
|
444
|
+
*/
|
|
445
|
+
clearAlerts() {
|
|
446
|
+
this.alerts = [];
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Check if running
|
|
450
|
+
*/
|
|
451
|
+
isActive() {
|
|
452
|
+
return this.isRunning;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Manual alert trigger (for custom security checks)
|
|
456
|
+
*/
|
|
457
|
+
alert(options) {
|
|
458
|
+
this.addAlert(options);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
exports.SecurityMonitor = SecurityMonitor;
|
|
462
|
+
// ==================== Static Factory ====================
|
|
463
|
+
let globalMonitor = null;
|
|
464
|
+
/**
|
|
465
|
+
* Create or get the global security monitor singleton
|
|
466
|
+
*/
|
|
467
|
+
function getGlobalMonitor() {
|
|
468
|
+
return globalMonitor;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Initialize the global security monitor
|
|
472
|
+
*/
|
|
473
|
+
function initSecurityMonitor(prorm, options) {
|
|
474
|
+
globalMonitor = new SecurityMonitor(prorm, options);
|
|
475
|
+
return globalMonitor;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Quick security check for a query (static method)
|
|
479
|
+
*/
|
|
480
|
+
function analyzeQuerySecurity(query) {
|
|
481
|
+
const detectedPatterns = [];
|
|
482
|
+
// Check SQL injection patterns
|
|
483
|
+
for (const pattern of SQL_INJECTION_PATTERNS) {
|
|
484
|
+
if (pattern.test(query)) {
|
|
485
|
+
detectedPatterns.push(`SQL_INJECTION:${pattern.source}`);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
// Check for sensitive data
|
|
489
|
+
let isSensitive = false;
|
|
490
|
+
for (const [name, pattern] of Object.entries(PII_PATTERNS)) {
|
|
491
|
+
if (pattern.test(query)) {
|
|
492
|
+
detectedPatterns.push(`SENSITIVE:${name}`);
|
|
493
|
+
isSensitive = true;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
// Determine risk level
|
|
497
|
+
let riskLevel = 'low';
|
|
498
|
+
if (detectedPatterns.some(p => p.startsWith('SQL_INJECTION'))) {
|
|
499
|
+
riskLevel = 'critical';
|
|
500
|
+
}
|
|
501
|
+
else if (detectedPatterns.length > 0) {
|
|
502
|
+
riskLevel = 'high';
|
|
503
|
+
}
|
|
504
|
+
else if (isSensitive) {
|
|
505
|
+
riskLevel = 'medium';
|
|
506
|
+
}
|
|
507
|
+
return {
|
|
508
|
+
isSQLInjection: detectedPatterns.some(p => p.startsWith('SQL_INJECTION')),
|
|
509
|
+
isSensitive,
|
|
510
|
+
riskLevel,
|
|
511
|
+
detectedPatterns,
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
// ==================== Compliance Integration ====================
|
|
515
|
+
/**
|
|
516
|
+
* MTAT with Compliance Integration
|
|
517
|
+
* Extends the basic monitor with framework-specific rules
|
|
518
|
+
*/
|
|
519
|
+
class ComplianceSecurityMonitor extends SecurityMonitor {
|
|
520
|
+
constructor(prorm, options = {}) {
|
|
521
|
+
super(prorm, options);
|
|
522
|
+
// Additional setup for compliance-specific monitoring
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
exports.ComplianceSecurityMonitor = ComplianceSecurityMonitor;
|