@bgord/bun 1.9.0 → 1.9.2
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/dist/basic-auth-password.vo.d.ts +1 -1
- package/dist/basic-auth-password.vo.d.ts.map +1 -1
- package/dist/basic-auth-password.vo.js +1 -1
- package/dist/basic-auth-password.vo.js.map +1 -1
- package/dist/basic-auth-username.vo.d.ts +1 -1
- package/dist/basic-auth-username.vo.d.ts.map +1 -1
- package/dist/basic-auth-username.vo.js +1 -1
- package/dist/basic-auth-username.vo.js.map +1 -1
- package/dist/binary.vo.d.ts +1 -1
- package/dist/binary.vo.d.ts.map +1 -1
- package/dist/binary.vo.js +1 -1
- package/dist/binary.vo.js.map +1 -1
- package/dist/cache-subject-segment-env.strategy.d.ts +3 -3
- package/dist/client-ip.vo.d.ts +1 -1
- package/dist/client-ip.vo.d.ts.map +1 -1
- package/dist/client-ip.vo.js +1 -1
- package/dist/client-ip.vo.js.map +1 -1
- package/dist/client-user-agent.vo.d.ts +1 -1
- package/dist/client-user-agent.vo.d.ts.map +1 -1
- package/dist/client-user-agent.vo.js +1 -1
- package/dist/client-user-agent.vo.js.map +1 -1
- package/dist/command.types.d.ts +1 -1
- package/dist/command.types.d.ts.map +1 -1
- package/dist/commit-sha-value.vo.d.ts +1 -1
- package/dist/commit-sha-value.vo.d.ts.map +1 -1
- package/dist/commit-sha-value.vo.js +1 -1
- package/dist/commit-sha-value.vo.js.map +1 -1
- package/dist/correlation-id.vo.d.ts +1 -1
- package/dist/correlation-id.vo.d.ts.map +1 -1
- package/dist/dispatching-event-store.d.ts +1 -1
- package/dist/dispatching-event-store.d.ts.map +1 -1
- package/dist/encryption-key-value.vo.d.ts +1 -1
- package/dist/encryption-key-value.vo.d.ts.map +1 -1
- package/dist/encryption-key-value.vo.js +1 -1
- package/dist/encryption-key-value.vo.js.map +1 -1
- package/dist/environment-loader-encrypted.adapter.d.ts +4 -4
- package/dist/environment-loader-encrypted.adapter.d.ts.map +1 -1
- package/dist/environment-loader-noop.adapter.d.ts +3 -3
- package/dist/environment-loader-noop.adapter.d.ts.map +1 -1
- package/dist/environment-loader-process-safe.adapter.d.ts +4 -4
- package/dist/environment-loader-process-safe.adapter.d.ts.map +1 -1
- package/dist/environment-loader-process.adapter.d.ts +4 -4
- package/dist/environment-loader-process.adapter.d.ts.map +1 -1
- package/dist/environment-loader.port.d.ts +3 -3
- package/dist/environment-loader.port.d.ts.map +1 -1
- package/dist/event-envelope.d.ts +1 -1
- package/dist/event-envelope.d.ts.map +1 -1
- package/dist/event-envelope.js +1 -1
- package/dist/event-envelope.js.map +1 -1
- package/dist/event-handler-bare.strategy.d.ts +1 -1
- package/dist/event-handler-bare.strategy.d.ts.map +1 -1
- package/dist/event-handler-noop.strategy.d.ts +1 -1
- package/dist/event-handler-noop.strategy.d.ts.map +1 -1
- package/dist/event-handler-with-logger.strategy.d.ts +1 -1
- package/dist/event-handler-with-logger.strategy.d.ts.map +1 -1
- package/dist/event-handler.strategy.d.ts +1 -1
- package/dist/event-handler.strategy.d.ts.map +1 -1
- package/dist/event-store.d.ts +1 -1
- package/dist/event-store.d.ts.map +1 -1
- package/dist/event-stream.vo.d.ts +1 -1
- package/dist/event-stream.vo.d.ts.map +1 -1
- package/dist/event-stream.vo.js +1 -1
- package/dist/event-stream.vo.js.map +1 -1
- package/dist/event.types.d.ts +1 -1
- package/dist/event.types.d.ts.map +1 -1
- package/dist/hash-value.vo.d.ts +1 -1
- package/dist/hash-value.vo.d.ts.map +1 -1
- package/dist/hash-value.vo.js +1 -1
- package/dist/hash-value.vo.js.map +1 -1
- package/dist/hcaptcha-secret-key.vo.d.ts +1 -1
- package/dist/hcaptcha-secret-key.vo.d.ts.map +1 -1
- package/dist/hcaptcha-secret-key.vo.js +1 -1
- package/dist/hcaptcha-secret-key.vo.js.map +1 -1
- package/dist/hcaptcha-site-key.vo.d.ts +1 -1
- package/dist/hcaptcha-site-key.vo.d.ts.map +1 -1
- package/dist/hcaptcha-site-key.vo.js +1 -1
- package/dist/hcaptcha-site-key.vo.js.map +1 -1
- package/dist/healthcheck.service.d.ts +3 -3
- package/dist/logger-winston-local.adapter.d.ts.map +1 -1
- package/dist/logger-winston-local.adapter.js +2 -1
- package/dist/logger-winston-local.adapter.js.map +1 -1
- package/dist/logger-winston-production.adapter.d.ts.map +1 -1
- package/dist/logger-winston-production.adapter.js +3 -2
- package/dist/logger-winston-production.adapter.js.map +1 -1
- package/dist/logger-winston.adapter.d.ts +2 -2
- package/dist/logger.port.d.ts +3 -3
- package/dist/logger.port.d.ts.map +1 -1
- package/dist/logger.port.js +1 -1
- package/dist/logger.port.js.map +1 -1
- package/dist/mailer-content-html.vo.d.ts +1 -1
- package/dist/mailer-content-html.vo.d.ts.map +1 -1
- package/dist/mailer-content-html.vo.js +1 -1
- package/dist/mailer-content-html.vo.js.map +1 -1
- package/dist/mailer-subject.vo.d.ts +1 -1
- package/dist/mailer-subject.vo.d.ts.map +1 -1
- package/dist/mailer-subject.vo.js +1 -1
- package/dist/mailer-subject.vo.js.map +1 -1
- package/dist/modules/history/events/HISTORY_CLEARED_EVENT.d.ts +1 -1
- package/dist/modules/history/events/HISTORY_CLEARED_EVENT.d.ts.map +1 -1
- package/dist/modules/history/events/HISTORY_CLEARED_EVENT.js +1 -1
- package/dist/modules/history/events/HISTORY_CLEARED_EVENT.js.map +1 -1
- package/dist/modules/history/events/HISTORY_POPULATED_EVENT.d.ts +1 -1
- package/dist/modules/history/events/HISTORY_POPULATED_EVENT.d.ts.map +1 -1
- package/dist/modules/history/events/HISTORY_POPULATED_EVENT.js +1 -1
- package/dist/modules/history/events/HISTORY_POPULATED_EVENT.js.map +1 -1
- package/dist/modules/history/value-objects/history-created-at.d.ts +1 -1
- package/dist/modules/history/value-objects/history-created-at.d.ts.map +1 -1
- package/dist/modules/history/value-objects/history-operation.d.ts +1 -1
- package/dist/modules/history/value-objects/history-operation.d.ts.map +1 -1
- package/dist/modules/history/value-objects/history-operation.js +1 -1
- package/dist/modules/history/value-objects/history-operation.js.map +1 -1
- package/dist/modules/history/value-objects/history-payload.d.ts +1 -1
- package/dist/modules/history/value-objects/history-payload.d.ts.map +1 -1
- package/dist/modules/history/value-objects/history-payload.js +1 -1
- package/dist/modules/history/value-objects/history-payload.js.map +1 -1
- package/dist/modules/history/value-objects/history-subject.d.ts +1 -1
- package/dist/modules/history/value-objects/history-subject.d.ts.map +1 -1
- package/dist/modules/history/value-objects/history-subject.js +1 -1
- package/dist/modules/history/value-objects/history-subject.js.map +1 -1
- package/dist/modules/history/value-objects/history.d.ts +1 -1
- package/dist/modules/history/value-objects/history.d.ts.map +1 -1
- package/dist/modules/history/value-objects/history.js +1 -1
- package/dist/modules/history/value-objects/history.js.map +1 -1
- package/dist/modules/preferences/commands/SET_USER_LANGUAGE_COMMAND.d.ts +1 -1
- package/dist/modules/preferences/commands/SET_USER_LANGUAGE_COMMAND.d.ts.map +1 -1
- package/dist/modules/preferences/commands/SET_USER_LANGUAGE_COMMAND.js +1 -1
- package/dist/modules/preferences/commands/SET_USER_LANGUAGE_COMMAND.js.map +1 -1
- package/dist/modules/preferences/events/USER_LANGUAGE_SET_EVENT.d.ts +1 -1
- package/dist/modules/preferences/events/USER_LANGUAGE_SET_EVENT.d.ts.map +1 -1
- package/dist/modules/preferences/events/USER_LANGUAGE_SET_EVENT.js +1 -1
- package/dist/modules/preferences/events/USER_LANGUAGE_SET_EVENT.js.map +1 -1
- package/dist/modules/system/events/HOUR_HAS_PASSED_EVENT.d.ts +1 -1
- package/dist/modules/system/events/HOUR_HAS_PASSED_EVENT.d.ts.map +1 -1
- package/dist/modules/system/events/HOUR_HAS_PASSED_EVENT.js +1 -1
- package/dist/modules/system/events/HOUR_HAS_PASSED_EVENT.js.map +1 -1
- package/dist/modules/system/events/MINUTE_HAS_PASSED_EVENT.d.ts +1 -1
- package/dist/modules/system/events/MINUTE_HAS_PASSED_EVENT.d.ts.map +1 -1
- package/dist/modules/system/events/MINUTE_HAS_PASSED_EVENT.js +1 -1
- package/dist/modules/system/events/MINUTE_HAS_PASSED_EVENT.js.map +1 -1
- package/dist/modules/system/events/SECURITY_VIOLATION_DETECTED_EVENT.d.ts +1 -1
- package/dist/modules/system/events/SECURITY_VIOLATION_DETECTED_EVENT.d.ts.map +1 -1
- package/dist/modules/system/events/SECURITY_VIOLATION_DETECTED_EVENT.js +1 -1
- package/dist/modules/system/events/SECURITY_VIOLATION_DETECTED_EVENT.js.map +1 -1
- package/dist/node-env.vo.d.ts +11 -9
- package/dist/node-env.vo.d.ts.map +1 -1
- package/dist/node-env.vo.js +10 -3
- package/dist/node-env.vo.js.map +1 -1
- package/dist/nonce-value.vo.d.ts +1 -1
- package/dist/nonce-value.vo.d.ts.map +1 -1
- package/dist/nonce-value.vo.js +1 -1
- package/dist/nonce-value.vo.js.map +1 -1
- package/dist/port.vo.d.ts +1 -1
- package/dist/port.vo.d.ts.map +1 -1
- package/dist/port.vo.js +1 -1
- package/dist/port.vo.js.map +1 -1
- package/dist/prerequisite-verifier-timezone-utc.adapter.d.ts +1 -1
- package/dist/prerequisite-verifier-timezone-utc.adapter.d.ts.map +1 -1
- package/dist/prerequisite-verifier-timezone-utc.adapter.js +1 -1
- package/dist/prerequisite-verifier-timezone-utc.adapter.js.map +1 -1
- package/dist/recaptcha-secret-key.vo.d.ts +1 -1
- package/dist/recaptcha-secret-key.vo.d.ts.map +1 -1
- package/dist/recaptcha-secret-key.vo.js +1 -1
- package/dist/recaptcha-secret-key.vo.js.map +1 -1
- package/dist/recaptcha-site-key.vo.d.ts +1 -1
- package/dist/recaptcha-site-key.vo.d.ts.map +1 -1
- package/dist/recaptcha-site-key.vo.js +1 -1
- package/dist/recaptcha-site-key.vo.js.map +1 -1
- package/dist/security-countermeasure-name.vo.d.ts +1 -1
- package/dist/security-countermeasure-name.vo.d.ts.map +1 -1
- package/dist/security-countermeasure-name.vo.js +1 -1
- package/dist/security-countermeasure-name.vo.js.map +1 -1
- package/dist/security-rule-name.vo.d.ts +1 -1
- package/dist/security-rule-name.vo.d.ts.map +1 -1
- package/dist/security-rule-name.vo.js +1 -1
- package/dist/security-rule-name.vo.js.map +1 -1
- package/dist/smtp-host.vo.d.ts +1 -1
- package/dist/smtp-host.vo.d.ts.map +1 -1
- package/dist/smtp-host.vo.js +1 -1
- package/dist/smtp-host.vo.js.map +1 -1
- package/dist/smtp-pass.vo.d.ts +1 -1
- package/dist/smtp-pass.vo.d.ts.map +1 -1
- package/dist/smtp-pass.vo.js +1 -1
- package/dist/smtp-pass.vo.js.map +1 -1
- package/dist/smtp-port.vo.d.ts +1 -1
- package/dist/smtp-port.vo.d.ts.map +1 -1
- package/dist/smtp-user.vo.d.ts +1 -1
- package/dist/smtp-user.vo.d.ts.map +1 -1
- package/dist/smtp-user.vo.js +1 -1
- package/dist/smtp-user.vo.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/uuid.vo.d.ts +1 -1
- package/dist/uuid.vo.d.ts.map +1 -1
- package/dist/uuid.vo.js +1 -1
- package/dist/uuid.vo.js.map +1 -1
- package/package.json +4 -3
- package/src/antivirus-clamav.adapter.ts +34 -0
- package/src/antivirus-noop.adapter.ts +8 -0
- package/src/antivirus.port.ts +9 -0
- package/src/api-version.middleware.ts +31 -0
- package/src/basic-auth-password.vo.ts +17 -0
- package/src/basic-auth-username.vo.ts +17 -0
- package/src/basic-auth.service.ts +14 -0
- package/src/better-auth-logger.service.ts +45 -0
- package/src/binary.vo.ts +22 -0
- package/src/bots.vo.ts +132 -0
- package/src/build-info-repository-file.strategy.ts +23 -0
- package/src/build-info-repository-noop.strategy.ts +16 -0
- package/src/build-info-repository-package-json.strategy.ts +25 -0
- package/src/build-info-repository.strategy.ts +13 -0
- package/src/cache-file.service.ts +37 -0
- package/src/cache-repository-lru-cache.adapter.ts +58 -0
- package/src/cache-repository-node-cache.adapter.ts +32 -0
- package/src/cache-repository-noop.adapter.ts +15 -0
- package/src/cache-repository.port.ts +11 -0
- package/src/cache-resolver-simple.strategy.ts +33 -0
- package/src/cache-resolver.strategy.ts +17 -0
- package/src/cache-response.middleware.ts +51 -0
- package/src/cache-subject-application-resolver.vo.ts +34 -0
- package/src/cache-subject-request-resolver.vo.ts +37 -0
- package/src/cache-subject-segment-application.strategy.ts +7 -0
- package/src/cache-subject-segment-build.strategy.ts +14 -0
- package/src/cache-subject-segment-cookie.strategy.ts +14 -0
- package/src/cache-subject-segment-env.strategy.ts +10 -0
- package/src/cache-subject-segment-fixed.strategy.ts +12 -0
- package/src/cache-subject-segment-header.strategy.ts +13 -0
- package/src/cache-subject-segment-ip.strategy.ts +9 -0
- package/src/cache-subject-segment-path.strategy.ts +8 -0
- package/src/cache-subject-segment-query.strategy.ts +18 -0
- package/src/cache-subject-segment-request.strategy.ts +9 -0
- package/src/cache-subject-segment-user.strategy.ts +8 -0
- package/src/certificate-inspector-noop.adapter.ts +10 -0
- package/src/certificate-inspector-tls.adapter.ts +42 -0
- package/src/certificate-inspector.port.ts +7 -0
- package/src/checksum.service.ts +12 -0
- package/src/client-from-hono.adapter.ts +20 -0
- package/src/client-ip.vo.ts +17 -0
- package/src/client-user-agent.vo.ts +17 -0
- package/src/client.vo.ts +52 -0
- package/src/clock-fixed.adapter.ts +14 -0
- package/src/clock-offset.adapter.ts +15 -0
- package/src/clock-system.adapter.ts +8 -0
- package/src/clock.port.ts +5 -0
- package/src/command-envelope.ts +16 -0
- package/src/command-logger.service.ts +23 -0
- package/src/command.types.ts +13 -0
- package/src/commit-sha-value.vo.ts +18 -0
- package/src/commit-sha.vo.ts +29 -0
- package/src/context.middleware.ts +24 -0
- package/src/correlation-id.vo.ts +6 -0
- package/src/correlation-storage.service.ts +31 -0
- package/src/crypto-aes-gcm.service.ts +37 -0
- package/src/crypto-key-provider-file.adapter.ts +29 -0
- package/src/crypto-key-provider-memory.adapter.ts +17 -0
- package/src/crypto-key-provider-noop.adapter.ts +9 -0
- package/src/crypto-key-provider-with-cache.adapter.ts +28 -0
- package/src/crypto-key-provider.port.ts +3 -0
- package/src/csv-stringifier.adapter.ts +8 -0
- package/src/csv-stringifier.port.ts +8 -0
- package/src/disk-space-checker-bun.adapter.ts +18 -0
- package/src/disk-space-checker-noop.adapter.ts +10 -0
- package/src/disk-space-checker.port.ts +5 -0
- package/src/dispatching-event-store.ts +36 -0
- package/src/encryption-aes-gcm.adapter.ts +57 -0
- package/src/encryption-iv.vo.ts +9 -0
- package/src/encryption-key-value.vo.ts +18 -0
- package/src/encryption-key.vo.ts +41 -0
- package/src/encryption-noop.adapter.ts +18 -0
- package/src/encryption.port.ts +12 -0
- package/src/environment-file-parser.service.ts +35 -0
- package/src/environment-loader-encrypted.adapter.ts +31 -0
- package/src/environment-loader-noop.adapter.ts +16 -0
- package/src/environment-loader-process-safe.adapter.ts +35 -0
- package/src/environment-loader-process.adapter.ts +16 -0
- package/src/environment-loader.port.ts +8 -0
- package/src/etag-extractor.middleware.ts +18 -0
- package/src/event-bus-like.types.ts +10 -0
- package/src/event-envelope.ts +27 -0
- package/src/event-handler-bare.strategy.ts +9 -0
- package/src/event-handler-noop.strategy.ts +9 -0
- package/src/event-handler-with-logger.strategy.ts +31 -0
- package/src/event-handler.strategy.ts +8 -0
- package/src/event-logger.service.ts +23 -0
- package/src/event-loop-lag.service.ts +32 -0
- package/src/event-loop-utilization.service.ts +21 -0
- package/src/event-publisher.types.ts +3 -0
- package/src/event-store-like.types.ts +3 -0
- package/src/event-store.ts +64 -0
- package/src/event-stream.vo.ts +14 -0
- package/src/event.types.ts +16 -0
- package/src/file-cleaner-bun-forgiving.adapter.ts +10 -0
- package/src/file-cleaner-bun.adapter.ts +8 -0
- package/src/file-cleaner-noop.adapter.ts +6 -0
- package/src/file-cleaner.port.ts +5 -0
- package/src/file-draft-zip.service.ts +34 -0
- package/src/file-draft.service.ts +33 -0
- package/src/file-reader-json-bun-forgiving.adapter.ts +14 -0
- package/src/file-reader-json-bun.adapter.ts +10 -0
- package/src/file-reader-json-noop.adapter.ts +12 -0
- package/src/file-reader-json-with-cache.adapter.ts +34 -0
- package/src/file-reader-json.port.ts +7 -0
- package/src/file-renamer-fs-forgiving.adapter.ts +17 -0
- package/src/file-renamer-fs.adapter.ts +15 -0
- package/src/file-renamer-noop.adapter.ts +9 -0
- package/src/file-renamer.port.ts +8 -0
- package/src/file-uploader.middleware.ts +39 -0
- package/src/graceful-shutdown.service.ts +68 -0
- package/src/gzip-bun.adapter.ts +12 -0
- package/src/gzip-noop.adapter.ts +7 -0
- package/src/gzip-stream.adapter.ts +19 -0
- package/src/gzip.port.ts +10 -0
- package/src/hash-content-noop.strategy.ts +8 -0
- package/src/hash-content-sha256-bun.strategy.ts +11 -0
- package/src/hash-content.strategy.ts +5 -0
- package/src/hash-file-noop.adapter.ts +14 -0
- package/src/hash-file-sha256-bun.adapter.ts +23 -0
- package/src/hash-file.port.ts +13 -0
- package/src/hash-value.vo.ts +15 -0
- package/src/hash.vo.ts +29 -0
- package/src/hcaptcha-secret-key.vo.ts +15 -0
- package/src/hcaptcha-site-key.vo.ts +12 -0
- package/src/healthcheck.service.ts +138 -0
- package/src/http-logger.middleware.ts +100 -0
- package/src/i18n.service.ts +62 -0
- package/src/id-provider-crypto.adapter.ts +8 -0
- package/src/id-provider-deterministic.adapter.ts +21 -0
- package/src/id-provider.port.ts +5 -0
- package/src/image-alpha-noop.adapter.ts +7 -0
- package/src/image-alpha-sharp.adapter.ts +38 -0
- package/src/image-alpha.port.ts +19 -0
- package/src/image-blur-noop.adapter.ts +7 -0
- package/src/image-blur-sharp.adapter.ts +33 -0
- package/src/image-blur.port.ts +18 -0
- package/src/image-compressor-noop.adapter.ts +7 -0
- package/src/image-compressor-sharp.adapter.ts +36 -0
- package/src/image-compressor.port.ts +18 -0
- package/src/image-exif-clear-noop.adapter.ts +7 -0
- package/src/image-exif-clear-sharp.adapter.ts +30 -0
- package/src/image-exif-clear.port.ts +16 -0
- package/src/image-formatter-noop.adapter.ts +10 -0
- package/src/image-formatter-sharp.adapter.ts +40 -0
- package/src/image-formatter.port.ts +17 -0
- package/src/image-info-noop.adapter.ts +15 -0
- package/src/image-info-sharp.adapter.ts +27 -0
- package/src/image-info.port.ts +12 -0
- package/src/image-processor-noop.adapter.ts +10 -0
- package/src/image-processor-sharp.adapter.ts +60 -0
- package/src/image-processor.port.ts +25 -0
- package/src/image-resizer-noop.adapter.ts +7 -0
- package/src/image-resizer-sharp.adapter.ts +41 -0
- package/src/image-resizer.port.ts +18 -0
- package/src/in-flight-requests-tracker.service.ts +22 -0
- package/src/in-flight-requests.middleware.ts +15 -0
- package/src/index.ts +307 -0
- package/src/instrumentation.service.ts +39 -0
- package/src/invariant-error-handler.service.ts +22 -0
- package/src/invariant.service.ts +27 -0
- package/src/job-handler-bare.strategy.ts +15 -0
- package/src/job-handler-noop.strategy.ts +9 -0
- package/src/job-handler-with-logger.strategy.ts +44 -0
- package/src/job-handler.strategy.ts +10 -0
- package/src/jobs.service.ts +16 -0
- package/src/logger-format-error.service.ts +27 -0
- package/src/logger-noop.adapter.ts +17 -0
- package/src/logger-winston-local.adapter.ts +24 -0
- package/src/logger-winston-production.adapter.ts +38 -0
- package/src/logger-winston.adapter.ts +63 -0
- package/src/logger.port.ts +64 -0
- package/src/mailer-content-html.vo.ts +11 -0
- package/src/mailer-noop.adapter.ts +21 -0
- package/src/mailer-smtp-with-logger.adapter.ts +33 -0
- package/src/mailer-smtp.adapter.ts +33 -0
- package/src/mailer-subject.vo.ts +10 -0
- package/src/mailer.port.ts +6 -0
- package/src/maintenance-mode.middleware.ts +15 -0
- package/src/memory-consumption.service.ts +23 -0
- package/src/modules/history/event-handlers/index.ts +2 -0
- package/src/modules/history/event-handlers/onHistoryClearedEvent.ts +6 -0
- package/src/modules/history/event-handlers/onHistoryPopulatedEvent.ts +10 -0
- package/src/modules/history/events/HISTORY_CLEARED_EVENT.ts +13 -0
- package/src/modules/history/events/HISTORY_POPULATED_EVENT.ts +17 -0
- package/src/modules/history/events/index.ts +2 -0
- package/src/modules/history/index.ts +4 -0
- package/src/modules/history/ports/history-projection.ts +7 -0
- package/src/modules/history/ports/history-reader.ts +5 -0
- package/src/modules/history/ports/history-writer.ts +7 -0
- package/src/modules/history/ports/index.ts +3 -0
- package/src/modules/history/value-objects/history-created-at.ts +6 -0
- package/src/modules/history/value-objects/history-id.ts +3 -0
- package/src/modules/history/value-objects/history-operation.ts +12 -0
- package/src/modules/history/value-objects/history-payload.ts +15 -0
- package/src/modules/history/value-objects/history-subject.ts +14 -0
- package/src/modules/history/value-objects/history.ts +26 -0
- package/src/modules/history/value-objects/index.ts +6 -0
- package/src/modules/preferences/command-handlers/handleSetUserLanguageCommand.ts +36 -0
- package/src/modules/preferences/command-handlers/index.ts +1 -0
- package/src/modules/preferences/commands/SET_USER_LANGUAGE_COMMAND.ts +14 -0
- package/src/modules/preferences/commands/index.ts +1 -0
- package/src/modules/preferences/events/USER_LANGUAGE_SET_EVENT.ts +14 -0
- package/src/modules/preferences/events/index.ts +1 -0
- package/src/modules/preferences/index.ts +7 -0
- package/src/modules/preferences/invariants/index.ts +1 -0
- package/src/modules/preferences/invariants/user-language-has-changed.ts +26 -0
- package/src/modules/preferences/open-host-queries/index.ts +1 -0
- package/src/modules/preferences/open-host-queries/user-language.ts +23 -0
- package/src/modules/preferences/ports/index.ts +2 -0
- package/src/modules/preferences/ports/user-language-query.ts +5 -0
- package/src/modules/preferences/ports/user-language-resolver.ts +22 -0
- package/src/modules/preferences/value-objects/index.ts +1 -0
- package/src/modules/preferences/value-objects/supported-languages-set.ts +17 -0
- package/src/modules/system/events/HOUR_HAS_PASSED_EVENT.ts +13 -0
- package/src/modules/system/events/MINUTE_HAS_PASSED_EVENT.ts +13 -0
- package/src/modules/system/events/SECURITY_VIOLATION_DETECTED_EVENT.ts +23 -0
- package/src/modules/system/events/index.ts +3 -0
- package/src/modules/system/index.ts +2 -0
- package/src/modules/system/services/index.ts +2 -0
- package/src/modules/system/services/passage-of-time-hourly.service.ts +35 -0
- package/src/modules/system/services/passage-of-time-minute.service.ts +35 -0
- package/src/node-env.vo.ts +12 -0
- package/src/nonce-provider-crypto.adapter.ts +18 -0
- package/src/nonce-provider-deterministic.adapter.ts +21 -0
- package/src/nonce-provider-noop.adapter.ts +8 -0
- package/src/nonce-provider.port.ts +5 -0
- package/src/nonce-value.vo.ts +18 -0
- package/src/pdf-generator-noop.adapter.ts +23 -0
- package/src/pdf-generator.port.ts +5 -0
- package/src/ping.service.ts +7 -0
- package/src/port.vo.ts +14 -0
- package/src/prerequisite-runner-startup.service.ts +44 -0
- package/src/prerequisite-verifier-binary.adapter.ts +21 -0
- package/src/prerequisite-verifier-bun.adapter.ts +21 -0
- package/src/prerequisite-verifier-clock-drift.adapter.ts +32 -0
- package/src/prerequisite-verifier-directory.adapter.ts +48 -0
- package/src/prerequisite-verifier-dns.adapter.ts +20 -0
- package/src/prerequisite-verifier-external-api.adapter.ts +20 -0
- package/src/prerequisite-verifier-file.adapter.ts +49 -0
- package/src/prerequisite-verifier-jobs.adapter.ts +15 -0
- package/src/prerequisite-verifier-log-file.adapter.ts +29 -0
- package/src/prerequisite-verifier-mailer.adapter.ts +22 -0
- package/src/prerequisite-verifier-memory.adapter.ts +22 -0
- package/src/prerequisite-verifier-node.adapter.ts +21 -0
- package/src/prerequisite-verifier-os.adapter.ts +22 -0
- package/src/prerequisite-verifier-outside-connectivity.adapter.ts +23 -0
- package/src/prerequisite-verifier-port.adapter.ts +23 -0
- package/src/prerequisite-verifier-ram.adapter.ts +20 -0
- package/src/prerequisite-verifier-running-user.adapter.ts +17 -0
- package/src/prerequisite-verifier-self.adapter.ts +11 -0
- package/src/prerequisite-verifier-space.adapter.ts +32 -0
- package/src/prerequisite-verifier-sqlite.adapter.ts +25 -0
- package/src/prerequisite-verifier-ssl-certificate-expiry.adapter.ts +28 -0
- package/src/prerequisite-verifier-timezone-utc.adapter.ts +20 -0
- package/src/prerequisite-verifier-translations.adapter.ts +65 -0
- package/src/prerequisite-verifier-with-cache.adapter.ts +35 -0
- package/src/prerequisite-verifier-with-fail-safe.adapter.ts +37 -0
- package/src/prerequisite-verifier-with-logger.adapter.ts +51 -0
- package/src/prerequisite-verifier-with-retry.adapter.ts +35 -0
- package/src/prerequisite-verifier-with-timeout.adapter.ts +31 -0
- package/src/prerequisite-verifier.decorator.ts +49 -0
- package/src/prerequisite-verifier.port.ts +38 -0
- package/src/prerequisite.vo.ts +28 -0
- package/src/recaptcha-secret-key.vo.ts +15 -0
- package/src/recaptcha-site-key.vo.ts +12 -0
- package/src/redactor-compact-array.strategy.ts +10 -0
- package/src/redactor-compact-object.strategy.ts +25 -0
- package/src/redactor-composite.strategy.ts +9 -0
- package/src/redactor-mask.strategy.ts +38 -0
- package/src/redactor-noop.strategy.ts +7 -0
- package/src/redactor.strategy.ts +3 -0
- package/src/remote-file-storage-disk.adapter.ts +72 -0
- package/src/remote-file-storage-noop.adapter.ts +70 -0
- package/src/remote-file-storage.port.ts +17 -0
- package/src/retry-backoff-exponential.strategy.ts +10 -0
- package/src/retry-backoff-fibonacci.strategy.ts +16 -0
- package/src/retry-backoff-linear.strategy.ts +10 -0
- package/src/retry-backoff-noop.strategy.ts +8 -0
- package/src/retry-backoff.strategy.ts +5 -0
- package/src/retry.service.ts +37 -0
- package/src/safe-parse-body.service.ts +12 -0
- package/src/sealer-aes-gcm.adapter.ts +38 -0
- package/src/sealer-noop.adapter.ts +11 -0
- package/src/sealer.port.ts +4 -0
- package/src/security-context.vo.ts +13 -0
- package/src/security-countermeasure-ban.strategy.ts +63 -0
- package/src/security-countermeasure-mirage.strategy.ts +31 -0
- package/src/security-countermeasure-name.vo.ts +22 -0
- package/src/security-countermeasure-noop.strategy.ts +12 -0
- package/src/security-countermeasure-report.strategy.ts +27 -0
- package/src/security-countermeasure-tarpit.strategy.ts +31 -0
- package/src/security-countermeasure.strategy.ts +16 -0
- package/src/security-policy.vo.ts +9 -0
- package/src/security-rule-and.strategy.ts +25 -0
- package/src/security-rule-bait-routes.strategy.ts +15 -0
- package/src/security-rule-fail.strategy.ts +12 -0
- package/src/security-rule-honey-pot-field.strategy.ts +20 -0
- package/src/security-rule-name.vo.ts +22 -0
- package/src/security-rule-or.strategy.ts +25 -0
- package/src/security-rule-pass.strategy.ts +12 -0
- package/src/security-rule-user-agent.strategy.ts +20 -0
- package/src/security-rule-violation-threshold.strategy.ts +50 -0
- package/src/security-rule.strategy.ts +8 -0
- package/src/setup.service.ts +102 -0
- package/src/shield-api-key.strategy.ts +20 -0
- package/src/shield-auth.strategy.ts +38 -0
- package/src/shield-basic-auth.strategy.ts +17 -0
- package/src/shield-csrf.strategy.ts +23 -0
- package/src/shield-hcaptcha-local.strategy.ts +22 -0
- package/src/shield-hcaptcha.strategy.ts +24 -0
- package/src/shield-noop.strategy.ts +6 -0
- package/src/shield-rate-limit.strategy.ts +41 -0
- package/src/shield-recaptcha.strategy.ts +49 -0
- package/src/shield-security.strategy.ts +80 -0
- package/src/shield-timeout.strategy.ts +19 -0
- package/src/shield.strategy.ts +5 -0
- package/src/simulated-error.middleware.ts +8 -0
- package/src/sleeper-noop.adapter.ts +5 -0
- package/src/sleeper-system.adapter.ts +8 -0
- package/src/sleeper.port.ts +5 -0
- package/src/slower.middleware.ts +14 -0
- package/src/smtp-host.vo.ts +17 -0
- package/src/smtp-pass.vo.ts +17 -0
- package/src/smtp-port.vo.ts +5 -0
- package/src/smtp-user.vo.ts +17 -0
- package/src/ssr.ts +57 -0
- package/src/static-files.service.ts +85 -0
- package/src/stopwatch.service.ts +30 -0
- package/src/temporary-file-absolute.adapter.ts +31 -0
- package/src/temporary-file-noop.adapter.ts +16 -0
- package/src/temporary-file.port.ts +9 -0
- package/src/time-zone-offset.middleware.ts +24 -0
- package/src/timekeeper-google.adapter.ts +18 -0
- package/src/timekeeper-noop.adapter.ts +12 -0
- package/src/timekeeper.port.ts +5 -0
- package/src/timeout-cancellable-runner-bare.adapter.ts +35 -0
- package/src/timeout-cancellable-runner-noop.adapter.ts +9 -0
- package/src/timeout-cancellable-runner.port.ts +7 -0
- package/src/timeout-runner-bare.adapter.ts +23 -0
- package/src/timeout-runner-error.adapter.ts +8 -0
- package/src/timeout-runner-monitor.adapter.ts +24 -0
- package/src/timeout-runner-noop.adapter.ts +8 -0
- package/src/timeout-runner.port.ts +7 -0
- package/src/to-event-map.types.ts +3 -0
- package/src/translations.service.ts +20 -0
- package/src/uptime.service.ts +17 -0
- package/src/uuid.vo.ts +7 -0
- package/src/visitor-id-client.strategy.ts +20 -0
- package/src/visitor-id.strategy.ts +5 -0
- package/src/weak-etag-extractor.middleware.ts +17 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SecurityRuleStrategy } from "./security-rule.strategy";
|
|
2
|
+
import { SecurityRuleName } from "./security-rule-name.vo";
|
|
3
|
+
|
|
4
|
+
export class SecurityRuleFailStrategy implements SecurityRuleStrategy {
|
|
5
|
+
async isViolated() {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
get name() {
|
|
10
|
+
return SecurityRuleName.parse("fail");
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
import type { SecurityRuleStrategy } from "./security-rule.strategy";
|
|
3
|
+
import { SecurityRuleName } from "./security-rule-name.vo";
|
|
4
|
+
|
|
5
|
+
export class SecurityRuleHoneyPotFieldStrategy implements SecurityRuleStrategy {
|
|
6
|
+
constructor(private readonly field: string) {}
|
|
7
|
+
|
|
8
|
+
async isViolated(c: Context) {
|
|
9
|
+
const request = c.req.raw.clone();
|
|
10
|
+
|
|
11
|
+
const body = await request.json().catch(() => ({}));
|
|
12
|
+
const value = body[this.field];
|
|
13
|
+
|
|
14
|
+
return value !== undefined && value !== null && value !== "";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get name() {
|
|
18
|
+
return SecurityRuleName.parse("honey_pot_field");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as z from "zod/v4";
|
|
2
|
+
|
|
3
|
+
export const SecurityRuleNameError = {
|
|
4
|
+
Type: "security.rule.name.type",
|
|
5
|
+
Empty: "security.rule.name.empty",
|
|
6
|
+
TooLong: "security.rule.name.too.long",
|
|
7
|
+
BadChars: "security.rule.name.bad.chars",
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// One to sixty four letters, digits, or underscores
|
|
11
|
+
const CHARS_WHITELIST = /^[a-zA-Z0-9_]{1,512}$/;
|
|
12
|
+
|
|
13
|
+
// Stryker disable all
|
|
14
|
+
export const SecurityRuleName = z
|
|
15
|
+
// Stryker restore all
|
|
16
|
+
.string(SecurityRuleNameError.Type)
|
|
17
|
+
.min(1, SecurityRuleNameError.Empty)
|
|
18
|
+
.max(512, SecurityRuleNameError.TooLong)
|
|
19
|
+
.regex(CHARS_WHITELIST, SecurityRuleNameError.BadChars)
|
|
20
|
+
.brand("SecurityRuleName");
|
|
21
|
+
|
|
22
|
+
export type SecurityRuleNameType = z.infer<typeof SecurityRuleName>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
import type { SecurityRuleStrategy } from "./security-rule.strategy";
|
|
3
|
+
import { SecurityRuleName } from "./security-rule-name.vo";
|
|
4
|
+
|
|
5
|
+
export const SecurityRuleOrStrategyError = {
|
|
6
|
+
MissingRules: "security.rule.or.adapter.error.missing.rules",
|
|
7
|
+
MaxRules: "security.rule.or.adapter.error.max.rules",
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export class SecurityRuleOrStrategy implements SecurityRuleStrategy {
|
|
11
|
+
constructor(private readonly rules: SecurityRuleStrategy[]) {
|
|
12
|
+
if (rules.length === 0) throw new Error(SecurityRuleOrStrategyError.MissingRules);
|
|
13
|
+
if (rules.length > 5) throw new Error(SecurityRuleOrStrategyError.MaxRules);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async isViolated(c: Context) {
|
|
17
|
+
const reports = await Promise.all(this.rules.map((rule) => rule.isViolated(c)));
|
|
18
|
+
|
|
19
|
+
return reports.some(Boolean);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get name() {
|
|
23
|
+
return SecurityRuleName.parse(`or_${this.rules.map((rule) => rule.name).join("_")}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SecurityRuleStrategy } from "./security-rule.strategy";
|
|
2
|
+
import { SecurityRuleName } from "./security-rule-name.vo";
|
|
3
|
+
|
|
4
|
+
export class SecurityRulePassStrategy implements SecurityRuleStrategy {
|
|
5
|
+
async isViolated() {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
get name() {
|
|
10
|
+
return SecurityRuleName.parse("pass");
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
import { ALL_BOTS } from "./bots.vo";
|
|
3
|
+
import { ClientFromHono } from "./client-from-hono.adapter";
|
|
4
|
+
import { ClientUserAgent } from "./client-user-agent.vo";
|
|
5
|
+
import type { SecurityRuleStrategy } from "./security-rule.strategy";
|
|
6
|
+
import { SecurityRuleName } from "./security-rule-name.vo";
|
|
7
|
+
|
|
8
|
+
export class SecurityRuleUserAgentStrategy implements SecurityRuleStrategy {
|
|
9
|
+
constructor(private readonly blacklist: string[] = ALL_BOTS) {}
|
|
10
|
+
|
|
11
|
+
async isViolated(c: Context) {
|
|
12
|
+
const client = ClientFromHono.translate(c);
|
|
13
|
+
|
|
14
|
+
return this.blacklist.some((bot) => client.matchesUa(ClientUserAgent.parse(bot)));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get name() {
|
|
18
|
+
return SecurityRuleName.parse("user_agent");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
|
+
import type { Context } from "hono";
|
|
3
|
+
import type { CacheRepositoryPort } from "./cache-repository.port";
|
|
4
|
+
import { CacheSubjectRequestResolver } from "./cache-subject-request-resolver.vo";
|
|
5
|
+
import { CacheSubjectSegmentFixedStrategy } from "./cache-subject-segment-fixed.strategy";
|
|
6
|
+
import { CacheSubjectSegmentIpStrategy } from "./cache-subject-segment-ip.strategy";
|
|
7
|
+
import type { HashContentStrategy } from "./hash-content.strategy";
|
|
8
|
+
import type { SecurityRuleStrategy } from "./security-rule.strategy";
|
|
9
|
+
import { SecurityRuleName } from "./security-rule-name.vo";
|
|
10
|
+
|
|
11
|
+
type Dependencies = { CacheRepository: CacheRepositoryPort; HashContent: HashContentStrategy };
|
|
12
|
+
|
|
13
|
+
export class SecurityRuleViolationThresholdStrategy implements SecurityRuleStrategy {
|
|
14
|
+
constructor(
|
|
15
|
+
private readonly rule: SecurityRuleStrategy,
|
|
16
|
+
private readonly config: { threshold: tools.IntegerPositiveType },
|
|
17
|
+
private readonly deps: Dependencies,
|
|
18
|
+
) {}
|
|
19
|
+
|
|
20
|
+
// Best-effort increment, occasional lost increments are acceptable for concurrent requests.
|
|
21
|
+
async isViolated(c: Context) {
|
|
22
|
+
const resolver = new CacheSubjectRequestResolver(
|
|
23
|
+
[new CacheSubjectSegmentFixedStrategy(this.name), new CacheSubjectSegmentIpStrategy()],
|
|
24
|
+
this.deps,
|
|
25
|
+
);
|
|
26
|
+
const subject = await resolver.resolve(c);
|
|
27
|
+
|
|
28
|
+
const violated = await this.rule.isViolated(c);
|
|
29
|
+
|
|
30
|
+
if (!violated) return false;
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const count = (await this.deps.CacheRepository.get<tools.IntegerNonNegativeType>(subject.hex)) ?? 0;
|
|
34
|
+
|
|
35
|
+
await this.deps.CacheRepository.set<tools.IntegerNonNegativeType>(
|
|
36
|
+
subject.hex,
|
|
37
|
+
tools.IntegerNonNegative.parse(count + 1),
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (count + 1 >= this.config.threshold) return true;
|
|
41
|
+
return false;
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get name() {
|
|
48
|
+
return SecurityRuleName.parse(`violation_threshold_${this.config.threshold}_${this.rule.name}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
|
+
import { bodyLimit } from "hono/body-limit";
|
|
3
|
+
import { cors } from "hono/cors";
|
|
4
|
+
import { languageDetector } from "hono/language";
|
|
5
|
+
import { requestId } from "hono/request-id";
|
|
6
|
+
import { secureHeaders } from "hono/secure-headers";
|
|
7
|
+
import { timing } from "hono/timing";
|
|
8
|
+
import { ApiVersion } from "./api-version.middleware";
|
|
9
|
+
import type { BuildInfoRepositoryStrategy } from "./build-info-repository.strategy";
|
|
10
|
+
import type { CacheResolverStrategy } from "./cache-resolver.strategy";
|
|
11
|
+
import type { ClockPort } from "./clock.port";
|
|
12
|
+
import { Context } from "./context.middleware";
|
|
13
|
+
import { CorrelationStorage } from "./correlation-storage.service";
|
|
14
|
+
import { ETagExtractor } from "./etag-extractor.middleware";
|
|
15
|
+
import type { HashContentStrategy } from "./hash-content.strategy";
|
|
16
|
+
import { HttpLogger, type HttpLoggerOptions } from "./http-logger.middleware";
|
|
17
|
+
import type { I18nConfigType } from "./i18n.service";
|
|
18
|
+
import type { IdProviderPort } from "./id-provider.port";
|
|
19
|
+
import type { LoggerPort } from "./logger.port";
|
|
20
|
+
import { MaintenanceMode, type MaintenanceModeConfigType } from "./maintenance-mode.middleware";
|
|
21
|
+
import { type ShieldCsrfConfigType, ShieldCsrfStrategy } from "./shield-csrf.strategy";
|
|
22
|
+
import { TimeZoneOffset } from "./time-zone-offset.middleware";
|
|
23
|
+
import { WeakETagExtractor } from "./weak-etag-extractor.middleware";
|
|
24
|
+
|
|
25
|
+
type SetupConfigType = {
|
|
26
|
+
csrf: ShieldCsrfConfigType;
|
|
27
|
+
cors?: Parameters<typeof cors>[0];
|
|
28
|
+
httpLogger?: HttpLoggerOptions;
|
|
29
|
+
maintenanceMode?: MaintenanceModeConfigType;
|
|
30
|
+
BODY_LIMIT_MAX_SIZE?: tools.Size;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type Dependencies = {
|
|
34
|
+
Logger: LoggerPort;
|
|
35
|
+
IdProvider: IdProviderPort;
|
|
36
|
+
I18n: I18nConfigType;
|
|
37
|
+
Clock: ClockPort;
|
|
38
|
+
CacheResolver: CacheResolverStrategy;
|
|
39
|
+
HashContent: HashContentStrategy;
|
|
40
|
+
BuildInfoRepository: BuildInfoRepositoryStrategy;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export class Setup {
|
|
44
|
+
static essentials(config: SetupConfigType, deps: Dependencies) {
|
|
45
|
+
const BODY_LIMIT_MAX_SIZE = config.BODY_LIMIT_MAX_SIZE ?? tools.Size.fromKb(128);
|
|
46
|
+
|
|
47
|
+
return [
|
|
48
|
+
MaintenanceMode.build(config.maintenanceMode),
|
|
49
|
+
requestId({
|
|
50
|
+
limitLength: 36,
|
|
51
|
+
headerName: "x-correlation-id",
|
|
52
|
+
generator: () => deps.IdProvider.generate(),
|
|
53
|
+
}),
|
|
54
|
+
ApiVersion.build(deps),
|
|
55
|
+
new ShieldCsrfStrategy(config.csrf).verify,
|
|
56
|
+
secureHeaders({
|
|
57
|
+
referrerPolicy: "no-referrer",
|
|
58
|
+
xContentTypeOptions: "nosniff",
|
|
59
|
+
xDnsPrefetchControl: false,
|
|
60
|
+
xDownloadOptions: true,
|
|
61
|
+
xPermittedCrossDomainPolicies: false,
|
|
62
|
+
crossOriginEmbedderPolicy: false,
|
|
63
|
+
crossOriginOpenerPolicy: false,
|
|
64
|
+
crossOriginResourcePolicy: false,
|
|
65
|
+
originAgentCluster: false,
|
|
66
|
+
xFrameOptions: false,
|
|
67
|
+
}),
|
|
68
|
+
bodyLimit({ maxSize: BODY_LIMIT_MAX_SIZE.toBytes() }),
|
|
69
|
+
cors({
|
|
70
|
+
// Stryker disable all
|
|
71
|
+
origin: (origin, c) => {
|
|
72
|
+
// server-to-server, curl, same-origin navigation
|
|
73
|
+
if (!origin) return undefined;
|
|
74
|
+
|
|
75
|
+
// same-origin fetch
|
|
76
|
+
if (origin === new URL(c.req.url).origin) return origin;
|
|
77
|
+
|
|
78
|
+
// deny cross-origin
|
|
79
|
+
return null;
|
|
80
|
+
},
|
|
81
|
+
// Stryker restore all
|
|
82
|
+
credentials: false,
|
|
83
|
+
maxAge: tools.Duration.Minutes(10).seconds,
|
|
84
|
+
...config.cors,
|
|
85
|
+
}),
|
|
86
|
+
languageDetector({
|
|
87
|
+
supportedLanguages: Object.keys(deps.I18n.supportedLanguages),
|
|
88
|
+
fallbackLanguage: deps.I18n.defaultLanguage,
|
|
89
|
+
// Stryker disable all
|
|
90
|
+
caches: false,
|
|
91
|
+
// Stryker restore all
|
|
92
|
+
}),
|
|
93
|
+
TimeZoneOffset.attach,
|
|
94
|
+
Context.attach,
|
|
95
|
+
WeakETagExtractor.attach,
|
|
96
|
+
ETagExtractor.attach,
|
|
97
|
+
HttpLogger.build(deps, config.httpLogger),
|
|
98
|
+
timing(),
|
|
99
|
+
CorrelationStorage.handle(),
|
|
100
|
+
];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type * as tools from "@bgord/tools";
|
|
2
|
+
import { createMiddleware } from "hono/factory";
|
|
3
|
+
import { HTTPException } from "hono/http-exception";
|
|
4
|
+
import type { ShieldStrategy } from "./shield.strategy";
|
|
5
|
+
|
|
6
|
+
type ApiKeyShieldConfigType = { API_KEY: tools.ApiKeyType };
|
|
7
|
+
|
|
8
|
+
export const ShieldApiKeyError = new HTTPException(403, { message: "shield.api.key" });
|
|
9
|
+
|
|
10
|
+
export class ShieldApiKeyStrategy implements ShieldStrategy {
|
|
11
|
+
static readonly HEADER_NAME = "bgord-api-key";
|
|
12
|
+
|
|
13
|
+
constructor(private readonly config: ApiKeyShieldConfigType) {}
|
|
14
|
+
|
|
15
|
+
verify = createMiddleware(async (context, next) => {
|
|
16
|
+
if (context.req.header(ShieldApiKeyStrategy.HEADER_NAME) === this.config.API_KEY) return next();
|
|
17
|
+
|
|
18
|
+
throw ShieldApiKeyError;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { betterAuth } from "better-auth";
|
|
2
|
+
import type hono from "hono";
|
|
3
|
+
import { createMiddleware } from "hono/factory";
|
|
4
|
+
import { HTTPException } from "hono/http-exception";
|
|
5
|
+
|
|
6
|
+
export const ShieldAuthError = new HTTPException(403, { message: "shield.auth" });
|
|
7
|
+
|
|
8
|
+
export class ShieldAuthStrategy {
|
|
9
|
+
constructor(private readonly Auth: ReturnType<typeof betterAuth>) {}
|
|
10
|
+
|
|
11
|
+
attach = createMiddleware(async (c: hono.Context, next: hono.Next) => {
|
|
12
|
+
const session = await this.Auth.api.getSession({ headers: c.req.raw.headers });
|
|
13
|
+
|
|
14
|
+
if (!session) {
|
|
15
|
+
c.set("user", null);
|
|
16
|
+
c.set("session", null);
|
|
17
|
+
return next();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
c.set("user", session.user);
|
|
21
|
+
c.set("session", session.session);
|
|
22
|
+
return next();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
verify = createMiddleware(async (c: hono.Context, next: hono.Next) => {
|
|
26
|
+
const user = c.get("user");
|
|
27
|
+
|
|
28
|
+
if (!user) throw ShieldAuthError;
|
|
29
|
+
return next();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
reverse = createMiddleware(async (c: hono.Context, next: hono.Next) => {
|
|
33
|
+
const user = c.get("user");
|
|
34
|
+
|
|
35
|
+
if (user) throw ShieldAuthError;
|
|
36
|
+
return next();
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { basicAuth } from "hono/basic-auth";
|
|
2
|
+
import { createMiddleware } from "hono/factory";
|
|
3
|
+
import type { BasicAuthPasswordType } from "./basic-auth-password.vo";
|
|
4
|
+
import type { BasicAuthUsernameType } from "./basic-auth-username.vo";
|
|
5
|
+
import type { ShieldStrategy } from "./shield.strategy";
|
|
6
|
+
|
|
7
|
+
type ShieldBasicAuthConfigType = { username: BasicAuthUsernameType; password: BasicAuthPasswordType };
|
|
8
|
+
|
|
9
|
+
export class ShieldBasicAuthStrategy implements ShieldStrategy {
|
|
10
|
+
private readonly basicAuth;
|
|
11
|
+
|
|
12
|
+
constructor(config: ShieldBasicAuthConfigType) {
|
|
13
|
+
this.basicAuth = basicAuth(config);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
verify = createMiddleware(async (context, next) => this.basicAuth(context, next));
|
|
17
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createMiddleware } from "hono/factory";
|
|
2
|
+
import { HTTPException } from "hono/http-exception";
|
|
3
|
+
import type { ShieldStrategy } from "./shield.strategy";
|
|
4
|
+
|
|
5
|
+
const STATE_CHANGING_METHODS = ["POST", "PUT", "PATCH", "DELETE"];
|
|
6
|
+
|
|
7
|
+
export type ShieldCsrfConfigType = { origin: string[] };
|
|
8
|
+
|
|
9
|
+
export const ShieldCsrfError = new HTTPException(403, { message: "shield.csrf" });
|
|
10
|
+
|
|
11
|
+
export class ShieldCsrfStrategy implements ShieldStrategy {
|
|
12
|
+
constructor(private readonly config: ShieldCsrfConfigType) {}
|
|
13
|
+
|
|
14
|
+
verify = createMiddleware(async (context, next) => {
|
|
15
|
+
if (!STATE_CHANGING_METHODS.includes(context.req.method)) return next();
|
|
16
|
+
|
|
17
|
+
const origin = context.req.header("origin");
|
|
18
|
+
|
|
19
|
+
if (!origin) return next();
|
|
20
|
+
if (!this.config.origin.includes(origin)) throw ShieldCsrfError;
|
|
21
|
+
return next();
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import hcaptcha from "hcaptcha";
|
|
2
|
+
import { createMiddleware } from "hono/factory";
|
|
3
|
+
import { HTTPException } from "hono/http-exception";
|
|
4
|
+
import type { HCaptchaSecretKeyType } from "./hcaptcha-secret-key.vo";
|
|
5
|
+
import type { ShieldStrategy } from "./shield.strategy";
|
|
6
|
+
|
|
7
|
+
export const ShieldHcaptchaLocalError = new HTTPException(403, { message: "shield.hcaptcha.local" });
|
|
8
|
+
|
|
9
|
+
export class ShieldHcaptchaLocalStrategy implements ShieldStrategy {
|
|
10
|
+
constructor(private readonly secretKey: HCaptchaSecretKeyType) {}
|
|
11
|
+
|
|
12
|
+
verify = createMiddleware(async (_, next) => {
|
|
13
|
+
try {
|
|
14
|
+
const result = await hcaptcha.verify(this.secretKey, "10000000-aaaa-bbbb-cccc-000000000001");
|
|
15
|
+
|
|
16
|
+
if (!result.success) throw ShieldHcaptchaLocalError;
|
|
17
|
+
return next();
|
|
18
|
+
} catch {
|
|
19
|
+
throw ShieldHcaptchaLocalError;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import hcaptcha from "hcaptcha";
|
|
2
|
+
import { createMiddleware } from "hono/factory";
|
|
3
|
+
import { HTTPException } from "hono/http-exception";
|
|
4
|
+
import type { HCaptchaSecretKeyType } from "./hcaptcha-secret-key.vo";
|
|
5
|
+
import type { ShieldStrategy } from "./shield.strategy";
|
|
6
|
+
|
|
7
|
+
export const ShieldHcaptchaError = new HTTPException(403, { message: "shield.hcaptcha" });
|
|
8
|
+
|
|
9
|
+
export class ShieldHcaptchaStrategy implements ShieldStrategy {
|
|
10
|
+
constructor(private readonly secretKey: HCaptchaSecretKeyType) {}
|
|
11
|
+
|
|
12
|
+
verify = createMiddleware(async (context, next) => {
|
|
13
|
+
try {
|
|
14
|
+
const form = await context.req.formData();
|
|
15
|
+
const hcaptchaTokenFormData = form.get("h-captcha-response")?.toString() as string;
|
|
16
|
+
const result = await hcaptcha.verify(this.secretKey, hcaptchaTokenFormData);
|
|
17
|
+
|
|
18
|
+
if (!result.success) throw ShieldHcaptchaError;
|
|
19
|
+
return next();
|
|
20
|
+
} catch {
|
|
21
|
+
throw ShieldHcaptchaError;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
|
+
import { createMiddleware } from "hono/factory";
|
|
3
|
+
import { HTTPException } from "hono/http-exception";
|
|
4
|
+
import type { CacheResolverStrategy } from "./cache-resolver.strategy";
|
|
5
|
+
import type { CacheSubjectRequestResolver } from "./cache-subject-request-resolver.vo";
|
|
6
|
+
import type { ClockPort } from "./clock.port";
|
|
7
|
+
import type { ShieldStrategy } from "./shield.strategy";
|
|
8
|
+
|
|
9
|
+
type ShieldRateLimitOptionsType = {
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
resolver: CacheSubjectRequestResolver;
|
|
12
|
+
window: tools.Duration;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type Dependencies = { Clock: ClockPort; CacheResolver: CacheResolverStrategy };
|
|
16
|
+
|
|
17
|
+
export const ShieldRateLimitError = new HTTPException(429, { message: "shield.rate.limit" });
|
|
18
|
+
|
|
19
|
+
export class ShieldRateLimitStrategy implements ShieldStrategy {
|
|
20
|
+
constructor(
|
|
21
|
+
private readonly options: ShieldRateLimitOptionsType,
|
|
22
|
+
private readonly deps: Dependencies,
|
|
23
|
+
) {}
|
|
24
|
+
|
|
25
|
+
verify = createMiddleware(async (context, next) => {
|
|
26
|
+
if (!this.options.enabled) return next();
|
|
27
|
+
|
|
28
|
+
const subject = await this.options.resolver.resolve(context);
|
|
29
|
+
|
|
30
|
+
const limiter = await this.deps.CacheResolver.resolve(
|
|
31
|
+
subject.hex,
|
|
32
|
+
async () => new tools.RateLimiter(this.options.window),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const result = limiter.verify(this.deps.Clock.now());
|
|
36
|
+
|
|
37
|
+
if (!result.allowed) throw ShieldRateLimitError;
|
|
38
|
+
|
|
39
|
+
return next();
|
|
40
|
+
});
|
|
41
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
|
+
import { createMiddleware } from "hono/factory";
|
|
3
|
+
import { HTTPException } from "hono/http-exception";
|
|
4
|
+
import type { RecaptchaSecretKeyType } from "./recaptcha-secret-key.vo";
|
|
5
|
+
import type { ShieldStrategy } from "./shield.strategy";
|
|
6
|
+
|
|
7
|
+
export type RecaptchaVerifierConfigType = { secretKey: RecaptchaSecretKeyType };
|
|
8
|
+
export type RecaptchaResultType = { success: boolean; score: number };
|
|
9
|
+
|
|
10
|
+
export const ShieldRecaptchaError = new HTTPException(403, { message: "shield.recaptcha" });
|
|
11
|
+
|
|
12
|
+
export class ShieldRecaptchaStrategy implements ShieldStrategy {
|
|
13
|
+
private static readonly URL = tools.UrlWithoutSlash.parse(
|
|
14
|
+
"https://www.google.com/recaptcha/api/siteverify",
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
constructor(private readonly config: RecaptchaVerifierConfigType) {}
|
|
18
|
+
|
|
19
|
+
verify = createMiddleware(async (context, next) => {
|
|
20
|
+
try {
|
|
21
|
+
const header = context.req.header("x-recaptcha-token");
|
|
22
|
+
const query = context.req.query("recaptchaToken");
|
|
23
|
+
const form = (await context.req.formData()).get("g-recaptcha-response")?.toString();
|
|
24
|
+
|
|
25
|
+
const token = header ?? query ?? form;
|
|
26
|
+
|
|
27
|
+
if (!token) throw ShieldRecaptchaError;
|
|
28
|
+
|
|
29
|
+
// cSpell:ignore remoteip
|
|
30
|
+
const remoteip = context.req.header("x-forwarded-for") ?? "";
|
|
31
|
+
|
|
32
|
+
const params = new URLSearchParams({ secret: this.config.secretKey, response: token, remoteip });
|
|
33
|
+
|
|
34
|
+
const response = await fetch(ShieldRecaptchaStrategy.URL, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
37
|
+
body: params,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const result: RecaptchaResultType = await response.json();
|
|
41
|
+
|
|
42
|
+
if (!result.success || result.score < 0.5) throw ShieldRecaptchaError;
|
|
43
|
+
|
|
44
|
+
await next();
|
|
45
|
+
} catch {
|
|
46
|
+
throw ShieldRecaptchaError;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { createMiddleware } from "hono/factory";
|
|
2
|
+
import type { ContentfulStatusCode } from "hono/utils/http-status";
|
|
3
|
+
import { ClientFromHono } from "./client-from-hono.adapter";
|
|
4
|
+
import { SecurityContext } from "./security-context.vo";
|
|
5
|
+
import type { SecurityPolicy } from "./security-policy.vo";
|
|
6
|
+
import type { ShieldStrategy } from "./shield.strategy";
|
|
7
|
+
import type { SleeperPort } from "./sleeper.port";
|
|
8
|
+
|
|
9
|
+
type Dependencies = { Sleeper: SleeperPort };
|
|
10
|
+
|
|
11
|
+
export const ShieldSecurityAdapterError = {
|
|
12
|
+
Unhandled: "shield.security.adapter.error.unhandled",
|
|
13
|
+
MissingPolicies: "shield.security.adapter.error.missing.policies",
|
|
14
|
+
MaxPolicies: "shield.security.adapter.error.max.policies",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export class ShieldSecurityStrategy implements ShieldStrategy {
|
|
18
|
+
constructor(
|
|
19
|
+
private readonly policies: SecurityPolicy[],
|
|
20
|
+
private readonly deps: Dependencies,
|
|
21
|
+
) {
|
|
22
|
+
if (policies.length === 0) throw new Error(ShieldSecurityAdapterError.MissingPolicies);
|
|
23
|
+
if (policies.length > 5) throw new Error(ShieldSecurityAdapterError.MaxPolicies);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
verify = createMiddleware(async (c, next) => {
|
|
27
|
+
for (const policy of this.policies) {
|
|
28
|
+
const violation = await policy.rule.isViolated(c);
|
|
29
|
+
|
|
30
|
+
if (!violation) continue;
|
|
31
|
+
|
|
32
|
+
const context = new SecurityContext(
|
|
33
|
+
policy.rule.name,
|
|
34
|
+
policy.countermeasure.name,
|
|
35
|
+
ClientFromHono.translate(c),
|
|
36
|
+
// Stryker disable all
|
|
37
|
+
c.get("user")?.id,
|
|
38
|
+
// Stryker restore all
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const action = await policy.countermeasure.execute(context);
|
|
42
|
+
|
|
43
|
+
// Stryker disable all
|
|
44
|
+
switch (action.kind) {
|
|
45
|
+
case "allow":
|
|
46
|
+
return next();
|
|
47
|
+
|
|
48
|
+
case "deny":
|
|
49
|
+
return c.text(action.reason, action.response.status as ContentfulStatusCode);
|
|
50
|
+
|
|
51
|
+
case "mirage":
|
|
52
|
+
return c.json({}, action.response.status as ContentfulStatusCode);
|
|
53
|
+
|
|
54
|
+
case "delay": {
|
|
55
|
+
await this.deps.Sleeper.wait(action.duration);
|
|
56
|
+
|
|
57
|
+
switch (action.after.kind) {
|
|
58
|
+
case "allow":
|
|
59
|
+
return next();
|
|
60
|
+
|
|
61
|
+
case "deny":
|
|
62
|
+
return c.text(action.after.reason, action.after.response.status as ContentfulStatusCode);
|
|
63
|
+
|
|
64
|
+
case "mirage":
|
|
65
|
+
return c.json({}, action.after.response.status as ContentfulStatusCode);
|
|
66
|
+
|
|
67
|
+
case "delay":
|
|
68
|
+
throw new Error(ShieldSecurityAdapterError.Unhandled);
|
|
69
|
+
|
|
70
|
+
default:
|
|
71
|
+
throw new Error(ShieldSecurityAdapterError.Unhandled);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Stryker restore all
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return next();
|
|
79
|
+
});
|
|
80
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type * as tools from "@bgord/tools";
|
|
2
|
+
import { createMiddleware } from "hono/factory";
|
|
3
|
+
import { HTTPException } from "hono/http-exception";
|
|
4
|
+
import { timeout } from "hono/timeout";
|
|
5
|
+
import type { ShieldStrategy } from "./shield.strategy";
|
|
6
|
+
|
|
7
|
+
export const ShieldTimeoutError = new HTTPException(408, { message: "shield.timeout" });
|
|
8
|
+
|
|
9
|
+
type ShieldTimeoutConfigType = { duration: tools.Duration };
|
|
10
|
+
|
|
11
|
+
export class ShieldTimeoutStrategy implements ShieldStrategy {
|
|
12
|
+
private readonly timeout;
|
|
13
|
+
|
|
14
|
+
constructor(config: ShieldTimeoutConfigType) {
|
|
15
|
+
this.timeout = timeout(config.duration.ms, ShieldTimeoutError);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
verify = createMiddleware(async (context, next) => this.timeout(context, next));
|
|
19
|
+
}
|