Jelajahi Sumber

feat: add client IP address logging to API requests

- Add Express proxy trust configuration for accurate IP detection behind reverse proxies
- Update request logging middleware to include client IP address in format: "METHOD /path from IP"
- Enhance authentication middleware to log client IP addresses for security monitoring
- Include IP addresses in authentication failure warnings for better security analysis

Changes:
- src/api/server.ts: Add trust proxy setting and IP logging in request middleware
- src/api/middleware/auth.ts: Include client IP in authentication failure messages

Example log output:
- GET /health from 127.0.0.1
- Authentication failed: Invalid token from 127.0.0.1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fszontagh 8 bulan lalu
induk
melakukan
9332afb2a3
3 mengubah file dengan 9 tambahan dan 4 penghapusan
  1. TEMPAT SAMPAH
      data/shops.db
  2. 4 3
      src/api/middleware/auth.ts
  3. 5 1
      src/api/server.ts

TEMPAT SAMPAH
data/shops.db


+ 4 - 3
src/api/middleware/auth.ts

@@ -6,24 +6,25 @@ import { logger } from '../../utils/logger';
  */
 export function authMiddleware(apiKey: string) {
   return (req: Request, res: Response, next: NextFunction): void => {
+    const clientIp = req.ip || req.socket.remoteAddress || 'unknown';
     const authHeader = req.headers.authorization;
 
     if (!authHeader) {
-      logger.warn('Authentication failed: No authorization header');
+      logger.warn(`Authentication failed: No authorization header from ${clientIp}`);
       res.status(401).json({ error: 'No authorization header provided' });
       return;
     }
 
     const parts = authHeader.split(' ');
     if (parts.length !== 2 || parts[0] !== 'Bearer') {
-      logger.warn('Authentication failed: Invalid authorization format');
+      logger.warn(`Authentication failed: Invalid authorization format from ${clientIp}`);
       res.status(401).json({ error: 'Invalid authorization format. Use: Bearer <token>' });
       return;
     }
 
     const token = parts[1];
     if (token !== apiKey) {
-      logger.warn('Authentication failed: Invalid token');
+      logger.warn(`Authentication failed: Invalid token from ${clientIp}`);
       res.status(401).json({ error: 'Invalid API key' });
       return;
     }

+ 5 - 1
src/api/server.ts

@@ -8,12 +8,16 @@ import { ShopDatabase } from '../database/Database';
 export function createServer(apiKey: string, jobQueue: JobQueue, db?: ShopDatabase): Express {
   const app = express();
 
+  // Trust proxy to get real IP addresses when behind reverse proxy
+  app.set('trust proxy', true);
+
   // Middleware
   app.use(express.json());
 
   // Logging middleware
   app.use((req, res, next) => {
-    logger.info(`${req.method} ${req.path}`);
+    const clientIp = req.ip || req.socket.remoteAddress || 'unknown';
+    logger.info(`${req.method} ${req.path} from ${clientIp}`);
     next();
   });