Upgrade system finished
This commit is contained in:
2
api/dist/middleware/auth.middleware.d.ts.map
vendored
2
api/dist/middleware/auth.middleware.d.ts.map
vendored
@@ -1 +1 @@
|
||||
{"version":3,"file":"auth.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAY1D,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,QAe5E;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,QAiB5E"}
|
||||
{"version":3,"file":"auth.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAa1D,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,QAoB5E;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,QAsB5E"}
|
||||
18
api/dist/middleware/auth.middleware.js
vendored
18
api/dist/middleware/auth.middleware.js
vendored
@@ -15,8 +15,13 @@ function authenticate(req, _res, next) {
|
||||
}
|
||||
const token = header.slice(7);
|
||||
try {
|
||||
const payload = jsonwebtoken_1.default.verify(token, env_1.env.JWT_ACCESS_SECRET);
|
||||
req.user = { id: payload.id, email: payload.email, role: payload.role };
|
||||
const payload = jsonwebtoken_1.default.verify(token, env_1.env.JWT_ACCESS_SECRET, { algorithms: ['HS256'] });
|
||||
req.user = {
|
||||
id: payload.id,
|
||||
email: payload.email,
|
||||
role: payload.role,
|
||||
roles: payload.roles || [payload.role], // Backwards compat: old JWTs without roles
|
||||
};
|
||||
next();
|
||||
}
|
||||
catch {
|
||||
@@ -31,8 +36,13 @@ function optionalAuth(req, _res, next) {
|
||||
}
|
||||
const token = header.slice(7);
|
||||
try {
|
||||
const payload = jsonwebtoken_1.default.verify(token, env_1.env.JWT_ACCESS_SECRET);
|
||||
req.user = { id: payload.id, email: payload.email, role: payload.role };
|
||||
const payload = jsonwebtoken_1.default.verify(token, env_1.env.JWT_ACCESS_SECRET, { algorithms: ['HS256'] });
|
||||
req.user = {
|
||||
id: payload.id,
|
||||
email: payload.email,
|
||||
role: payload.role,
|
||||
roles: payload.roles || [payload.role],
|
||||
};
|
||||
}
|
||||
catch {
|
||||
// Token invalid — continue without user
|
||||
|
||||
2
api/dist/middleware/auth.middleware.js.map
vendored
2
api/dist/middleware/auth.middleware.js.map
vendored
@@ -1 +1 @@
|
||||
{"version":3,"file":"auth.middleware.js","sourceRoot":"","sources":["../../src/middleware/auth.middleware.ts"],"names":[],"mappings":";;;;;AAYA,oCAeC;AAED,oCAiBC;AA7CD,gEAA+B;AAE/B,uCAAoC;AACpC,mDAA2C;AAQ3C,SAAgB,YAAY,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB;IAC3E,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,wBAAQ,CAAC,GAAG,EAAE,yBAAyB,EAAE,eAAe,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,SAAG,CAAC,iBAAiB,CAAiB,CAAC;QACzE,GAAG,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;QACxE,IAAI,EAAE,CAAC;IACT,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,wBAAQ,CAAC,GAAG,EAAE,0BAA0B,EAAE,eAAe,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAED,SAAgB,YAAY,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB;IAC3E,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,IAAI,EAAE,CAAC;QACP,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,SAAG,CAAC,iBAAiB,CAAiB,CAAC;QACzE,GAAG,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,wCAAwC;IAC1C,CAAC;IAED,IAAI,EAAE,CAAC;AACT,CAAC"}
|
||||
{"version":3,"file":"auth.middleware.js","sourceRoot":"","sources":["../../src/middleware/auth.middleware.ts"],"names":[],"mappings":";;;;;AAaA,oCAoBC;AAED,oCAsBC;AAxDD,gEAA+B;AAE/B,uCAAoC;AACpC,mDAA2C;AAS3C,SAAgB,YAAY,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB;IAC3E,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,wBAAQ,CAAC,GAAG,EAAE,yBAAyB,EAAE,eAAe,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,SAAG,CAAC,iBAAiB,EAAE,EAAE,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE,CAAiB,CAAC;QACpG,GAAG,CAAC,IAAI,GAAG;YACT,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,2CAA2C;SACpF,CAAC;QACF,IAAI,EAAE,CAAC;IACT,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,wBAAQ,CAAC,GAAG,EAAE,0BAA0B,EAAE,eAAe,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAED,SAAgB,YAAY,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB;IAC3E,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,IAAI,EAAE,CAAC;QACP,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,SAAG,CAAC,iBAAiB,EAAE,EAAE,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE,CAAiB,CAAC;QACpG,GAAG,CAAC,IAAI,GAAG;YACT,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;SACvC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,wCAAwC;IAC1C,CAAC;IAED,IAAI,EAAE,CAAC;AACT,CAAC"}
|
||||
12
api/dist/middleware/rate-limit.d.ts
vendored
12
api/dist/middleware/rate-limit.d.ts
vendored
@@ -6,7 +6,19 @@ export declare const canvassVisitRateLimit: import("express-rate-limit").RateLim
|
||||
export declare const canvassBulkVisitRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const gpsTrackingRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const canvassGeocodeRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const adTrackingRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const quickJoinRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const authRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const observabilityRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const docsAnalyticsRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const docsCommentAnonRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const docsCommentAuthRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const docsCommentFetchRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const profileViewRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const profileEditRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const profilePhotoRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const profilePasswordRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const eventSubmissionRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const errorReportRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
export declare const healthMetricsRateLimit: import("express-rate-limit").RateLimitRequestHandler;
|
||||
//# sourceMappingURL=rate-limit.d.ts.map
|
||||
2
api/dist/middleware/rate-limit.d.ts.map
vendored
2
api/dist/middleware/rate-limit.d.ts.map
vendored
@@ -1 +1 @@
|
||||
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe,sDAe1B,CAAC;AAEH,eAAO,MAAM,cAAc,sDAezB,CAAC;AAEH,eAAO,MAAM,iBAAiB,sDAe5B,CAAC;AAEH,eAAO,MAAM,oBAAoB,sDAe/B,CAAC;AAEH,eAAO,MAAM,qBAAqB,sDAehC,CAAC;AAEH,eAAO,MAAM,yBAAyB,sDAepC,CAAC;AAEH,eAAO,MAAM,oBAAoB,sDAe/B,CAAC;AAEH,eAAO,MAAM,uBAAuB,sDAelC,CAAC;AAEH,eAAO,MAAM,aAAa,sDAexB,CAAC;AAEH,eAAO,MAAM,sBAAsB,sDAejC,CAAC;AAEH,eAAO,MAAM,sBAAsB,sDAejC,CAAC"}
|
||||
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe,sDAe1B,CAAC;AAEH,eAAO,MAAM,cAAc,sDAezB,CAAC;AAEH,eAAO,MAAM,iBAAiB,sDAe5B,CAAC;AAEH,eAAO,MAAM,oBAAoB,sDAe/B,CAAC;AAEH,eAAO,MAAM,qBAAqB,sDAehC,CAAC;AAEH,eAAO,MAAM,yBAAyB,sDAepC,CAAC;AAEH,eAAO,MAAM,oBAAoB,sDAe/B,CAAC;AAEH,eAAO,MAAM,uBAAuB,sDAelC,CAAC;AAEH,eAAO,MAAM,mBAAmB,sDAe9B,CAAC;AAEH,eAAO,MAAM,kBAAkB,sDAe7B,CAAC;AAEH,eAAO,MAAM,aAAa,sDAexB,CAAC;AAEH,eAAO,MAAM,sBAAsB,sDAejC,CAAC;AAEH,eAAO,MAAM,sBAAsB,sDAejC,CAAC;AAEH,eAAO,MAAM,wBAAwB,sDAenC,CAAC;AAEH,eAAO,MAAM,wBAAwB,sDAenC,CAAC;AAEH,eAAO,MAAM,yBAAyB,sDAepC,CAAC;AAEH,eAAO,MAAM,oBAAoB,sDAe/B,CAAC;AAEH,eAAO,MAAM,oBAAoB,sDAe/B,CAAC;AAEH,eAAO,MAAM,qBAAqB,sDAehC,CAAC;AAEH,eAAO,MAAM,wBAAwB,sDAenC,CAAC;AAEH,eAAO,MAAM,wBAAwB,sDAenC,CAAC;AAEH,eAAO,MAAM,oBAAoB,sDAe/B,CAAC;AAEH,eAAO,MAAM,sBAAsB,sDAejC,CAAC"}
|
||||
194
api/dist/middleware/rate-limit.js
vendored
194
api/dist/middleware/rate-limit.js
vendored
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.healthMetricsRateLimit = exports.observabilityRateLimit = exports.authRateLimit = exports.canvassGeocodeRateLimit = exports.gpsTrackingRateLimit = exports.canvassBulkVisitRateLimit = exports.canvassVisitRateLimit = exports.shiftSignupRateLimit = exports.responseRateLimit = exports.emailRateLimit = exports.globalRateLimit = void 0;
|
||||
exports.healthMetricsRateLimit = exports.errorReportRateLimit = exports.eventSubmissionRateLimit = exports.profilePasswordRateLimit = exports.profilePhotoRateLimit = exports.profileEditRateLimit = exports.profileViewRateLimit = exports.docsCommentFetchRateLimit = exports.docsCommentAuthRateLimit = exports.docsCommentAnonRateLimit = exports.docsAnalyticsRateLimit = exports.observabilityRateLimit = exports.authRateLimit = exports.quickJoinRateLimit = exports.adTrackingRateLimit = exports.canvassGeocodeRateLimit = exports.gpsTrackingRateLimit = exports.canvassBulkVisitRateLimit = exports.canvassVisitRateLimit = exports.shiftSignupRateLimit = exports.responseRateLimit = exports.emailRateLimit = exports.globalRateLimit = void 0;
|
||||
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
||||
const rate_limit_redis_1 = __importDefault(require("rate-limit-redis"));
|
||||
const redis_1 = require("../config/redis");
|
||||
@@ -136,6 +136,38 @@ exports.canvassGeocodeRateLimit = (0, express_rate_limit_1.default)({
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.adTrackingRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 60 * 1000, // 1 minute
|
||||
max: 60, // 60 events/min per IP (generous for scroll-heavy gallery pages)
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: new rate_limit_redis_1.default({
|
||||
sendCommand: (command, ...args) => redis_1.redis.call(command, ...args),
|
||||
prefix: 'rl:ad-track:',
|
||||
}),
|
||||
message: {
|
||||
error: {
|
||||
message: 'Too many tracking requests',
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.quickJoinRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 60 * 60 * 1000, // 1 hour
|
||||
max: 10,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: new rate_limit_redis_1.default({
|
||||
sendCommand: (command, ...args) => redis_1.redis.call(command, ...args),
|
||||
prefix: 'rl:quick-join:',
|
||||
}),
|
||||
message: {
|
||||
error: {
|
||||
message: 'Too many join attempts, please try again later',
|
||||
code: 'QUICK_JOIN_RATE_LIMIT_EXCEEDED',
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.authRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 10, // Reduced from 20 to prevent brute force attacks
|
||||
@@ -168,6 +200,166 @@ exports.observabilityRateLimit = (0, express_rate_limit_1.default)({
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.docsAnalyticsRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 60 * 1000, // 1 minute
|
||||
max: 60, // 60 requests/min per IP
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: new rate_limit_redis_1.default({
|
||||
sendCommand: (command, ...args) => redis_1.redis.call(command, ...args),
|
||||
prefix: 'rl:docs-analytics:',
|
||||
}),
|
||||
message: {
|
||||
error: {
|
||||
message: 'Too many tracking requests, please slow down',
|
||||
code: 'DOCS_ANALYTICS_RATE_LIMIT_EXCEEDED',
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.docsCommentAnonRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 60 * 60 * 1000, // 1 hour
|
||||
max: 5,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: new rate_limit_redis_1.default({
|
||||
sendCommand: (command, ...args) => redis_1.redis.call(command, ...args),
|
||||
prefix: 'rl:docs-comment-anon:',
|
||||
}),
|
||||
message: {
|
||||
error: {
|
||||
message: 'Too many anonymous comments, please try again later',
|
||||
code: 'DOCS_COMMENT_ANON_RATE_LIMIT_EXCEEDED',
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.docsCommentAuthRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 60 * 60 * 1000, // 1 hour
|
||||
max: 30,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: new rate_limit_redis_1.default({
|
||||
sendCommand: (command, ...args) => redis_1.redis.call(command, ...args),
|
||||
prefix: 'rl:docs-comment-auth:',
|
||||
}),
|
||||
message: {
|
||||
error: {
|
||||
message: 'Too many comments, please try again later',
|
||||
code: 'DOCS_COMMENT_AUTH_RATE_LIMIT_EXCEEDED',
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.docsCommentFetchRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 60 * 1000, // 1 minute
|
||||
max: 60,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: new rate_limit_redis_1.default({
|
||||
sendCommand: (command, ...args) => redis_1.redis.call(command, ...args),
|
||||
prefix: 'rl:docs-comment-fetch:',
|
||||
}),
|
||||
message: {
|
||||
error: {
|
||||
message: 'Too many comment fetch requests, please slow down',
|
||||
code: 'DOCS_COMMENT_FETCH_RATE_LIMIT_EXCEEDED',
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.profileViewRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 60 * 1000, // 1 minute
|
||||
max: 60, // 60 requests per minute (shared across profile, photo, activity endpoints)
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: new rate_limit_redis_1.default({
|
||||
sendCommand: (command, ...args) => redis_1.redis.call(command, ...args),
|
||||
prefix: 'rl:profile-view:',
|
||||
}),
|
||||
message: {
|
||||
error: {
|
||||
message: 'Too many profile requests, please try again later',
|
||||
code: 'PROFILE_VIEW_RATE_LIMIT_EXCEEDED',
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.profileEditRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 60 * 60 * 1000, // 1 hour
|
||||
max: 20,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: new rate_limit_redis_1.default({
|
||||
sendCommand: (command, ...args) => redis_1.redis.call(command, ...args),
|
||||
prefix: 'rl:profile-edit:',
|
||||
}),
|
||||
message: {
|
||||
error: {
|
||||
message: 'Too many profile edit requests, please try again later',
|
||||
code: 'PROFILE_EDIT_RATE_LIMIT_EXCEEDED',
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.profilePhotoRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 60 * 60 * 1000, // 1 hour
|
||||
max: 5,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: new rate_limit_redis_1.default({
|
||||
sendCommand: (command, ...args) => redis_1.redis.call(command, ...args),
|
||||
prefix: 'rl:profile-photo:',
|
||||
}),
|
||||
message: {
|
||||
error: {
|
||||
message: 'Too many photo uploads, please try again later',
|
||||
code: 'PROFILE_PHOTO_RATE_LIMIT_EXCEEDED',
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.profilePasswordRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 15 * 60 * 1000, // 15 minutes
|
||||
max: 5, // Stricter than auth (10/15min) — profile passwords may be simpler
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: new rate_limit_redis_1.default({
|
||||
sendCommand: (command, ...args) => redis_1.redis.call(command, ...args),
|
||||
prefix: 'rl:profile-password:',
|
||||
}),
|
||||
message: {
|
||||
error: {
|
||||
message: 'Too many password attempts, please try again later',
|
||||
code: 'PROFILE_PASSWORD_RATE_LIMIT_EXCEEDED',
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.eventSubmissionRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 60 * 60 * 1000, // 1 hour
|
||||
max: 5,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: new rate_limit_redis_1.default({
|
||||
sendCommand: (command, ...args) => redis_1.redis.call(command, ...args),
|
||||
prefix: 'rl:event-submit:',
|
||||
}),
|
||||
message: {
|
||||
error: {
|
||||
message: 'Too many event submissions, please try again later',
|
||||
code: 'EVENT_SUBMISSION_RATE_LIMIT_EXCEEDED',
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.errorReportRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 60 * 60 * 1000, // 1 hour
|
||||
max: 5,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
store: new rate_limit_redis_1.default({
|
||||
sendCommand: (command, ...args) => redis_1.redis.call(command, ...args),
|
||||
prefix: 'rl:error-report:',
|
||||
}),
|
||||
message: {
|
||||
error: {
|
||||
message: 'Too many error reports, please try again later',
|
||||
code: 'ERROR_REPORT_RATE_LIMIT_EXCEEDED',
|
||||
},
|
||||
},
|
||||
});
|
||||
exports.healthMetricsRateLimit = (0, express_rate_limit_1.default)({
|
||||
windowMs: 60 * 1000, // 1 minute
|
||||
max: 30, // 30 requests per minute
|
||||
|
||||
2
api/dist/middleware/rate-limit.js.map
vendored
2
api/dist/middleware/rate-limit.js.map
vendored
File diff suppressed because one or more lines are too long
2
api/dist/middleware/rbac.middleware.d.ts.map
vendored
2
api/dist/middleware/rbac.middleware.d.ts.map
vendored
@@ -1 +1 @@
|
||||
{"version":3,"file":"rbac.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/rbac.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG1C,wBAAgB,WAAW,CAAC,GAAG,KAAK,EAAE,QAAQ,EAAE,IACtC,KAAK,OAAO,EAAE,MAAM,QAAQ,EAAE,MAAM,YAAY,UAWzD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,QAU9E"}
|
||||
{"version":3,"file":"rbac.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/rbac.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG1C,wBAAgB,WAAW,CAAC,GAAG,KAAK,EAAE,QAAQ,EAAE,IACtC,KAAK,OAAO,EAAE,MAAM,QAAQ,EAAE,MAAM,YAAY,UAqBzD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,QAY9E"}
|
||||
13
api/dist/middleware/rbac.middleware.js
vendored
13
api/dist/middleware/rbac.middleware.js
vendored
@@ -9,7 +9,14 @@ function requireRole(...roles) {
|
||||
if (!req.user) {
|
||||
throw new error_handler_1.AppError(401, 'Authentication required', 'AUTH_REQUIRED');
|
||||
}
|
||||
if (!roles.includes(req.user.role)) {
|
||||
// Check multi-role array (falls back to single role via auth middleware)
|
||||
const userRoles = req.user.roles || [req.user.role];
|
||||
// SUPER_ADMIN bypasses all role checks
|
||||
if (userRoles.includes(client_1.UserRole.SUPER_ADMIN)) {
|
||||
return next();
|
||||
}
|
||||
const hasRole = userRoles.some(r => roles.includes(r));
|
||||
if (!hasRole) {
|
||||
throw new error_handler_1.AppError(403, 'Insufficient permissions', 'FORBIDDEN');
|
||||
}
|
||||
next();
|
||||
@@ -19,7 +26,9 @@ function requireNonTemp(req, _res, next) {
|
||||
if (!req.user) {
|
||||
throw new error_handler_1.AppError(401, 'Authentication required', 'AUTH_REQUIRED');
|
||||
}
|
||||
if (req.user.role === client_1.UserRole.TEMP) {
|
||||
const userRoles = req.user.roles || [req.user.role];
|
||||
// User is "temp only" if their only role is TEMP
|
||||
if (userRoles.length === 1 && userRoles[0] === client_1.UserRole.TEMP) {
|
||||
throw new error_handler_1.AppError(403, 'Temporary accounts cannot access this resource', 'TEMP_FORBIDDEN');
|
||||
}
|
||||
next();
|
||||
|
||||
2
api/dist/middleware/rbac.middleware.js.map
vendored
2
api/dist/middleware/rbac.middleware.js.map
vendored
@@ -1 +1 @@
|
||||
{"version":3,"file":"rbac.middleware.js","sourceRoot":"","sources":["../../src/middleware/rbac.middleware.ts"],"names":[],"mappings":";;AAIA,kCAYC;AAED,wCAUC;AA3BD,2CAA0C;AAC1C,mDAA2C;AAE3C,SAAgB,WAAW,CAAC,GAAG,KAAiB;IAC9C,OAAO,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB,EAAE,EAAE;QAC1D,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,IAAI,wBAAQ,CAAC,GAAG,EAAE,yBAAyB,EAAE,eAAe,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,wBAAQ,CAAC,GAAG,EAAE,0BAA0B,EAAE,WAAW,CAAC,CAAC;QACnE,CAAC;QAED,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,cAAc,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB;IAC7E,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,IAAI,wBAAQ,CAAC,GAAG,EAAE,yBAAyB,EAAE,eAAe,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,iBAAQ,CAAC,IAAI,EAAE,CAAC;QACpC,MAAM,IAAI,wBAAQ,CAAC,GAAG,EAAE,gDAAgD,EAAE,gBAAgB,CAAC,CAAC;IAC9F,CAAC;IAED,IAAI,EAAE,CAAC;AACT,CAAC"}
|
||||
{"version":3,"file":"rbac.middleware.js","sourceRoot":"","sources":["../../src/middleware/rbac.middleware.ts"],"names":[],"mappings":";;AAIA,kCAsBC;AAED,wCAYC;AAvCD,2CAA0C;AAC1C,mDAA2C;AAE3C,SAAgB,WAAW,CAAC,GAAG,KAAiB;IAC9C,OAAO,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB,EAAE,EAAE;QAC1D,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,IAAI,wBAAQ,CAAC,GAAG,EAAE,yBAAyB,EAAE,eAAe,CAAC,CAAC;QACtE,CAAC;QAED,yEAAyE;QACzE,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEpD,uCAAuC;QACvC,IAAI,SAAS,CAAC,QAAQ,CAAC,iBAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAC7C,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAEvD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,wBAAQ,CAAC,GAAG,EAAE,0BAA0B,EAAE,WAAW,CAAC,CAAC;QACnE,CAAC;QAED,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,cAAc,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB;IAC7E,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,IAAI,wBAAQ,CAAC,GAAG,EAAE,yBAAyB,EAAE,eAAe,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,iDAAiD;IACjD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,iBAAQ,CAAC,IAAI,EAAE,CAAC;QAC7D,MAAM,IAAI,wBAAQ,CAAC,GAAG,EAAE,gDAAgD,EAAE,gBAAgB,CAAC,CAAC;IAC9F,CAAC;IAED,IAAI,EAAE,CAAC;AACT,CAAC"}
|
||||
Reference in New Issue
Block a user