chore(repo): prune dead code and duplicate abstractions (#3413)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-12 13:09:42 +02:00
1 parent c17091768c
commit c9fdf8fead
2937 files changed
+42233 -176793

No files matched your search

-1
View File
@@ -13,7 +13,6 @@
},
"devDependencies": {
"@types/node": "catalog:",
"@vitest/coverage-v8": "catalog:",
"typescript": "catalog:ts7",
"vitest": "catalog:"
}
+5 -36
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import type {IpAddressFamily, ParsedIpAddress} from '@fluxer/ip_utils/src/IpAddress';
import type {ParsedIpAddress} from '@fluxer/ip_utils/src/IpAddress';
import {parseIpAddress} from '@fluxer/ip_utils/src/IpAddress';
interface ClientIpExtractionOptions {
@@ -8,14 +8,6 @@ interface ClientIpExtractionOptions {
clientIpHeaderName?: string;
}
type ClientIpSource = 'client-ip-header';
interface ExtractedClientIp {
ip: string;
source: ClientIpSource;
ipVersion: IpAddressFamily;
}
export class MissingClientIpError extends Error {
readonly code = 'FORBIDDEN';
readonly status = 403;
@@ -26,10 +18,6 @@ export class MissingClientIpError extends Error {
}
}
interface HeaderReader {
get(name: string): string | null;
}
const DEFAULT_CLIENT_IP_HEADER_NAME = 'x-forwarded-for';
function normalizeHeaderName(headerName: string): string {
@@ -47,32 +35,13 @@ function parseClientIpHeaderValue(value: string | null): ParsedIpAddress | null
return parseIpAddress(value.split(',', 1)[0]);
}
function extractClientIpDetailsFromReader(
headerReader: HeaderReader,
options?: ClientIpExtractionOptions,
): ExtractedClientIp | null {
export function extractClientIp(req: Request, options?: ClientIpExtractionOptions): string | null {
if (!options?.trustClientIpHeader) {
return null;
}
const headerName = resolveClientIpHeaderName(options.clientIpHeaderName);
const clientIpHeader = parseClientIpHeaderValue(headerReader.get(headerName));
if (clientIpHeader) {
return {
ip: clientIpHeader.normalized,
source: 'client-ip-header',
ipVersion: clientIpHeader.family,
};
}
return null;
}
export function extractClientIpDetails(req: Request, options?: ClientIpExtractionOptions): ExtractedClientIp | null {
return extractClientIpDetailsFromReader(req.headers, options);
}
export function extractClientIp(req: Request, options?: ClientIpExtractionOptions): string | null {
const extracted = extractClientIpDetails(req, options);
return extracted?.ip ?? null;
return (
parseClientIpHeaderValue(req.headers.get(resolveClientIpHeaderName(options.clientIpHeaderName)))?.normalized ?? null
);
}
export function requireClientIp(req: Request, options?: ClientIpExtractionOptions): string {
+58
View File
@@ -331,3 +331,61 @@ export function getSubnet(ip: string): string | null {
ipv6PrefixLength: 48,
});
}
export function ipToBytes(address: string): {family: IpAddressFamily; bytes: Uint8Array} | null {
const normalized = stripIpv6Brackets(address.trim().toLowerCase());
if (isIPv4(normalized)) return {family: 'ipv4', bytes: Uint8Array.from(normalized.split('.').map(Number))};
if (!isIPv6(normalized)) {
return null;
}
let head = normalized;
let embeddedIpv4Octets: Array<number> | null = null;
const lastColonIndex = head.lastIndexOf(':');
const trailing = head.slice(lastColonIndex + 1);
if (trailing.includes('.')) {
if (!isIPv4(trailing)) {
return null;
}
embeddedIpv4Octets = trailing.split('.').map((part) => Number.parseInt(part, 10));
head = `${head.slice(0, lastColonIndex + 1)}0:0`;
}
let groups: Array<string>;
if (head.indexOf('::') === -1) {
groups = head.split(':');
if (groups.length !== 8) {
return null;
}
} else {
const [beforePart, afterPart] = head.split('::');
const before = beforePart.length > 0 ? beforePart.split(':') : [];
const after = afterPart.length > 0 ? afterPart.split(':') : [];
const missing = 8 - before.length - after.length;
if (missing < 1) {
return null;
}
groups = [...before, ...new Array(missing).fill('0'), ...after];
}
const bytes = new Uint8Array(16);
for (let index = 0; index < 8; index += 1) {
const value = parseHexGroup(groups[index]);
if (value === null) {
return null;
}
bytes[index * 2] = (value >> 8) & 0xff;
bytes[index * 2 + 1] = value & 0xff;
}
if (embeddedIpv4Octets) {
bytes[12] = embeddedIpv4Octets[0];
bytes[13] = embeddedIpv4Octets[1];
bytes[14] = embeddedIpv4Octets[2];
bytes[15] = embeddedIpv4Octets[3];
}
return {family: 'ipv6', bytes};
}
function parseHexGroup(value: string | undefined): number | null {
if (!value || !/^[0-9a-f]{1,4}$/.test(value)) {
return null;
}
return Number.parseInt(value, 16);
}
@@ -2,7 +2,6 @@
import {
extractClientIp,
extractClientIpDetails,
MissingClientIpError,
requireClientIp,
resolveClientIpHeaderName,
@@ -109,25 +108,6 @@ describe('resolveClientIpHeaderName', () => {
});
});
describe('extractClientIpDetails', () => {
it('returns extracted ip and source', () => {
const request = new Request('http://example.com', {
headers: {'X-Forwarded-For': '203.0.113.50'},
});
expect(extractClientIpDetails(request, {trustClientIpHeader: true})).toEqual({
ip: '203.0.113.50',
source: 'client-ip-header',
ipVersion: 'ipv4',
});
});
it('returns null when trust is disabled', () => {
const request = new Request('http://example.com', {
headers: {'X-Forwarded-For': '203.0.113.50'},
});
expect(extractClientIpDetails(request, {trustClientIpHeader: false})).toBeNull();
});
});
describe('requireClientIp', () => {
it('returns ip when present and trusted', () => {
const request = new Request('http://example.com', {