fix: add authentication to metrics routes

This commit is contained in:
2026-03-12 21:53:41 +01:00
parent 21e2e094d6
commit 96a68b46ae
4 changed files with 49 additions and 2 deletions

View File

@@ -37,6 +37,7 @@ import type {
ChatSocket,
ChatUser,
} from './types/chat.js';
import { basicAuth } from 'hono/basic-auth';
const redis = getRedisConnection();
const MESSAGE_HISTORY_SIZE = 100;
@@ -300,13 +301,25 @@ async function deleteMessageFromHistory(targetUsername: string, msgId: string):
const app = new Hono();
const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app });
if (process.env.NODE_ENV === 'production') {
app.use('/metrics', basicAuth({ username: process.env.METRICS_USER!, password: process.env.METRICS_PASS! }));
}
app.get('/', async (c) => {
return c.text(threed);
});
app.get('/up', async (c) => {
return c.text('it works');
return c.text('hello world');
});
app.get('/metrics', async () => {
return new Response(await chatMetricsRegistry.metrics(), {
headers: {
'Content-Type': chatMetricsRegistry.contentType,
'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate',
},
});
});
app.get(

View File

@@ -1,9 +1,16 @@
import { webMetricsRegistry } from '@/lib/metrics';
import { NextRequest, NextResponse } from 'next/server';
export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';
export async function GET() {
export async function GET(req: NextRequest) {
if (process.env.NODE_ENV === 'production' && !isAuthenticated(req)) {
return new NextResponse('Authentication required', {
status: 401,
headers: { 'WWW-Authenticate': 'Basic' },
});
}
return new Response(await webMetricsRegistry.metrics(), {
headers: {
'Content-Type': webMetricsRegistry.contentType,
@@ -11,3 +18,22 @@ export async function GET() {
},
});
}
// source: https://vancelucas.com/blog/how-to-add-http-basic-auth-to-next-js/
function isAuthenticated(req: NextRequest) {
const authheader = req.headers.get('authorization') || req.headers.get('Authorization');
if (!authheader) {
return false;
}
const auth = Buffer.from(authheader.split(' ')[1], 'base64').toString().split(':');
const user = auth[0];
const pass = auth[1];
if (user == process.env.METRICS_USER && pass == process.env.METRICS_PASS) {
return true;
} else {
return false;
}
}

View File

@@ -77,6 +77,8 @@ services:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.enable-lifecycle'
env_file:
- .env
volumes:
- './observability/prometheus.yml:/etc/prometheus/prometheus.yml:ro'
- 'prometheus_data:/prometheus'

View File

@@ -5,12 +5,18 @@ global:
scrape_configs:
- job_name: web
metrics_path: /api/metrics
basic_auth:
username: ${METRICS_USER}
password: ${METRICS_PASS}
static_configs:
- targets:
- hctv:3000
- job_name: chat
metrics_path: /metrics
basic_auth:
username: ${METRICS_USER}
password: ${METRICS_PASS}
static_configs:
- targets:
- chat:8000