mirror of
https://github.com/stonith404/pingvin-share.git
synced 2024-06-30 06:30:11 +02:00
feat: add new config strategy to backend
This commit is contained in:
parent
13f98cc32c
commit
1b5e53ff7e
|
@ -9,6 +9,9 @@
|
|||
"format": "prettier --write 'src/**/*.ts'",
|
||||
"test:system": "npx prisma migrate reset -f && nest start & sleep 10 && newman run ./test/system/newman-system-tests.json"
|
||||
},
|
||||
"prisma": {
|
||||
"seed": "ts-node prisma/seed/config.seed.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^9.1.2",
|
||||
"@nestjs/config": "^2.2.0",
|
||||
|
|
|
@ -77,3 +77,14 @@ model ShareSecurity {
|
|||
shareId String? @unique
|
||||
share Share? @relation(fields: [shareId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model Config {
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
key String @id
|
||||
type String
|
||||
value String?
|
||||
default String
|
||||
secret Boolean @default(true)
|
||||
locked Boolean @default(false)
|
||||
}
|
||||
|
|
118
backend/prisma/seed/config.seed.ts
Normal file
118
backend/prisma/seed/config.seed.ts
Normal file
|
@ -0,0 +1,118 @@
|
|||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
const configVariables = [
|
||||
{
|
||||
key: "setupFinished",
|
||||
type: "boolean",
|
||||
default: "false",
|
||||
secret: false,
|
||||
locked: true
|
||||
},
|
||||
{
|
||||
key: "appUrl",
|
||||
type: "string",
|
||||
default: "http://localhost:3000",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "showHomePage",
|
||||
type: "boolean",
|
||||
default: "true",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "allowRegistration",
|
||||
type: "boolean",
|
||||
default: "true",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "allowUnauthenticatedShares",
|
||||
type: "boolean",
|
||||
default: "false",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "maxFileSize",
|
||||
type: "number",
|
||||
default: "1000000000",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "jwtSecret",
|
||||
type: "string",
|
||||
default: "long-random-string",
|
||||
locked: true
|
||||
},
|
||||
{
|
||||
key: "emailRecipientsEnabled",
|
||||
type: "boolean",
|
||||
default: "false",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "smtpHost",
|
||||
type: "string",
|
||||
default: "",
|
||||
},
|
||||
{
|
||||
key: "smtpPort",
|
||||
type: "number",
|
||||
default: "",
|
||||
},
|
||||
{
|
||||
key: "smtpEmail",
|
||||
type: "string",
|
||||
default: "",
|
||||
},
|
||||
{
|
||||
key: "smtpPassword",
|
||||
type: "string",
|
||||
default: "",
|
||||
},
|
||||
];
|
||||
|
||||
async function main() {
|
||||
for (const variable of configVariables) {
|
||||
const existingConfigVariable = await prisma.config.findUnique({
|
||||
where: { key: variable.key },
|
||||
});
|
||||
|
||||
// Create a new config variable if it doesn't exist
|
||||
if (!existingConfigVariable) {
|
||||
await prisma.config.create({
|
||||
data: variable,
|
||||
});
|
||||
} else {
|
||||
// Update the config variable if the default value has changed
|
||||
if (existingConfigVariable.default != variable.default) {
|
||||
await prisma.config.update({
|
||||
where: { key: variable.key },
|
||||
data: { default: variable.default },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the config variable if it doesn't exist anymore
|
||||
const configVariablesFromDatabase = await prisma.config.findMany();
|
||||
|
||||
for (const configVariableFromDatabase of configVariablesFromDatabase) {
|
||||
if (!configVariables.find((v) => v.key == configVariableFromDatabase.key)) {
|
||||
await prisma.config.delete({
|
||||
where: { key: configVariableFromDatabase.key },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
main()
|
||||
.then(async () => {
|
||||
await prisma.$disconnect();
|
||||
})
|
||||
.catch(async (e) => {
|
||||
console.error(e);
|
||||
await prisma.$disconnect();
|
||||
process.exit(1);
|
||||
});
|
|
@ -1,11 +1,14 @@
|
|||
import { Module } from "@nestjs/common";
|
||||
import { ConfigModule } from "@nestjs/config";
|
||||
|
||||
import { ScheduleModule } from "@nestjs/schedule";
|
||||
import { AuthModule } from "./auth/auth.module";
|
||||
import { JobsService } from "./jobs/jobs.service";
|
||||
|
||||
import { APP_GUARD } from "@nestjs/core";
|
||||
import { ThrottlerGuard, ThrottlerModule } from "@nestjs/throttler";
|
||||
import { ConfigModule } from "./config/config.module";
|
||||
import { ConfigService } from "./config/config.service";
|
||||
import { EmailModule } from "./email/email.module";
|
||||
import { FileController } from "./file/file.controller";
|
||||
import { FileModule } from "./file/file.module";
|
||||
import { PrismaModule } from "./prisma/prisma.module";
|
||||
|
@ -13,7 +16,6 @@ import { PrismaService } from "./prisma/prisma.service";
|
|||
import { ShareController } from "./share/share.controller";
|
||||
import { ShareModule } from "./share/share.module";
|
||||
import { UserController } from "./user/user.controller";
|
||||
import { EmailModule } from "./email/email.module";
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
@ -22,7 +24,7 @@ import { EmailModule } from "./email/email.module";
|
|||
FileModule,
|
||||
EmailModule,
|
||||
PrismaModule,
|
||||
ConfigModule.forRoot({ isGlobal: true }),
|
||||
ConfigModule,
|
||||
ThrottlerModule.forRoot({
|
||||
ttl: 60,
|
||||
limit: 100,
|
||||
|
@ -30,8 +32,16 @@ import { EmailModule } from "./email/email.module";
|
|||
ScheduleModule.forRoot(),
|
||||
],
|
||||
providers: [
|
||||
ConfigService,
|
||||
PrismaService,
|
||||
JobsService,
|
||||
{
|
||||
provide: "CONFIG_VARIABLES",
|
||||
useFactory: async (prisma: PrismaService) => {
|
||||
return await prisma.config.findMany();
|
||||
},
|
||||
inject: [PrismaService],
|
||||
},
|
||||
{
|
||||
provide: APP_GUARD,
|
||||
useClass: ThrottlerGuard,
|
||||
|
|
|
@ -5,8 +5,8 @@ import {
|
|||
HttpCode,
|
||||
Post,
|
||||
} from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { Throttle } from "@nestjs/throttler";
|
||||
import { ConfigService } from "src/config/config.service";
|
||||
import { AuthService } from "./auth.service";
|
||||
import { AuthRegisterDTO } from "./dto/authRegister.dto";
|
||||
import { AuthSignInDTO } from "./dto/authSignIn.dto";
|
||||
|
@ -21,8 +21,8 @@ export class AuthController {
|
|||
|
||||
@Throttle(10, 5 * 60)
|
||||
@Post("signUp")
|
||||
signUp(@Body() dto: AuthRegisterDTO) {
|
||||
if (this.config.get("ALLOW_REGISTRATION") == "false")
|
||||
async signUp(@Body() dto: AuthRegisterDTO) {
|
||||
if (!this.config.get("allowRegistration"))
|
||||
throw new ForbiddenException("Registration is not allowed");
|
||||
return this.authService.signUp(dto);
|
||||
}
|
||||
|
|
|
@ -3,12 +3,12 @@ import {
|
|||
Injectable,
|
||||
UnauthorizedException,
|
||||
} from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { JwtService } from "@nestjs/jwt";
|
||||
import { User } from "@prisma/client";
|
||||
import { PrismaClientKnownRequestError } from "@prisma/client/runtime";
|
||||
import * as argon from "argon2";
|
||||
import * as moment from "moment";
|
||||
import { ConfigService } from "src/config/config.service";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { AuthRegisterDTO } from "./dto/authRegister.dto";
|
||||
import { AuthSignInDTO } from "./dto/authSignIn.dto";
|
||||
|
@ -68,7 +68,7 @@ export class AuthService {
|
|||
},
|
||||
{
|
||||
expiresIn: "15min",
|
||||
secret: this.config.get("JWT_SECRET"),
|
||||
secret: this.config.get("jwtSecret"),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
import { ExecutionContext } from "@nestjs/common";
|
||||
import { ExecutionContext, Injectable } from "@nestjs/common";
|
||||
import { AuthGuard } from "@nestjs/passport";
|
||||
import { ConfigService } from "src/config/config.service";
|
||||
|
||||
@Injectable()
|
||||
export class JwtGuard extends AuthGuard("jwt") {
|
||||
constructor() {
|
||||
constructor(private config: ConfigService) {
|
||||
super();
|
||||
}
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
try {
|
||||
return (await super.canActivate(context)) as boolean;
|
||||
} catch {
|
||||
return process.env.ALLOW_UNAUTHENTICATED_SHARES == "true";
|
||||
return this.config.get("allowUnauthenticatedShares");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,27 @@
|
|||
import { Injectable } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { PassportStrategy } from "@nestjs/passport";
|
||||
import { User } from "@prisma/client";
|
||||
import { ExtractJwt, Strategy } from "passport-jwt";
|
||||
import { ConfigService } from "src/config/config.service";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
|
||||
@Injectable()
|
||||
export class JwtStrategy extends PassportStrategy(Strategy) {
|
||||
constructor(config: ConfigService, private prisma: PrismaService) {
|
||||
console.log(config.get("jwtSecret"));
|
||||
config.get("jwtSecret");
|
||||
super({
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
secretOrKey: config.get("JWT_SECRET"),
|
||||
secretOrKey: config.get("jwtSecret"),
|
||||
});
|
||||
}
|
||||
|
||||
async validate(payload: { sub: string }) {
|
||||
console.log("vali");
|
||||
const user: User = await this.prisma.user.findUnique({
|
||||
where: { id: payload.sub },
|
||||
});
|
||||
|
||||
console.log({ user });
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
|
18
backend/src/config/config.controller.ts
Normal file
18
backend/src/config/config.controller.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { Controller, Get } from "@nestjs/common";
|
||||
import { ConfigService } from "./config.service";
|
||||
import { ConfigDTO } from "./dto/config.dto";
|
||||
|
||||
@Controller("configs")
|
||||
export class ConfigController {
|
||||
constructor(private configService: ConfigService) {}
|
||||
|
||||
@Get()
|
||||
async list() {
|
||||
return new ConfigDTO().fromList(await this.configService.list())
|
||||
}
|
||||
|
||||
@Get("admin")
|
||||
async listForAdmin() {
|
||||
return await this.configService.listForAdmin();
|
||||
}
|
||||
}
|
21
backend/src/config/config.module.ts
Normal file
21
backend/src/config/config.module.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { Global, Module } from "@nestjs/common";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { ConfigController } from "./config.controller";
|
||||
import { ConfigService } from "./config.service";
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [
|
||||
{
|
||||
provide: "CONFIG_VARIABLES",
|
||||
useFactory: async (prisma: PrismaService) => {
|
||||
return await prisma.config.findMany();
|
||||
},
|
||||
inject: [PrismaService],
|
||||
},
|
||||
ConfigService,
|
||||
],
|
||||
controllers: [ConfigController],
|
||||
exports: [ConfigService],
|
||||
})
|
||||
export class ConfigModule {}
|
41
backend/src/config/config.service.ts
Normal file
41
backend/src/config/config.service.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import { Inject, Injectable } from "@nestjs/common";
|
||||
import { Config } from "@prisma/client";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
|
||||
@Injectable()
|
||||
export class ConfigService {
|
||||
constructor(
|
||||
@Inject("CONFIG_VARIABLES") private configVariables: Config[],
|
||||
private prisma: PrismaService
|
||||
) {}
|
||||
|
||||
get(key: string): any {
|
||||
const configVariable = this.configVariables.filter(
|
||||
(variable) => variable.key == key
|
||||
)[0];
|
||||
|
||||
if (!configVariable) throw new Error(`Config variable ${key} not found`);
|
||||
|
||||
const value = configVariable.value ?? configVariable.default;
|
||||
|
||||
if (configVariable.type == "number") return parseInt(value);
|
||||
if (configVariable.type == "boolean") return value == "true";
|
||||
if (configVariable.type == "string") return value;
|
||||
}
|
||||
|
||||
async listForAdmin() {
|
||||
return await this.prisma.config.findMany();
|
||||
}
|
||||
|
||||
async list() {
|
||||
const configVariables = await this.prisma.config.findMany({
|
||||
where: { secret: { equals: false } },
|
||||
});
|
||||
|
||||
return configVariables.map((configVariable) => {
|
||||
if (!configVariable.value) configVariable.value = configVariable.default;
|
||||
|
||||
return configVariable;
|
||||
});
|
||||
}
|
||||
}
|
18
backend/src/config/dto/config.dto.ts
Normal file
18
backend/src/config/dto/config.dto.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { Expose, plainToClass } from "class-transformer";
|
||||
|
||||
export class ConfigDTO {
|
||||
@Expose()
|
||||
key: string;
|
||||
|
||||
@Expose()
|
||||
value: string;
|
||||
|
||||
@Expose()
|
||||
type: string;
|
||||
|
||||
fromList(partial: Partial<ConfigDTO>[]) {
|
||||
return partial.map((part) =>
|
||||
plainToClass(ConfigDTO, part, { excludeExtraneousValues: true })
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,34 +1,35 @@
|
|||
import { Injectable, InternalServerErrorException } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { User } from "@prisma/client";
|
||||
import * as nodemailer from "nodemailer";
|
||||
import { ConfigService } from "src/config/config.service";
|
||||
|
||||
@Injectable()
|
||||
export class EmailService {
|
||||
constructor(private config: ConfigService) {}
|
||||
|
||||
// create reusable transporter object using the default SMTP transport
|
||||
transporter = nodemailer.createTransport({
|
||||
host: this.config.get("SMTP_HOST"),
|
||||
port: parseInt(this.config.get("SMTP_PORT")),
|
||||
secure: parseInt(this.config.get("SMTP_PORT")) == 465,
|
||||
auth: {
|
||||
user: this.config.get("SMTP_EMAIL"),
|
||||
pass: this.config.get("SMTP_PASSWORD"),
|
||||
},
|
||||
});
|
||||
|
||||
async sendMail(recipientEmail: string, shareId: string, creator: User) {
|
||||
if (this.config.get("EMAIL_RECIPIENTS_ENABLED") == "false")
|
||||
// create reusable transporter object using the default SMTP transport
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: this.config.get("SMTP_HOST"),
|
||||
port: parseInt(this.config.get("SMTP_PORT")),
|
||||
secure: parseInt(this.config.get("SMTP_PORT")) == 465,
|
||||
auth: {
|
||||
user: this.config.get("SMTP_EMAIL"),
|
||||
pass: this.config.get("SMTP_PASSWORD"),
|
||||
},
|
||||
});
|
||||
|
||||
if (!this.config.get("emailRecepientsEnabled"))
|
||||
throw new InternalServerErrorException("Email service disabled");
|
||||
|
||||
const shareUrl = `${this.config.get("APP_URL")}/share/${shareId}`;
|
||||
const creatorIdentifier = creator ?
|
||||
creator.firstName && creator.lastName
|
||||
const creatorIdentifier = creator
|
||||
? creator.firstName && creator.lastName
|
||||
? `${creator.firstName} ${creator.lastName}`
|
||||
: creator.email : "A Pingvin Share user";
|
||||
: creator.email
|
||||
: "A Pingvin Share user";
|
||||
|
||||
await this.transporter.sendMail({
|
||||
await transporter.sendMail({
|
||||
from: `"Pingvin Share" <${this.config.get("SMTP_EMAIL")}>`,
|
||||
to: recipientEmail,
|
||||
subject: "Files shared with you",
|
||||
|
|
|
@ -2,7 +2,6 @@ import {
|
|||
Controller,
|
||||
Get,
|
||||
Param,
|
||||
ParseFilePipeBuilder,
|
||||
Post,
|
||||
Res,
|
||||
StreamableFile,
|
||||
|
@ -19,6 +18,7 @@ import { ShareDTO } from "src/share/dto/share.dto";
|
|||
import { ShareOwnerGuard } from "src/share/guard/shareOwner.guard";
|
||||
import { ShareSecurityGuard } from "src/share/guard/shareSecurity.guard";
|
||||
import { FileService } from "./file.service";
|
||||
import { FileValidationPipe } from "./pipe/fileValidation.pipe";
|
||||
|
||||
@Controller("shares/:shareId/files")
|
||||
export class FileController {
|
||||
|
@ -32,13 +32,7 @@ export class FileController {
|
|||
})
|
||||
)
|
||||
async create(
|
||||
@UploadedFile(
|
||||
new ParseFilePipeBuilder()
|
||||
.addMaxSizeValidator({
|
||||
maxSize: parseInt(process.env.MAX_FILE_SIZE),
|
||||
})
|
||||
.build()
|
||||
)
|
||||
@UploadedFile(FileValidationPipe)
|
||||
file: Express.Multer.File,
|
||||
@Param("shareId") shareId: string
|
||||
) {
|
||||
|
|
|
@ -3,11 +3,12 @@ import { JwtModule } from "@nestjs/jwt";
|
|||
import { ShareModule } from "src/share/share.module";
|
||||
import { FileController } from "./file.controller";
|
||||
import { FileService } from "./file.service";
|
||||
import { FileValidationPipe } from "./pipe/fileValidation.pipe";
|
||||
|
||||
@Module({
|
||||
imports: [JwtModule.register({}), ShareModule],
|
||||
controllers: [FileController],
|
||||
providers: [FileService],
|
||||
providers: [FileService, FileValidationPipe],
|
||||
exports: [FileService],
|
||||
})
|
||||
export class FileModule {}
|
||||
|
|
|
@ -3,11 +3,11 @@ import {
|
|||
Injectable,
|
||||
NotFoundException,
|
||||
} from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { JwtService } from "@nestjs/jwt";
|
||||
import { randomUUID } from "crypto";
|
||||
import * as fs from "fs";
|
||||
import * as mime from "mime-types";
|
||||
import { ConfigService } from "src/config/config.service";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
|
||||
@Injectable()
|
||||
|
@ -78,14 +78,14 @@ export class FileService {
|
|||
return fs.createReadStream(`./data/uploads/shares/${shareId}/archive.zip`);
|
||||
}
|
||||
|
||||
getFileDownloadUrl(shareId: string, fileId: string) {
|
||||
async getFileDownloadUrl(shareId: string, fileId: string) {
|
||||
const downloadToken = this.generateFileDownloadToken(shareId, fileId);
|
||||
return `${this.config.get(
|
||||
"APP_URL"
|
||||
)}/api/shares/${shareId}/files/${fileId}?token=${downloadToken}`;
|
||||
}
|
||||
|
||||
generateFileDownloadToken(shareId: string, fileId: string) {
|
||||
async generateFileDownloadToken(shareId: string, fileId: string) {
|
||||
if (fileId == "zip") fileId = undefined;
|
||||
|
||||
return this.jwtService.sign(
|
||||
|
@ -95,15 +95,15 @@ export class FileService {
|
|||
},
|
||||
{
|
||||
expiresIn: "10min",
|
||||
secret: this.config.get("JWT_SECRET"),
|
||||
secret: this.config.get("jwtSecret"),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
verifyFileDownloadToken(shareId: string, token: string) {
|
||||
async verifyFileDownloadToken(shareId: string, token: string) {
|
||||
try {
|
||||
const claims = this.jwtService.verify(token, {
|
||||
secret: this.config.get("JWT_SECRET"),
|
||||
secret: this.config.get("jwtSecret"),
|
||||
});
|
||||
return claims.shareId == shareId;
|
||||
} catch {
|
||||
|
|
13
backend/src/file/pipe/fileValidation.pipe.ts
Normal file
13
backend/src/file/pipe/fileValidation.pipe.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { ArgumentMetadata, Injectable, PipeTransform } from "@nestjs/common";
|
||||
import { ConfigService } from "src/config/config.service";
|
||||
|
||||
@Injectable()
|
||||
export class FileValidationPipe implements PipeTransform {
|
||||
constructor(private config: ConfigService) {}
|
||||
async transform(value: any, metadata: ArgumentMetadata) {
|
||||
// "value" is an object containing the file's attributes and metadata
|
||||
console.log(this.config.get("maxFileSize"));
|
||||
const oneKb = 1000;
|
||||
return value.size < oneKb;
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ import { PrismaClient } from "@prisma/client";
|
|||
|
||||
@Injectable()
|
||||
export class PrismaService extends PrismaClient {
|
||||
constructor(config: ConfigService) {
|
||||
constructor() {
|
||||
super({
|
||||
datasources: {
|
||||
db: {
|
||||
|
|
|
@ -4,13 +4,13 @@ import {
|
|||
Injectable,
|
||||
NotFoundException,
|
||||
} from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { JwtService } from "@nestjs/jwt";
|
||||
import { Share, User } from "@prisma/client";
|
||||
import * as archiver from "archiver";
|
||||
import * as argon from "argon2";
|
||||
import * as fs from "fs";
|
||||
import * as moment from "moment";
|
||||
import { ConfigService } from "src/config/config.service";
|
||||
import { EmailService } from "src/email/email.service";
|
||||
import { FileService } from "src/file/file.service";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
|
@ -235,7 +235,7 @@ export class ShareService {
|
|||
},
|
||||
{
|
||||
expiresIn: moment(expiration).diff(new Date(), "seconds") + "s",
|
||||
secret: this.config.get("JWT_SECRET"),
|
||||
secret: this.config.get("jwtSecret"),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ export class ShareService {
|
|||
|
||||
try {
|
||||
const claims = this.jwtService.verify(token, {
|
||||
secret: this.config.get("JWT_SECRET"),
|
||||
secret: this.config.get("jwtSecret"),
|
||||
// Ignore expiration if expiration is 0
|
||||
ignoreExpiration: moment(expiration).isSame(0),
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user