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",
|
"collection": "@nestjs/schematics",
|
||||||
"sourceRoot": "src",
|
"sourceRoot": "src",
|
||||||
"compilerOptions": {
|
"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 { BullConfigService } from './redis/service/bull-config.service';
|
||||||
import { RedisService } from './redis/service/redis.service';
|
import { RedisService } from './redis/service/redis.service';
|
||||||
import { OrganizationModule } from './organization/organization.module';
|
import { OrganizationModule } from './organization/organization.module';
|
||||||
|
import { ClientModule } from './client/client.module';
|
||||||
|
import { ViewModule } from './view/view.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -68,6 +70,8 @@ import { OrganizationModule } from './organization/organization.module';
|
||||||
UserModule,
|
UserModule,
|
||||||
AuthModule,
|
AuthModule,
|
||||||
OrganizationModule,
|
OrganizationModule,
|
||||||
|
ClientModule,
|
||||||
|
ViewModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService],
|
providers: [AppService],
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Body, Controller, Get, Post, Query, Render, Req, Res, UseGuards } from '@nestjs/common';
|
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 { AuthService } from '../services/auth.service';
|
||||||
import { ForgotPasswordDto } from '../dto/forgotPassword.dto';
|
import { ForgotPasswordDto } from '../dto/forgotPassword.dto';
|
||||||
|
@ -8,6 +8,7 @@ import { LoginUserDto } from '../dto/loginUser.dto';
|
||||||
import { User } from '../decorators/user.decorator';
|
import { User } from '../decorators/user.decorator';
|
||||||
import { LoginGuard } from '../guard/login.guard';
|
import { LoginGuard } from '../guard/login.guard';
|
||||||
import { Response, Request } from 'express';
|
import { Response, Request } from 'express';
|
||||||
|
import { LoginResponse } from '../dto/loginResponse.dto';
|
||||||
|
|
||||||
// TODO: Implement RateLimit
|
// TODO: Implement RateLimit
|
||||||
@Controller('auth')
|
@Controller('auth')
|
||||||
|
@ -20,7 +21,7 @@ export class AuthController {
|
||||||
@Body() body: LoginUserDto,
|
@Body() body: LoginUserDto,
|
||||||
@Res({ passthrough: true }) res: Response,
|
@Res({ passthrough: true }) res: Response,
|
||||||
@Req() req: Request,
|
@Req() req: Request,
|
||||||
): Promise<any> {
|
): Promise<LoginResponse> {
|
||||||
const userId = await this.authService.login(body.username, body.password);
|
const userId = await this.authService.login(body.username, body.password);
|
||||||
|
|
||||||
const interaction = await this.authService.checkInteractionStatus(req, res);
|
const interaction = await this.authService.checkInteractionStatus(req, res);
|
||||||
|
@ -49,50 +50,6 @@ export class AuthController {
|
||||||
|
|
||||||
// ==== Render pages ==== //
|
// ==== 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')
|
@Get('verify-email')
|
||||||
@UseGuards(LoginGuard)
|
@UseGuards(LoginGuard)
|
||||||
@ApiExcludeEndpoint()
|
@ApiExcludeEndpoint()
|
||||||
|
@ -121,10 +78,4 @@ export class AuthController {
|
||||||
|
|
||||||
response.redirect('/auth/login');
|
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;
|
prompt: any;
|
||||||
params: InteractionParams;
|
params: InteractionParams;
|
||||||
} = await this.interactionService.get(req, res).catch((err: unknown) => {
|
} = await this.interactionService.get(req, res).catch((err: unknown) => {
|
||||||
console.log(err);
|
|
||||||
//TODO: Handle error in a nice way.
|
//TODO: Handle error in a nice way.
|
||||||
throw new BadRequestException("Couldn't get interaction details", { cause: err });
|
throw new BadRequestException("Couldn't get interaction details", { cause: err });
|
||||||
});
|
});
|
||||||
|
@ -46,24 +45,14 @@ export class InteractionController {
|
||||||
const { uid, prompt, params } = details;
|
const { uid, prompt, params } = details;
|
||||||
switch (prompt.name) {
|
switch (prompt.name) {
|
||||||
case 'login': {
|
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) {
|
if (!uid) {
|
||||||
throw new InternalServerErrorException('No uid found');
|
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(
|
return await this.interactionService.interactionRedirectToLoginPage(
|
||||||
res,
|
res,
|
||||||
uid,
|
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 authType = this.clsService.get('authType');
|
||||||
const response = context.switchToHttp().getResponse() as Response;
|
const response = context.switchToHttp().getResponse() as Response;
|
||||||
|
|
||||||
|
console.log('test');
|
||||||
if (authType === 'session') {
|
if (authType === 'session') {
|
||||||
response.redirect('/auth/auth-test');
|
response.redirect('/auth/auth-test');
|
||||||
return false;
|
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 { Response, Request } from 'express';
|
||||||
|
|
||||||
import { UserService } from '../../user/service/user.service';
|
import { UserService } from '../../user/service/user.service';
|
||||||
|
@ -14,6 +19,7 @@ import {
|
||||||
import { OidcService } from '../oidc/service/core.service';
|
import { OidcService } from '../oidc/service/core.service';
|
||||||
import { InteractionService } from '../oidc/service/interaction.service';
|
import { InteractionService } from '../oidc/service/interaction.service';
|
||||||
import { Interaction } from '../oidc/types/interaction.type';
|
import { Interaction } from '../oidc/types/interaction.type';
|
||||||
|
import { LoginResponse, LoginStatusResponse } from '../dto/loginResponse.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
|
@ -84,14 +90,13 @@ export class AuthService {
|
||||||
return user.id;
|
return user.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Make response DTOs
|
|
||||||
/**
|
/**
|
||||||
* Create a session for a user and set the session copokies.
|
* Create a session for a user and set the session copokies.
|
||||||
* @param response The Response object
|
* @param response The Response object
|
||||||
* @param userId The User's ID
|
* @param userId The User's ID
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public async createSession(res: Response, userId: string) {
|
public async createSession(res: Response, userId: string): Promise<LoginResponse> {
|
||||||
const sessionData = await this.oidcService.createSession(userId);
|
const sessionData = await this.oidcService.createSession(userId);
|
||||||
|
|
||||||
sessionData.cookiesForms.forEach((cookie) => {
|
sessionData.cookiesForms.forEach((cookie) => {
|
||||||
|
@ -102,7 +107,7 @@ export class AuthService {
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: 'success',
|
status: LoginStatusResponse.SUCCESS,
|
||||||
message: 'Login Successful',
|
message: 'Login Successful',
|
||||||
sessionId: sessionData.sessionId,
|
sessionId: sessionData.sessionId,
|
||||||
};
|
};
|
||||||
|
@ -114,11 +119,19 @@ export class AuthService {
|
||||||
* @param userId The User's ID
|
* @param userId The User's ID
|
||||||
* @return
|
* @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);
|
const redirectUrl = await this.interactionService.login(req, res, userId, true);
|
||||||
|
|
||||||
|
if (!redirectUrl) {
|
||||||
|
throw new InternalServerErrorException('No redirect URL after building interaction');
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: 'redirect',
|
status: LoginStatusResponse.REDIRECT,
|
||||||
message: 'Login Successful, Redirect to session page',
|
message: 'Login Successful, Redirect to session page',
|
||||||
redirectUrl,
|
redirectUrl,
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,4 +10,4 @@ import { DATABASE_ENTITIES } from 'src/database/database.entities';
|
||||||
providers: [],
|
providers: [],
|
||||||
exports: [],
|
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