Skip to content

Commit

Permalink
feat: send socket.io error only through middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
alexey-yarmosh committed Jul 17, 2023
1 parent 944801d commit a897964
Show file tree
Hide file tree
Showing 6 changed files with 12 additions and 49 deletions.
3 changes: 0 additions & 3 deletions src/lib/ws/gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { handleStatsReport } from '../../probe/handler/stats.js';
import { scopedLogger } from '../logger.js';
import { getWsServer, PROBES_NAMESPACE } from './server.js';
import { probeMetadata } from './middleware/probe-metadata.js';
import { verifyIpLimit } from './helper/probe-ip-limit.js';
import { errorHandler } from './helper/error-handler.js';
import { subscribeWithHandler } from './helper/subscribe-handler.js';

Expand All @@ -22,8 +21,6 @@ io
.of(PROBES_NAMESPACE)
.use(probeMetadata)
.on('connect', errorHandler(async (socket: Socket) => {
await verifyIpLimit(socket);

const probe = socket.data['probe'] as Probe;
socket.emit('api:connect:location', probe.location);
logger.info(`ws client ${socket.id} connected from ${probe.location.city}, ${probe.location.country} [${probe.ipAddress} - ${probe.location.network}]`);
Expand Down
5 changes: 0 additions & 5 deletions src/lib/ws/helper/error-handler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { Socket } from 'socket.io';
import getProbeIp from '../../get-probe-ip.js';
import { scopedLogger } from '../../logger.js';
import { WsError } from '../ws-error.js';

const logger = scopedLogger('ws:error');

Expand All @@ -27,10 +26,6 @@ export const errorHandler = (next: NextArgument) => (socket: Socket, mwNext?: (e
logger.info(`disconnecting client ${socket.id} for (${reason}) [${clientIp}]`);
logger.debug(error);

if (error instanceof WsError) {
socket.emit('api:error', error.toJson());
}

if (mwNext) {
mwNext(error);
}
Expand Down
22 changes: 5 additions & 17 deletions src/lib/ws/helper/probe-ip-limit.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,20 @@
import * as process from 'node:process';
import type { Socket } from 'socket.io';
import type { Probe } from '../../../probe/types.js';
import { WsError } from '../ws-error.js';
import { fetchSockets } from '../server.js';
import { scopedLogger } from '../../logger.js';
import { InternalError } from '../../internal-error.js';

const logger = scopedLogger('ws:limit');

export const verifyIpLimit = async (socket: Socket): Promise<void> => {
export const verifyIpLimit = async (ip: string, socketId: string): Promise<void> => {
if (process.env['FAKE_PROBE_IP']) {
return;
}

const probe = socket.data['probe'] as Probe;

const socketList = await fetchSockets();
const previousSocket = socketList.find(s => s.data.probe.ipAddress === probe.ipAddress && s.id !== socket.id);
const previousSocket = socketList.find(s => s.data.probe.ipAddress === ip && s.id !== socketId);

if (previousSocket) {
logger.info(`ws client ${socket.id} has reached the concurrent IP limit.`, { message: previousSocket.data.probe.ipAddress });
throw new WsError(
'IP Limit',
{
code: 'ip_limit',
socketId: socket.id,
probe,
ipAddress: probe.ipAddress,
},
);
logger.info(`ws client ${socketId} has reached the concurrent IP limit.`, { message: previousSocket.data.probe.ipAddress });
throw new InternalError('ip limit', true);
}
};
1 change: 0 additions & 1 deletion src/lib/ws/middleware/probe-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export const probeMetadata = errorHandler(async (socket: Socket, next: (error?:
}

throw new WsError(message, {
socketId: socket.id,
ipAddress: clientIp ?? '',
});
}
Expand Down
27 changes: 4 additions & 23 deletions src/lib/ws/ws-error.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,12 @@
import type { Probe } from '../../probe/types.js';

type Info = {
socketId: string;
type Data = {
ipAddress: string;
// A string used for message parsing
code?: string;
probe?: Probe;
cause?: unknown;
};

type JsonResponse = {
message: string;
info: Info;
};

export class WsError extends Error {
info: Info;
constructor (message: string, info: Info) {
data: Data;
constructor (message: string, data: Data) {
super(message);
this.info = info;
}

toJson (): JsonResponse {
return {
message: this.message,
info: this.info,
};
this.data = data;
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/probe/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { createGeoipClient } from '../lib/geoip/client.js';
import getProbeIp from '../lib/get-probe-ip.js';
import { getRegion } from '../lib/ip-ranges.js';
import type { Probe, ProbeLocation, Tag } from './types.js';
import { verifyIpLimit } from '../lib/ws/helper/probe-ip-limit.js';

const fakeIpForDebug = () => {
return _.sample([
Expand Down Expand Up @@ -62,6 +63,8 @@ export const buildProbe = async (socket: Socket): Promise<Probe> => {
throw new Error(`couldn't detect probe location for ip ${clientIp}`);
}

await verifyIpLimit(clientIp, socket.id);

const location = getLocation(ipInfo);

const tags = getTags(clientIp);
Expand Down

0 comments on commit a897964

Please sign in to comment.