Skip to content

Commit f92662f

Browse files
authored
Merge pull request #1820 from rocket-admin/backend_fixes
feat: enhance WebSocket connection handling with token validation and update response caching
2 parents 0c90d2d + 40afa98 commit f92662f

4 files changed

Lines changed: 20 additions & 4 deletions

File tree

autoadmin-ws-server/src/handlers/command.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export async function executeCommand(c: Context): Promise<Response> {
4242
resolve(c.json({ error: message }, status as 400));
4343
};
4444

45-
cacheResponse(resId, handleResolve, handleReject, handleSendError);
45+
cacheResponse(resId, handleResolve, handleReject, handleSendError, connectionToken.token);
4646

4747
try {
4848
sendCommandToClient(connectionToken.token, body, resId);

autoadmin-ws-server/src/handlers/websocket.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ import { validateConnectionToken } from '../services/token-validator.js';
99
import { hashToken } from '../utils/crypto.js';
1010
import { logger } from '../utils/logger.js';
1111

12+
interface AuthenticatedSocket extends WebSocket {
13+
agentToken?: string;
14+
}
15+
1216
export function setupWebSocketServer(server: Server): WebSocketServer {
1317
const wss = new WebSocketServer({ server });
1418

@@ -46,12 +50,22 @@ export function setupWebSocketServer(server: Server): WebSocketServer {
4650
);
4751
connectionToken = hashedToken;
4852
data.connectionToken = connectionToken;
53+
(ws as AuthenticatedSocket).agentToken = hashedToken;
4954
}
5055

5156
if (operationType === COMMAND_TYPE.dataFromAgent && resId) {
5257
const cachedResponse = responseCache.get(resId);
5358

5459
if (cachedResponse) {
60+
const socketToken = (ws as AuthenticatedSocket).agentToken;
61+
if (!socketToken || socketToken !== cachedResponse.routedToken) {
62+
logger.warn(
63+
{ resId, authenticated: !!socketToken },
64+
'Discarding dataFromAgent from a socket not bound to the routed connection token',
65+
);
66+
return;
67+
}
68+
5569
logger.debug({ resId }, 'Received data from agent');
5670
cachedResponse.resolve(rawMessage.toString());
5771
responseCache.delete(resId);

autoadmin-ws-server/src/services/response-cache.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ interface CachedResponse {
77
reject: (error: Error) => void;
88
sendError: (status: number, message: string) => void;
99
createdAt: Date;
10+
routedToken: string;
1011
}
1112

1213
export const responseCache = new LRUCache<string, CachedResponse>({
@@ -23,12 +24,14 @@ export function cacheResponse(
2324
resolve: (data: string) => void,
2425
reject: (error: Error) => void,
2526
sendError: (status: number, message: string) => void,
27+
routedToken: string,
2628
): void {
2729
responseCache.set(resId, {
2830
resolve,
2931
reject,
3032
sendError,
3133
createdAt: new Date(),
34+
routedToken,
3235
});
3336
logger.debug({ resId }, 'Response cached');
3437
}

shared-code/src/data-access-layer/data-access-objects/data-access-object-agent.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -821,13 +821,12 @@ export class DataAccessObjectAgent implements IDataAccessObjectAgent {
821821
}
822822

823823
private generateJWT(connectionToken: string): string {
824-
const exp = new Date();
825-
exp.setDate(exp.getDate() + 60);
824+
const exp = Math.floor(Date.now() / 1000) + 120;
826825
const secret = process.env.JWT_SECRET;
827826
return jwt.sign(
828827
{
829828
token: connectionToken,
830-
exp: Math.floor(exp.getTime() / 1000),
829+
exp,
831830
},
832831
secret,
833832
);

0 commit comments

Comments
 (0)