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 {
|
import type {
|
||||||
FastifyInstance,
|
FastifyInstance,
|
||||||
FastifyPluginAsync,
|
FastifyPluginAsync,
|
||||||
|
|
@ -11,6 +15,21 @@ const F: (
|
||||||
) => Omit<FastifyInstance, 'io'> & { io: Server } = (f) =>
|
) => Omit<FastifyInstance, 'io'> & { io: Server } = (f) =>
|
||||||
f as Omit<FastifyInstance, 'io'> & { io: Server };
|
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) => {
|
const fastifySocketIO: FastifyPluginAsync = fp(async (fastify) => {
|
||||||
function defaultPreClose(done: HookHandlerDoneFunction) {
|
function defaultPreClose(done: HookHandlerDoneFunction) {
|
||||||
F(fastify).io.local.disconnectSockets(true);
|
F(fastify).io.local.disconnectSockets(true);
|
||||||
|
|
@ -20,6 +39,36 @@ const fastifySocketIO: FastifyPluginAsync = fp(async (fastify) => {
|
||||||
'io',
|
'io',
|
||||||
new Server(fastify.server, { path: '/api/chat/socket.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('preClose', defaultPreClose);
|
||||||
fastify.addHook('onClose', (instance: FastifyInstance, done) => {
|
fastify.addHook('onClose', (instance: FastifyInstance, done) => {
|
||||||
F(instance).io.close();
|
F(instance).io.close();
|
||||||
|
|
@ -28,4 +77,3 @@ const fastifySocketIO: FastifyPluginAsync = fp(async (fastify) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
export default fastifySocketIO;
|
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 {
|
import type {
|
||||||
FastifyInstance,
|
FastifyInstance,
|
||||||
FastifyPluginAsync,
|
FastifyPluginAsync,
|
||||||
|
|
@ -11,6 +15,21 @@ const F: (
|
||||||
) => Omit<FastifyInstance, 'io'> & { io: Server } = (f) =>
|
) => Omit<FastifyInstance, 'io'> & { io: Server } = (f) =>
|
||||||
f as Omit<FastifyInstance, 'io'> & { io: Server };
|
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) => {
|
const fastifySocketIO: FastifyPluginAsync = fp(async (fastify) => {
|
||||||
function defaultPreClose(done: HookHandlerDoneFunction) {
|
function defaultPreClose(done: HookHandlerDoneFunction) {
|
||||||
F(fastify).io.local.disconnectSockets(true);
|
F(fastify).io.local.disconnectSockets(true);
|
||||||
|
|
@ -20,6 +39,36 @@ const fastifySocketIO: FastifyPluginAsync = fp(async (fastify) => {
|
||||||
'io',
|
'io',
|
||||||
new Server(fastify.server, { path: '/api/ttt/socket.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('preClose', defaultPreClose);
|
||||||
fastify.addHook('onClose', (instance: FastifyInstance, done) => {
|
fastify.addHook('onClose', (instance: FastifyInstance, done) => {
|
||||||
F(instance).io.close();
|
F(instance).io.close();
|
||||||
|
|
@ -28,4 +77,3 @@ const fastifySocketIO: FastifyPluginAsync = fp(async (fastify) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
export default fastifySocketIO;
|
export default fastifySocketIO;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue