@groundbrick/express-adapter 0.2.1 → 0.2.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/README.md +51 -0
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/cookies/index.js +18 -2
- package/dist/cookies/index.js.map +1 -1
- package/dist/core/ExpressApp.d.ts.map +1 -1
- package/dist/core/ExpressApp.js +8 -0
- package/dist/core/ExpressApp.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/instrument.d.ts +2 -0
- package/dist/instrument.d.ts.map +1 -0
- package/dist/instrument.js +38 -0
- package/dist/instrument.js.map +1 -0
- package/dist/middleware/InMemoryRateLimiter.d.ts +39 -0
- package/dist/middleware/InMemoryRateLimiter.d.ts.map +1 -0
- package/dist/middleware/InMemoryRateLimiter.js +41 -0
- package/dist/middleware/InMemoryRateLimiter.js.map +1 -0
- package/dist/middleware/RateLimitMiddleware.d.ts +32 -0
- package/dist/middleware/RateLimitMiddleware.d.ts.map +1 -0
- package/dist/middleware/RateLimitMiddleware.js +31 -0
- package/dist/middleware/RateLimitMiddleware.js.map +1 -0
- package/dist/middleware/TurnstileMiddleware.d.ts +25 -0
- package/dist/middleware/TurnstileMiddleware.d.ts.map +1 -0
- package/dist/middleware/TurnstileMiddleware.js +87 -0
- package/dist/middleware/TurnstileMiddleware.js.map +1 -0
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ Express.js integration adapter para o microframework TypeScript com middleware e
|
|
|
11
11
|
- **📊 Response Helpers** - Formatação padronizada de respostas da API
|
|
12
12
|
- **✅ Validation Utilities** - Helpers de validação e sanitização
|
|
13
13
|
- **📄 Pagination Support** - Utilitários de paginação e ordenação
|
|
14
|
+
- **📡 Sentry (Error Tracking + APM)** - Observabilidade opt-in, ativada por variáveis de ambiente
|
|
14
15
|
|
|
15
16
|
## Instalação
|
|
16
17
|
|
|
@@ -369,6 +370,53 @@ A classe `ExpressApp` configura automaticamente:
|
|
|
369
370
|
- **Request Logging**: Log automático de requests com timing
|
|
370
371
|
- **Response Formatting**: Formatação padronizada de respostas
|
|
371
372
|
- **Error Handling**: Tratamento global de erros
|
|
373
|
+
- **Sentry**: Error handler do Sentry (quando ativado por `SENTRY_DSN`), antes do handler global
|
|
374
|
+
|
|
375
|
+
## Sentry (Error Tracking + APM)
|
|
376
|
+
|
|
377
|
+
O adapter integra o [Sentry Node SDK](https://docs.sentry.io/platforms/javascript/guides/node/)
|
|
378
|
+
como uma capacidade **opt-in**, ativada simplesmente pela presença da variável `SENTRY_DSN`.
|
|
379
|
+
Cobre captura de erros, tracing (HTTP, Express e PostgreSQL `pg`) e profiling de CPU, dando
|
|
380
|
+
visibilidade sobre erros e gargalos de performance (endpoints e queries lentas). Se `SENTRY_DSN`
|
|
381
|
+
não estiver definida, é um no-op completo (apps sem DSN e testes não são afetados).
|
|
382
|
+
|
|
383
|
+
### Como funciona
|
|
384
|
+
|
|
385
|
+
Em ESM, o `Sentry.init()` tem de correr **antes** de qualquer módulo instrumentado (`http`,
|
|
386
|
+
`express`, `pg`) ser carregado. Por isso o package expõe um módulo side-effecting que deve ser
|
|
387
|
+
pré-carregado via a flag `--import` do Node, e o `ExpressApp` regista automaticamente o error
|
|
388
|
+
handler do Sentry (antes do error handler global) quando o SDK foi inicializado.
|
|
389
|
+
|
|
390
|
+
### Ativação
|
|
391
|
+
|
|
392
|
+
1. Pré-carregar o módulo de instrumentação nos scripts do app:
|
|
393
|
+
|
|
394
|
+
```jsonc
|
|
395
|
+
// package.json do app
|
|
396
|
+
{
|
|
397
|
+
"scripts": {
|
|
398
|
+
"dev": "tsx watch --import @groundbrick/express-adapter/instrument src/server.ts",
|
|
399
|
+
"start": "node --import @groundbrick/express-adapter/instrument dist/src/server.js"
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
2. Definir as variáveis de ambiente (DSN vazio = Sentry desativado):
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
# Sentry (error tracking + APM). SENTRY_DSN vazio = desativado.
|
|
408
|
+
SENTRY_DSN=https://<key>@<org>.ingest.sentry.io/<project>
|
|
409
|
+
SENTRY_ENVIRONMENT=development
|
|
410
|
+
# Tracing: % de transações capturadas (1.0 = 100%). Baixar em produção (ex.: 0.1).
|
|
411
|
+
SENTRY_TRACES_SAMPLE_RATE=1.0
|
|
412
|
+
# Profiling: % das transações amostradas que também são profiled.
|
|
413
|
+
SENTRY_PROFILES_SAMPLE_RATE=1.0
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
Não é preciso código no `server.ts`: o error handler do Sentry é montado pelo `ExpressApp`
|
|
417
|
+
(depois das rotas, antes do error handler global), pelo que as respostas de erro continuam a sair
|
|
418
|
+
no formato padrão `{ success: false, error: { ... } }`. Em testes (sem o preload `--import`) o
|
|
419
|
+
Sentry nunca inicializa, logo a integração fica inerte.
|
|
372
420
|
|
|
373
421
|
## Exemplo Completo com Autenticação
|
|
374
422
|
|
|
@@ -435,6 +483,9 @@ Este adapter funciona perfeitamente com:
|
|
|
435
483
|
- `@groundbrick/logger` - Logging functionality
|
|
436
484
|
- `@groundbrick/service-base` - Service base classes
|
|
437
485
|
- `@groundbrick/db-core` - Database core abstractions
|
|
486
|
+
- `@sentry/node` - Error tracking + APM (Sentry Node SDK)
|
|
487
|
+
- `@sentry/profiling-node` - CPU profiling integration para o Sentry
|
|
488
|
+
- `dotenv` - Carrega `.env` no preload de instrumentação do Sentry
|
|
438
489
|
|
|
439
490
|
### Peer Dependencies
|
|
440
491
|
- `express` - Express.js framework
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cookies/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAMvD,MAAM,WAAW,gBAAgB;IAC7B,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,YAAY,EAAE,OAAO,CAAC;IACtB,wCAAwC;IACxC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IACrC,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cookies/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAMvD,MAAM,WAAW,gBAAgB;IAC7B,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,YAAY,EAAE,OAAO,CAAC;IACtB,wCAAwC;IACxC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IACrC,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,GAAG,aAAa,CAsC/E;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC;IAI7E;;OAEG;aACM,QAAQ,SAAS,MAAM,YAAY,MAAM,GAAG,IAAI;IAQzD;;;OAGG;eACQ,QAAQ,GAAG,IAAI;IAK1B;;OAEG;0BACmB,MAAM,GAAG,aAAa;EAOnD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,GAAE,MAAc,GAAG,MAAM,CAWpE;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,GAAE,MAAc,GAAG,MAAM,CAE3E"}
|
package/dist/cookies/index.js
CHANGED
|
@@ -6,8 +6,24 @@
|
|
|
6
6
|
* These options MUST be consistent between set and clear operations.
|
|
7
7
|
*/
|
|
8
8
|
export function createAuthCookieOptions(config) {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
let secure = config.secure ?? config.isProduction;
|
|
10
|
+
let sameSite = config.sameSite ?? (config.isProduction ? 'strict' : 'lax');
|
|
11
|
+
// Production hardening: even if env vars try to lower security, force secure
|
|
12
|
+
// cookie flags. This prevents accidental misconfiguration (e.g. an operator
|
|
13
|
+
// setting AUTH_COOKIE_SECURE=false to debug something and forgetting to revert)
|
|
14
|
+
// from shipping an insecure cookie in production.
|
|
15
|
+
if (config.isProduction) {
|
|
16
|
+
if (secure !== true) {
|
|
17
|
+
throw new Error('Refusing to issue auth cookie with secure=false in production. ' +
|
|
18
|
+
'Unset AUTH_COOKIE_SECURE or set it to true.');
|
|
19
|
+
}
|
|
20
|
+
if (sameSite !== 'strict' && sameSite !== 'lax') {
|
|
21
|
+
// sameSite='none' would require secure (already enforced) but is too
|
|
22
|
+
// permissive for auth cookies; force strict.
|
|
23
|
+
throw new Error(`Refusing to issue auth cookie with sameSite="${sameSite}" in production. ` +
|
|
24
|
+
'Unset AUTH_COOKIE_SAMESITE or set it to "strict" (recommended) or "lax".');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
11
27
|
const options = {
|
|
12
28
|
path: '/',
|
|
13
29
|
domain: config.domain,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cookies/index.ts"],"names":[],"mappings":"AAmBA,+EAA+E;AAC/E,mBAAmB;AACnB,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAwB;IAC5D,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cookies/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpressApp.d.ts","sourceRoot":"","sources":["../../src/core/ExpressApp.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"ExpressApp.d.ts","sourceRoot":"","sources":["../../src/core/ExpressApp.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAQ9D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAK3D,qBAAa,UAAU;IACnB,OAAO,CAAC,GAAG,CAAU;IACrB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,aAAa,CAAgB;gBAEzB,MAAM,GAAE,aAAkB;IAqCtC,OAAO,CAAC,eAAe;IA+DvB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,WAAW;IAoBZ,SAAS,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,IAAI;IAS1C,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAItC,MAAM,IAAI,OAAO;IAIjB,kBAAkB,IAAI,IAAI;IA4B1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CA6BhC"}
|
package/dist/core/ExpressApp.js
CHANGED
|
@@ -2,6 +2,7 @@ import express from 'express';
|
|
|
2
2
|
import cors from 'cors';
|
|
3
3
|
import helmet from 'helmet';
|
|
4
4
|
import cookieParser from 'cookie-parser';
|
|
5
|
+
import * as Sentry from '@sentry/node';
|
|
5
6
|
// import rateLimit, { RateLimitRequestHandler } from 'express-rate-limit';
|
|
6
7
|
import { createLogger } from '@groundbrick/logger';
|
|
7
8
|
import { ErrorHandler } from '../middleware/ErrorHandler.js';
|
|
@@ -153,6 +154,13 @@ export class ExpressApp {
|
|
|
153
154
|
}
|
|
154
155
|
});
|
|
155
156
|
});
|
|
157
|
+
// Sentry captures unhandled route exceptions and forwards them (next(err))
|
|
158
|
+
// to the groundbrick ErrorHandler below, which still formats the response.
|
|
159
|
+
// Only attaches when Sentry was initialized (i.e. SENTRY_DSN present, via the
|
|
160
|
+
// @groundbrick/express-adapter/instrument preload). No-op otherwise (and in tests).
|
|
161
|
+
if (Sentry.isInitialized()) {
|
|
162
|
+
Sentry.setupExpressErrorHandler(this.app);
|
|
163
|
+
}
|
|
156
164
|
// Global error handler - must be last
|
|
157
165
|
this.app.use(this.errorHandler.handle);
|
|
158
166
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpressApp.js","sourceRoot":"","sources":["../../src/core/ExpressApp.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ExpressApp.js","sourceRoot":"","sources":["../../src/core/ExpressApp.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,9 @@ export { ErrorHandler } from './middleware/ErrorHandler.js';
|
|
|
4
4
|
export { RequestLogger } from './middleware/RequestLogger.js';
|
|
5
5
|
export { ResponseFormatter } from './middleware/ResponseFormatter.js';
|
|
6
6
|
export { JwtMiddleware } from './middleware/JwtMiddleware.js';
|
|
7
|
+
export { createRateLimitMiddleware, type CreateRateLimitOptions } from './middleware/RateLimitMiddleware.js';
|
|
8
|
+
export { InMemoryRateLimiter, type TrackResult } from './middleware/InMemoryRateLimiter.js';
|
|
9
|
+
export { createTurnstileMiddleware, type CreateTurnstileOptions } from './middleware/TurnstileMiddleware.js';
|
|
7
10
|
export type * from './types/index.js';
|
|
8
11
|
export { ResponseHelper, ValidationHelper, PaginationHelper, RequestHelper, SecurityHelper } from './utils/index.js';
|
|
9
12
|
export * from './cookies/index.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,KAAK,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7G,OAAO,EAAE,mBAAmB,EAAE,KAAK,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAC5F,OAAO,EAAE,yBAAyB,EAAE,KAAK,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAG7G,mBAAmB,kBAAkB,CAAC;AAGtC,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACf,MAAM,kBAAkB,CAAC;AAG1B,cAAc,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,9 @@ export { ErrorHandler } from './middleware/ErrorHandler.js';
|
|
|
6
6
|
export { RequestLogger } from './middleware/RequestLogger.js';
|
|
7
7
|
export { ResponseFormatter } from './middleware/ResponseFormatter.js';
|
|
8
8
|
export { JwtMiddleware } from './middleware/JwtMiddleware.js';
|
|
9
|
+
export { createRateLimitMiddleware } from './middleware/RateLimitMiddleware.js';
|
|
10
|
+
export { InMemoryRateLimiter } from './middleware/InMemoryRateLimiter.js';
|
|
11
|
+
export { createTurnstileMiddleware } from './middleware/TurnstileMiddleware.js';
|
|
9
12
|
// Utility helpers
|
|
10
13
|
export { ResponseHelper, ValidationHelper, PaginationHelper, RequestHelper, SecurityHelper } from './utils/index.js';
|
|
11
14
|
// Cookie utilities
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,eAAe;AACf,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,aAAa;AACb,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,eAAe;AACf,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,aAAa;AACb,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAA+B,MAAM,qCAAqC,CAAC;AAC7G,OAAO,EAAE,mBAAmB,EAAoB,MAAM,qCAAqC,CAAC;AAC5F,OAAO,EAAE,yBAAyB,EAA+B,MAAM,qCAAqC,CAAC;AAK7G,kBAAkB;AAClB,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACf,MAAM,kBAAkB,CAAC;AAE1B,mBAAmB;AACnB,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrument.d.ts","sourceRoot":"","sources":["../src/instrument.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Sentry instrumentation entry point.
|
|
2
|
+
//
|
|
3
|
+
// This module is side-effecting: importing it initializes the Sentry Node SDK.
|
|
4
|
+
// It MUST be preloaded before any application code so that the SDK can patch
|
|
5
|
+
// `http`, `express` and `pg` for tracing. In ESM that means referencing it via
|
|
6
|
+
// Node's `--import` flag, e.g.:
|
|
7
|
+
//
|
|
8
|
+
// node --import @groundbrick/express-adapter/instrument dist/src/server.js
|
|
9
|
+
//
|
|
10
|
+
// Activation is opt-in and env-driven: if `SENTRY_DSN` is not set, this is a
|
|
11
|
+
// complete no-op, so apps (and tests) that don't configure Sentry are unaffected.
|
|
12
|
+
import * as dotenv from 'dotenv';
|
|
13
|
+
// The preload runs before the app loads its own config, so the .env file has not
|
|
14
|
+
// been read yet. Load it here so SENTRY_* variables are available.
|
|
15
|
+
dotenv.config();
|
|
16
|
+
import * as Sentry from '@sentry/node';
|
|
17
|
+
import { nodeProfilingIntegration } from '@sentry/profiling-node';
|
|
18
|
+
const dsn = process.env.SENTRY_DSN;
|
|
19
|
+
if (dsn) {
|
|
20
|
+
const environment = process.env.SENTRY_ENVIRONMENT || process.env.NODE_ENV || 'development';
|
|
21
|
+
Sentry.init({
|
|
22
|
+
dsn,
|
|
23
|
+
environment,
|
|
24
|
+
// Send structured logs to Sentry.
|
|
25
|
+
enableLogs: true,
|
|
26
|
+
// CPU profiling (function-level) to surface performance bottlenecks.
|
|
27
|
+
integrations: [nodeProfilingIntegration()],
|
|
28
|
+
// Tracing: percentage of transactions captured. 1.0 = 100% (ideal for
|
|
29
|
+
// diagnosis/trial). Lower in production via the env var below.
|
|
30
|
+
tracesSampleRate: Number(process.env.SENTRY_TRACES_SAMPLE_RATE ?? '1.0'),
|
|
31
|
+
// Profiling: percentage of already-sampled transactions that are also profiled.
|
|
32
|
+
profilesSampleRate: Number(process.env.SENTRY_PROFILES_SAMPLE_RATE ?? '1.0'),
|
|
33
|
+
});
|
|
34
|
+
// Runs before the app logger is configured, so a plain console line is the right
|
|
35
|
+
// tool here. Confirms at boot that error tracking + APM are active.
|
|
36
|
+
console.log(`[sentry] initialized (environment=${environment})`);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=instrument.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrument.js","sourceRoot":"","sources":["../src/instrument.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,EAAE;AACF,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAC/E,gCAAgC;AAChC,EAAE;AACF,6EAA6E;AAC7E,EAAE;AACF,6EAA6E;AAC7E,kFAAkF;AAClF,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,iFAAiF;AACjF,mEAAmE;AACnE,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAElE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;AAEnC,IAAI,GAAG,EAAE,CAAC;IACR,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAC;IAE5F,MAAM,CAAC,IAAI,CAAC;QACV,GAAG;QACH,WAAW;QACX,kCAAkC;QAClC,UAAU,EAAE,IAAI;QAChB,qEAAqE;QACrE,YAAY,EAAE,CAAC,wBAAwB,EAAE,CAAC;QAC1C,sEAAsE;QACtE,+DAA+D;QAC/D,gBAAgB,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,KAAK,CAAC;QACxE,gFAAgF;QAChF,kBAAkB,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,KAAK,CAAC;KAC7E,CAAC,CAAC;IAEH,iFAAiF;IACjF,oEAAoE;IACpE,OAAO,CAAC,GAAG,CAAC,qCAAqC,WAAW,GAAG,CAAC,CAAC;AACnE,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-local rate limiter for use INSIDE services (not as Express middleware).
|
|
3
|
+
*
|
|
4
|
+
* Use case: throttling notifications, internal job dispatch, or any side-effect that
|
|
5
|
+
* isn't a public endpoint and so doesn't fit an HTTP rate-limit middleware. The
|
|
6
|
+
* service calls `.track(key, max, windowMs)` before performing the action and only
|
|
7
|
+
* proceeds if `allowed` is true.
|
|
8
|
+
*
|
|
9
|
+
* Caveats:
|
|
10
|
+
* - Process-local. Multiple Node workers each have their own counters; the global
|
|
11
|
+
* rate equals N × max where N is the number of replicas. Acceptable as a first
|
|
12
|
+
* pass; swap for Redis-backed if scaling horizontally.
|
|
13
|
+
* - No persistence. Counters reset on restart.
|
|
14
|
+
* - Uses sliding window (oldest entries are pruned lazily on each `.track` call).
|
|
15
|
+
*/
|
|
16
|
+
export interface TrackResult {
|
|
17
|
+
/** Whether the action is allowed to proceed. */
|
|
18
|
+
allowed: boolean;
|
|
19
|
+
/** Remaining attempts in the current window. */
|
|
20
|
+
remaining: number;
|
|
21
|
+
/** Timestamp (ms epoch) when the oldest attempt in the window will fall out. */
|
|
22
|
+
resetAt: number;
|
|
23
|
+
}
|
|
24
|
+
export declare class InMemoryRateLimiter {
|
|
25
|
+
private buckets;
|
|
26
|
+
/**
|
|
27
|
+
* Record an attempt for `key` and tell the caller whether it is allowed.
|
|
28
|
+
*
|
|
29
|
+
* Sliding-window algorithm: keep timestamps of the last `max` attempts that
|
|
30
|
+
* are still inside `[now - windowMs, now]`. If we already have `max` such
|
|
31
|
+
* attempts, deny; otherwise add the current timestamp and allow.
|
|
32
|
+
*/
|
|
33
|
+
track(key: string, max: number, windowMs: number): TrackResult;
|
|
34
|
+
/** Manually drop a key's history. Used after a successful login resets brute-force tracking. */
|
|
35
|
+
reset(key: string): void;
|
|
36
|
+
/** Snapshot for tests/observability. */
|
|
37
|
+
size(): number;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=InMemoryRateLimiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InMemoryRateLimiter.d.ts","sourceRoot":"","sources":["../../src/middleware/InMemoryRateLimiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,WAAW;IACxB,gDAAgD;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,mBAAmB;IAC5B,OAAO,CAAC,OAAO,CAA+B;IAE9C;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW;IAyB9D,gGAAgG;IAChG,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIxB,wCAAwC;IACxC,IAAI,IAAI,MAAM;CAGjB"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export class InMemoryRateLimiter {
|
|
2
|
+
buckets = new Map();
|
|
3
|
+
/**
|
|
4
|
+
* Record an attempt for `key` and tell the caller whether it is allowed.
|
|
5
|
+
*
|
|
6
|
+
* Sliding-window algorithm: keep timestamps of the last `max` attempts that
|
|
7
|
+
* are still inside `[now - windowMs, now]`. If we already have `max` such
|
|
8
|
+
* attempts, deny; otherwise add the current timestamp and allow.
|
|
9
|
+
*/
|
|
10
|
+
track(key, max, windowMs) {
|
|
11
|
+
const now = Date.now();
|
|
12
|
+
const cutoff = now - windowMs;
|
|
13
|
+
const entries = (this.buckets.get(key) ?? []).filter((ts) => ts > cutoff);
|
|
14
|
+
if (entries.length >= max) {
|
|
15
|
+
// Don't append the rejected attempt — otherwise a tight loop would push
|
|
16
|
+
// resetAt forever forwards. We only count actual passes.
|
|
17
|
+
this.buckets.set(key, entries);
|
|
18
|
+
return {
|
|
19
|
+
allowed: false,
|
|
20
|
+
remaining: 0,
|
|
21
|
+
resetAt: entries[0] + windowMs
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
entries.push(now);
|
|
25
|
+
this.buckets.set(key, entries);
|
|
26
|
+
return {
|
|
27
|
+
allowed: true,
|
|
28
|
+
remaining: max - entries.length,
|
|
29
|
+
resetAt: entries[0] + windowMs
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** Manually drop a key's history. Used after a successful login resets brute-force tracking. */
|
|
33
|
+
reset(key) {
|
|
34
|
+
this.buckets.delete(key);
|
|
35
|
+
}
|
|
36
|
+
/** Snapshot for tests/observability. */
|
|
37
|
+
size() {
|
|
38
|
+
return this.buckets.size;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=InMemoryRateLimiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InMemoryRateLimiter.js","sourceRoot":"","sources":["../../src/middleware/InMemoryRateLimiter.ts"],"names":[],"mappings":"AAwBA,MAAM,OAAO,mBAAmB;IACpB,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE9C;;;;;;OAMG;IACH,KAAK,CAAC,GAAW,EAAE,GAAW,EAAE,QAAgB;QAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,GAAG,GAAG,QAAQ,CAAC;QAC9B,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC;QAE1E,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;YACxB,wEAAwE;YACxE,yDAAyD;YACzD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YAC/B,OAAO;gBACH,OAAO,EAAE,KAAK;gBACd,SAAS,EAAE,CAAC;gBACZ,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ;aACjC,CAAC;QACN,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC/B,OAAO;YACH,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM;YAC/B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ;SACjC,CAAC;IACN,CAAC;IAED,gGAAgG;IAChG,KAAK,CAAC,GAAW;QACb,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,wCAAwC;IACxC,IAAI;QACA,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC7B,CAAC;CACJ"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction, RequestHandler } from 'express';
|
|
2
|
+
import { type Options as ExpressRateLimitOptions } from 'express-rate-limit';
|
|
3
|
+
export interface CreateRateLimitOptions {
|
|
4
|
+
/** Time window in milliseconds. */
|
|
5
|
+
windowMs: number;
|
|
6
|
+
/** Maximum number of requests allowed within the window. */
|
|
7
|
+
max: number;
|
|
8
|
+
/** Build the rate-limit key from the request. Default: client IP. */
|
|
9
|
+
keyGenerator?: (req: Request) => string;
|
|
10
|
+
/** Skip counting on successful (status < 400) responses. Useful for /login so legit users don't burn their budget. */
|
|
11
|
+
skipSuccessfulRequests?: boolean;
|
|
12
|
+
/** Override the handler called when the limit is exceeded. Default: 429 JSON. */
|
|
13
|
+
handler?: (req: Request, res: Response, next: NextFunction, options: ExpressRateLimitOptions) => void;
|
|
14
|
+
/** Optional message returned in the default 429 body. */
|
|
15
|
+
message?: string;
|
|
16
|
+
/** Standard RateLimit-* headers (RFC). Default: true. */
|
|
17
|
+
standardHeaders?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Build an Express rate-limit middleware with sane defaults for AgendaPet-style APIs.
|
|
21
|
+
*
|
|
22
|
+
* Defaults:
|
|
23
|
+
* standardHeaders: true (modern RateLimit-* headers)
|
|
24
|
+
* legacyHeaders: false (no X-RateLimit-*)
|
|
25
|
+
* keyGenerator: req.ip (uses Express's trust-proxy chain)
|
|
26
|
+
*
|
|
27
|
+
* Store: in-memory (process-local). Each Node worker has its own counters; not safe
|
|
28
|
+
* across horizontally-scaled replicas. For multi-instance deployments inject a shared
|
|
29
|
+
* store (e.g. rate-limit-redis) via the underlying express-rate-limit API.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createRateLimitMiddleware(options: CreateRateLimitOptions): RequestHandler;
|
|
32
|
+
//# sourceMappingURL=RateLimitMiddleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimitMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware/RateLimitMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC/E,OAAkB,EAAE,KAAK,OAAO,IAAI,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAExF,MAAM,WAAW,sBAAsB;IACnC,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;IACxC,sHAAsH;IACtH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,iFAAiF;IACjF,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAC;IACtG,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,sBAAsB,GAAG,cAAc,CAgBzF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import rateLimit from 'express-rate-limit';
|
|
2
|
+
/**
|
|
3
|
+
* Build an Express rate-limit middleware with sane defaults for AgendaPet-style APIs.
|
|
4
|
+
*
|
|
5
|
+
* Defaults:
|
|
6
|
+
* standardHeaders: true (modern RateLimit-* headers)
|
|
7
|
+
* legacyHeaders: false (no X-RateLimit-*)
|
|
8
|
+
* keyGenerator: req.ip (uses Express's trust-proxy chain)
|
|
9
|
+
*
|
|
10
|
+
* Store: in-memory (process-local). Each Node worker has its own counters; not safe
|
|
11
|
+
* across horizontally-scaled replicas. For multi-instance deployments inject a shared
|
|
12
|
+
* store (e.g. rate-limit-redis) via the underlying express-rate-limit API.
|
|
13
|
+
*/
|
|
14
|
+
export function createRateLimitMiddleware(options) {
|
|
15
|
+
return rateLimit({
|
|
16
|
+
windowMs: options.windowMs,
|
|
17
|
+
max: options.max,
|
|
18
|
+
standardHeaders: options.standardHeaders ?? true,
|
|
19
|
+
legacyHeaders: false,
|
|
20
|
+
keyGenerator: options.keyGenerator ?? ((req) => req.ip ?? 'unknown'),
|
|
21
|
+
skipSuccessfulRequests: options.skipSuccessfulRequests ?? false,
|
|
22
|
+
handler: options.handler ?? ((req, res) => {
|
|
23
|
+
res.status(429).json({
|
|
24
|
+
success: false,
|
|
25
|
+
message: options.message ?? 'Demasiados pedidos. Aguarde alguns minutos.',
|
|
26
|
+
code: 'RATE_LIMITED'
|
|
27
|
+
});
|
|
28
|
+
})
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=RateLimitMiddleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimitMiddleware.js","sourceRoot":"","sources":["../../src/middleware/RateLimitMiddleware.ts"],"names":[],"mappings":"AACA,OAAO,SAAsD,MAAM,oBAAoB,CAAC;AAmBxF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAA+B;IACrE,OAAO,SAAS,CAAC;QACb,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,eAAe,EAAE,OAAO,CAAC,eAAe,IAAI,IAAI;QAChD,aAAa,EAAE,KAAK;QACpB,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,SAAS,CAAC;QAC7E,sBAAsB,EAAE,OAAO,CAAC,sBAAsB,IAAI,KAAK;QAC/D,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACtC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACjB,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,6CAA6C;gBACzE,IAAI,EAAE,cAAc;aACvB,CAAC,CAAC;QACP,CAAC,CAAC;KACL,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { RequestHandler } from 'express';
|
|
2
|
+
export interface CreateTurnstileOptions {
|
|
3
|
+
/** Cloudflare Turnstile secret key. If missing or empty, middleware short-circuits to next() (no-op). */
|
|
4
|
+
secretKey: string | undefined;
|
|
5
|
+
/** Body field where the client puts the Turnstile token. Default: 'turnstile_token'. */
|
|
6
|
+
tokenField?: string;
|
|
7
|
+
/** Verify endpoint (override for testing). */
|
|
8
|
+
verifyUrl?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Express middleware that validates a Cloudflare Turnstile token submitted with the
|
|
12
|
+
* request body. On valid token: next(). On missing or invalid token: 400.
|
|
13
|
+
*
|
|
14
|
+
* Designed to be safe when not yet configured: if secretKey is undefined or empty,
|
|
15
|
+
* the middleware is a no-op (next()). This lets the same code run in dev/staging
|
|
16
|
+
* without Cloudflare credentials, and lets ops flip Turnstile on in production by
|
|
17
|
+
* just setting the env var.
|
|
18
|
+
*
|
|
19
|
+
* The IP of the caller is forwarded to Cloudflare so they can apply geographic /
|
|
20
|
+
* behavioural rules. We use req.ip which respects Express's trust-proxy setting.
|
|
21
|
+
*
|
|
22
|
+
* Docs: https://developers.cloudflare.com/turnstile/get-started/server-side-validation/
|
|
23
|
+
*/
|
|
24
|
+
export declare function createTurnstileMiddleware(options: CreateTurnstileOptions): RequestHandler;
|
|
25
|
+
//# sourceMappingURL=TurnstileMiddleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TurnstileMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware/TurnstileMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmC,cAAc,EAAE,MAAM,SAAS,CAAC;AAE/E,MAAM,WAAW,sBAAsB;IACnC,yGAAyG;IACzG,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,sBAAsB,GAAG,cAAc,CAkFzF"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express middleware that validates a Cloudflare Turnstile token submitted with the
|
|
3
|
+
* request body. On valid token: next(). On missing or invalid token: 400.
|
|
4
|
+
*
|
|
5
|
+
* Designed to be safe when not yet configured: if secretKey is undefined or empty,
|
|
6
|
+
* the middleware is a no-op (next()). This lets the same code run in dev/staging
|
|
7
|
+
* without Cloudflare credentials, and lets ops flip Turnstile on in production by
|
|
8
|
+
* just setting the env var.
|
|
9
|
+
*
|
|
10
|
+
* The IP of the caller is forwarded to Cloudflare so they can apply geographic /
|
|
11
|
+
* behavioural rules. We use req.ip which respects Express's trust-proxy setting.
|
|
12
|
+
*
|
|
13
|
+
* Docs: https://developers.cloudflare.com/turnstile/get-started/server-side-validation/
|
|
14
|
+
*/
|
|
15
|
+
export function createTurnstileMiddleware(options) {
|
|
16
|
+
const verifyUrl = options.verifyUrl ?? 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
|
|
17
|
+
const tokenField = options.tokenField ?? 'turnstile_token';
|
|
18
|
+
return async (req, res, next) => {
|
|
19
|
+
const secret = options.secretKey;
|
|
20
|
+
if (!secret) {
|
|
21
|
+
// Not configured — skip silently. Safe default for dev/staging.
|
|
22
|
+
return next();
|
|
23
|
+
}
|
|
24
|
+
const token = req.body?.[tokenField];
|
|
25
|
+
if (!token || typeof token !== 'string') {
|
|
26
|
+
// Most common production cause: the frontend never sent a token, usually
|
|
27
|
+
// because the matching PUBLIC site key is not configured on the client.
|
|
28
|
+
console.warn('[turnstile] request blocked: token missing', {
|
|
29
|
+
path: req.path,
|
|
30
|
+
ip: req.ip,
|
|
31
|
+
tokenField,
|
|
32
|
+
tokenType: typeof token
|
|
33
|
+
});
|
|
34
|
+
res.status(400).json({
|
|
35
|
+
success: false,
|
|
36
|
+
code: 'CAPTCHA_REQUIRED',
|
|
37
|
+
message: 'Validação anti-bot em falta.'
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const params = new URLSearchParams();
|
|
43
|
+
params.set('secret', secret);
|
|
44
|
+
params.set('response', token);
|
|
45
|
+
if (req.ip) {
|
|
46
|
+
params.set('remoteip', req.ip);
|
|
47
|
+
}
|
|
48
|
+
const response = await fetch(verifyUrl, {
|
|
49
|
+
method: 'POST',
|
|
50
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
51
|
+
body: params
|
|
52
|
+
});
|
|
53
|
+
const result = (await response.json());
|
|
54
|
+
if (!result.success) {
|
|
55
|
+
// Log the full Cloudflare verdict so misconfigurations are diagnosable
|
|
56
|
+
// from the backend logs. Common error-codes:
|
|
57
|
+
// invalid-input-secret -> wrong/missing TURNSTILE_SECRET_KEY
|
|
58
|
+
// invalid-input-response-> token bad, expired or already used
|
|
59
|
+
// timeout-or-duplicate -> token replayed
|
|
60
|
+
// A hostname that doesn't match the deployed domain means the site key
|
|
61
|
+
// belongs to a Turnstile widget configured for a different domain.
|
|
62
|
+
console.warn('[turnstile] verification rejected by Cloudflare', {
|
|
63
|
+
path: req.path,
|
|
64
|
+
ip: req.ip,
|
|
65
|
+
errorCodes: result['error-codes'] ?? [],
|
|
66
|
+
hostname: result.hostname,
|
|
67
|
+
action: result.action
|
|
68
|
+
});
|
|
69
|
+
res.status(400).json({
|
|
70
|
+
success: false,
|
|
71
|
+
code: 'CAPTCHA_INVALID',
|
|
72
|
+
message: 'Validação anti-bot falhou. Tente novamente.'
|
|
73
|
+
});
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
return next();
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
// Don't block legit users if Cloudflare is unreachable. Log and pass through;
|
|
80
|
+
// the deeper rate-limit and honeypot defences still apply.
|
|
81
|
+
// Caller can adjust to fail-closed in higher-risk endpoints.
|
|
82
|
+
console.error('[turnstile] verify call failed, falling through to allow:', error);
|
|
83
|
+
return next();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=TurnstileMiddleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TurnstileMiddleware.js","sourceRoot":"","sources":["../../src/middleware/TurnstileMiddleware.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@groundbrick/express-adapter",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Express.js integration adapter with middleware, controllers, and error handling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
"import": "./dist/index.js",
|
|
11
11
|
"require": "./dist/index.js",
|
|
12
12
|
"types": "./dist/index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./instrument": {
|
|
15
|
+
"import": "./dist/instrument.js",
|
|
16
|
+
"types": "./dist/instrument.d.ts"
|
|
13
17
|
}
|
|
14
18
|
},
|
|
15
19
|
"files": [
|
|
@@ -45,7 +49,10 @@
|
|
|
45
49
|
"@groundbrick/db-core": "^0.2.0",
|
|
46
50
|
"@groundbrick/logger": "^0.4.0",
|
|
47
51
|
"@groundbrick/service-base": "^0.2.0",
|
|
48
|
-
"@
|
|
52
|
+
"@sentry/node": "^10.58.0",
|
|
53
|
+
"@sentry/profiling-node": "^10.58.0",
|
|
54
|
+
"@types/ms": "^2.1.0",
|
|
55
|
+
"dotenv": "^16.6.1"
|
|
49
56
|
},
|
|
50
57
|
"peerDependencies": {
|
|
51
58
|
"compression": "^1.7.4",
|