Skip to content

Commit 875e790

Browse files
committed
next+conat: come up with a universal client IP address extractor
1 parent c1d826d commit 875e790

File tree

7 files changed

+455
-85
lines changed

7 files changed

+455
-85
lines changed

src/.claude/settings.local.json

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/packages/conat/core/server.ts

Lines changed: 30 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -28,53 +28,56 @@ cd packages/server
2828
*/
2929

3030
import type { ConnectionStats, ServerInfo } from "./types";
31+
32+
import { delay } from "awaiting";
33+
import { EventEmitter } from "events";
34+
import { throttle } from "lodash";
35+
import { Server } from "socket.io";
36+
37+
import { getClientIpAddress } from "@cocalc/util/get-client-ip-address";
38+
import { getLogger } from "@cocalc/conat/client";
39+
import { UsageMonitor } from "@cocalc/conat/monitor/usage";
40+
import { type ConatSocketServer } from "@cocalc/conat/socket";
3141
import {
3242
isValidSubject,
3343
isValidSubjectWithoutWildcards,
3444
} from "@cocalc/conat/util";
35-
import { Server } from "socket.io";
36-
import { delay } from "awaiting";
45+
import { once, until } from "@cocalc/util/async-utils";
46+
import { is_array } from "@cocalc/util/misc";
47+
import { reuseInFlight } from "@cocalc/util/reuse-in-flight";
48+
import { Metrics } from "../types";
3749
import {
38-
ConatError,
39-
connect,
4050
Client,
4151
type ClientOptions,
52+
ConatError,
53+
connect,
4254
MAX_INTEREST_TIMEOUT,
4355
STICKY_QUEUE_GROUP,
4456
} from "./client";
45-
import {
46-
RESOURCE,
47-
MAX_CONNECTIONS_PER_USER,
48-
MAX_CONNECTIONS,
49-
MAX_PAYLOAD,
50-
MAX_SUBSCRIPTIONS_PER_CLIENT,
51-
MAX_SUBSCRIPTIONS_PER_HUB,
52-
} from "./constants";
53-
import { Patterns } from "./patterns";
54-
import { is_array } from "@cocalc/util/misc";
55-
import { UsageMonitor } from "@cocalc/conat/monitor/usage";
56-
import { once, until } from "@cocalc/util/async-utils";
5757
import {
5858
clusterLink,
5959
type ClusterLink,
6060
clusterStreams,
6161
type ClusterStreams,
62-
trimClusterStreams,
6362
createClusterPersistServer,
64-
Sticky,
65-
Interest,
6663
hashInterest,
6764
hashSticky,
65+
Interest,
66+
Sticky,
67+
trimClusterStreams,
6868
} from "./cluster";
69-
import { type ConatSocketServer } from "@cocalc/conat/socket";
70-
import { throttle } from "lodash";
71-
import { getLogger } from "@cocalc/conat/client";
72-
import { reuseInFlight } from "@cocalc/util/reuse-in-flight";
73-
import { type SysConatServer, sysApiSubject, sysApi } from "./sys";
69+
import {
70+
MAX_CONNECTIONS,
71+
MAX_CONNECTIONS_PER_USER,
72+
MAX_PAYLOAD,
73+
MAX_SUBSCRIPTIONS_PER_CLIENT,
74+
MAX_SUBSCRIPTIONS_PER_HUB,
75+
RESOURCE,
76+
} from "./constants";
77+
import { Patterns } from "./patterns";
7478
import { forkedConatServer } from "./start-server";
7579
import { stickyChoice } from "./sticky";
76-
import { EventEmitter } from "events";
77-
import { Metrics } from "../types";
80+
import { sysApi, sysApiSubject, type SysConatServer } from "./sys";
7881

7982
const logger = getLogger("conat:core:server");
8083

@@ -1755,27 +1758,7 @@ export function randomChoice(v: Set<string>): string {
17551758

17561759
// See https://socket.io/how-to/get-the-ip-address-of-the-client
17571760
function getAddress(socket) {
1758-
const header = socket.handshake.headers["forwarded"];
1759-
if (header) {
1760-
for (const directive of header.split(",")[0].split(";")) {
1761-
if (directive.startsWith("for=")) {
1762-
return directive.substring(4);
1763-
}
1764-
}
1765-
}
1766-
1767-
let addr = socket.handshake.headers["x-forwarded-for"]?.split(",")?.[0];
1768-
if (addr) {
1769-
return addr;
1770-
}
1771-
for (const other of ["cf-connecting-ip", "fastly-client-ip"]) {
1772-
addr = socket.handshake.headers[other];
1773-
if (addr) {
1774-
return addr;
1775-
}
1776-
}
1777-
1778-
return socket.handshake.address;
1761+
return getClientIpAddress(socket.handshake) ?? socket.handshake.address;
17791762
}
17801763

17811764
export function updateInterest(

src/packages/next/lib/user-id.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,28 @@ import type { Request } from "express";
77

88
import { getServerSettings } from "@cocalc/database/settings/server-settings";
99
import { ANALYTICS_COOKIE_NAME } from "@cocalc/util/consts";
10+
import { getClientIpAddress } from "@cocalc/util/get-client-ip-address";
1011
import { isValidAnonymousID } from "@cocalc/util/misc";
1112

1213
// Get anonymous user ID from cookie or IP address
13-
export async function getAnonymousID(req: Request): Promise<string | undefined> {
14+
export async function getAnonymousID(
15+
req: Request,
16+
): Promise<string | undefined> {
1417
const { analytics_cookie: analytics_enabled } = await getServerSettings();
15-
18+
1619
if (analytics_enabled) {
1720
const cookie = req.cookies[ANALYTICS_COOKIE_NAME];
1821
if (isValidAnonymousID(cookie)) {
1922
return cookie;
2023
}
2124
}
22-
23-
// Fall back to IP address - check headers in order of preference
24-
const connectingIp = (req.headers["cf-connecting-ip"] ||
25-
req.headers["x-forwarded-for"] ||
26-
req.socket?.remoteAddress) as string;
27-
25+
26+
// Fall back to IP address
27+
const connectingIp = getClientIpAddress(req);
28+
2829
if (isValidAnonymousID(connectingIp)) {
2930
return connectingIp;
3031
}
31-
32+
3233
return undefined;
3334
}

src/packages/pnpm-lock.yaml

Lines changed: 16 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)