chore: sync submodule state (parent ref update)
Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
export function cacheMiddleware(_ttl?: number) {
|
||||
return (req: unknown, res: unknown, next: () => void) => next();
|
||||
}
|
||||
55
services/token-aggregation/src/api/middleware/auth.ts
Normal file
55
services/token-aggregation/src/api/middleware/auth.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'token-aggregation-secret';
|
||||
|
||||
export interface AuthUser {
|
||||
id: number;
|
||||
username: string;
|
||||
email?: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
export interface AuthRequest extends Request {
|
||||
userId?: number;
|
||||
username?: string;
|
||||
role?: string;
|
||||
user?: AuthUser;
|
||||
}
|
||||
|
||||
export function authenticateToken(req: AuthRequest, res: Response, next: NextFunction): void {
|
||||
const authHeader = req.headers.authorization;
|
||||
const token = authHeader && authHeader.split(' ')[1];
|
||||
if (!token) {
|
||||
res.status(401).json({ error: 'Access token required' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const payload = jwt.verify(token, JWT_SECRET) as { userId: number; username: string; role: string };
|
||||
req.userId = payload.userId;
|
||||
req.username = payload.username;
|
||||
req.role = payload.role;
|
||||
req.user = { id: payload.userId, username: payload.username, role: payload.role };
|
||||
next();
|
||||
} catch {
|
||||
res.status(403).json({ error: 'Invalid or expired token' });
|
||||
}
|
||||
}
|
||||
|
||||
export function requireRole(...allowed: string[]) {
|
||||
return (req: AuthRequest, res: Response, next: NextFunction): void => {
|
||||
if (!req.role || !allowed.includes(req.role)) {
|
||||
res.status(403).json({ error: 'Insufficient permissions' });
|
||||
return;
|
||||
}
|
||||
next();
|
||||
};
|
||||
}
|
||||
|
||||
export function generateToken(userId: number, username: string, role: string): string {
|
||||
return jwt.sign(
|
||||
{ userId, username, role },
|
||||
JWT_SECRET,
|
||||
{ expiresIn: '24h' }
|
||||
);
|
||||
}
|
||||
46
services/token-aggregation/src/api/middleware/cache.ts
Normal file
46
services/token-aggregation/src/api/middleware/cache.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
|
||||
interface CacheEntry {
|
||||
data: any;
|
||||
expiresAt: number;
|
||||
}
|
||||
|
||||
const cache = new Map<string, CacheEntry>();
|
||||
const DEFAULT_TTL = 60 * 1000; // 1 minute
|
||||
|
||||
export function cacheMiddleware(ttl: number = DEFAULT_TTL) {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
const key = `${req.method}:${req.originalUrl}`;
|
||||
const cached = cache.get(key);
|
||||
|
||||
if (cached && cached.expiresAt > Date.now()) {
|
||||
return res.json(cached.data);
|
||||
}
|
||||
|
||||
// Store original json method
|
||||
const originalJson = res.json.bind(res);
|
||||
|
||||
// Override json method to cache response
|
||||
res.json = function (body: any) {
|
||||
cache.set(key, {
|
||||
data: body,
|
||||
expiresAt: Date.now() + ttl,
|
||||
});
|
||||
return originalJson(body);
|
||||
};
|
||||
|
||||
next();
|
||||
};
|
||||
}
|
||||
|
||||
export function clearCache(): void {
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
export function clearCacheForPattern(pattern: string): void {
|
||||
for (const key of cache.keys()) {
|
||||
if (key.includes(pattern)) {
|
||||
cache.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
services/token-aggregation/src/api/middleware/rate-limit.ts
Normal file
20
services/token-aggregation/src/api/middleware/rate-limit.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import rateLimit from 'express-rate-limit';
|
||||
|
||||
const windowMs = parseInt(process.env.RATE_LIMIT_WINDOW_MS || '60000', 10);
|
||||
const maxRequests = parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '100', 10);
|
||||
|
||||
export const apiRateLimiter = rateLimit({
|
||||
windowMs,
|
||||
max: maxRequests,
|
||||
message: 'Too many requests from this IP, please try again later.',
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
|
||||
export const strictRateLimiter = rateLimit({
|
||||
windowMs: 60 * 1000, // 1 minute
|
||||
max: 10,
|
||||
message: 'Too many requests, please try again later.',
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
Reference in New Issue
Block a user