@adaptic/backend-legacy 0.0.996 → 0.0.998
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/esm/auth/authorization-map.d.ts +77 -0
- package/esm/auth/authorization-map.d.ts.map +1 -0
- package/esm/auth/authorization-map.js.map +1 -0
- package/esm/auth/authorization-map.mjs +132 -0
- package/esm/auth/cortex-auth-checker.d.ts +114 -0
- package/esm/auth/cortex-auth-checker.d.ts.map +1 -0
- package/esm/auth/cortex-auth-checker.js.map +1 -0
- package/esm/auth/cortex-auth-checker.mjs +163 -0
- package/esm/middleware/__tests__/rate-limit-test-utils.d.ts +60 -0
- package/esm/middleware/__tests__/rate-limit-test-utils.d.ts.map +1 -0
- package/esm/middleware/__tests__/rate-limit-test-utils.js.map +1 -0
- package/esm/middleware/__tests__/rate-limit-test-utils.mjs +85 -0
- package/esm/middleware/rate-limiter.d.ts +81 -4
- package/esm/middleware/rate-limiter.d.ts.map +1 -1
- package/esm/middleware/rate-limiter.js.map +1 -1
- package/esm/middleware/rate-limiter.mjs +154 -48
- package/esm/middleware/rate-tier.d.ts +56 -0
- package/esm/middleware/rate-tier.d.ts.map +1 -0
- package/esm/middleware/rate-tier.js.map +1 -0
- package/esm/middleware/rate-tier.mjs +103 -0
- package/package.json +1 -1
- package/server.cjs +61 -1
package/server.cjs
CHANGED
|
@@ -59,8 +59,11 @@ const body_parser_1 = __importDefault(require("body-parser"));
|
|
|
59
59
|
const ws_1 = require("ws");
|
|
60
60
|
const ws_2 = require("graphql-ws/lib/use/ws");
|
|
61
61
|
const auth_1 = require("./middleware/auth.cjs");
|
|
62
|
+
const rate_limiter_1 = require("./middleware/rate-limiter.cjs");
|
|
62
63
|
const audit_logger_1 = require("./middleware/audit-logger.cjs");
|
|
63
64
|
const tenancy_scoping_1 = require("./middleware/tenancy-scoping.cjs");
|
|
65
|
+
const cortex_auth_checker_1 = require("./auth/cortex-auth-checker.cjs");
|
|
66
|
+
const authorization_map_1 = require("./auth/authorization-map.cjs");
|
|
64
67
|
const http_status_mapper_1 = require("./plugins/http-status-mapper.cjs");
|
|
65
68
|
const graphql_validation_plugin_1 = require("./middleware/graphql-validation-plugin.cjs");
|
|
66
69
|
const query_complexity_1 = require("./middleware/query-complexity.cjs");
|
|
@@ -100,7 +103,15 @@ function principalToUser(principal) {
|
|
|
100
103
|
};
|
|
101
104
|
}
|
|
102
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Default number of proxy hops trusted for X-Forwarded-For resolution when
|
|
108
|
+
* `TRUST_PROXY` is unset. One hop matches a single fronting LB/ingress proxy;
|
|
109
|
+
* operators must set `TRUST_PROXY` to the exact hop count of their deployment
|
|
110
|
+
* (audit B01-backend-legacy-02 / -12).
|
|
111
|
+
*/
|
|
112
|
+
const DEFAULT_TRUST_PROXY_HOPS = 1;
|
|
103
113
|
const startServer = async () => {
|
|
114
|
+
var _a;
|
|
104
115
|
// Boot-time invariant: in production, `GOOGLE_OAUTH_CLIENT_IDS` must be set.
|
|
105
116
|
// Without it, no Google ID token can be safely verified — and the verifier
|
|
106
117
|
// would surface a per-request `misconfigured` error indefinitely. Refuse to
|
|
@@ -110,6 +121,21 @@ const startServer = async () => {
|
|
|
110
121
|
// is on (defaults on in production/staging). Registers default Node.js metrics
|
|
111
122
|
// and starts the uptime gauge ticker. See: src/config/metrics.ts.
|
|
112
123
|
(0, metrics_1.initMetrics)();
|
|
124
|
+
// CORTEX-P0-001 phase 2 (audit B01-backend-legacy-03): decorate generated
|
|
125
|
+
// CRUD resolvers with @Authorized() — full coverage on the 5 investor-relations
|
|
126
|
+
// models, delete mutations elsewhere — so the authChecker below actually
|
|
127
|
+
// executes. Must run BEFORE buildSchema (decorators land in TypeGraphQL's
|
|
128
|
+
// metadata storage). The checker stays SHADOW-FIRST: would-denies are logged
|
|
129
|
+
// + counted but ALLOWED until CORTEX_AUTHCHECKER_ENFORCE is flipped on.
|
|
130
|
+
// The boot log satisfies audit B01-backend-legacy-07: a zero decorated-action
|
|
131
|
+
// count means the checker is unreachable and its metrics are meaningless.
|
|
132
|
+
const authzSummary = (0, authorization_map_1.applyCortexAuthorizationMap)();
|
|
133
|
+
logger_1.logger.info('[cortex-authz] applied @Authorized coverage (authChecker in shadow unless CORTEX_AUTHCHECKER_ENFORCE)', {
|
|
134
|
+
fullCoverageModels: authzSummary.fullCoverageModels,
|
|
135
|
+
deleteCoverageModels: authzSummary.deleteCoverageModels,
|
|
136
|
+
decoratedActions: authzSummary.decoratedActions,
|
|
137
|
+
skippedActions: authzSummary.skippedActions.length,
|
|
138
|
+
});
|
|
113
139
|
const schema = await (0, type_graphql_1.buildSchema)({
|
|
114
140
|
resolvers: [...typegraphql_prisma_1.resolvers, custom_1.OptionsGreeksHistoryCustomResolver],
|
|
115
141
|
validate: false,
|
|
@@ -118,12 +144,42 @@ const startServer = async () => {
|
|
|
118
144
|
// and unauthenticated callers are bypassed in every mode. Gated by
|
|
119
145
|
// `TENANCY_SCOPING_MODE` (default `shadow`).
|
|
120
146
|
globalMiddlewares: [(0, tenancy_scoping_1.createTenancyScopingMiddleware)()],
|
|
147
|
+
// Resolver-level authorization (CORTEX-P0-001). Invoked for the
|
|
148
|
+
// `@Authorized()`-decorated fields applied by applyCortexAuthorizationMap
|
|
149
|
+
// above. SHADOW-FIRST: while `CORTEX_AUTHCHECKER_ENFORCE` is OFF (default),
|
|
150
|
+
// it observes + counts would-deny operations but always allows —
|
|
151
|
+
// byte-identical live behaviour until enforcement is flipped on.
|
|
152
|
+
authChecker: cortex_auth_checker_1.cortexAuthChecker,
|
|
121
153
|
});
|
|
122
154
|
const app = (0, express_1.default)();
|
|
123
155
|
const httpServer = (0, http_1.createServer)(app);
|
|
156
|
+
// Trust the load-balancer proxy chain so `req.ip` resolves the CLIENT address
|
|
157
|
+
// from X-Forwarded-For instead of the proxy hop (audit B01-backend-legacy-02).
|
|
158
|
+
// Without this, every external caller shares one rate-limit bucket per tier,
|
|
159
|
+
// invalidating the shadow signal and making any future enforce flip an outage
|
|
160
|
+
// switch for the whole /graphql surface. `TRUST_PROXY` accepts a hop count
|
|
161
|
+
// (recommended: the EXACT number of proxy hops, so a spoofed X-Forwarded-For
|
|
162
|
+
// cannot mint arbitrary identifiers — audit B01-backend-legacy-12) or an
|
|
163
|
+
// Express trust-proxy string (CIDR / preset). Defaults to 1 hop.
|
|
164
|
+
const rawTrustProxy = ((_a = process.env.TRUST_PROXY) !== null && _a !== void 0 ? _a : '').trim();
|
|
165
|
+
const trustProxy = rawTrustProxy === ''
|
|
166
|
+
? DEFAULT_TRUST_PROXY_HOPS
|
|
167
|
+
: /^\d+$/.test(rawTrustProxy)
|
|
168
|
+
? parseInt(rawTrustProxy, 10)
|
|
169
|
+
: rawTrustProxy;
|
|
170
|
+
app.set('trust proxy', trustProxy);
|
|
124
171
|
// HTTP request metrics — must be mounted early to capture every request.
|
|
125
172
|
// The middleware is a no-op when metrics are disabled.
|
|
126
173
|
app.use(metrics_1.metricsMiddleware);
|
|
174
|
+
// Rate limiting (CORTEX-P0-001). SHADOW-FIRST: while `CORTEX_RATE_LIMIT_ENFORCE`
|
|
175
|
+
// is OFF (default), the limiters observe + count requests that WOULD be blocked
|
|
176
|
+
// but never touch the response, so live behaviour is byte-identical. The
|
|
177
|
+
// GraphQL limiter is mounted INSIDE the /graphql chain after cors() (see below)
|
|
178
|
+
// so an enforce-mode 429 carries CORS headers and browser clients can read the
|
|
179
|
+
// Retry-After instead of seeing an opaque CORS failure
|
|
180
|
+
// (audit B01-backend-legacy-11). Mounted before `/api` auth so limiting
|
|
181
|
+
// precedes the (more expensive) auth work.
|
|
182
|
+
app.use('/api', rate_limiter_1.authRateLimiter);
|
|
127
183
|
app.use('/api', (req, res, next) => (0, auth_1.authMiddleware)(req, res, next));
|
|
128
184
|
// APQ cache: in-memory LRU, gated by `APQ_ENABLED` (default on). The
|
|
129
185
|
// Apollo Server option only accepts a value when a cache is provided;
|
|
@@ -242,7 +298,11 @@ const startServer = async () => {
|
|
|
242
298
|
allowedHeaders: ['Content-Type', 'Authorization', 'X-Request-ID'],
|
|
243
299
|
maxAge: 86400, // 24h preflight cache
|
|
244
300
|
};
|
|
245
|
-
app.use('/graphql', (0, cors_1.default)(corsOptions),
|
|
301
|
+
app.use('/graphql', (0, cors_1.default)(corsOptions),
|
|
302
|
+
// After cors() so enforce-mode 429s carry CORS headers; before body parsing
|
|
303
|
+
// so limiting stays cheap. OPTIONS preflights are skipped inside the
|
|
304
|
+
// limiter (audit B01-backend-legacy-11).
|
|
305
|
+
rate_limiter_1.graphqlRateLimiter, body_parser_1.default.json(), (0, express4_1.expressMiddleware)(server, {
|
|
246
306
|
context: async ({ req }) => {
|
|
247
307
|
// Ensure we're using the global prisma instance and never disconnecting it between requests
|
|
248
308
|
if (!global.prisma) {
|