feat: remove unused packages, config
This commit is contained in:
parent
bc4dcc26ef
commit
e52c9acf2d
@ -23,7 +23,6 @@
|
|||||||
"@nestjs/common": "^10.0.0",
|
"@nestjs/common": "^10.0.0",
|
||||||
"@nestjs/config": "^3.3.0",
|
"@nestjs/config": "^3.3.0",
|
||||||
"@nestjs/core": "^10.0.0",
|
"@nestjs/core": "^10.0.0",
|
||||||
"@nestjs/jwt": "^10.2.0",
|
|
||||||
"@nestjs/mapped-types": "^2.0.6",
|
"@nestjs/mapped-types": "^2.0.6",
|
||||||
"@nestjs/platform-express": "^10.4.11",
|
"@nestjs/platform-express": "^10.4.11",
|
||||||
"@nestjs/platform-socket.io": "^10.4.12",
|
"@nestjs/platform-socket.io": "^10.4.12",
|
||||||
@ -34,6 +33,7 @@
|
|||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.1",
|
"class-validator": "^0.14.1",
|
||||||
"joi": "^17.13.3",
|
"joi": "^17.13.3",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
"jwks-rsa": "^3.1.0",
|
"jwks-rsa": "^3.1.0",
|
||||||
"nestjs-prisma": "^0.23.0",
|
"nestjs-prisma": "^0.23.0",
|
||||||
"prisma": "^6.0.1",
|
"prisma": "^6.0.1",
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import env from "@Config/env";
|
import env from "@Config/env";
|
||||||
import { Module } from "@nestjs/common";
|
import { Module } from "@nestjs/common";
|
||||||
import { ConfigModule, ConfigService } from "@nestjs/config";
|
import { ConfigModule } from "@nestjs/config";
|
||||||
import { JwtModule } from "@nestjs/jwt";
|
|
||||||
import { envValidation } from "@Validations/env.validation";
|
import { envValidation } from "@Validations/env.validation";
|
||||||
|
|
||||||
import { AuthModule } from "@Modules/auth/auth.module";
|
import { AuthModule } from "@Modules/auth/auth.module";
|
||||||
@ -17,16 +16,6 @@ import { ClassModule } from "./modules/class/class.module";
|
|||||||
load: [env],
|
load: [env],
|
||||||
validationSchema: envValidation,
|
validationSchema: envValidation,
|
||||||
}),
|
}),
|
||||||
JwtModule.registerAsync({
|
|
||||||
global: true,
|
|
||||||
inject: [ConfigService],
|
|
||||||
useFactory: async (configService: ConfigService) => ({
|
|
||||||
secret: configService.get<string>("JWT.secret"),
|
|
||||||
signOptions: {
|
|
||||||
expiresIn: configService.get<string>("JWT.expiresIn"),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
PrismaModule.forRoot({
|
PrismaModule.forRoot({
|
||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
}),
|
}),
|
||||||
@ -34,6 +23,6 @@ import { ClassModule } from "./modules/class/class.module";
|
|||||||
AuthModule,
|
AuthModule,
|
||||||
ClassModule,
|
ClassModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController]
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
@ -1,19 +1,6 @@
|
|||||||
export default () => ({
|
export default () => ({
|
||||||
JWT: {
|
auth: {
|
||||||
secret: process.env.JWT_SECRET,
|
jwksURL: process.env.AUTH_JWKS_URI,
|
||||||
expiresIn: process.env.JWT_EXPIRES_IN,
|
usernameField: process.env.AUTH_USERNAME_FIELD
|
||||||
refresh: {
|
|
||||||
secret: process.env.REFRESH_JWT_SECRET,
|
|
||||||
expiresIn: process.env.REFRESH_JWT_EXPIRES_IN,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
oauth2: {
|
|
||||||
authorizationURL: process.env.OAUTH2_AUTHORIZATION_URL,
|
|
||||||
tokenURL: process.env.OAUTH2_TOKEN_URL,
|
|
||||||
clientID: process.env.OAUTH2_CLIENT_ID,
|
|
||||||
clientSecret: process.env.OAUTH2_CLIENT_SECRET,
|
|
||||||
callbackURL: process.env.OAUTH2_CALLBACK_URL,
|
|
||||||
profileURL: process.env.OAUTH2_PROFILE_URL,
|
|
||||||
scopes: process.env.OAUTH2_SCOPES,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { UserModule } from "@Modules/user/user.module";
|
|
||||||
import { Module } from "@nestjs/common";
|
import { Module } from "@nestjs/common";
|
||||||
import { AuthService } from "./auth.service";
|
import { AuthService } from "./auth.service";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [UserModule],
|
|
||||||
providers: [AuthService],
|
providers: [AuthService],
|
||||||
|
exports: [AuthService],
|
||||||
})
|
})
|
||||||
export class AuthModule {}
|
export class AuthModule {}
|
||||||
|
@ -1,41 +1,49 @@
|
|||||||
import { Injectable } from "@nestjs/common";
|
import { Injectable, UnauthorizedException } from "@nestjs/common";
|
||||||
import { ConfigService } from "@nestjs/config";
|
import { ConfigService } from "@nestjs/config";
|
||||||
import { JwtService } from "@nestjs/jwt";
|
import * as jwt from "jsonwebtoken";
|
||||||
|
import JwksRsa, * as jwksRsa from "jwks-rsa";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
constructor(
|
private jwksClient: JwksRsa.JwksClient;
|
||||||
private readonly jwtService: JwtService,
|
|
||||||
private readonly configService: ConfigService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
accessToken(user: { id: string }) {
|
constructor(configService: ConfigService) {
|
||||||
return this.jwtService.sign(
|
this.jwksClient = jwksRsa({
|
||||||
{ id: user.id },
|
jwksUri: configService.get<string>("AUTH_JWKS_URI"),
|
||||||
{
|
cache: true,
|
||||||
secret: this.configService.get<string>("JWT.secret"),
|
rateLimit: true,
|
||||||
expiresIn: this.configService.get<string>("JWT.expiresIn"),
|
jwksRequestsPerMinute: 10,
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshToken(user: { id: string }) {
|
|
||||||
return this.jwtService.sign(
|
|
||||||
{ id: user.id },
|
|
||||||
{
|
|
||||||
secret: this.configService.get<string>("JWT.refresh.secret"),
|
|
||||||
expiresIn: this.configService.get<string>(
|
|
||||||
"JWT.refresh.expiresIn",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async verifyToken(token: string): Promise<{
|
|
||||||
id: string;
|
|
||||||
}> {
|
|
||||||
return await this.jwtService.verifyAsync(token, {
|
|
||||||
secret: this.configService.get<string>("JWT.secret"),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getSigningKey(kid: string): Promise<string> {
|
||||||
|
const key = await this.jwksClient.getSigningKey(kid);
|
||||||
|
return key.getPublicKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
decodeJwt(token: string) {
|
||||||
|
return jwt.decode(token, { complete: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyJwt(token: string, key: string) {
|
||||||
|
return jwt.verify(token, key, {
|
||||||
|
algorithms: ["RS256"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkToken(token: string): Promise<jwt.JwtPayload> {
|
||||||
|
const decodedHeader = this.decodeJwt(token);
|
||||||
|
const kid = decodedHeader?.header?.kid;
|
||||||
|
|
||||||
|
if (!kid) throw "Token kid not found";
|
||||||
|
|
||||||
|
const key = await this.getSigningKey(kid);
|
||||||
|
|
||||||
|
const jwtPayload = this.verifyJwt(token, key);
|
||||||
|
|
||||||
|
if (typeof jwtPayload == "string")
|
||||||
|
throw new UnauthorizedException("Invalid token");
|
||||||
|
|
||||||
|
return jwtPayload;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,25 +5,16 @@ import {
|
|||||||
Injectable,
|
Injectable,
|
||||||
UnauthorizedException,
|
UnauthorizedException,
|
||||||
} from "@nestjs/common";
|
} from "@nestjs/common";
|
||||||
|
import { AuthService } from "../auth.service";
|
||||||
import { ConfigService } from "@nestjs/config";
|
import { ConfigService } from "@nestjs/config";
|
||||||
import * as jwt from "jsonwebtoken";
|
|
||||||
import * as jwksRsa from "jwks-rsa";
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class JwtAuthGuard implements CanActivate {
|
export class JwtAuthGuard implements CanActivate {
|
||||||
private jwksClient: jwksRsa.JwksClient;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
configService: ConfigService,
|
private readonly authService: AuthService,
|
||||||
) {
|
private readonly configService: ConfigService,
|
||||||
this.jwksClient = jwksRsa({
|
) {}
|
||||||
jwksUri: configService.get<string>("AUTH_JWKS_URI"),
|
|
||||||
cache: true,
|
|
||||||
rateLimit: true,
|
|
||||||
jwksRequestsPerMinute: 10,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
const request = context.switchToHttp().getRequest();
|
const request = context.switchToHttp().getRequest();
|
||||||
@ -34,25 +25,11 @@ export class JwtAuthGuard implements CanActivate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decodedHeader: any = jwt.decode(token, { complete: true });
|
const jwtPayload = await this.authService.checkToken(token);
|
||||||
const kid = decodedHeader?.header?.kid;
|
|
||||||
|
|
||||||
if (!kid) {
|
|
||||||
throw new UnauthorizedException("Token kid not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
const key = await this.getSigningKey(kid);
|
|
||||||
|
|
||||||
const verifiedToken = jwt.verify(token, key, {
|
|
||||||
algorithms: ["RS256"],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (typeof verifiedToken == "string")
|
|
||||||
throw new UnauthorizedException("Invalid token");
|
|
||||||
|
|
||||||
let user = await this.userService.findOrCreateByProviderId({
|
let user = await this.userService.findOrCreateByProviderId({
|
||||||
providerId: verifiedToken.sub.toString(),
|
providerId: jwtPayload.sub.toString(),
|
||||||
username: verifiedToken.preferred_username,
|
username: jwtPayload[this.configService.get("auth.usernameField")],
|
||||||
});
|
});
|
||||||
|
|
||||||
request.user = user;
|
request.user = user;
|
||||||
@ -74,9 +51,4 @@ export class JwtAuthGuard implements CanActivate {
|
|||||||
|
|
||||||
return parts[1];
|
return parts[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getSigningKey(kid: string): Promise<string> {
|
|
||||||
const key = await this.jwksClient.getSigningKey(kid);
|
|
||||||
return key.getPublicKey();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { Module } from "@nestjs/common";
|
import { Module } from "@nestjs/common";
|
||||||
import { ClassService } from "./class.service";
|
import { ClassService } from "./class.service";
|
||||||
import { ClassController } from "./class.controller";
|
import { ClassController } from "./class.controller";
|
||||||
import { UserService } from "../user/user.service";
|
import { UserModule } from "../user/user.module";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
imports: [UserModule],
|
||||||
controllers: [ClassController],
|
controllers: [ClassController],
|
||||||
providers: [ClassService, UserService],
|
providers: [ClassService],
|
||||||
})
|
})
|
||||||
export class ClassModule {}
|
export class ClassModule {}
|
||||||
|
@ -9,12 +9,14 @@ import {
|
|||||||
import { Server, Socket } from "socket.io";
|
import { Server, Socket } from "socket.io";
|
||||||
import { AuthService } from "../auth/auth.service";
|
import { AuthService } from "../auth/auth.service";
|
||||||
import { UserService } from "./user.service";
|
import { UserService } from "./user.service";
|
||||||
|
import { ConfigService } from "@nestjs/config";
|
||||||
|
|
||||||
@WebSocketGateway()
|
@WebSocketGateway()
|
||||||
export class UserGateway implements OnGatewayConnection, OnGatewayDisconnect {
|
export class UserGateway implements OnGatewayConnection, OnGatewayDisconnect {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly authService: AuthService,
|
private readonly authService: AuthService,
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
|
private readonly configService: ConfigService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@WebSocketServer() io: Server;
|
@WebSocketServer() io: Server;
|
||||||
@ -22,16 +24,21 @@ export class UserGateway implements OnGatewayConnection, OnGatewayDisconnect {
|
|||||||
public clients: Socket[] = [];
|
public clients: Socket[] = [];
|
||||||
|
|
||||||
async handleConnection(client: Socket) {
|
async handleConnection(client: Socket) {
|
||||||
const Authorization = client.handshake.headers.authorization;
|
const token = client.handshake.headers.authorization;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var jwtDecoded = await this.authService.verifyToken(Authorization);
|
var jwtPayload = await this.authService.checkToken(token);
|
||||||
|
|
||||||
|
if (!jwtPayload) throw "Invalid token";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
client.emit("auth", error);
|
client.emit("auth", error);
|
||||||
return client.disconnect();
|
return client.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await this.userService.findOne(jwtDecoded.id);
|
const user = await this.userService.findOrCreateByProviderId({
|
||||||
|
providerId: jwtPayload.sub.toString(),
|
||||||
|
username: jwtPayload[this.configService.get("auth.usernameField")],
|
||||||
|
});
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
client.emit("auth", "User not found");
|
client.emit("auth", "User not found");
|
||||||
|
@ -7,8 +7,8 @@ import { UserGateway } from "./user.gateway";
|
|||||||
import { UserService } from "./user.service";
|
import { UserService } from "./user.service";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [UserService, PrismaService, UserGateway, AuthService],
|
providers: [UserService, AuthService, PrismaService, UserGateway],
|
||||||
controllers: [UserController],
|
controllers: [UserController],
|
||||||
exports: [UserService],
|
exports: [UserService, AuthService],
|
||||||
})
|
})
|
||||||
export class UserModule {}
|
export class UserModule {}
|
||||||
|
@ -52,10 +52,9 @@ export class UserService {
|
|||||||
providerId: string;
|
providerId: string;
|
||||||
username: string;
|
username: string;
|
||||||
}) {
|
}) {
|
||||||
let user = await this.prisma.user.findUnique({
|
let user = await this.prisma.user.findFirst({
|
||||||
where: {
|
where: {
|
||||||
providerId,
|
OR: [{ providerId }, { username }],
|
||||||
username,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ export const envValidation = Joi.object({
|
|||||||
DATABASE_URL: Joi.string().required(),
|
DATABASE_URL: Joi.string().required(),
|
||||||
|
|
||||||
AUTH_JWKS_URI: Joi.string().uri().required(),
|
AUTH_JWKS_URI: Joi.string().uri().required(),
|
||||||
|
AUTH_USERNAME_FIELD: Joi.string().required(),
|
||||||
|
|
||||||
PORT: Joi.number().optional(),
|
PORT: Joi.number().optional(),
|
||||||
});
|
});
|
||||||
|
17
yarn.lock
17
yarn.lock
@ -318,14 +318,6 @@
|
|||||||
path-to-regexp "3.3.0"
|
path-to-regexp "3.3.0"
|
||||||
tslib "2.8.1"
|
tslib "2.8.1"
|
||||||
|
|
||||||
"@nestjs/jwt@^10.2.0":
|
|
||||||
version "10.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@nestjs/jwt/-/jwt-10.2.0.tgz#6aa35a04922d19c6426efced4671620f92e6dbd0"
|
|
||||||
integrity sha512-x8cG90SURkEiLOehNaN2aRlotxT0KZESUliOPKKnjWiyJOcWurkF3w345WOX0P4MgFzUjGoZ1Sy0aZnxeihT0g==
|
|
||||||
dependencies:
|
|
||||||
"@types/jsonwebtoken" "9.0.5"
|
|
||||||
jsonwebtoken "9.0.2"
|
|
||||||
|
|
||||||
"@nestjs/mapped-types@2.0.6", "@nestjs/mapped-types@^2.0.6":
|
"@nestjs/mapped-types@2.0.6", "@nestjs/mapped-types@^2.0.6":
|
||||||
version "2.0.6"
|
version "2.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-2.0.6.tgz#d2d8523709fd5d872a9b9e0c38162746e2a7f44e"
|
resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-2.0.6.tgz#d2d8523709fd5d872a9b9e0c38162746e2a7f44e"
|
||||||
@ -617,13 +609,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
||||||
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
||||||
|
|
||||||
"@types/jsonwebtoken@9.0.5":
|
|
||||||
version "9.0.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz#0bd9b841c9e6c5a937c17656e2368f65da025588"
|
|
||||||
integrity sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==
|
|
||||||
dependencies:
|
|
||||||
"@types/node" "*"
|
|
||||||
|
|
||||||
"@types/jsonwebtoken@^9.0.2":
|
"@types/jsonwebtoken@^9.0.2":
|
||||||
version "9.0.7"
|
version "9.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz#e49b96c2b29356ed462e9708fc73b833014727d2"
|
resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz#e49b96c2b29356ed462e9708fc73b833014727d2"
|
||||||
@ -2301,7 +2286,7 @@ jsonfile@^6.0.1:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
graceful-fs "^4.1.6"
|
graceful-fs "^4.1.6"
|
||||||
|
|
||||||
jsonwebtoken@9.0.2:
|
jsonwebtoken@^9.0.2:
|
||||||
version "9.0.2"
|
version "9.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3"
|
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3"
|
||||||
integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==
|
integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==
|
||||||
|
Loading…
Reference in New Issue
Block a user