fix: escape Prometheus label values (#2702)
fix: escape Prometheus label values (#2699) Co-authored-by: potatosips <potatosips@users.noreply.github.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { setHeader } from 'h3';
|
|||||||
import Database from '#server/utils/Database';
|
import Database from '#server/utils/Database';
|
||||||
import WireGuard from '#server/utils/WireGuard';
|
import WireGuard from '#server/utils/WireGuard';
|
||||||
import { defineMetricsHandler } from '#server/utils/handler';
|
import { defineMetricsHandler } from '#server/utils/handler';
|
||||||
|
import { formatPrometheusLabels } from '#server/utils/prometheus';
|
||||||
import { isPeerConnected } from '#shared/utils/time';
|
import { isPeerConnected } from '#shared/utils/time';
|
||||||
|
|
||||||
export default defineMetricsHandler('prometheus', async ({ event }) => {
|
export default defineMetricsHandler('prometheus', async ({ event }) => {
|
||||||
@@ -27,7 +28,13 @@ async function getPrometheusResponse() {
|
|||||||
wireguardConnectedPeersCount++;
|
wireguardConnectedPeersCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = `interface="${wgInterface.name}",enabled="${client.enabled}",ipv4Address="${client.ipv4Address}",ipv6Address="${client.ipv6Address}",name="${client.name}"`;
|
const id = formatPrometheusLabels({
|
||||||
|
interface: wgInterface.name,
|
||||||
|
enabled: client.enabled,
|
||||||
|
ipv4Address: client.ipv4Address,
|
||||||
|
ipv6Address: client.ipv6Address,
|
||||||
|
name: client.name,
|
||||||
|
});
|
||||||
|
|
||||||
wireguardSentBytes.push(
|
wireguardSentBytes.push(
|
||||||
`wireguard_sent_bytes{${id}} ${client.transferTx ?? 0}`
|
`wireguard_sent_bytes{${id}} ${client.transferTx ?? 0}`
|
||||||
@@ -41,7 +48,7 @@ async function getPrometheusResponse() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = `interface="${wgInterface.name}"`;
|
const id = formatPrometheusLabels({ interface: wgInterface.name });
|
||||||
|
|
||||||
const returnText = [
|
const returnText = [
|
||||||
'# HELP wireguard_configured_peers',
|
'# HELP wireguard_configured_peers',
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
export function escapePrometheusLabelValue(value: string): string {
|
||||||
|
return value
|
||||||
|
.replaceAll('\\', '\\\\')
|
||||||
|
.replaceAll('\n', '\\n')
|
||||||
|
.replaceAll('"', '\\"');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatPrometheusLabels(
|
||||||
|
labels: Record<string, string | number | boolean>
|
||||||
|
): string {
|
||||||
|
return Object.entries(labels)
|
||||||
|
.map(
|
||||||
|
([name, value]) =>
|
||||||
|
`${name}="${escapePrometheusLabelValue(String(value))}"`
|
||||||
|
)
|
||||||
|
.join(',');
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { describe, expect, test } from 'vitest';
|
||||||
|
|
||||||
|
import {
|
||||||
|
escapePrometheusLabelValue,
|
||||||
|
formatPrometheusLabels,
|
||||||
|
} from '#server/utils/prometheus';
|
||||||
|
|
||||||
|
describe('Prometheus label formatting', () => {
|
||||||
|
test('escapes quotes, backslashes, and newlines in label values', () => {
|
||||||
|
expect(escapePrometheusLabelValue('vpn"client')).toBe('vpn\\"client');
|
||||||
|
expect(escapePrometheusLabelValue('path\\client')).toBe('path\\\\client');
|
||||||
|
expect(escapePrometheusLabelValue('line one\nline two')).toBe(
|
||||||
|
'line one\\nline two'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('formats escaped values without changing scalar values', () => {
|
||||||
|
expect(
|
||||||
|
formatPrometheusLabels({
|
||||||
|
interface: 'wg"0',
|
||||||
|
enabled: true,
|
||||||
|
name: 'home\\office\npeer',
|
||||||
|
})
|
||||||
|
).toBe('interface="wg\\"0",enabled="true",name="home\\\\office\\npeer"');
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user