move session to module
This commit is contained in:
parent
ff431c958c
commit
9c7820dc94
50
src/main.ts
50
src/main.ts
@ -1,9 +1,6 @@
|
|||||||
import { NestFactory } from '@nestjs/core';
|
import { NestFactory } from '@nestjs/core';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
import * as dotenv from 'dotenv';
|
import * as dotenv from 'dotenv';
|
||||||
import * as session from 'express-session';
|
|
||||||
import * as connectRedis from 'connect-redis';
|
|
||||||
import * as redis from 'redis';
|
|
||||||
import * as cookieParser from 'cookie-parser';
|
import * as cookieParser from 'cookie-parser';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||||
@ -11,6 +8,7 @@ import { NestExpressApplication } from '@nestjs/platform-express';
|
|||||||
import { AdminApiModule } from './modules/api/admin/admin.module';
|
import { AdminApiModule } from './modules/api/admin/admin.module';
|
||||||
import { OAuth2RouterModule } from './modules/static-front-end/oauth2-router/oauth2-router.module';
|
import { OAuth2RouterModule } from './modules/static-front-end/oauth2-router/oauth2-router.module';
|
||||||
import { ConfigurationService } from './modules/config/config.service';
|
import { ConfigurationService } from './modules/config/config.service';
|
||||||
|
import { ApiModule } from './modules/api/api.module';
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
@ -23,20 +21,33 @@ async function bootstrap() {
|
|||||||
.setTitle('Icy Network Authentication Server')
|
.setTitle('Icy Network Authentication Server')
|
||||||
.setDescription('Central authentication and management server')
|
.setDescription('Central authentication and management server')
|
||||||
.setVersion('1.0')
|
.setVersion('1.0')
|
||||||
|
.addTag('api')
|
||||||
.addTag('admin')
|
.addTag('admin')
|
||||||
.addTag('oauth2')
|
.addTag('oauth2')
|
||||||
|
.addBearerAuth()
|
||||||
|
.addOAuth2({
|
||||||
|
type: 'oauth2',
|
||||||
|
flows: {
|
||||||
|
authorizationCode: {
|
||||||
|
authorizationUrl: '/oauth2/authorize',
|
||||||
|
tokenUrl: '/oauth2/token',
|
||||||
|
scopes: {
|
||||||
|
email: 'Access email address',
|
||||||
|
image: 'Access profile picture',
|
||||||
|
privileges: 'List of user privileges',
|
||||||
|
management: 'Administrative access',
|
||||||
|
openid: 'Get ID token',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
.build();
|
.build();
|
||||||
const document = SwaggerModule.createDocument(app, docBuilder, {
|
|
||||||
include: [AdminApiModule, OAuth2RouterModule],
|
|
||||||
});
|
|
||||||
SwaggerModule.setup('api', app, document);
|
|
||||||
|
|
||||||
const RedisStore = connectRedis(session);
|
const document = SwaggerModule.createDocument(app, docBuilder, {
|
||||||
const redisClient = redis.createClient({
|
include: [ApiModule, AdminApiModule, OAuth2RouterModule],
|
||||||
url: process.env.REDIS_URL || 'redis://localhost:6379',
|
|
||||||
legacyMode: true,
|
|
||||||
});
|
});
|
||||||
redisClient.connect();
|
|
||||||
|
SwaggerModule.setup('api/openapi', app, document);
|
||||||
|
|
||||||
// app.use(express.urlencoded());
|
// app.use(express.urlencoded());
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
@ -47,21 +58,6 @@ async function bootstrap() {
|
|||||||
app.disable('x-powered-by');
|
app.disable('x-powered-by');
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use(
|
|
||||||
/\/((?!api).)*/,
|
|
||||||
session({
|
|
||||||
name: config.get<string>('app.session_name'),
|
|
||||||
secret: config.get<string>('app.session_secret'),
|
|
||||||
resave: true,
|
|
||||||
saveUninitialized: false,
|
|
||||||
store: new RedisStore({ client: redisClient }),
|
|
||||||
cookie: {
|
|
||||||
sameSite: 'strict',
|
|
||||||
secure: process.env.NODE_ENV === 'production',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
app.useStaticAssets(join(__dirname, '..', 'public'), {
|
app.useStaticAssets(join(__dirname, '..', 'public'), {
|
||||||
prefix: '/public/',
|
prefix: '/public/',
|
||||||
});
|
});
|
||||||
|
@ -3,7 +3,6 @@ import { MulterModule } from '@nestjs/platform-express';
|
|||||||
import * as multer from 'multer';
|
import * as multer from 'multer';
|
||||||
import * as mime from 'mime-types';
|
import * as mime from 'mime-types';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { ConfigurationService } from '../../config/config.service';
|
|
||||||
import { OAuth2Module } from 'src/modules/oauth2/oauth2.module';
|
import { OAuth2Module } from 'src/modules/oauth2/oauth2.module';
|
||||||
import { ObjectsModule } from 'src/modules/objects/objects.module';
|
import { ObjectsModule } from 'src/modules/objects/objects.module';
|
||||||
import { OAuth2AdminController } from './oauth2-admin.controller';
|
import { OAuth2AdminController } from './oauth2-admin.controller';
|
||||||
@ -23,37 +22,34 @@ import { AuditAdminController } from './audit-admin.controller';
|
|||||||
imports: [
|
imports: [
|
||||||
ObjectsModule,
|
ObjectsModule,
|
||||||
OAuth2Module,
|
OAuth2Module,
|
||||||
|
ConfigurationModule,
|
||||||
MulterModule.registerAsync({
|
MulterModule.registerAsync({
|
||||||
imports: [ConfigurationModule],
|
useFactory: async () => ({
|
||||||
useFactory: async () => {
|
storage: multer.diskStorage({
|
||||||
return {
|
destination: (req, file, cb) => {
|
||||||
storage: multer.diskStorage({
|
cb(null, join(__dirname, '..', '..', '..', '..', 'uploads'));
|
||||||
destination: (req, file, cb) => {
|
|
||||||
cb(null, join(__dirname, '..', '..', '..', '..', 'uploads'));
|
|
||||||
},
|
|
||||||
filename: (req, file, cb) => {
|
|
||||||
const hashTruncate = req.user.uuid.split('-')[0];
|
|
||||||
const timestamp = Math.floor(Date.now() / 1000);
|
|
||||||
const ext = mime.extension(file.mimetype);
|
|
||||||
cb(null, `app-${hashTruncate}-${timestamp}.${ext}`);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
limits: {
|
|
||||||
fileSize: 1.049e7, // 10 MiB
|
|
||||||
},
|
},
|
||||||
fileFilter: (req, file, cb) => {
|
filename: (req, file, cb) => {
|
||||||
if (
|
const hashTruncate = req.user.uuid.split('-')[0];
|
||||||
!file.mimetype.startsWith('image/') ||
|
const timestamp = Math.floor(Date.now() / 1000);
|
||||||
file.mimetype.includes('svg')
|
const ext = mime.extension(file.mimetype);
|
||||||
) {
|
cb(null, `app-${hashTruncate}-${timestamp}.${ext}`);
|
||||||
return cb(new Error('Invalid file type.'), false);
|
},
|
||||||
}
|
}),
|
||||||
|
limits: {
|
||||||
|
fileSize: 1.049e7, // 10 MiB
|
||||||
|
},
|
||||||
|
fileFilter: (req, file, cb) => {
|
||||||
|
if (
|
||||||
|
!file.mimetype.startsWith('image/') ||
|
||||||
|
file.mimetype.includes('svg')
|
||||||
|
) {
|
||||||
|
return cb(new Error('Invalid file type.'), false);
|
||||||
|
}
|
||||||
|
|
||||||
cb(null, true);
|
cb(null, true);
|
||||||
},
|
},
|
||||||
};
|
}),
|
||||||
},
|
|
||||||
inject: [ConfigurationService],
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
providers: [AdminService],
|
providers: [AdminService],
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Controller, Get, Query, UseGuards } from '@nestjs/common';
|
import { Controller, Get, Query, UseGuards } from '@nestjs/common';
|
||||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
import { ApiBearerAuth, ApiOAuth2, ApiTags } from '@nestjs/swagger';
|
||||||
import { Privileges } from 'src/decorators/privileges.decorator';
|
import { Privileges } from 'src/decorators/privileges.decorator';
|
||||||
import { Scopes } from 'src/decorators/scopes.decorator';
|
import { Scopes } from 'src/decorators/scopes.decorator';
|
||||||
import { OAuth2Guard } from 'src/guards/oauth2.guard';
|
import { OAuth2Guard } from 'src/guards/oauth2.guard';
|
||||||
@ -14,6 +14,7 @@ import { PageOptions } from 'src/types/pagination.interfaces';
|
|||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ApiTags('admin')
|
@ApiTags('admin')
|
||||||
|
@ApiOAuth2(['management'])
|
||||||
@Controller('/api/admin/audit')
|
@Controller('/api/admin/audit')
|
||||||
@UseGuards(OAuth2Guard, PrivilegesGuard, ScopesGuard)
|
@UseGuards(OAuth2Guard, PrivilegesGuard, ScopesGuard)
|
||||||
export class AuditAdminController {
|
export class AuditAdminController {
|
||||||
|
@ -15,7 +15,7 @@ import {
|
|||||||
UseGuards,
|
UseGuards,
|
||||||
UseInterceptors,
|
UseInterceptors,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
import { ApiBearerAuth, ApiOAuth2, ApiTags } from '@nestjs/swagger';
|
||||||
import { FileInterceptor } from '@nestjs/platform-express';
|
import { FileInterceptor } from '@nestjs/platform-express';
|
||||||
import { unlink } from 'fs/promises';
|
import { unlink } from 'fs/promises';
|
||||||
import { Privileges } from 'src/decorators/privileges.decorator';
|
import { Privileges } from 'src/decorators/privileges.decorator';
|
||||||
@ -57,6 +57,7 @@ const REQUIRED_CLIENT_FIELDS = ['title', 'grants', 'activated'];
|
|||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ApiTags('admin')
|
@ApiTags('admin')
|
||||||
|
@ApiOAuth2(['management'])
|
||||||
@Controller('/api/admin/oauth2')
|
@Controller('/api/admin/oauth2')
|
||||||
@UseGuards(OAuth2Guard, PrivilegesGuard, ScopesGuard)
|
@UseGuards(OAuth2Guard, PrivilegesGuard, ScopesGuard)
|
||||||
export class OAuth2AdminController {
|
export class OAuth2AdminController {
|
||||||
|
@ -6,7 +6,7 @@ import {
|
|||||||
Post,
|
Post,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
import { ApiBearerAuth, ApiOAuth2, ApiTags } from '@nestjs/swagger';
|
||||||
import { Privileges } from 'src/decorators/privileges.decorator';
|
import { Privileges } from 'src/decorators/privileges.decorator';
|
||||||
import { Scopes } from 'src/decorators/scopes.decorator';
|
import { Scopes } from 'src/decorators/scopes.decorator';
|
||||||
import { OAuth2Guard } from 'src/guards/oauth2.guard';
|
import { OAuth2Guard } from 'src/guards/oauth2.guard';
|
||||||
@ -16,6 +16,7 @@ import { PrivilegeService } from 'src/modules/objects/privilege/privilege.servic
|
|||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ApiTags('admin')
|
@ApiTags('admin')
|
||||||
|
@ApiOAuth2(['management'])
|
||||||
@Controller('/api/admin/privileges')
|
@Controller('/api/admin/privileges')
|
||||||
@UseGuards(OAuth2Guard, PrivilegesGuard, ScopesGuard)
|
@UseGuards(OAuth2Guard, PrivilegesGuard, ScopesGuard)
|
||||||
export class PrivilegeAdminController {
|
export class PrivilegeAdminController {
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
Query,
|
Query,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
import { ApiBearerAuth, ApiOAuth2, ApiTags } from '@nestjs/swagger';
|
||||||
import { Privileges } from 'src/decorators/privileges.decorator';
|
import { Privileges } from 'src/decorators/privileges.decorator';
|
||||||
import { Scopes } from 'src/decorators/scopes.decorator';
|
import { Scopes } from 'src/decorators/scopes.decorator';
|
||||||
import { OAuth2Guard } from 'src/guards/oauth2.guard';
|
import { OAuth2Guard } from 'src/guards/oauth2.guard';
|
||||||
@ -29,6 +29,7 @@ const RELATIONS = ['picture', 'privileges'];
|
|||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ApiTags('admin')
|
@ApiTags('admin')
|
||||||
|
@ApiOAuth2(['management'])
|
||||||
@Controller('/api/admin/users')
|
@Controller('/api/admin/users')
|
||||||
@UseGuards(OAuth2Guard, PrivilegesGuard, ScopesGuard)
|
@UseGuards(OAuth2Guard, PrivilegesGuard, ScopesGuard)
|
||||||
export class UserAdminController {
|
export class UserAdminController {
|
||||||
|
@ -19,7 +19,9 @@ import { OAuth2ClientService } from '../objects/oauth2-client/oauth2-client.serv
|
|||||||
import { User } from '../objects/user/user.entity';
|
import { User } from '../objects/user/user.entity';
|
||||||
import { FormUtilityService } from '../utility/services/form-utility.service';
|
import { FormUtilityService } from '../utility/services/form-utility.service';
|
||||||
import { UploadService } from '../objects/upload/upload.service';
|
import { UploadService } from '../objects/upload/upload.service';
|
||||||
|
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
@ApiTags('api')
|
||||||
@Controller({
|
@Controller({
|
||||||
path: '/api',
|
path: '/api',
|
||||||
})
|
})
|
||||||
@ -31,7 +33,22 @@ export class ApiController {
|
|||||||
private _upload: UploadService,
|
private _upload: UploadService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
welcome() {
|
||||||
|
return {
|
||||||
|
welcome: { to: 'Icy Network!' },
|
||||||
|
api: true,
|
||||||
|
oauth2: {
|
||||||
|
authorizationUrl: '/oauth2/authorize',
|
||||||
|
tokenUrl: '/oauth2/token',
|
||||||
|
userUrl: '/api/user',
|
||||||
|
},
|
||||||
|
swaggerdoc: '/api/openapi',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Get('/user')
|
@Get('/user')
|
||||||
|
@ApiBearerAuth()
|
||||||
@UseGuards(OAuth2Guard)
|
@UseGuards(OAuth2Guard)
|
||||||
getCurrentUser(@CurrentUser() user: User, @Scope() scopeStr: string) {
|
getCurrentUser(@CurrentUser() user: User, @Scope() scopeStr: string) {
|
||||||
const scope = scopeStr.split(' ');
|
const scope = scopeStr.split(' ');
|
||||||
@ -73,6 +90,7 @@ export class ApiController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Get('/client')
|
@Get('/client')
|
||||||
|
@ApiBearerAuth()
|
||||||
@UseGuards(OAuth2Guard, ScopesGuard)
|
@UseGuards(OAuth2Guard, ScopesGuard)
|
||||||
async getCurrentClient(@Bearer() token: OAuth2AccessToken) {
|
async getCurrentClient(@Bearer() token: OAuth2AccessToken) {
|
||||||
const client = await this._oaClient.getById(token.client_id, [
|
const client = await this._oaClient.getById(token.client_id, [
|
||||||
@ -90,6 +108,7 @@ export class ApiController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Get('/upload/:file')
|
@Get('/upload/:file')
|
||||||
|
@ApiBearerAuth()
|
||||||
@UseGuards(OAuth2Guard)
|
@UseGuards(OAuth2Guard)
|
||||||
async sendFile(@Param('file') fileName: string) {
|
async sendFile(@Param('file') fileName: string) {
|
||||||
const cleanFile = decodeURI(fileName).replace(/(\&(.*))/, '');
|
const cleanFile = decodeURI(fileName).replace(/(\&(.*))/, '');
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
import {
|
import { Inject, MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
MiddlewareConsumer,
|
import { RequestHandler } from 'express';
|
||||||
Module,
|
|
||||||
NestModule,
|
|
||||||
RequestMethod,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
||||||
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
||||||
import { UserMiddleware } from 'src/middleware/user.middleware';
|
import { UserMiddleware } from 'src/middleware/user.middleware';
|
||||||
@ -11,19 +7,25 @@ import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware'
|
|||||||
import { AuditModule } from 'src/modules/objects/audit/audit.module';
|
import { AuditModule } from 'src/modules/objects/audit/audit.module';
|
||||||
import { UserTokenModule } from 'src/modules/objects/user-token/user-token.module';
|
import { UserTokenModule } from 'src/modules/objects/user-token/user-token.module';
|
||||||
import { UserModule } from 'src/modules/objects/user/user.module';
|
import { UserModule } from 'src/modules/objects/user/user.module';
|
||||||
|
import { SessionModule } from '../session/session.module';
|
||||||
import { LoginController } from './login.controller';
|
import { LoginController } from './login.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [UserModule, UserTokenModule, AuditModule],
|
imports: [UserModule, UserTokenModule, AuditModule, SessionModule],
|
||||||
controllers: [LoginController],
|
controllers: [LoginController],
|
||||||
})
|
})
|
||||||
export class LoginModule implements NestModule {
|
export class LoginModule implements NestModule {
|
||||||
configure(consumer: MiddlewareConsumer) {
|
constructor(@Inject('SESSION') private _session: RequestHandler) {}
|
||||||
consumer.apply(CSRFMiddleware, UserMiddleware).forRoutes(LoginController);
|
|
||||||
consumer
|
|
||||||
.apply(ValidateCSRFMiddleware)
|
|
||||||
.forRoutes({ path: 'login*', method: RequestMethod.POST });
|
|
||||||
|
|
||||||
consumer.apply(FlashMiddleware).forRoutes('login*');
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
consumer
|
||||||
|
.apply(
|
||||||
|
this._session,
|
||||||
|
CSRFMiddleware,
|
||||||
|
FlashMiddleware,
|
||||||
|
UserMiddleware,
|
||||||
|
ValidateCSRFMiddleware,
|
||||||
|
)
|
||||||
|
.forRoutes(LoginController);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
import { Inject, MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
|
import { RequestHandler } from 'express';
|
||||||
// import * as cors from 'cors';
|
// import * as cors from 'cors';
|
||||||
import { AuthMiddleware } from 'src/middleware/auth.middleware';
|
import { AuthMiddleware } from 'src/middleware/auth.middleware';
|
||||||
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
||||||
@ -7,26 +8,31 @@ import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware'
|
|||||||
import { OAuth2Module } from 'src/modules/oauth2/oauth2.module';
|
import { OAuth2Module } from 'src/modules/oauth2/oauth2.module';
|
||||||
import { OAuth2Service } from 'src/modules/oauth2/oauth2.service';
|
import { OAuth2Service } from 'src/modules/oauth2/oauth2.service';
|
||||||
import { UserModule } from 'src/modules/objects/user/user.module';
|
import { UserModule } from 'src/modules/objects/user/user.module';
|
||||||
|
import { SessionModule } from '../session/session.module';
|
||||||
import { OAuth2Controller } from './oauth2-router.controller';
|
import { OAuth2Controller } from './oauth2-router.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [OAuth2Controller],
|
controllers: [OAuth2Controller],
|
||||||
imports: [OAuth2Module, UserModule],
|
imports: [OAuth2Module, UserModule, SessionModule],
|
||||||
})
|
})
|
||||||
export class OAuth2RouterModule implements NestModule {
|
export class OAuth2RouterModule implements NestModule {
|
||||||
// private corsOpts = cors({ origin: true, credentials: true });
|
// private corsOpts = cors({ origin: true, credentials: true });
|
||||||
|
|
||||||
constructor(private _service: OAuth2Service) {}
|
constructor(
|
||||||
|
private _service: OAuth2Service,
|
||||||
|
@Inject('SESSION') private _session: RequestHandler,
|
||||||
|
) {}
|
||||||
|
|
||||||
configure(consumer: MiddlewareConsumer) {
|
configure(consumer: MiddlewareConsumer) {
|
||||||
consumer
|
consumer
|
||||||
.apply(
|
.apply(
|
||||||
|
this._session,
|
||||||
CSRFMiddleware,
|
CSRFMiddleware,
|
||||||
UserMiddleware,
|
UserMiddleware,
|
||||||
AuthMiddleware,
|
AuthMiddleware,
|
||||||
ValidateCSRFMiddleware,
|
ValidateCSRFMiddleware,
|
||||||
)
|
)
|
||||||
.forRoutes('oauth2/authorize');
|
.forRoutes('/oauth2/authorize');
|
||||||
|
|
||||||
// consumer
|
// consumer
|
||||||
// .apply(this.corsOpts)
|
// .apply(this.corsOpts)
|
||||||
|
@ -1,31 +1,30 @@
|
|||||||
import {
|
import { Inject, MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
MiddlewareConsumer,
|
import { RequestHandler } from 'express';
|
||||||
Module,
|
|
||||||
NestModule,
|
|
||||||
RequestMethod,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
||||||
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
||||||
import { UserMiddleware } from 'src/middleware/user.middleware';
|
import { UserMiddleware } from 'src/middleware/user.middleware';
|
||||||
import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware';
|
import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware';
|
||||||
import { AuditModule } from 'src/modules/objects/audit/audit.module';
|
import { AuditModule } from 'src/modules/objects/audit/audit.module';
|
||||||
import { UserModule } from 'src/modules/objects/user/user.module';
|
import { UserModule } from 'src/modules/objects/user/user.module';
|
||||||
|
import { SessionModule } from '../session/session.module';
|
||||||
import { RegisterController } from './register.controller';
|
import { RegisterController } from './register.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [UserModule, AuditModule],
|
imports: [UserModule, AuditModule, SessionModule],
|
||||||
controllers: [RegisterController],
|
controllers: [RegisterController],
|
||||||
})
|
})
|
||||||
export class RegisterModule implements NestModule {
|
export class RegisterModule implements NestModule {
|
||||||
|
constructor(@Inject('SESSION') private _session: RequestHandler) {}
|
||||||
|
|
||||||
configure(consumer: MiddlewareConsumer) {
|
configure(consumer: MiddlewareConsumer) {
|
||||||
consumer
|
consumer
|
||||||
.apply(CSRFMiddleware, UserMiddleware)
|
.apply(
|
||||||
|
this._session,
|
||||||
|
CSRFMiddleware,
|
||||||
|
FlashMiddleware,
|
||||||
|
UserMiddleware,
|
||||||
|
ValidateCSRFMiddleware,
|
||||||
|
)
|
||||||
.forRoutes(RegisterController);
|
.forRoutes(RegisterController);
|
||||||
|
|
||||||
consumer
|
|
||||||
.apply(ValidateCSRFMiddleware)
|
|
||||||
.forRoutes({ path: 'register*', method: RequestMethod.POST });
|
|
||||||
|
|
||||||
consumer.apply(FlashMiddleware).forRoutes('register*');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
src/modules/static-front-end/session/session.module.ts
Normal file
10
src/modules/static-front-end/session/session.module.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ConfigurationModule } from 'src/modules/config/config.module';
|
||||||
|
import { sessionProviders } from './session.providers';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
providers: [...sessionProviders],
|
||||||
|
exports: [...sessionProviders],
|
||||||
|
imports: [ConfigurationModule],
|
||||||
|
})
|
||||||
|
export class SessionModule {}
|
49
src/modules/static-front-end/session/session.providers.ts
Normal file
49
src/modules/static-front-end/session/session.providers.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { FactoryProvider } from '@nestjs/common';
|
||||||
|
import { ConfigurationService } from 'src/modules/config/config.service';
|
||||||
|
|
||||||
|
import * as session from 'express-session';
|
||||||
|
import * as connectRedis from 'connect-redis';
|
||||||
|
import * as redis from 'redis';
|
||||||
|
import { RequestHandler } from 'express';
|
||||||
|
|
||||||
|
export const sessionProviders = [
|
||||||
|
{
|
||||||
|
provide: 'SESSION_STORE',
|
||||||
|
useFactory: async (
|
||||||
|
config: ConfigurationService,
|
||||||
|
): Promise<connectRedis.RedisStore> => {
|
||||||
|
const RedisStore = connectRedis(session);
|
||||||
|
const redisClient = redis.createClient({
|
||||||
|
url:
|
||||||
|
process.env.REDIS_URL ||
|
||||||
|
config.get<string>('app.redis_url') ||
|
||||||
|
'redis://localhost:6379',
|
||||||
|
legacyMode: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await redisClient.connect();
|
||||||
|
|
||||||
|
return new RedisStore({ client: redisClient });
|
||||||
|
},
|
||||||
|
inject: [ConfigurationService],
|
||||||
|
} as FactoryProvider<connectRedis.RedisStore>,
|
||||||
|
{
|
||||||
|
provide: 'SESSION',
|
||||||
|
useFactory: (
|
||||||
|
store: connectRedis.RedisStore,
|
||||||
|
config: ConfigurationService,
|
||||||
|
) =>
|
||||||
|
session({
|
||||||
|
name: config.get<string>('app.session_name'),
|
||||||
|
secret: config.get<string>('app.session_secret'),
|
||||||
|
resave: true,
|
||||||
|
saveUninitialized: false,
|
||||||
|
store,
|
||||||
|
cookie: {
|
||||||
|
sameSite: 'strict',
|
||||||
|
secure: process.env.NODE_ENV === 'production',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
inject: ['SESSION_STORE', ConfigurationService],
|
||||||
|
} as FactoryProvider<RequestHandler>,
|
||||||
|
];
|
@ -1,9 +1,4 @@
|
|||||||
import {
|
import { Inject, MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
MiddlewareConsumer,
|
|
||||||
Module,
|
|
||||||
NestModule,
|
|
||||||
RequestMethod,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { MulterModule } from '@nestjs/platform-express';
|
import { MulterModule } from '@nestjs/platform-express';
|
||||||
import * as multer from 'multer';
|
import * as multer from 'multer';
|
||||||
import * as mime from 'mime-types';
|
import * as mime from 'mime-types';
|
||||||
@ -12,7 +7,6 @@ import { AuthMiddleware } from 'src/middleware/auth.middleware';
|
|||||||
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
||||||
import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware';
|
import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware';
|
||||||
import { ConfigurationModule } from 'src/modules/config/config.module';
|
import { ConfigurationModule } from 'src/modules/config/config.module';
|
||||||
import { ConfigurationService } from 'src/modules/config/config.service';
|
|
||||||
import { UploadModule } from 'src/modules/objects/upload/upload.module';
|
import { UploadModule } from 'src/modules/objects/upload/upload.module';
|
||||||
import { UserModule } from 'src/modules/objects/user/user.module';
|
import { UserModule } from 'src/modules/objects/user/user.module';
|
||||||
import { OAuth2TokenModule } from 'src/modules/objects/oauth2-token/oauth2-token.module';
|
import { OAuth2TokenModule } from 'src/modules/objects/oauth2-token/oauth2-token.module';
|
||||||
@ -24,6 +18,8 @@ import { SettingsService } from './settings.service';
|
|||||||
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
||||||
import { UserMiddleware } from 'src/middleware/user.middleware';
|
import { UserMiddleware } from 'src/middleware/user.middleware';
|
||||||
import { AuditModule } from 'src/modules/objects/audit/audit.module';
|
import { AuditModule } from 'src/modules/objects/audit/audit.module';
|
||||||
|
import { RequestHandler } from 'express';
|
||||||
|
import { SessionModule } from '../session/session.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [SettingsController],
|
controllers: [SettingsController],
|
||||||
@ -32,59 +28,55 @@ import { AuditModule } from 'src/modules/objects/audit/audit.module';
|
|||||||
UploadModule,
|
UploadModule,
|
||||||
UserModule,
|
UserModule,
|
||||||
UserTokenModule,
|
UserTokenModule,
|
||||||
|
SessionModule,
|
||||||
AuditModule,
|
AuditModule,
|
||||||
OAuth2Module,
|
OAuth2Module,
|
||||||
OAuth2ClientModule,
|
OAuth2ClientModule,
|
||||||
OAuth2TokenModule,
|
OAuth2TokenModule,
|
||||||
MulterModule.registerAsync({
|
MulterModule.registerAsync({
|
||||||
imports: [ConfigurationModule],
|
useFactory: async () => ({
|
||||||
useFactory: async (config: ConfigurationService) => {
|
storage: multer.diskStorage({
|
||||||
return {
|
destination: (req, file, cb) => {
|
||||||
storage: multer.diskStorage({
|
cb(null, join(__dirname, '..', '..', '..', '..', 'uploads'));
|
||||||
destination: (req, file, cb) => {
|
|
||||||
cb(null, join(__dirname, '..', '..', '..', '..', 'uploads'));
|
|
||||||
},
|
|
||||||
filename: (req, file, cb) => {
|
|
||||||
const hashTruncate = req.user.uuid.split('-')[0];
|
|
||||||
const timestamp = Math.floor(Date.now() / 1000);
|
|
||||||
const ext = mime.extension(file.mimetype);
|
|
||||||
cb(null, `user-${hashTruncate}-${timestamp}.${ext}`);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
limits: {
|
|
||||||
fileSize: 1.049e7, // 10 MiB
|
|
||||||
},
|
},
|
||||||
fileFilter: (req, file, cb) => {
|
filename: (req, file, cb) => {
|
||||||
if (
|
const hashTruncate = req.user.uuid.split('-')[0];
|
||||||
!file.mimetype.startsWith('image/') ||
|
const timestamp = Math.floor(Date.now() / 1000);
|
||||||
file.mimetype.includes('svg')
|
const ext = mime.extension(file.mimetype);
|
||||||
) {
|
cb(null, `user-${hashTruncate}-${timestamp}.${ext}`);
|
||||||
return cb(new Error('Invalid file type.'), false);
|
},
|
||||||
}
|
}),
|
||||||
|
limits: {
|
||||||
|
fileSize: 1.049e7, // 10 MiB
|
||||||
|
},
|
||||||
|
fileFilter: (req, file, cb) => {
|
||||||
|
if (
|
||||||
|
!file.mimetype.startsWith('image/') ||
|
||||||
|
file.mimetype.includes('svg')
|
||||||
|
) {
|
||||||
|
return cb(new Error('Invalid file type.'), false);
|
||||||
|
}
|
||||||
|
|
||||||
cb(null, true);
|
cb(null, true);
|
||||||
},
|
},
|
||||||
};
|
}),
|
||||||
},
|
|
||||||
inject: [ConfigurationService],
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
providers: [SettingsService],
|
providers: [SettingsService],
|
||||||
})
|
})
|
||||||
export class SettingsModule implements NestModule {
|
export class SettingsModule implements NestModule {
|
||||||
|
constructor(@Inject('SESSION') private _session: RequestHandler) {}
|
||||||
|
|
||||||
configure(consumer: MiddlewareConsumer) {
|
configure(consumer: MiddlewareConsumer) {
|
||||||
consumer
|
consumer
|
||||||
.apply(CSRFMiddleware, UserMiddleware)
|
.apply(
|
||||||
|
this._session,
|
||||||
|
CSRFMiddleware,
|
||||||
|
FlashMiddleware,
|
||||||
|
UserMiddleware,
|
||||||
|
AuthMiddleware,
|
||||||
|
ValidateCSRFMiddleware,
|
||||||
|
)
|
||||||
.forRoutes(SettingsController);
|
.forRoutes(SettingsController);
|
||||||
consumer
|
|
||||||
.apply(ValidateCSRFMiddleware)
|
|
||||||
.forRoutes(
|
|
||||||
{ path: '/account*', method: RequestMethod.POST },
|
|
||||||
{ path: '/account*', method: RequestMethod.PATCH },
|
|
||||||
{ path: '/account*', method: RequestMethod.DELETE },
|
|
||||||
);
|
|
||||||
|
|
||||||
consumer.apply(AuthMiddleware).forRoutes('account*');
|
|
||||||
consumer.apply(FlashMiddleware).forRoutes('account*');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,13 @@ import { ObjectsModule } from '../objects/objects.module';
|
|||||||
import { LoginModule } from './login/login.module';
|
import { LoginModule } from './login/login.module';
|
||||||
import { OAuth2RouterModule } from './oauth2-router/oauth2-router.module';
|
import { OAuth2RouterModule } from './oauth2-router/oauth2-router.module';
|
||||||
import { RegisterModule } from './register/register.module';
|
import { RegisterModule } from './register/register.module';
|
||||||
|
import { SessionModule } from './session/session.module';
|
||||||
import { SettingsModule } from './settings/settings.module';
|
import { SettingsModule } from './settings/settings.module';
|
||||||
import { TwoFactorModule } from './two-factor/two-factor.module';
|
import { TwoFactorModule } from './two-factor/two-factor.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
SessionModule,
|
||||||
ConfigurationModule,
|
ConfigurationModule,
|
||||||
JWTModule,
|
JWTModule,
|
||||||
|
|
||||||
|
@ -1,23 +1,33 @@
|
|||||||
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
import { Inject, MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
|
import { RequestHandler } from 'express';
|
||||||
import { AuthMiddleware } from 'src/middleware/auth.middleware';
|
import { AuthMiddleware } from 'src/middleware/auth.middleware';
|
||||||
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
import { CSRFMiddleware } from 'src/middleware/csrf.middleware';
|
||||||
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
import { FlashMiddleware } from 'src/middleware/flash.middleware';
|
||||||
import { UserMiddleware } from 'src/middleware/user.middleware';
|
import { UserMiddleware } from 'src/middleware/user.middleware';
|
||||||
|
import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware';
|
||||||
import { AuditModule } from 'src/modules/objects/audit/audit.module';
|
import { AuditModule } from 'src/modules/objects/audit/audit.module';
|
||||||
import { UserTokenModule } from 'src/modules/objects/user-token/user-token.module';
|
import { UserTokenModule } from 'src/modules/objects/user-token/user-token.module';
|
||||||
import { UserModule } from 'src/modules/objects/user/user.module';
|
import { UserModule } from 'src/modules/objects/user/user.module';
|
||||||
|
import { SessionModule } from '../session/session.module';
|
||||||
import { TwoFactorController } from './two-factor.controller';
|
import { TwoFactorController } from './two-factor.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [UserModule, UserTokenModule, AuditModule],
|
imports: [UserModule, UserTokenModule, AuditModule, SessionModule],
|
||||||
controllers: [TwoFactorController],
|
controllers: [TwoFactorController],
|
||||||
})
|
})
|
||||||
export class TwoFactorModule implements NestModule {
|
export class TwoFactorModule implements NestModule {
|
||||||
|
constructor(@Inject('SESSION') private _session: RequestHandler) {}
|
||||||
|
|
||||||
configure(consumer: MiddlewareConsumer) {
|
configure(consumer: MiddlewareConsumer) {
|
||||||
consumer
|
consumer
|
||||||
.apply(CSRFMiddleware, UserMiddleware)
|
.apply(
|
||||||
|
this._session,
|
||||||
|
CSRFMiddleware,
|
||||||
|
UserMiddleware,
|
||||||
|
AuthMiddleware,
|
||||||
|
FlashMiddleware,
|
||||||
|
ValidateCSRFMiddleware,
|
||||||
|
)
|
||||||
.forRoutes(TwoFactorController);
|
.forRoutes(TwoFactorController);
|
||||||
consumer.apply(AuthMiddleware).forRoutes('account/two-factor/activate');
|
|
||||||
consumer.apply(FlashMiddleware).forRoutes('account/two-factor/activate');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user