@zintrust/core 0.1.19 → 0.1.21
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/README.md +10 -10
- package/bin/zintrust-main.d.ts.map +1 -1
- package/bin/zintrust-main.js +9 -0
- package/package.json +3 -2
- package/public/error-pages/404.html +145 -0
- package/public/error-pages/500.html +266 -0
- package/public/error-pages/error.css +628 -0
- package/public/error-pages/error.js +428 -0
- package/public/zintrust.svg +30 -0
- package/routes/api.d.ts.map +1 -1
- package/routes/api.js +41 -17
- package/routes/metrics.d.ts +9 -0
- package/routes/metrics.d.ts.map +1 -0
- package/routes/metrics.js +20 -0
- package/routes/openapi.d.ts +9 -0
- package/routes/openapi.d.ts.map +1 -0
- package/routes/openapi.js +76 -0
- package/src/boot/Application.d.ts +2 -2
- package/src/boot/Application.d.ts.map +1 -1
- package/src/boot/Application.js +66 -13
- package/src/boot/Server.d.ts +3 -2
- package/src/boot/Server.d.ts.map +1 -1
- package/src/boot/Server.js +39 -165
- package/src/boot/bootstrap.js +2 -0
- package/src/cache/Cache.d.ts +1 -1
- package/src/cache/Cache.d.ts.map +1 -1
- package/src/cache/CacheDriver.d.ts +4 -0
- package/src/cache/CacheDriver.d.ts.map +1 -1
- package/src/cache/drivers/KVDriver.d.ts +1 -1
- package/src/cache/drivers/KVDriver.d.ts.map +1 -1
- package/src/cache/drivers/MemoryDriver.d.ts +1 -1
- package/src/cache/drivers/MemoryDriver.d.ts.map +1 -1
- package/src/cache/drivers/MemoryDriver.js +16 -0
- package/src/cache/drivers/MongoDriver.d.ts +1 -1
- package/src/cache/drivers/MongoDriver.d.ts.map +1 -1
- package/src/cache/drivers/RedisDriver.d.ts +1 -1
- package/src/cache/drivers/RedisDriver.d.ts.map +1 -1
- package/src/cli/CLI.d.ts.map +1 -1
- package/src/cli/CLI.js +10 -4
- package/src/cli/commands/AddCommand.d.ts +2 -2
- package/src/cli/commands/AddCommand.d.ts.map +1 -1
- package/src/cli/commands/AddCommand.js +135 -58
- package/src/cli/commands/ConfigCommand.d.ts +1 -1
- package/src/cli/commands/ConfigCommand.d.ts.map +1 -1
- package/src/cli/commands/CreateCommand.d.ts +15 -0
- package/src/cli/commands/CreateCommand.d.ts.map +1 -0
- package/src/cli/commands/CreateCommand.js +143 -0
- package/src/cli/commands/D1MigrateCommand.d.ts +1 -1
- package/src/cli/commands/D1MigrateCommand.d.ts.map +1 -1
- package/src/cli/commands/D1MigrateCommand.js +16 -20
- package/src/cli/commands/DbSeedCommand.d.ts +9 -0
- package/src/cli/commands/DbSeedCommand.d.ts.map +1 -0
- package/src/cli/commands/DbSeedCommand.js +171 -0
- package/src/cli/commands/DebugCommand.d.ts +1 -1
- package/src/cli/commands/DebugCommand.d.ts.map +1 -1
- package/src/cli/commands/FixCommand.d.ts +1 -1
- package/src/cli/commands/FixCommand.d.ts.map +1 -1
- package/src/cli/commands/JwtDevCommand.d.ts +8 -0
- package/src/cli/commands/JwtDevCommand.d.ts.map +1 -0
- package/src/cli/commands/JwtDevCommand.js +114 -0
- package/src/cli/commands/KeyGenerateCommand.d.ts +1 -1
- package/src/cli/commands/KeyGenerateCommand.d.ts.map +1 -1
- package/src/cli/commands/LogsCommand.d.ts +2 -2
- package/src/cli/commands/LogsCommand.d.ts.map +1 -1
- package/src/cli/commands/LogsCommand.js +36 -2
- package/src/cli/commands/MakeMailTemplateCommand.d.ts +1 -1
- package/src/cli/commands/MakeMailTemplateCommand.d.ts.map +1 -1
- package/src/cli/commands/MakeNotificationTemplateCommand.d.ts +1 -1
- package/src/cli/commands/MakeNotificationTemplateCommand.d.ts.map +1 -1
- package/src/cli/commands/MigrateCommand.d.ts +1 -1
- package/src/cli/commands/MigrateCommand.d.ts.map +1 -1
- package/src/cli/commands/MigrateCommand.js +324 -35
- package/src/cli/commands/NewCommand.d.ts +1 -1
- package/src/cli/commands/NewCommand.d.ts.map +1 -1
- package/src/cli/commands/NewCommand.js +12 -4
- package/src/cli/commands/PluginCommand.d.ts +1 -1
- package/src/cli/commands/PluginCommand.d.ts.map +1 -1
- package/src/cli/commands/PrepareCommand.d.ts +1 -1
- package/src/cli/commands/PrepareCommand.d.ts.map +1 -1
- package/src/cli/commands/QACommand.d.ts +2 -2
- package/src/cli/commands/QACommand.d.ts.map +1 -1
- package/src/cli/commands/RoutesCommand.d.ts +10 -0
- package/src/cli/commands/RoutesCommand.d.ts.map +1 -0
- package/src/cli/commands/RoutesCommand.js +242 -0
- package/src/cli/commands/SimulateCommand.d.ts +1 -1
- package/src/cli/commands/SimulateCommand.d.ts.map +1 -1
- package/src/cli/commands/index.d.ts +3 -0
- package/src/cli/commands/index.d.ts.map +1 -1
- package/src/cli/commands/index.js +3 -0
- package/src/cli/config/ConfigManager.d.ts +1 -1
- package/src/cli/config/ConfigManager.d.ts.map +1 -1
- package/src/cli/config/ConfigValidator.d.ts +1 -1
- package/src/cli/config/ConfigValidator.d.ts.map +1 -1
- package/src/cli/config/ConfigValidator.js +1 -1
- package/src/cli/d1/D1SqlMigrations.d.ts +20 -0
- package/src/cli/d1/D1SqlMigrations.d.ts.map +1 -0
- package/src/cli/d1/D1SqlMigrations.js +229 -0
- package/src/cli/d1/WranglerConfig.d.ts +4 -0
- package/src/cli/d1/WranglerConfig.d.ts.map +1 -0
- package/src/cli/d1/WranglerConfig.js +122 -0
- package/src/cli/d1/WranglerD1.d.ts +11 -0
- package/src/cli/d1/WranglerD1.d.ts.map +1 -0
- package/src/cli/d1/WranglerD1.js +16 -0
- package/src/cli/scaffolding/ControllerGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/ControllerGenerator.js +76 -26
- package/src/cli/scaffolding/FactoryGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/FactoryGenerator.js +3 -1
- package/src/cli/scaffolding/GovernanceScaffolder.d.ts +23 -0
- package/src/cli/scaffolding/GovernanceScaffolder.d.ts.map +1 -0
- package/src/cli/scaffolding/GovernanceScaffolder.js +327 -0
- package/src/cli/scaffolding/MigrationGenerator.d.ts +10 -0
- package/src/cli/scaffolding/MigrationGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/MigrationGenerator.js +137 -51
- package/src/cli/scaffolding/ModelGenerator.js +1 -1
- package/src/cli/scaffolding/ProjectScaffolder.d.ts.map +1 -1
- package/src/cli/scaffolding/ProjectScaffolder.js +36 -4
- package/src/cli/scaffolding/RouteGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/RouteGenerator.js +79 -43
- package/src/cli/scaffolding/SeederGenerator.d.ts +5 -0
- package/src/cli/scaffolding/SeederGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/SeederGenerator.js +63 -15
- package/src/cli/scaffolding/ServiceScaffolder.d.ts.map +1 -1
- package/src/cli/scaffolding/ServiceScaffolder.js +28 -7
- package/src/cli/scaffolding/index.d.ts +2 -0
- package/src/cli/scaffolding/index.d.ts.map +1 -1
- package/src/cli/scaffolding/index.js +1 -0
- package/src/common/index.d.ts +8 -0
- package/src/common/index.d.ts.map +1 -1
- package/src/common/index.js +28 -0
- package/src/common/utility.d.ts +38 -0
- package/src/common/utility.d.ts.map +1 -0
- package/src/common/utility.js +101 -0
- package/src/config/FileLogWriter.d.ts +2 -1
- package/src/config/FileLogWriter.d.ts.map +1 -1
- package/src/config/FileLogWriter.js +83 -2
- package/src/config/app.d.ts.map +1 -1
- package/src/config/app.js +3 -1
- package/src/config/broadcast.d.ts +14 -28
- package/src/config/broadcast.d.ts.map +1 -1
- package/src/config/broadcast.js +69 -35
- package/src/config/cache.d.ts +13 -45
- package/src/config/cache.d.ts.map +1 -1
- package/src/config/cache.js +69 -25
- package/src/config/cloudflare.d.ts +1 -1
- package/src/config/cloudflare.d.ts.map +1 -1
- package/src/config/database.d.ts +22 -64
- package/src/config/database.d.ts.map +1 -1
- package/src/config/database.js +191 -37
- package/src/config/env.d.ts +12 -0
- package/src/config/env.d.ts.map +1 -1
- package/src/config/env.js +14 -0
- package/src/config/index.d.ts +33 -137
- package/src/config/index.d.ts.map +1 -1
- package/src/config/logging/KvLogger.js +1 -1
- package/src/config/logging/SlackLogger.js +2 -2
- package/src/config/mail.d.ts +19 -55
- package/src/config/mail.d.ts.map +1 -1
- package/src/config/mail.js +63 -21
- package/src/config/middleware.d.ts +44 -1
- package/src/config/middleware.d.ts.map +1 -1
- package/src/config/middleware.js +157 -5
- package/src/config/notification.d.ts +14 -27
- package/src/config/notification.d.ts.map +1 -1
- package/src/config/notification.js +82 -36
- package/src/config/queue.d.ts +21 -51
- package/src/config/queue.d.ts.map +1 -1
- package/src/config/queue.js +72 -27
- package/src/config/security.d.ts +1 -1
- package/src/config/security.js +1 -1
- package/src/config/storage.d.ts +27 -34
- package/src/config/storage.d.ts.map +1 -1
- package/src/config/storage.js +97 -56
- package/src/config/type.d.ts +13 -2
- package/src/config/type.d.ts.map +1 -1
- package/src/events/EventDispatcher.d.ts.map +1 -1
- package/src/events/EventDispatcher.js +6 -4
- package/src/exceptions/ZintrustError.d.ts +7 -0
- package/src/exceptions/ZintrustError.d.ts.map +1 -1
- package/src/exceptions/ZintrustError.js +56 -0
- package/src/features/Auth.d.ts +1 -1
- package/src/features/Auth.d.ts.map +1 -1
- package/src/features/Auth.js +3 -3
- package/src/features/Queue.js +1 -1
- package/src/functions/cloudflare.d.ts.map +1 -1
- package/src/functions/cloudflare.js +3 -14
- package/src/functions/deno.d.ts.map +1 -1
- package/src/functions/deno.js +3 -14
- package/src/functions/lambda.d.ts.map +1 -1
- package/src/functions/lambda.js +3 -14
- package/src/health/StartupHealthChecks.js +1 -1
- package/src/http/Controller.d.ts +2 -2
- package/src/http/Controller.d.ts.map +1 -1
- package/src/http/FileUpload.d.ts +68 -0
- package/src/http/FileUpload.d.ts.map +1 -0
- package/src/http/FileUpload.js +120 -0
- package/src/http/Kernel.d.ts +5 -5
- package/src/http/Kernel.d.ts.map +1 -1
- package/src/http/Kernel.js +139 -23
- package/src/http/Request.d.ts +20 -1
- package/src/http/Request.d.ts.map +1 -1
- package/src/http/Request.js +23 -0
- package/src/http/RequestContext.d.ts +6 -0
- package/src/http/RequestContext.d.ts.map +1 -1
- package/src/http/RequestContext.js +77 -1
- package/src/http/Response.d.ts +1 -1
- package/src/http/Response.d.ts.map +1 -1
- package/src/http/ValidationHelper.d.ts +78 -0
- package/src/http/ValidationHelper.d.ts.map +1 -0
- package/src/http/ValidationHelper.js +121 -0
- package/src/http/error-pages/ErrorPageRenderer.d.ts +17 -0
- package/src/http/error-pages/ErrorPageRenderer.d.ts.map +1 -0
- package/src/http/error-pages/ErrorPageRenderer.js +88 -0
- package/src/http/middleware/BodyParsingMiddleware.d.ts +12 -0
- package/src/http/middleware/BodyParsingMiddleware.d.ts.map +1 -0
- package/src/http/middleware/BodyParsingMiddleware.js +251 -0
- package/src/http/middleware/FileUploadMiddleware.d.ts +12 -0
- package/src/http/middleware/FileUploadMiddleware.d.ts.map +1 -0
- package/src/http/middleware/FileUploadMiddleware.js +74 -0
- package/src/http/parsers/BodyParsers.d.ts +32 -0
- package/src/http/parsers/BodyParsers.d.ts.map +1 -0
- package/src/http/parsers/BodyParsers.js +159 -0
- package/src/http/parsers/MultipartParser.d.ts +33 -0
- package/src/http/parsers/MultipartParser.d.ts.map +1 -0
- package/src/http/parsers/MultipartParser.js +156 -0
- package/src/http/parsers/MultipartParserRegistry.d.ts +34 -0
- package/src/http/parsers/MultipartParserRegistry.d.ts.map +1 -0
- package/src/http/parsers/MultipartParserRegistry.js +20 -0
- package/src/http/validated.d.ts +12 -0
- package/src/http/validated.d.ts.map +1 -0
- package/src/http/validated.js +41 -0
- package/src/index.d.ts +73 -12
- package/src/index.d.ts.map +1 -1
- package/src/index.js +60 -5
- package/src/microservices/PostgresAdapter.d.ts.map +1 -1
- package/src/microservices/PostgresAdapter.js +0 -1
- package/src/microservices/RequestTracingMiddleware.d.ts +2 -2
- package/src/microservices/RequestTracingMiddleware.d.ts.map +1 -1
- package/src/microservices/RequestTracingMiddleware.js +3 -0
- package/src/microservices/ServiceAuthMiddleware.d.ts +2 -2
- package/src/microservices/ServiceAuthMiddleware.d.ts.map +1 -1
- package/src/middleware/AuthMiddleware.d.ts +10 -0
- package/src/middleware/AuthMiddleware.d.ts.map +1 -0
- package/src/middleware/AuthMiddleware.js +16 -0
- package/src/middleware/CsrfMiddleware.d.ts +11 -1
- package/src/middleware/CsrfMiddleware.d.ts.map +1 -1
- package/src/middleware/CsrfMiddleware.js +33 -0
- package/src/middleware/JwtAuthMiddleware.d.ts +11 -0
- package/src/middleware/JwtAuthMiddleware.d.ts.map +1 -0
- package/src/middleware/JwtAuthMiddleware.js +73 -0
- package/src/middleware/LoggingMiddleware.d.ts.map +1 -1
- package/src/middleware/LoggingMiddleware.js +8 -3
- package/src/middleware/MiddlewareStack.d.ts +2 -2
- package/src/middleware/MiddlewareStack.d.ts.map +1 -1
- package/src/middleware/RateLimiter.d.ts +2 -2
- package/src/middleware/RateLimiter.d.ts.map +1 -1
- package/src/middleware/SanitizeBodyMiddleware.d.ts +12 -0
- package/src/middleware/SanitizeBodyMiddleware.d.ts.map +1 -0
- package/src/middleware/SanitizeBodyMiddleware.js +31 -0
- package/src/middleware/SecurityMiddleware.d.ts +1 -1
- package/src/middleware/SecurityMiddleware.d.ts.map +1 -1
- package/src/middleware/SessionMiddleware.d.ts +1 -1
- package/src/middleware/SessionMiddleware.d.ts.map +1 -1
- package/src/middleware/ValidationMiddleware.d.ts +25 -0
- package/src/middleware/ValidationMiddleware.d.ts.map +1 -0
- package/src/middleware/ValidationMiddleware.js +251 -0
- package/src/migrations/MigrationDiscovery.d.ts +5 -0
- package/src/migrations/MigrationDiscovery.d.ts.map +1 -0
- package/src/migrations/MigrationDiscovery.js +16 -0
- package/src/migrations/MigrationLoader.d.ts +5 -0
- package/src/migrations/MigrationLoader.d.ts.map +1 -0
- package/src/migrations/MigrationLoader.js +43 -0
- package/src/migrations/MigrationLock.d.ts +4 -0
- package/src/migrations/MigrationLock.d.ts.map +1 -0
- package/src/migrations/MigrationLock.js +33 -0
- package/src/migrations/Migrator.d.ts +23 -0
- package/src/migrations/Migrator.d.ts.map +1 -0
- package/src/migrations/Migrator.js +4 -0
- package/src/migrations/MigratorFactory.d.ts +25 -0
- package/src/migrations/MigratorFactory.d.ts.map +1 -0
- package/src/migrations/MigratorFactory.js +339 -0
- package/src/migrations/schema/Blueprint.d.ts +5 -0
- package/src/migrations/schema/Blueprint.d.ts.map +1 -0
- package/src/migrations/schema/Blueprint.js +189 -0
- package/src/migrations/schema/Schema.d.ts +8 -0
- package/src/migrations/schema/Schema.d.ts.map +1 -0
- package/src/migrations/schema/Schema.js +141 -0
- package/src/migrations/schema/SchemaCompiler.d.ts +20 -0
- package/src/migrations/schema/SchemaCompiler.d.ts.map +1 -0
- package/src/migrations/schema/SchemaCompiler.js +262 -0
- package/src/migrations/schema/index.d.ts +5 -0
- package/src/migrations/schema/index.d.ts.map +1 -0
- package/src/migrations/schema/index.js +3 -0
- package/src/migrations/schema/types.d.ts +86 -0
- package/src/migrations/schema/types.d.ts.map +1 -0
- package/src/migrations/schema/types.js +1 -0
- package/src/migrations/types.d.ts +45 -0
- package/src/migrations/types.d.ts.map +1 -0
- package/src/migrations/types.js +1 -0
- package/src/node-singletons/crypto.d.ts +1 -1
- package/src/node-singletons/crypto.d.ts.map +1 -1
- package/src/node-singletons/crypto.js +1 -1
- package/src/node-singletons/fs.d.ts +2 -2
- package/src/node-singletons/fs.d.ts.map +1 -1
- package/src/node-singletons/fs.js +1 -1
- package/src/node-singletons/util.d.ts +6 -0
- package/src/node-singletons/util.d.ts.map +1 -0
- package/src/node-singletons/util.js +5 -0
- package/src/node.d.ts +3 -1
- package/src/node.d.ts.map +1 -1
- package/src/node.js +6 -2
- package/src/observability/OpenTelemetry.d.ts +62 -0
- package/src/observability/OpenTelemetry.d.ts.map +1 -0
- package/src/observability/OpenTelemetry.js +167 -0
- package/src/observability/PrometheusMetrics.d.ts +25 -0
- package/src/observability/PrometheusMetrics.d.ts.map +1 -0
- package/src/observability/PrometheusMetrics.js +114 -0
- package/src/openapi/OpenApiGenerator.d.ts +68 -0
- package/src/openapi/OpenApiGenerator.d.ts.map +1 -0
- package/src/openapi/OpenApiGenerator.js +287 -0
- package/src/orm/Database.d.ts +5 -2
- package/src/orm/Database.d.ts.map +1 -1
- package/src/orm/Database.js +219 -63
- package/src/orm/DatabaseAdapter.d.ts +14 -0
- package/src/orm/DatabaseAdapter.d.ts.map +1 -1
- package/src/orm/DatabaseAdapterRegistry.d.ts.map +1 -1
- package/src/orm/DatabaseAdapterRegistry.js +3 -1
- package/src/orm/DatabaseRuntimeRegistration.d.ts.map +1 -1
- package/src/orm/DatabaseRuntimeRegistration.js +12 -0
- package/src/orm/Model.d.ts +30 -2
- package/src/orm/Model.d.ts.map +1 -1
- package/src/orm/Model.js +255 -62
- package/src/orm/QueryBuilder.d.ts +22 -1
- package/src/orm/QueryBuilder.d.ts.map +1 -1
- package/src/orm/QueryBuilder.js +406 -99
- package/src/orm/Relationships.d.ts +7 -1
- package/src/orm/Relationships.d.ts.map +1 -1
- package/src/orm/Relationships.js +18 -0
- package/src/orm/SchemaCompiler.d.ts +9 -0
- package/src/orm/SchemaCompiler.d.ts.map +1 -0
- package/src/orm/SchemaCompiler.js +145 -0
- package/src/orm/adapters/D1Adapter.d.ts +1 -1
- package/src/orm/adapters/D1Adapter.d.ts.map +1 -1
- package/src/orm/adapters/MySQLAdapter.d.ts +1 -1
- package/src/orm/adapters/MySQLAdapter.d.ts.map +1 -1
- package/src/orm/adapters/MySQLAdapter.js +88 -69
- package/src/orm/adapters/PostgreSQLAdapter.d.ts +1 -1
- package/src/orm/adapters/PostgreSQLAdapter.d.ts.map +1 -1
- package/src/orm/adapters/PostgreSQLAdapter.js +88 -69
- package/src/orm/adapters/SQLServerAdapter.d.ts +1 -1
- package/src/orm/adapters/SQLServerAdapter.d.ts.map +1 -1
- package/src/orm/adapters/SQLiteAdapter.d.ts +1 -1
- package/src/orm/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/src/orm/adapters/SQLiteAdapter.js +59 -3
- package/src/orm/maintenance/SqliteMaintenance.d.ts +5 -0
- package/src/orm/maintenance/SqliteMaintenance.d.ts.map +1 -0
- package/src/orm/maintenance/SqliteMaintenance.js +14 -0
- package/src/orm/migrations/MigrationStore.d.ts +38 -0
- package/src/orm/migrations/MigrationStore.d.ts.map +1 -0
- package/src/orm/migrations/MigrationStore.js +157 -0
- package/src/performance/CodeGenerationBenchmark.d.ts.map +1 -1
- package/src/performance/Optimizer.d.ts +7 -6
- package/src/performance/Optimizer.d.ts.map +1 -1
- package/src/performance/Optimizer.js +170 -55
- package/src/profiling/MemoryProfiler.d.ts +1 -1
- package/src/profiling/MemoryProfiler.d.ts.map +1 -1
- package/src/profiling/N1Detector.d.ts +1 -1
- package/src/profiling/N1Detector.d.ts.map +1 -1
- package/src/profiling/QueryLogger.d.ts +1 -1
- package/src/profiling/QueryLogger.d.ts.map +1 -1
- package/src/profiling/RequestProfiler.d.ts +3 -3
- package/src/profiling/RequestProfiler.d.ts.map +1 -1
- package/src/routes/metrics.d.ts +2 -0
- package/src/routes/metrics.d.ts.map +1 -0
- package/src/routes/metrics.js +1 -0
- package/src/routing/CoreRoutes.d.ts +12 -0
- package/src/routing/CoreRoutes.d.ts.map +1 -0
- package/src/routing/CoreRoutes.js +151 -0
- package/src/routing/RouteRegistry.d.ts +39 -0
- package/src/routing/RouteRegistry.d.ts.map +1 -0
- package/src/routing/RouteRegistry.js +44 -0
- package/src/routing/Router.d.ts +26 -9
- package/src/routing/Router.d.ts.map +1 -1
- package/src/routing/Router.js +79 -35
- package/src/routing/common.d.ts +15 -0
- package/src/routing/common.d.ts.map +1 -0
- package/src/routing/common.js +47 -0
- package/src/routing/doc.d.ts +27 -0
- package/src/routing/doc.d.ts.map +1 -0
- package/src/routing/doc.js +110 -0
- package/src/routing/error.d.ts +21 -0
- package/src/routing/error.d.ts.map +1 -0
- package/src/routing/error.js +126 -0
- package/src/routing/errorPages.d.ts +14 -0
- package/src/routing/errorPages.d.ts.map +1 -0
- package/src/routing/errorPages.js +103 -0
- package/src/routing/publicRoot.d.ts +27 -0
- package/src/routing/publicRoot.d.ts.map +1 -0
- package/src/routing/publicRoot.js +110 -0
- package/src/runtime/PluginAutoImports.d.ts +21 -0
- package/src/runtime/PluginAutoImports.d.ts.map +1 -0
- package/src/runtime/PluginAutoImports.js +59 -0
- package/src/runtime/PluginManager.d.ts +1 -5
- package/src/runtime/PluginManager.d.ts.map +1 -1
- package/src/runtime/PluginManager.js +25 -18
- package/src/runtime/RuntimeDetector.d.ts +1 -1
- package/src/runtime/RuntimeDetector.d.ts.map +1 -1
- package/src/runtime/StartupConfigFileRegistry.d.ts +20 -0
- package/src/runtime/StartupConfigFileRegistry.d.ts.map +1 -0
- package/src/runtime/StartupConfigFileRegistry.js +44 -0
- package/src/runtime/adapters/CloudflareAdapter.d.ts +1 -1
- package/src/runtime/adapters/CloudflareAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/CloudflareAdapter.js +1 -1
- package/src/runtime/adapters/DenoAdapter.d.ts +1 -1
- package/src/runtime/adapters/DenoAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/DenoAdapter.js +1 -1
- package/src/runtime/adapters/LambdaAdapter.d.ts +1 -1
- package/src/runtime/adapters/LambdaAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/LambdaAdapter.js +1 -1
- package/src/runtime/adapters/NodeServerAdapter.d.ts +1 -1
- package/src/runtime/adapters/NodeServerAdapter.d.ts.map +1 -1
- package/src/runtime/getKernel.d.ts +9 -0
- package/src/runtime/getKernel.d.ts.map +1 -0
- package/src/runtime/getKernel.js +27 -0
- package/src/runtime/useFileLoader.d.ts +26 -0
- package/src/runtime/useFileLoader.d.ts.map +1 -0
- package/src/runtime/useFileLoader.js +188 -0
- package/src/scripts/TemplateImportsCheck.js +40 -0
- package/src/scripts/TemplateSync.js +90 -24
- package/src/security/Encryptor.d.ts.map +1 -1
- package/src/security/Encryptor.js +64 -7
- package/src/security/JwtManager.d.ts +1 -0
- package/src/security/JwtManager.d.ts.map +1 -1
- package/src/security/JwtManager.js +33 -0
- package/src/security/Sanitizer.d.ts +76 -0
- package/src/security/Sanitizer.d.ts.map +1 -0
- package/src/security/Sanitizer.js +412 -0
- package/src/security/TokenRevocation.d.ts +7 -0
- package/src/security/TokenRevocation.d.ts.map +1 -0
- package/src/security/TokenRevocation.js +57 -0
- package/src/security/XssProtection.d.ts.map +1 -1
- package/src/security/XssProtection.js +62 -14
- package/src/seeders/SeederDiscovery.d.ts +5 -0
- package/src/seeders/SeederDiscovery.d.ts.map +1 -0
- package/src/seeders/SeederDiscovery.js +21 -0
- package/src/seeders/SeederLoader.d.ts +5 -0
- package/src/seeders/SeederLoader.d.ts.map +1 -0
- package/src/seeders/SeederLoader.js +60 -0
- package/src/seeders/types.d.ts +18 -0
- package/src/seeders/types.d.ts.map +1 -0
- package/src/seeders/types.js +1 -0
- package/src/session/SessionManager.js +1 -1
- package/src/templates/adapters/MySQLAdapter.ts.tpl +109 -85
- package/src/templates/adapters/PostgreSQLAdapter.ts.tpl +129 -88
- package/src/templates/adapters/SQLServerAdapter.ts.tpl +5 -9
- package/src/templates/adapters/SQLiteAdapter.ts.tpl +78 -11
- package/src/templates/features/Queue.ts.tpl +3 -2
- package/src/templates/project/basic/app/Controllers/AuthController.ts.tpl +217 -0
- package/src/templates/project/basic/app/Controllers/UserController.ts.tpl +1 -12
- package/src/templates/project/basic/app/Types/controller.ts.tpl +46 -0
- package/src/templates/project/basic/config/FileLogWriter.ts.tpl +5 -236
- package/src/templates/project/basic/config/SecretsManager.ts.tpl +10 -447
- package/src/templates/project/basic/config/StartupConfigValidator.ts.tpl +9 -268
- package/src/templates/project/basic/config/app.ts.tpl +13 -153
- package/src/templates/project/basic/config/broadcast.ts.tpl +29 -126
- package/src/templates/project/basic/config/cache.ts.tpl +12 -70
- package/src/templates/project/basic/config/cloudflare.ts.tpl +4 -39
- package/src/templates/project/basic/config/constants.ts.tpl +9 -65
- package/src/templates/project/basic/config/database.ts.tpl +66 -123
- package/src/templates/project/basic/config/env.ts.tpl +5 -169
- package/src/templates/project/basic/config/features.ts.tpl +6 -54
- package/src/templates/project/basic/config/index.ts.tpl +8 -23
- package/src/templates/project/basic/config/logging/HttpLogger.ts.tpl +7 -114
- package/src/templates/project/basic/config/mail.ts.tpl +9 -62
- package/src/templates/project/basic/config/microservices.ts.tpl +11 -97
- package/src/templates/project/basic/config/middleware.ts.tpl +25 -43
- package/src/templates/project/basic/config/notification.ts.tpl +13 -114
- package/src/templates/project/basic/config/queue.ts.tpl +9 -40
- package/src/templates/project/basic/config/security.ts.tpl +11 -163
- package/src/templates/project/basic/config/startup.ts.tpl +10 -21
- package/src/templates/project/basic/config/storage.ts.tpl +57 -137
- package/src/templates/project/basic/config/type.ts.tpl +32 -451
- package/src/templates/project/basic/database/factories/UserFactory.ts.tpl +80 -0
- package/src/templates/project/basic/database/migrations/create_tasks_table.ts.tpl +28 -0
- package/src/templates/project/basic/database/migrations/create_users_table.ts.tpl +29 -0
- package/src/templates/project/basic/database/seeders/DatabaseSeeder.ts.tpl +19 -0
- package/src/templates/project/basic/database/seeders/UserSeeder.ts.tpl +18 -0
- package/src/templates/project/basic/database/seeders/index.ts.tpl +2 -0
- package/src/templates/project/basic/routes/api.ts.tpl +71 -33
- package/src/templates/project/basic/routes/metrics.ts.tpl +22 -0
- package/src/templates/project/basic/src/index.ts.tpl +3 -0
- package/src/templates/project/basic/tsconfig.json.tpl +12 -11
- package/src/testing/TestEnvironment.d.ts +40 -0
- package/src/testing/TestEnvironment.d.ts.map +1 -0
- package/src/testing/TestEnvironment.js +141 -0
- package/src/testing/TestHttp.d.ts +29 -0
- package/src/testing/TestHttp.d.ts.map +1 -0
- package/src/testing/TestHttp.js +96 -0
- package/src/testing/index.d.ts +5 -0
- package/src/testing/index.d.ts.map +1 -0
- package/src/testing/index.js +2 -0
- package/src/time/DateTime.d.ts +181 -0
- package/src/time/DateTime.d.ts.map +1 -0
- package/src/time/DateTime.js +300 -0
- package/src/time/index.d.ts +7 -0
- package/src/time/index.d.ts.map +1 -0
- package/src/time/index.js +5 -0
- package/src/tools/http/Http.d.ts.map +1 -1
- package/src/tools/http/Http.js +4 -0
- package/src/tools/mail/drivers/Smtp.js +1 -1
- package/src/tools/queue/drivers/InMemory.d.ts +1 -1
- package/src/tools/queue/drivers/InMemory.d.ts.map +1 -1
- package/src/tools/queue/drivers/InMemory.js +1 -1
- package/src/tools/queue/drivers/Redis.d.ts +1 -1
- package/src/tools/queue/drivers/Redis.d.ts.map +1 -1
- package/src/tools/queue/drivers/Redis.js +1 -1
- package/src/validation/ValidationError.d.ts.map +1 -1
- package/src/validation/ValidationError.js +4 -2
- package/src/validation/Validator.d.ts +49 -16
- package/src/validation/Validator.d.ts.map +1 -1
- package/src/validation/Validator.js +307 -5
- package/src/common/uuid.d.ts +0 -3
- package/src/common/uuid.d.ts.map +0 -1
- package/src/common/uuid.js +0 -30
- package/src/templates/project/basic/.env.example.tpl +0 -74
- package/src/templates/project/basic/.env.tpl +0 -166
- package/src/templates/project/basic/config/logging/KvLogger.ts.tpl +0 -181
- package/src/templates/project/basic/config/logging/SlackLogger.ts.tpl +0 -156
- package/src/templates/project/basic/database/migrations/index.ts.tpl +0 -2
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input Sanitizer (Character Whitelisting)
|
|
3
|
+
*
|
|
4
|
+
* Provides small utilities to remove unwanted characters from user input.
|
|
5
|
+
*
|
|
6
|
+
* Important:
|
|
7
|
+
* - This is NOT a complete SQL injection defense.
|
|
8
|
+
* - Always use parameterized queries / the ORM / QueryBuilder.
|
|
9
|
+
*
|
|
10
|
+
* Use this for:
|
|
11
|
+
* - Normalizing identifiers (username, slug-ish strings)
|
|
12
|
+
* - Cleaning phone numbers / numeric strings
|
|
13
|
+
* - Reducing unexpected characters before storage/logging
|
|
14
|
+
*
|
|
15
|
+
* Bulletproof Mode:
|
|
16
|
+
* - Enabled by default (`bulletproof=true`) for security-critical methods
|
|
17
|
+
* - Throws SanitizerError instead of returning empty/invalid values
|
|
18
|
+
* - Validates numeric ranges, leading zeros, type coercion attacks
|
|
19
|
+
* - ~5-15% performance overhead; disable for performance-critical paths
|
|
20
|
+
*/
|
|
21
|
+
import { ErrorFactory } from '../exceptions/ZintrustError.js';
|
|
22
|
+
const MAX_NUMERIC_INPUT_LEN = 64;
|
|
23
|
+
const MAX_EMAIL_LEN = 254;
|
|
24
|
+
const MAX_NAME_LEN = 200;
|
|
25
|
+
const MAX_PASSWORD_LEN = 256;
|
|
26
|
+
const assertMaxLen = (method, label, value, maxLen) => {
|
|
27
|
+
if (value.length <= maxLen)
|
|
28
|
+
return;
|
|
29
|
+
throw ErrorFactory.createSanitizerError(method, `${label} too long`, value);
|
|
30
|
+
};
|
|
31
|
+
const isEmpty = (value) => {
|
|
32
|
+
// Preserve legacy semantics: treat 0 and "0" as empty.
|
|
33
|
+
return (value === null ||
|
|
34
|
+
value === undefined ||
|
|
35
|
+
value === false ||
|
|
36
|
+
value === 0 ||
|
|
37
|
+
value === '' ||
|
|
38
|
+
value === '0');
|
|
39
|
+
};
|
|
40
|
+
const toStr = (value) => {
|
|
41
|
+
return String(value ?? '');
|
|
42
|
+
};
|
|
43
|
+
const stripSpaces = (value) => {
|
|
44
|
+
return toStr(value).replaceAll(' ', '');
|
|
45
|
+
};
|
|
46
|
+
const sanitize = (value, pattern, stripSpace = false) => {
|
|
47
|
+
const input = stripSpace ? stripSpaces(value) : toStr(value);
|
|
48
|
+
return input.replace(pattern, '');
|
|
49
|
+
};
|
|
50
|
+
const isNumericString = (value) => {
|
|
51
|
+
const trimmed = value.trim();
|
|
52
|
+
if (trimmed.length === 0)
|
|
53
|
+
return false;
|
|
54
|
+
const n = Number(trimmed);
|
|
55
|
+
return Number.isFinite(n);
|
|
56
|
+
};
|
|
57
|
+
const parseAmount = (value, bulletproof = true) => {
|
|
58
|
+
if (isEmpty(value))
|
|
59
|
+
return 0;
|
|
60
|
+
const cleaned = sanitize(value, /[^0-9.-]/g, true);
|
|
61
|
+
const num = Number(cleaned);
|
|
62
|
+
if (bulletproof) {
|
|
63
|
+
// Handle string edge cases - check original value
|
|
64
|
+
const str = String(value);
|
|
65
|
+
const trimmed = str.trim();
|
|
66
|
+
assertMaxLen('parseAmount', 'Input', trimmed, MAX_NUMERIC_INPUT_LEN);
|
|
67
|
+
// Reject explicit plus sign prefixes (type confusion)
|
|
68
|
+
if (trimmed.startsWith('+')) {
|
|
69
|
+
throw ErrorFactory.createSanitizerError('parseAmount', 'Plus sign not allowed', value);
|
|
70
|
+
}
|
|
71
|
+
// Reject "Infinity", "-Infinity", "NaN" explicitly
|
|
72
|
+
if (/^[+-]?infinity$/i.test(trimmed) || /^nan$/i.test(trimmed)) {
|
|
73
|
+
throw ErrorFactory.createSanitizerError('parseAmount', 'Non-finite number', value);
|
|
74
|
+
}
|
|
75
|
+
// Reject scientific notation (e.g., "1e308", "2.5e10")
|
|
76
|
+
if (/[eE]/.test(trimmed)) {
|
|
77
|
+
throw ErrorFactory.createSanitizerError('parseAmount', 'Scientific notation not allowed', value);
|
|
78
|
+
}
|
|
79
|
+
assertMaxLen('parseAmount', 'Sanitized numeric', cleaned, MAX_NUMERIC_INPUT_LEN);
|
|
80
|
+
// Require a strict numeric shape after sanitization (prevents "1-2" -> NaN etc.)
|
|
81
|
+
if (!/^-?\d+(?:\.\d+)?$/.test(cleaned)) {
|
|
82
|
+
throw ErrorFactory.createSanitizerError('parseAmount', 'Invalid numeric format', value);
|
|
83
|
+
}
|
|
84
|
+
// Reject Infinity, NaN, and overflow attacks
|
|
85
|
+
if (!Number.isFinite(num)) {
|
|
86
|
+
throw ErrorFactory.createSanitizerError('parseAmount', 'Non-finite number', value);
|
|
87
|
+
}
|
|
88
|
+
if (Math.abs(num) > Number.MAX_SAFE_INTEGER) {
|
|
89
|
+
throw ErrorFactory.createSanitizerError('parseAmount', 'Number exceeds safe integer range', value);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return Number.isFinite(num) ? num : 0;
|
|
93
|
+
};
|
|
94
|
+
const alphanumeric = (value) => {
|
|
95
|
+
if (isEmpty(value))
|
|
96
|
+
return '';
|
|
97
|
+
return sanitize(value, /[^A-Za-z0-9]/g, true);
|
|
98
|
+
};
|
|
99
|
+
const alphanumericDotDash = (value) => {
|
|
100
|
+
if (isEmpty(value))
|
|
101
|
+
return '';
|
|
102
|
+
return sanitize(value, /[^A-Za-z0-9\-.]/g, true);
|
|
103
|
+
};
|
|
104
|
+
const validateNonNegativeNumericStringPreSanitization = (trimmed, value) => {
|
|
105
|
+
assertMaxLen('nonNegativeNumericStringOrNull', 'Input', trimmed, MAX_NUMERIC_INPUT_LEN);
|
|
106
|
+
// Reject explicit plus sign prefixes (type confusion)
|
|
107
|
+
if (trimmed.startsWith('+')) {
|
|
108
|
+
throw ErrorFactory.createSanitizerError('nonNegativeNumericStringOrNull', 'Plus sign not allowed', value);
|
|
109
|
+
}
|
|
110
|
+
// Reject scientific notation before sanitization can mask it
|
|
111
|
+
if (/[eE]/.test(trimmed)) {
|
|
112
|
+
throw ErrorFactory.createSanitizerError('nonNegativeNumericStringOrNull', 'Scientific notation not allowed', value);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const validateNonNegativeNumericStringPostSanitization = (da, value) => {
|
|
116
|
+
assertMaxLen('nonNegativeNumericStringOrNull', 'Sanitized numeric', da, MAX_NUMERIC_INPUT_LEN);
|
|
117
|
+
// Strict shape: allow optional leading '-' and optional fractional part.
|
|
118
|
+
if (!/^-?\d+(?:\.\d+)?$/.test(da)) {
|
|
119
|
+
throw ErrorFactory.createSanitizerError('nonNegativeNumericStringOrNull', 'Invalid numeric format', value);
|
|
120
|
+
}
|
|
121
|
+
// For integers (no decimal point), validate leading zeros
|
|
122
|
+
if (da.includes('.')) {
|
|
123
|
+
// For decimals, only check overflow
|
|
124
|
+
const num = Number(da);
|
|
125
|
+
if (Math.abs(num) > Number.MAX_SAFE_INTEGER) {
|
|
126
|
+
throw ErrorFactory.createSanitizerError('nonNegativeNumericStringOrNull', 'Number exceeds safe integer range', value);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const numericId = Number.parseInt(da, 10);
|
|
131
|
+
if (!Number.isFinite(numericId) ||
|
|
132
|
+
numericId < 0 ||
|
|
133
|
+
numericId > Number.MAX_SAFE_INTEGER ||
|
|
134
|
+
numericId.toString() !== da) {
|
|
135
|
+
throw ErrorFactory.createSanitizerError('nonNegativeNumericStringOrNull', 'Invalid numeric format (leading zeros, overflow, or type mismatch)', value);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
const nonNegativeNumericStringOrNull = (value, bulletproof = true) => {
|
|
140
|
+
if (isEmpty(value))
|
|
141
|
+
return 0;
|
|
142
|
+
const raw = stripSpaces(value);
|
|
143
|
+
if (bulletproof) {
|
|
144
|
+
const trimmed = raw.trim();
|
|
145
|
+
validateNonNegativeNumericStringPreSanitization(trimmed, value);
|
|
146
|
+
}
|
|
147
|
+
const da = raw.replaceAll(/[^0-9\-.]/g, '');
|
|
148
|
+
const numeric = isNumericString(da);
|
|
149
|
+
if (numeric && Number(da) < 0)
|
|
150
|
+
return 0;
|
|
151
|
+
if (!numeric) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
if (bulletproof) {
|
|
155
|
+
validateNonNegativeNumericStringPostSanitization(da, value);
|
|
156
|
+
}
|
|
157
|
+
return da;
|
|
158
|
+
};
|
|
159
|
+
const digitsOnly = (value, bulletproof = true) => {
|
|
160
|
+
// Special handling for '0' string
|
|
161
|
+
if (value === '0') {
|
|
162
|
+
if (bulletproof) {
|
|
163
|
+
throw ErrorFactory.createSanitizerError('digitsOnly', 'Invalid numeric ID (zero, negative, overflow, or leading zeros)', value);
|
|
164
|
+
}
|
|
165
|
+
return '0';
|
|
166
|
+
}
|
|
167
|
+
if (isEmpty(value))
|
|
168
|
+
return '';
|
|
169
|
+
const da = sanitize(value, /\D/g);
|
|
170
|
+
if (bulletproof) {
|
|
171
|
+
assertMaxLen('digitsOnly', 'Sanitized numeric', da, 16);
|
|
172
|
+
// After removing non-digits, check if result is empty
|
|
173
|
+
if (da.length === 0) {
|
|
174
|
+
throw ErrorFactory.createSanitizerError('digitsOnly', 'Empty result after removing non-digits', value);
|
|
175
|
+
}
|
|
176
|
+
// Check for special characters that get stripped (like +)
|
|
177
|
+
const str = String(value);
|
|
178
|
+
if (/^[+-]/.test(str.trim())) {
|
|
179
|
+
throw ErrorFactory.createSanitizerError('digitsOnly', 'Invalid numeric ID (starts with +/- sign)', value);
|
|
180
|
+
}
|
|
181
|
+
const numericId = Number.parseInt(da, 10);
|
|
182
|
+
if (!Number.isFinite(numericId) ||
|
|
183
|
+
numericId <= 0 ||
|
|
184
|
+
numericId > Number.MAX_SAFE_INTEGER ||
|
|
185
|
+
numericId.toString() !== da) {
|
|
186
|
+
throw ErrorFactory.createSanitizerError('digitsOnly', 'Invalid numeric ID (zero, negative, overflow, or leading zeros)', value);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return da.replaceAll(' ', '');
|
|
190
|
+
};
|
|
191
|
+
const validateDecimalStringPreSanitization = (trimmed, value) => {
|
|
192
|
+
assertMaxLen('decimalString', 'Input', trimmed, MAX_NUMERIC_INPUT_LEN);
|
|
193
|
+
// Reject explicit plus/minus prefixes and scientific notation (type confusion)
|
|
194
|
+
if (/^[+-]/.test(trimmed)) {
|
|
195
|
+
throw ErrorFactory.createSanitizerError('decimalString', 'Signed values not allowed', value);
|
|
196
|
+
}
|
|
197
|
+
if (/[eE]/.test(trimmed)) {
|
|
198
|
+
throw ErrorFactory.createSanitizerError('decimalString', 'Scientific notation not allowed', value);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
const validateDecimalStringPostSanitization = (result, cleaned, value) => {
|
|
202
|
+
assertMaxLen('decimalString', 'Sanitized numeric', cleaned, MAX_NUMERIC_INPUT_LEN);
|
|
203
|
+
if (result.length === 0) {
|
|
204
|
+
throw ErrorFactory.createSanitizerError('decimalString', 'Empty result after sanitization', value);
|
|
205
|
+
}
|
|
206
|
+
if (!/^\d+(?:\.\d+)?$/.test(result)) {
|
|
207
|
+
throw ErrorFactory.createSanitizerError('decimalString', 'Invalid decimal format', value);
|
|
208
|
+
}
|
|
209
|
+
const num = Number(result);
|
|
210
|
+
if (!Number.isFinite(num)) {
|
|
211
|
+
throw ErrorFactory.createSanitizerError('decimalString', 'Non-numeric decimal value', value);
|
|
212
|
+
}
|
|
213
|
+
if (Math.abs(num) > Number.MAX_SAFE_INTEGER) {
|
|
214
|
+
throw ErrorFactory.createSanitizerError('decimalString', 'Decimal value exceeds safe range', value);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
const decimalString = (value, bulletproof = true) => {
|
|
218
|
+
if (isEmpty(value))
|
|
219
|
+
return '';
|
|
220
|
+
if (bulletproof) {
|
|
221
|
+
const trimmed = String(value).trim();
|
|
222
|
+
validateDecimalStringPreSanitization(trimmed, value);
|
|
223
|
+
}
|
|
224
|
+
// Allow only valid decimal format: digits and at most one decimal point
|
|
225
|
+
const cleaned = sanitize(value, /[^0-9.]/g);
|
|
226
|
+
const parts = cleaned.split('.');
|
|
227
|
+
// Bulletproof mode: reject multiple decimal points rather than merging.
|
|
228
|
+
// Legacy/unsafe mode: normalize by keeping the first decimal point.
|
|
229
|
+
let result;
|
|
230
|
+
if (parts.length > 2) {
|
|
231
|
+
result = bulletproof ? '' : `${parts[0]}.${parts.slice(1).join('')}`;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
result = cleaned;
|
|
235
|
+
}
|
|
236
|
+
if (bulletproof) {
|
|
237
|
+
validateDecimalStringPostSanitization(result, cleaned, value);
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
};
|
|
241
|
+
const numericDotOnly = (value) => {
|
|
242
|
+
if (isEmpty(value))
|
|
243
|
+
return '';
|
|
244
|
+
return sanitize(value, /[^0-9.]/g);
|
|
245
|
+
};
|
|
246
|
+
const createBasicSanitizers = () => {
|
|
247
|
+
return {
|
|
248
|
+
parseAmount,
|
|
249
|
+
alphanumeric,
|
|
250
|
+
alphanumericDotDash,
|
|
251
|
+
nonNegativeNumericStringOrNull,
|
|
252
|
+
digitsOnly,
|
|
253
|
+
decimalString,
|
|
254
|
+
numericDotOnly,
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
const addressTextSanitizer = (value) => {
|
|
258
|
+
if (isEmpty(value))
|
|
259
|
+
return '';
|
|
260
|
+
return sanitize(value, /[^A-Za-z0-9\-.@+, _]/g);
|
|
261
|
+
};
|
|
262
|
+
const emailLikeSanitizer = (value) => {
|
|
263
|
+
if (isEmpty(value))
|
|
264
|
+
return '';
|
|
265
|
+
return sanitize(value, /[^A-Za-z0-9\-.@+_]/g);
|
|
266
|
+
};
|
|
267
|
+
const emailSanitizer = (value, bulletproof = true) => {
|
|
268
|
+
if (isEmpty(value))
|
|
269
|
+
return '';
|
|
270
|
+
const result = sanitize(value, /[^A-Za-z0-9\-.@_]/g);
|
|
271
|
+
if (bulletproof) {
|
|
272
|
+
const trimmed = result.trim();
|
|
273
|
+
assertMaxLen('email', 'Email', trimmed, MAX_EMAIL_LEN);
|
|
274
|
+
if (trimmed.length === 0) {
|
|
275
|
+
throw ErrorFactory.createSanitizerError('email', 'Empty result after sanitization', value);
|
|
276
|
+
}
|
|
277
|
+
if (!trimmed.includes('@')) {
|
|
278
|
+
throw ErrorFactory.createSanitizerError('email', 'Missing @ symbol in email', value);
|
|
279
|
+
}
|
|
280
|
+
// Basic validation: something@something
|
|
281
|
+
const parts = trimmed.split('@');
|
|
282
|
+
if (parts.length !== 2 || parts[0].length === 0 || parts[1].length === 0) {
|
|
283
|
+
throw ErrorFactory.createSanitizerError('email', 'Invalid email format', value);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return result;
|
|
287
|
+
};
|
|
288
|
+
const messageTextSanitizer = (value) => {
|
|
289
|
+
if (isEmpty(value))
|
|
290
|
+
return '';
|
|
291
|
+
return sanitize(value, /[^A-Za-z0-9\-.@+_&$%!,()? ]/g);
|
|
292
|
+
};
|
|
293
|
+
const nameTextSanitizer = (value, bulletproof = true) => {
|
|
294
|
+
if (isEmpty(value))
|
|
295
|
+
return '';
|
|
296
|
+
const result = sanitize(value, /[^A-Za-z0-9 .]/g);
|
|
297
|
+
if (bulletproof) {
|
|
298
|
+
const trimmed = result.trim();
|
|
299
|
+
assertMaxLen('nameText', 'Name', trimmed, MAX_NAME_LEN);
|
|
300
|
+
if (trimmed.length === 0) {
|
|
301
|
+
throw ErrorFactory.createSanitizerError('nameText', 'Empty or whitespace-only result', value);
|
|
302
|
+
}
|
|
303
|
+
// Names should have at least one letter
|
|
304
|
+
if (!/[A-Za-z]/.test(trimmed)) {
|
|
305
|
+
throw ErrorFactory.createSanitizerError('nameText', 'Name must contain at least one letter', value);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return result;
|
|
309
|
+
};
|
|
310
|
+
const wordCharsAndSpacesSanitizer = (value) => {
|
|
311
|
+
if (isEmpty(value))
|
|
312
|
+
return '';
|
|
313
|
+
return sanitize(value, /[^A-Za-z0-9_\s]/g);
|
|
314
|
+
};
|
|
315
|
+
const safePasswordCharsSanitizer = (value, bulletproof = true) => {
|
|
316
|
+
if (isEmpty(value))
|
|
317
|
+
return '';
|
|
318
|
+
const result = sanitize(value, /[^!@#$%&*/\sA-Za-z0-9_]/g);
|
|
319
|
+
if (bulletproof) {
|
|
320
|
+
const trimmed = result.trim();
|
|
321
|
+
assertMaxLen('safePasswordChars', 'Password', trimmed, MAX_PASSWORD_LEN);
|
|
322
|
+
if (trimmed.length === 0) {
|
|
323
|
+
throw ErrorFactory.createSanitizerError('safePasswordChars', 'Empty result after sanitization', value);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return result;
|
|
327
|
+
};
|
|
328
|
+
const createTextSanitizers = () => {
|
|
329
|
+
return {
|
|
330
|
+
addressText: addressTextSanitizer,
|
|
331
|
+
emailLike: emailLikeSanitizer,
|
|
332
|
+
email: emailSanitizer,
|
|
333
|
+
messageText: messageTextSanitizer,
|
|
334
|
+
nameText: nameTextSanitizer,
|
|
335
|
+
wordCharsAndSpaces: wordCharsAndSpacesSanitizer,
|
|
336
|
+
safePasswordChars: safePasswordCharsSanitizer,
|
|
337
|
+
};
|
|
338
|
+
};
|
|
339
|
+
const createSpecializedSanitizers = () => {
|
|
340
|
+
const ipAddressText = (value) => {
|
|
341
|
+
if (isEmpty(value))
|
|
342
|
+
return '';
|
|
343
|
+
return sanitize(value, /[^A-Za-z0-9:.]/g);
|
|
344
|
+
};
|
|
345
|
+
const alphaNumericColonDash = (value) => {
|
|
346
|
+
if (isEmpty(value))
|
|
347
|
+
return '';
|
|
348
|
+
return sanitize(value, /[^A-Za-z0-9:-]/g);
|
|
349
|
+
};
|
|
350
|
+
const dateSlash = (value) => {
|
|
351
|
+
if (isEmpty(value))
|
|
352
|
+
return '';
|
|
353
|
+
return sanitize(value, /[^0-9/]/g);
|
|
354
|
+
};
|
|
355
|
+
const lowercaseAlphanumeric = (value) => {
|
|
356
|
+
if (isEmpty(value))
|
|
357
|
+
return '';
|
|
358
|
+
return sanitize(value, /[^A-Za-z0-9]/g).toLowerCase();
|
|
359
|
+
};
|
|
360
|
+
const uppercaseAlphanumeric = (value) => {
|
|
361
|
+
if (isEmpty(value))
|
|
362
|
+
return '';
|
|
363
|
+
return sanitize(value, /[^A-Za-z0-9]/g).toUpperCase();
|
|
364
|
+
};
|
|
365
|
+
const alphanumericNoSpaces = (value) => {
|
|
366
|
+
if (isEmpty(value))
|
|
367
|
+
return '';
|
|
368
|
+
return sanitize(value, /[^A-Za-z0-9 ]/g, true);
|
|
369
|
+
};
|
|
370
|
+
const dateSlashNoSpaces = (value) => {
|
|
371
|
+
if (isEmpty(value))
|
|
372
|
+
return '';
|
|
373
|
+
return sanitize(value, /[^0-9/]/g, true);
|
|
374
|
+
};
|
|
375
|
+
// Legacy naming was misleading; this is closer to a "uuid/token safe" whitelist.
|
|
376
|
+
const uuidTokenSafe = (value) => {
|
|
377
|
+
if (isEmpty(value))
|
|
378
|
+
return '';
|
|
379
|
+
return sanitize(value, /[^A-Za-z0-9\-=]/g, true);
|
|
380
|
+
};
|
|
381
|
+
// Base64url-like (plus "=") token whitelisting.
|
|
382
|
+
const tokenSafe = (value) => {
|
|
383
|
+
if (isEmpty(value))
|
|
384
|
+
return '';
|
|
385
|
+
return sanitize(value, /[^A-Za-z0-9\-=_]/g, true);
|
|
386
|
+
};
|
|
387
|
+
const keyLike = (value) => {
|
|
388
|
+
if (isEmpty(value))
|
|
389
|
+
return '';
|
|
390
|
+
return sanitize(value, /[^A-Za-z0-9\-:. ]/g, true);
|
|
391
|
+
};
|
|
392
|
+
return {
|
|
393
|
+
ipAddressText,
|
|
394
|
+
alphaNumericColonDash,
|
|
395
|
+
dateSlash,
|
|
396
|
+
lowercaseAlphanumeric,
|
|
397
|
+
uppercaseAlphanumeric,
|
|
398
|
+
alphanumericNoSpaces,
|
|
399
|
+
dateSlashNoSpaces,
|
|
400
|
+
uuidTokenSafe,
|
|
401
|
+
tokenSafe,
|
|
402
|
+
keyLike,
|
|
403
|
+
};
|
|
404
|
+
};
|
|
405
|
+
export const createSanitizer = () => {
|
|
406
|
+
return Object.freeze({
|
|
407
|
+
...createBasicSanitizers(),
|
|
408
|
+
...createTextSanitizers(),
|
|
409
|
+
...createSpecializedSanitizers(),
|
|
410
|
+
});
|
|
411
|
+
};
|
|
412
|
+
export const Sanitizer = createSanitizer();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type AuthorizationHeader = string | string[] | undefined;
|
|
2
|
+
export declare const TokenRevocation: Readonly<{
|
|
3
|
+
revoke(header: AuthorizationHeader): string | null;
|
|
4
|
+
isRevoked(token: string): boolean;
|
|
5
|
+
}>;
|
|
6
|
+
export default TokenRevocation;
|
|
7
|
+
//# sourceMappingURL=TokenRevocation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TokenRevocation.d.ts","sourceRoot":"","sources":["../../../src/security/TokenRevocation.ts"],"names":[],"mappings":"AAGA,KAAK,mBAAmB,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;AAsCzD,eAAO,MAAM,eAAe;mBACX,mBAAmB,GAAG,MAAM,GAAG,IAAI;qBASjC,MAAM,GAAG,OAAO;EAUjC,CAAC;AAEH,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { securityConfig } from '../config/security.js';
|
|
2
|
+
import { JwtManager } from './JwtManager.js';
|
|
3
|
+
const revokedTokens = new Map();
|
|
4
|
+
const defaultTtlMs = Math.max(securityConfig.jwt.expiresIn * 1000, 60_000);
|
|
5
|
+
const getBearerToken = (header) => {
|
|
6
|
+
const value = Array.isArray(header) ? header[0] : header;
|
|
7
|
+
if (typeof value !== 'string')
|
|
8
|
+
return null;
|
|
9
|
+
const [scheme, token] = value.trim().split(' ');
|
|
10
|
+
if (scheme.toLowerCase() !== 'bearer')
|
|
11
|
+
return null;
|
|
12
|
+
if (typeof token !== 'string' || token.trim() === '')
|
|
13
|
+
return null;
|
|
14
|
+
return token;
|
|
15
|
+
};
|
|
16
|
+
const cleanupExpired = () => {
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
for (const [token, expiresAt] of revokedTokens.entries()) {
|
|
19
|
+
if (expiresAt <= now) {
|
|
20
|
+
revokedTokens.delete(token);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const resolveExpiryMs = (token) => {
|
|
25
|
+
try {
|
|
26
|
+
const payload = JwtManager.create().decode(token);
|
|
27
|
+
if (typeof payload.exp === 'number' && Number.isFinite(payload.exp)) {
|
|
28
|
+
return payload.exp * 1000;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// ignore decode errors; fallback to default TTL
|
|
33
|
+
}
|
|
34
|
+
return Date.now() + defaultTtlMs;
|
|
35
|
+
};
|
|
36
|
+
export const TokenRevocation = Object.freeze({
|
|
37
|
+
revoke(header) {
|
|
38
|
+
const token = getBearerToken(header);
|
|
39
|
+
if (token === null)
|
|
40
|
+
return null;
|
|
41
|
+
cleanupExpired();
|
|
42
|
+
revokedTokens.set(token, resolveExpiryMs(token));
|
|
43
|
+
return token;
|
|
44
|
+
},
|
|
45
|
+
isRevoked(token) {
|
|
46
|
+
cleanupExpired();
|
|
47
|
+
const expiresAt = revokedTokens.get(token);
|
|
48
|
+
if (expiresAt === undefined)
|
|
49
|
+
return false;
|
|
50
|
+
if (expiresAt <= Date.now()) {
|
|
51
|
+
revokedTokens.delete(token);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
export default TokenRevocation;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"XssProtection.d.ts","sourceRoot":"","sources":["../../../src/security/XssProtection.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"XssProtection.d.ts","sourceRoot":"","sources":["../../../src/security/XssProtection.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA0WH;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,OAAO,KAAG,MAGzC,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC;CAClC;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,cAO1B,CAAC"}
|
|
@@ -27,30 +27,51 @@ const escapeHtml = (text) => {
|
|
|
27
27
|
/**
|
|
28
28
|
* Sanitize HTML by removing dangerous tags and attributes
|
|
29
29
|
*/
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
return '';
|
|
33
|
-
}
|
|
30
|
+
const MAX_SANITIZE_LOOPS = 50;
|
|
31
|
+
function removeScripts(input) {
|
|
34
32
|
// Remove script tags and content (loop until stable to avoid incomplete multi-character sanitization)
|
|
35
|
-
let sanitized =
|
|
36
|
-
let
|
|
33
|
+
let sanitized = input;
|
|
34
|
+
let prevSanitized;
|
|
35
|
+
let loopCount = 0;
|
|
37
36
|
do {
|
|
38
|
-
|
|
37
|
+
prevSanitized = sanitized;
|
|
39
38
|
sanitized = sanitized.replaceAll(/<script\b[\s\S]*?<\/script[^<]*?>/gi, '');
|
|
40
|
-
|
|
39
|
+
loopCount++;
|
|
40
|
+
} while (sanitized !== prevSanitized && loopCount < MAX_SANITIZE_LOOPS);
|
|
41
|
+
if (loopCount >= MAX_SANITIZE_LOOPS) {
|
|
42
|
+
Logger.warn('[XSS] Sanitization loop limit reached (script removal)');
|
|
43
|
+
return ''; // Fail safe: return empty string if attack detected
|
|
44
|
+
}
|
|
45
|
+
return sanitized;
|
|
46
|
+
}
|
|
47
|
+
function removeDangerousTags(input) {
|
|
41
48
|
// Remove iframe, object, embed, and base tags
|
|
49
|
+
let sanitized = input;
|
|
42
50
|
sanitized = sanitized.replaceAll(/<(?:iframe|object|embed|base)\b[\s\S]*?>/gi, '');
|
|
43
51
|
sanitized = sanitized.replaceAll(/<\/(?:iframe|object|embed|base)>/gi, '');
|
|
52
|
+
return sanitized;
|
|
53
|
+
}
|
|
54
|
+
function removeEventHandlers(input) {
|
|
44
55
|
// Remove event handlers (on*). Re-apply until stable to avoid incomplete multi-character sanitization.
|
|
45
|
-
let
|
|
56
|
+
let sanitized = input;
|
|
57
|
+
let prevSanitized;
|
|
58
|
+
let loopCount = 0;
|
|
46
59
|
do {
|
|
47
|
-
|
|
60
|
+
prevSanitized = sanitized;
|
|
48
61
|
sanitized = sanitized.replaceAll(/\bon\w+\s*=\s*(?:'[^']*'|"[^"]*"|`[^`]*`|[^\s>]*)/gi, '');
|
|
49
|
-
|
|
62
|
+
loopCount++;
|
|
63
|
+
} while (sanitized !== prevSanitized && loopCount < MAX_SANITIZE_LOOPS);
|
|
64
|
+
if (loopCount >= MAX_SANITIZE_LOOPS) {
|
|
65
|
+
Logger.warn('[XSS] Sanitization loop limit reached (event handler removal)');
|
|
66
|
+
return '';
|
|
67
|
+
}
|
|
68
|
+
return sanitized;
|
|
69
|
+
}
|
|
70
|
+
function stripDangerousUrlAttributes(input) {
|
|
50
71
|
// Remove dangerous protocols in URL-bearing attributes.
|
|
51
72
|
// This uses the same protocol normalization logic as encodeHref to prevent obfuscations like:
|
|
52
73
|
// href="javascript:..." or href="java\nscript:..." or href="%6a%61..."
|
|
53
|
-
|
|
74
|
+
return input.replaceAll(/(\s)(href|src|action|formaction|xlink:href)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/gi, (match, _leadingWhitespace, _attributeName, doubleQuotedValue, singleQuotedValue, unquotedValue) => {
|
|
54
75
|
const rawValue = doubleQuotedValue ?? singleQuotedValue ?? unquotedValue ?? '';
|
|
55
76
|
const protocolCheck = normalizeHrefForProtocolCheck(rawValue);
|
|
56
77
|
// Allow relative URLs and fragments.
|
|
@@ -92,19 +113,46 @@ const sanitizeHtml = (html) => {
|
|
|
92
113
|
// Otherwise, keep the attribute (e.g. relative-like values without a scheme).
|
|
93
114
|
return match;
|
|
94
115
|
});
|
|
116
|
+
}
|
|
117
|
+
function removeStyles(input) {
|
|
95
118
|
// Remove style tags and style attributes with potentially dangerous content
|
|
119
|
+
let sanitized = input;
|
|
96
120
|
let prevSanitized;
|
|
121
|
+
let loopCount = 0;
|
|
97
122
|
do {
|
|
98
123
|
prevSanitized = sanitized;
|
|
99
124
|
sanitized = sanitized.replaceAll(/<style\b[\s\S]*?<\/style>/gi, '');
|
|
100
|
-
|
|
125
|
+
loopCount++;
|
|
126
|
+
} while (sanitized !== prevSanitized && loopCount < MAX_SANITIZE_LOOPS);
|
|
127
|
+
if (loopCount >= MAX_SANITIZE_LOOPS) {
|
|
128
|
+
Logger.warn('[XSS] Sanitization loop limit reached (style removal)');
|
|
129
|
+
return '';
|
|
130
|
+
}
|
|
101
131
|
sanitized = sanitized.replaceAll(/\bstyle\s*=\s*(?:'[^']*'|"[^"]*"|[^\s>]*)/gi, '');
|
|
132
|
+
return sanitized;
|
|
133
|
+
}
|
|
134
|
+
function sanitizeHtml(html) {
|
|
135
|
+
if (typeof html !== 'string') {
|
|
136
|
+
return '';
|
|
137
|
+
}
|
|
138
|
+
let sanitized = html;
|
|
139
|
+
sanitized = removeScripts(sanitized);
|
|
140
|
+
if (!sanitized)
|
|
141
|
+
return '';
|
|
142
|
+
sanitized = removeDangerousTags(sanitized);
|
|
143
|
+
sanitized = removeEventHandlers(sanitized);
|
|
144
|
+
if (!sanitized)
|
|
145
|
+
return '';
|
|
146
|
+
sanitized = stripDangerousUrlAttributes(sanitized);
|
|
147
|
+
sanitized = removeStyles(sanitized);
|
|
148
|
+
if (!sanitized)
|
|
149
|
+
return '';
|
|
102
150
|
// Remove form elements
|
|
103
151
|
sanitized = sanitized.replaceAll(/<form\b[\s\S]*?<\/form>/gi, '');
|
|
104
152
|
// Remove object and embed tags
|
|
105
153
|
sanitized = sanitized.replaceAll(/<(?:object|embed|applet|meta|link|base)\b[\s\S]*?>/gi, '');
|
|
106
154
|
return sanitized.trim();
|
|
107
|
-
}
|
|
155
|
+
}
|
|
108
156
|
/**
|
|
109
157
|
* Encode URI component to prevent injection in URLs
|
|
110
158
|
*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SeederDiscovery.d.ts","sourceRoot":"","sources":["../../../src/seeders/SeederDiscovery.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,eAAe;4BACF,MAAM,OAAO,MAAM,GAAG,MAAM;yBAI/B,MAAM,GAAG,MAAM,EAAE;EAQtC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import fs from '../node-singletons/fs.js';
|
|
2
|
+
import * as path from '../node-singletons/path.js';
|
|
3
|
+
const isSeederFile = (file) => {
|
|
4
|
+
if (file.endsWith('.d.ts'))
|
|
5
|
+
return false;
|
|
6
|
+
return file.endsWith('.ts') || file.endsWith('.js');
|
|
7
|
+
};
|
|
8
|
+
export const SeederDiscovery = Object.freeze({
|
|
9
|
+
resolveDir(projectRoot, dir) {
|
|
10
|
+
return path.resolve(projectRoot, dir);
|
|
11
|
+
},
|
|
12
|
+
listSeederFiles(dir) {
|
|
13
|
+
if (!fs.existsSync(dir))
|
|
14
|
+
return [];
|
|
15
|
+
const files = fs.readdirSync(dir);
|
|
16
|
+
return files
|
|
17
|
+
.filter(isSeederFile)
|
|
18
|
+
.sort((a, b) => a.localeCompare(b))
|
|
19
|
+
.map((f) => path.join(dir, f));
|
|
20
|
+
},
|
|
21
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SeederLoader.d.ts","sourceRoot":"","sources":["../../../src/seeders/SeederLoader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,iBAAiB,CAAC;AAwDnE,eAAO,MAAM,YAAY;mBACF,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;EA0BnD,CAAC"}
|