feat(auth): close connection on unauthenticated socket connection
This commit is contained in:
parent
90a40aa626
commit
156379ab54
4 changed files with 122 additions and 2 deletions
12
src/chat/src/@types/socket.io.d.ts
vendored
Normal file
12
src/chat/src/@types/socket.io.d.ts
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { type UserId } from '@shared/database/mixin/user';
|
||||
|
||||
declare module 'socket.io'
|
||||
{
|
||||
interface Socket {
|
||||
authUser: {
|
||||
id: UserId;
|
||||
name: string;
|
||||
guest: boolean;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1,3 +1,7 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { JwtType } from '@shared/auth';
|
||||
import { UserId } from '@shared/database/mixin/user';
|
||||
import { isNullish } from '@shared/utils';
|
||||
import type {
|
||||
FastifyInstance,
|
||||
FastifyPluginAsync,
|
||||
|
|
@ -11,6 +15,21 @@ const F: (
|
|||
) => Omit<FastifyInstance, 'io'> & { io: Server } = (f) =>
|
||||
f as Omit<FastifyInstance, 'io'> & { io: Server };
|
||||
|
||||
function authenticateToken(
|
||||
fastify: FastifyInstance,
|
||||
token: string,
|
||||
): { id: UserId; name: string; guest: boolean } {
|
||||
const tok = fastify.jwt.verify<JwtType>(token);
|
||||
if (tok.kind != 'auth') {
|
||||
throw new Error('Token isn\'t correct type');
|
||||
}
|
||||
const user = fastify.db.getUser(tok.who);
|
||||
if (isNullish(user)) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
return { id: user.id, name: user.name, guest: user.guest };
|
||||
}
|
||||
|
||||
const fastifySocketIO: FastifyPluginAsync = fp(async (fastify) => {
|
||||
function defaultPreClose(done: HookHandlerDoneFunction) {
|
||||
F(fastify).io.local.disconnectSockets(true);
|
||||
|
|
@ -20,6 +39,36 @@ const fastifySocketIO: FastifyPluginAsync = fp(async (fastify) => {
|
|||
'io',
|
||||
new Server(fastify.server, { path: '/api/chat/socket.io' }),
|
||||
);
|
||||
F(fastify).io.use((socket, next) => {
|
||||
const cookieHeader = socket.request.headers.cookie;
|
||||
|
||||
if (!cookieHeader) {
|
||||
throw new Error('Missing token cookie');
|
||||
}
|
||||
|
||||
const cookies = Object.fromEntries(
|
||||
cookieHeader.split(';').map((c) => {
|
||||
const [k, v] = c.trim().split('=');
|
||||
return [k, v];
|
||||
}),
|
||||
);
|
||||
|
||||
if (!cookies.token) {
|
||||
throw new Error('Missing token cookie');
|
||||
}
|
||||
try {
|
||||
socket.authUser = authenticateToken(fastify, cookies.token);
|
||||
next();
|
||||
}
|
||||
catch (e: any) {
|
||||
next({
|
||||
name: 'Unauthorized',
|
||||
message: e.message,
|
||||
data: { status: 401 },
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
fastify.addHook('preClose', defaultPreClose);
|
||||
fastify.addHook('onClose', (instance: FastifyInstance, done) => {
|
||||
F(instance).io.close();
|
||||
|
|
@ -28,4 +77,3 @@ const fastifySocketIO: FastifyPluginAsync = fp(async (fastify) => {
|
|||
});
|
||||
|
||||
export default fastifySocketIO;
|
||||
|
||||
|
|
|
|||
12
src/tic-tac-toe/src/@types/socket.io.d.ts
vendored
Normal file
12
src/tic-tac-toe/src/@types/socket.io.d.ts
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { type UserId } from '@shared/database/mixin/user';
|
||||
|
||||
declare module 'socket.io'
|
||||
{
|
||||
interface Socket {
|
||||
authUser: {
|
||||
id: UserId;
|
||||
name: string;
|
||||
guest: boolean;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1,3 +1,7 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { JwtType } from '@shared/auth';
|
||||
import { UserId } from '@shared/database/mixin/user';
|
||||
import { isNullish } from '@shared/utils';
|
||||
import type {
|
||||
FastifyInstance,
|
||||
FastifyPluginAsync,
|
||||
|
|
@ -11,6 +15,21 @@ const F: (
|
|||
) => Omit<FastifyInstance, 'io'> & { io: Server } = (f) =>
|
||||
f as Omit<FastifyInstance, 'io'> & { io: Server };
|
||||
|
||||
function authenticateToken(
|
||||
fastify: FastifyInstance,
|
||||
token: string,
|
||||
): { id: UserId; name: string; guest: boolean } {
|
||||
const tok = fastify.jwt.verify<JwtType>(token);
|
||||
if (tok.kind != 'auth') {
|
||||
throw new Error('Token isn\'t correct type');
|
||||
}
|
||||
const user = fastify.db.getUser(tok.who);
|
||||
if (isNullish(user)) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
return { id: user.id, name: user.name, guest: user.guest };
|
||||
}
|
||||
|
||||
const fastifySocketIO: FastifyPluginAsync = fp(async (fastify) => {
|
||||
function defaultPreClose(done: HookHandlerDoneFunction) {
|
||||
F(fastify).io.local.disconnectSockets(true);
|
||||
|
|
@ -20,6 +39,36 @@ const fastifySocketIO: FastifyPluginAsync = fp(async (fastify) => {
|
|||
'io',
|
||||
new Server(fastify.server, { path: '/api/ttt/socket.io' }),
|
||||
);
|
||||
F(fastify).io.use((socket, next) => {
|
||||
const cookieHeader = socket.request.headers.cookie;
|
||||
|
||||
if (!cookieHeader) {
|
||||
throw new Error('Missing token cookie');
|
||||
}
|
||||
|
||||
const cookies = Object.fromEntries(
|
||||
cookieHeader.split(';').map((c) => {
|
||||
const [k, v] = c.trim().split('=');
|
||||
return [k, v];
|
||||
}),
|
||||
);
|
||||
|
||||
if (!cookies.token) {
|
||||
throw new Error('Missing token cookie');
|
||||
}
|
||||
try {
|
||||
socket.authUser = authenticateToken(fastify, cookies.token);
|
||||
next();
|
||||
}
|
||||
catch (e: any) {
|
||||
next({
|
||||
name: 'Unauthorized',
|
||||
message: e.message,
|
||||
data: { status: 401 },
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
fastify.addHook('preClose', defaultPreClose);
|
||||
fastify.addHook('onClose', (instance: FastifyInstance, done) => {
|
||||
F(instance).io.close();
|
||||
|
|
@ -28,4 +77,3 @@ const fastifySocketIO: FastifyPluginAsync = fp(async (fastify) => {
|
|||
});
|
||||
|
||||
export default fastifySocketIO;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue