feat: implement swagger plugin
refactor: move views into a seperate controller for ease of management
This commit is contained in:
parent
ea98ed7976
commit
178d922f24
14 changed files with 145 additions and 72 deletions
|
@ -3,6 +3,7 @@
|
|||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src",
|
||||
"compilerOptions": {
|
||||
"deleteOutDir": true
|
||||
"deleteOutDir": true,
|
||||
"plugins": ["@nestjs/swagger"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ import { BullModule } from '@nestjs/bullmq';
|
|||
import { BullConfigService } from './redis/service/bull-config.service';
|
||||
import { RedisService } from './redis/service/redis.service';
|
||||
import { OrganizationModule } from './organization/organization.module';
|
||||
import { ClientModule } from './client/client.module';
|
||||
import { ViewModule } from './view/view.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
@ -68,6 +70,8 @@ import { OrganizationModule } from './organization/organization.module';
|
|||
UserModule,
|
||||
AuthModule,
|
||||
OrganizationModule,
|
||||
ClientModule,
|
||||
ViewModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Body, Controller, Get, Post, Query, Render, Req, Res, UseGuards } from '@nestjs/common';
|
||||
import { ApiExcludeEndpoint, ApiTags } from '@nestjs/swagger';
|
||||
import { ApiExcludeEndpoint, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AuthService } from '../services/auth.service';
|
||||
import { ForgotPasswordDto } from '../dto/forgotPassword.dto';
|
||||
|
@ -8,6 +8,7 @@ import { LoginUserDto } from '../dto/loginUser.dto';
|
|||
import { User } from '../decorators/user.decorator';
|
||||
import { LoginGuard } from '../guard/login.guard';
|
||||
import { Response, Request } from 'express';
|
||||
import { LoginResponse } from '../dto/loginResponse.dto';
|
||||
|
||||
// TODO: Implement RateLimit
|
||||
@Controller('auth')
|
||||
|
@ -20,7 +21,7 @@ export class AuthController {
|
|||
@Body() body: LoginUserDto,
|
||||
@Res({ passthrough: true }) res: Response,
|
||||
@Req() req: Request,
|
||||
): Promise<any> {
|
||||
): Promise<LoginResponse> {
|
||||
const userId = await this.authService.login(body.username, body.password);
|
||||
|
||||
const interaction = await this.authService.checkInteractionStatus(req, res);
|
||||
|
@ -49,50 +50,6 @@ export class AuthController {
|
|||
|
||||
// ==== Render pages ==== //
|
||||
|
||||
@Get('login')
|
||||
@UseGuards(LoginGuard)
|
||||
@Render('auth/login')
|
||||
@ApiExcludeEndpoint()
|
||||
public async getHello(): Promise<any> {
|
||||
return {
|
||||
forgot_password: 'forgot-password',
|
||||
register: 'register',
|
||||
login_url: '/auth/login',
|
||||
//background_image: 'https://waterwolf.club/static/img/portal/portal7.jpg',
|
||||
};
|
||||
}
|
||||
|
||||
@Get('login/totp')
|
||||
@UseGuards(LoginGuard)
|
||||
@Render('auth/login-totp')
|
||||
@ApiExcludeEndpoint()
|
||||
public async getLoginTotp(): Promise<any> {
|
||||
return {
|
||||
login: 'login',
|
||||
methods: ['authenticator', 'email'],
|
||||
};
|
||||
}
|
||||
|
||||
@Get('register')
|
||||
@UseGuards(LoginGuard)
|
||||
@Render('auth/register')
|
||||
@ApiExcludeEndpoint()
|
||||
public async getRegister(): Promise<any> {
|
||||
return {
|
||||
login: 'login',
|
||||
};
|
||||
}
|
||||
|
||||
@Get('forgot-password')
|
||||
@UseGuards(LoginGuard)
|
||||
@Render('auth/forgot-password')
|
||||
@ApiExcludeEndpoint()
|
||||
public async getForgotPassword(): Promise<any> {
|
||||
return {
|
||||
login: 'login',
|
||||
};
|
||||
}
|
||||
|
||||
@Get('verify-email')
|
||||
@UseGuards(LoginGuard)
|
||||
@ApiExcludeEndpoint()
|
||||
|
@ -121,10 +78,4 @@ export class AuthController {
|
|||
|
||||
response.redirect('/auth/login');
|
||||
}
|
||||
|
||||
@Get('auth-test')
|
||||
@ApiExcludeEndpoint()
|
||||
public async getAuthTest(@User() user: any): Promise<any> {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ export class InteractionController {
|
|||
prompt: any;
|
||||
params: InteractionParams;
|
||||
} = await this.interactionService.get(req, res).catch((err: unknown) => {
|
||||
console.log(err);
|
||||
//TODO: Handle error in a nice way.
|
||||
throw new BadRequestException("Couldn't get interaction details", { cause: err });
|
||||
});
|
||||
|
@ -46,24 +45,14 @@ export class InteractionController {
|
|||
const { uid, prompt, params } = details;
|
||||
switch (prompt.name) {
|
||||
case 'login': {
|
||||
//Set a login redirect cookie to redirect the user back to the interaction page after login.
|
||||
// Take the interaction cookies and write them to /auth/login
|
||||
// _interaction, _interaction.sig, interactionId
|
||||
|
||||
if (!uid) {
|
||||
throw new InternalServerErrorException('No uid found');
|
||||
}
|
||||
|
||||
const cookies = req.cookies;
|
||||
|
||||
// Log in console when the packet expires
|
||||
|
||||
console.log(cookies);
|
||||
|
||||
return await this.interactionService.interactionRedirectToLoginPage(
|
||||
res,
|
||||
uid,
|
||||
cookies['_interaction.sig'],
|
||||
req.cookies['_interaction.sig'],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
14
src/auth/dto/loginResponse.dto.ts
Normal file
14
src/auth/dto/loginResponse.dto.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
export class LoginResponse {
|
||||
status: LoginStatusResponse;
|
||||
|
||||
message: string;
|
||||
|
||||
sessionId?: string;
|
||||
|
||||
redirectUrl?: string;
|
||||
}
|
||||
|
||||
export enum LoginStatusResponse {
|
||||
SUCCESS = 'success',
|
||||
REDIRECT = 'redirect',
|
||||
}
|
|
@ -10,6 +10,7 @@ export class LoginGuard implements CanActivate {
|
|||
const authType = this.clsService.get('authType');
|
||||
const response = context.switchToHttp().getResponse() as Response;
|
||||
|
||||
console.log('test');
|
||||
if (authType === 'session') {
|
||||
response.redirect('/auth/auth-test');
|
||||
return false;
|
||||
|
|
10
src/auth/oidc/helper/scopes.helper.ts
Normal file
10
src/auth/oidc/helper/scopes.helper.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
export const scopesArray = {
|
||||
profile: {
|
||||
scope: 'profile',
|
||||
displayName: 'General Profile Information',
|
||||
},
|
||||
email: {
|
||||
scope: 'email',
|
||||
displayName: '',
|
||||
},
|
||||
};
|
|
@ -1,4 +1,9 @@
|
|||
import { BadRequestException, Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import {
|
||||
BadRequestException,
|
||||
Injectable,
|
||||
InternalServerErrorException,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import { Response, Request } from 'express';
|
||||
|
||||
import { UserService } from '../../user/service/user.service';
|
||||
|
@ -14,6 +19,7 @@ import {
|
|||
import { OidcService } from '../oidc/service/core.service';
|
||||
import { InteractionService } from '../oidc/service/interaction.service';
|
||||
import { Interaction } from '../oidc/types/interaction.type';
|
||||
import { LoginResponse, LoginStatusResponse } from '../dto/loginResponse.dto';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
|
@ -84,14 +90,13 @@ export class AuthService {
|
|||
return user.id;
|
||||
}
|
||||
|
||||
//TODO: Make response DTOs
|
||||
/**
|
||||
* Create a session for a user and set the session copokies.
|
||||
* @param response The Response object
|
||||
* @param userId The User's ID
|
||||
* @returns
|
||||
*/
|
||||
public async createSession(res: Response, userId: string) {
|
||||
public async createSession(res: Response, userId: string): Promise<LoginResponse> {
|
||||
const sessionData = await this.oidcService.createSession(userId);
|
||||
|
||||
sessionData.cookiesForms.forEach((cookie) => {
|
||||
|
@ -102,7 +107,7 @@ export class AuthService {
|
|||
});
|
||||
|
||||
return {
|
||||
status: 'success',
|
||||
status: LoginStatusResponse.SUCCESS,
|
||||
message: 'Login Successful',
|
||||
sessionId: sessionData.sessionId,
|
||||
};
|
||||
|
@ -114,11 +119,19 @@ export class AuthService {
|
|||
* @param userId The User's ID
|
||||
* @return
|
||||
*/
|
||||
public async loginExistingInteraction(req: Request, res: Response, userId: string) {
|
||||
public async loginExistingInteraction(
|
||||
req: Request,
|
||||
res: Response,
|
||||
userId: string,
|
||||
): Promise<LoginResponse> {
|
||||
const redirectUrl = await this.interactionService.login(req, res, userId, true);
|
||||
|
||||
if (!redirectUrl) {
|
||||
throw new InternalServerErrorException('No redirect URL after building interaction');
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'redirect',
|
||||
status: LoginStatusResponse.REDIRECT,
|
||||
message: 'Login Successful, Redirect to session page',
|
||||
redirectUrl,
|
||||
};
|
||||
|
|
|
@ -10,4 +10,4 @@ import { DATABASE_ENTITIES } from 'src/database/database.entities';
|
|||
providers: [],
|
||||
exports: [],
|
||||
})
|
||||
export class UserModule {}
|
||||
export class ClientModule {}
|
||||
|
|
6
src/client/controller/client.controller.ts
Normal file
6
src/client/controller/client.controller.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query } from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
|
||||
@Controller('organization')
|
||||
@ApiTags('Clients')
|
||||
export class ClientsController {}
|
0
src/client/dto/listClient.dto.ts
Normal file
0
src/client/dto/listClient.dto.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { OidcClient } from '../../database/models/oidc_client.model';
|
||||
import { Repository } from 'typeorm';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
@Injectable()
|
||||
export class ClientService {
|
||||
constructor(
|
||||
@InjectRepository(OidcClient)
|
||||
private readonly clientRepository: Repository<OidcClient>,
|
||||
) {}
|
||||
|
||||
public async getClients() {}
|
||||
}
|
59
src/view/controllers/view.controller.ts
Normal file
59
src/view/controllers/view.controller.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { Controller, Get, Render, UseGuards } from '@nestjs/common';
|
||||
import { ApiExcludeController, ApiExcludeEndpoint } from '@nestjs/swagger';
|
||||
|
||||
import { LoginGuard } from '../../auth/guard/login.guard';
|
||||
import { User } from '../../auth/decorators/user.decorator';
|
||||
|
||||
@ApiExcludeController()
|
||||
@Controller()
|
||||
export class ViewController {
|
||||
@Get('auth/login')
|
||||
@Render('auth/login')
|
||||
@ApiExcludeEndpoint()
|
||||
@UseGuards(LoginGuard)
|
||||
public async loginView(): Promise<any> {
|
||||
return {
|
||||
forgot_password: 'forgot-password',
|
||||
register: 'register',
|
||||
login_url: '/auth/login',
|
||||
//background_image: 'https://waterwolf.club/static/img/portal/portal7.jpg',
|
||||
};
|
||||
}
|
||||
|
||||
@Get('auth/login/totp')
|
||||
@Render('auth/login-totp')
|
||||
@ApiExcludeEndpoint()
|
||||
@UseGuards(LoginGuard)
|
||||
public async getLoginTotp(): Promise<any> {
|
||||
return {
|
||||
login: 'login',
|
||||
methods: ['authenticator', 'email'],
|
||||
};
|
||||
}
|
||||
|
||||
@Get('auth/register')
|
||||
@Render('auth/register')
|
||||
@ApiExcludeEndpoint()
|
||||
@UseGuards(LoginGuard)
|
||||
public async getRegister(): Promise<any> {
|
||||
return {
|
||||
login: 'login',
|
||||
};
|
||||
}
|
||||
|
||||
@Get('auth/forgot-password')
|
||||
@UseGuards(LoginGuard)
|
||||
@Render('auth/forgot-password')
|
||||
@ApiExcludeEndpoint()
|
||||
public async getForgotPassword(): Promise<any> {
|
||||
return {
|
||||
login: 'login',
|
||||
};
|
||||
}
|
||||
|
||||
@Get('auth/auth-test')
|
||||
@ApiExcludeEndpoint()
|
||||
public async getAuthTest(@User() user: any): Promise<any> {
|
||||
return user;
|
||||
}
|
||||
}
|
10
src/view/view.module.ts
Normal file
10
src/view/view.module.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { ViewController } from './controllers/view.controller';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [ViewController],
|
||||
providers: [],
|
||||
exports: [],
|
||||
})
|
||||
export class ViewModule {}
|
Loading…
Reference in a new issue