Skip to content

Commit

Permalink
API is now protected by KC
Browse files Browse the repository at this point in the history
  • Loading branch information
Ratatinator97 committed Mar 13, 2024
1 parent 6a2015b commit f0e04f8
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 35 deletions.
2 changes: 1 addition & 1 deletion config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ server:
db:
type: 'postgres'
port: 5432
database: 'pictalk-keycloak'
database: 'pictalk'
#database: "pictalk"

jwt:
Expand Down
2 changes: 1 addition & 1 deletion config/development.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ db:
host: 'localhost' # This is the name of the service (see docker-compose.yml from pictalk-frontend) that runs the database
username: 'postgres'
password: 'postgres'
synchronize: true
synchronize: false

jwt:
secret: 'WayTooMuchSunScreen'
10 changes: 3 additions & 7 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,13 @@ import {
RoleGuard,
} from 'nest-keycloak-connect';
import { APP_GUARD } from '@nestjs/core';
import keycloakConfig from './config/keycloak.config';
@Module({
imports: [
ConfigModule.forRoot(),
TypeOrmModule.forRoot(typeOrmConfig),
KeycloakConnectModule.register({
authServerUrl: 'https://auth.picmind.org',
realm: 'master',
clientId: 'pictalk-api',
secret: 'CWLSdXiTtaRfaVmg1DIDHAfqK67E3HGd',
// Secret key of the client taken from keycloak server
}),
ConfigModule.forRoot({ load: [keycloakConfig] }),
KeycloakConnectModule.register(keycloakConfig()),
PictoModule,
CollectionModule,
AuthModule,
Expand Down
18 changes: 11 additions & 7 deletions src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import { Notif } from 'src/entities/notification.entity';
import { usernameRegexp } from 'src/utilities/creation';
import { modifyCollectionDto } from 'src/collection/dto/collection.modify.dto';
import { AuthenticatedUser, Public, AuthGuard } from 'nest-keycloak-connect';
import { UserGuard } from './user.guard';
import { GetUser } from './get-user.decorator';
@UseGuards(UserGuard)
@Controller('')
export class AuthController {
private logger = new Logger('AuthController');
Expand Down Expand Up @@ -102,14 +105,14 @@ export class AuthController {
}

@Get('user/details')
getUserDetails(@AuthenticatedUser() user: User): Promise<User> {
getUserDetails(@GetUser() user: User): Promise<User> {
this.logger.verbose(`User "${user.username}" is trying to get Details`);
return this.authService.getUserDetails(user);
}

@Put('user/details')
async editUser(
@AuthenticatedUser() user: User,
@GetUser() user: User,
@Body(ValidationPipe) editUserDto: EditUserDto,
): Promise<User> {
if (editUserDto.mailingList) {
Expand Down Expand Up @@ -148,21 +151,22 @@ export class AuthController {
}

@Get('/user/root')
async getRoot(@AuthenticatedUser() user: User): Promise<Collection> {

async getRoot(@GetUser() user: User): Promise<Collection> {
this.logger.verbose(`User "${user.username}" getting his root`);
const root = await this.authService.getRoot(user);
return this.collectionService.getCollectionById(root, user);
}

@Get('/user/sider')
async getSider(@AuthenticatedUser() user: User): Promise<Collection> {
async getSider(@GetUser() user: User): Promise<Collection> {
this.logger.verbose(`User "${user.username}" getting his root`);
const sider = await this.authService.getSider(user);
return this.collectionService.getCollectionById(sider, user);
}

@Get('/user/shared')
async getShared(@AuthenticatedUser() user: User): Promise<Collection> {
async getShared(@GetUser() user: User): Promise<Collection> {
this.logger.verbose(
`User "${user.username}" getting his shared with me Collection`,
);
Expand All @@ -171,12 +175,12 @@ export class AuthController {
}

@Get('/user/notification')
async getNotifications(@AuthenticatedUser() user: User): Promise<Notif[]> {
async getNotifications(@GetUser() user: User): Promise<Notif[]> {
return this.authService.getNotifications(user);
}

@Delete('/user/notification')
async clearNotifications(@AuthenticatedUser() user: User): Promise<Notif[]> {
async clearNotifications(@GetUser() user: User): Promise<Notif[]> {
this.logger.verbose(`User "${user.username}" clearing his notifications`);
return this.authService.clearNotifications(user);
}
Expand Down
18 changes: 18 additions & 0 deletions src/auth/dto/keycloak.user.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
interface KeycloakUser {
exp: number;
iat: number;
jti: string;
iss: string;
sub: string;
typ: string;
azp: string;
session_state: string;
acr: string;
scope: string;
sid: string;
email_verified: boolean;
preferred_username: string;
given_name: string;
family_name: string;
email: string;
}
8 changes: 8 additions & 0 deletions src/auth/get-user.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const GetUser = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
},
);
17 changes: 17 additions & 0 deletions src/auth/user.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';

@Injectable()
export class UserGuard implements CanActivate {
constructor(private authService: AuthService) {}

canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
const user = this.authService.findWithUsername(request.user.username);
request.user = user;
return true;
}
}
23 changes: 13 additions & 10 deletions src/collection/collection.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ import { SearchCollectionDto } from './dto/collection.search.public.dto';
import { levelCollectionDto } from './dto/collection.level.dto';
import { MoveToCollectionDto } from './dto/collection.move.dto';
import { AuthenticatedUser, Public, AuthGuard } from 'nest-keycloak-connect';
import { UserGuard } from 'src/auth/user.guard';
import { GetUser } from 'src/auth/get-user.decorator';
@UseGuards(UserGuard)
@Controller('collection')
export class CollectionController {
private logger = new Logger('CollectionController');
Expand All @@ -55,7 +58,7 @@ export class CollectionController {
@ApiOperation({ summary: 'get a collection that has the provided id' })
getCollectionById(
@Param('id', ParseIntPipe) id: number,
@AuthenticatedUser() user: User,
@GetUser() user: User,
): Promise<Collection> {
this.logger.verbose(
`User "${user.username}" getting Collection with id ${id}`,
Expand Down Expand Up @@ -120,7 +123,7 @@ export class CollectionController {
@Get()
@ApiOperation({ summary: 'get all your collection' })
getAllUserCollections(
@AuthenticatedUser() user: User,
@GetUser() user: User,
): Promise<Collection[]> {
this.logger.verbose(`User "${user.username}" getting all Collection`);
return this.collectionService.getAllUserCollections(user);
Expand All @@ -130,7 +133,7 @@ export class CollectionController {
@ApiOperation({ summary: 'copy a collection with its ID' })
async copyCollection(
@Body() copyCollectionDto: copyCollectionDto,
@AuthenticatedUser() user: User,
@GetUser() user: User,
): Promise<Collection> {
const fatherCollection = await this.collectionService.getCollectionById(
copyCollectionDto.fatherCollectionId,
Expand Down Expand Up @@ -174,7 +177,7 @@ export class CollectionController {
async shareCollectionById(
@Param('id', ParseIntPipe) id: number,
@Body() multipleShareCollectionDto: multipleShareCollectionDto,
@AuthenticatedUser() user: User,
@GetUser() user: User,
): Promise<Collection> {
let collection: Collection;
if (!multipleShareCollectionDto.role) {
Expand Down Expand Up @@ -203,7 +206,7 @@ export class CollectionController {
publishCollectionById(
@Param('id', ParseIntPipe) id: number,
@Body() publicCollectionDto: publicCollectionDto,
@AuthenticatedUser() user: User,
@GetUser() user: User,
): Promise<Collection> {
if (user.admin === true) {
return this.collectionService.publishCollectionById(
Expand Down Expand Up @@ -232,7 +235,7 @@ export class CollectionController {
)
async createCollection(
@Body() createCollectionDto: createCollectionDto,
@AuthenticatedUser() user: User,
@GetUser() user: User,
@UploadedFile() file: Express.Multer.File,
): Promise<Collection> {
if (!file) {
Expand Down Expand Up @@ -303,7 +306,7 @@ export class CollectionController {
}

@Post('/root')
createRoot(@AuthenticatedUser() user: User): Promise<number> {
createRoot(@GetUser() user: User): Promise<number> {
this.logger.verbose(
`User "${user.username}" Creating 'Root' Collection if needed`,
);
Expand All @@ -313,7 +316,7 @@ export class CollectionController {
@Delete()
deleteCollection(
@Query(ValidationPipe) deleteCollectionDto: deleteCollectionDto,
@AuthenticatedUser() user: User,
@GetUser() user: User,
): Promise<void> {
deleteCollectionDto.collectionId = Number(deleteCollectionDto.collectionId);
this.logger.verbose(
Expand All @@ -336,7 +339,7 @@ export class CollectionController {
)
async modifyCollection(
@Param('id', ParseIntPipe) id: number,
@AuthenticatedUser() user: User,
@GetUser() user: User,
@Body() modifyCollectionDto: modifyCollectionDto,
@UploadedFile() file: Express.Multer.File,
): Promise<Collection> {
Expand Down Expand Up @@ -374,7 +377,7 @@ export class CollectionController {
@UsePipes(ValidationPipe)
async moveToCollection(
@Param('id', ParseIntPipe) fatherCollectionId: number,
@AuthenticatedUser() user: User,
@GetUser() user: User,
@Body() moveToCollectionDto: MoveToCollectionDto,
): Promise<Collection> {
this.logger.verbose(
Expand Down
7 changes: 7 additions & 0 deletions src/config/keycloak.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default () => ({
authServerUrl:
process.env.KEYCLOAK_AUTH_SERVER_URL || 'http://localhost:8080',
realm: process.env.KEYCLOAK_REALM || 'master',
clientId: process.env.KEYCLOAK_CLIENT_ID || 'random',
secret: process.env.KEYCLOAK_SECRET || 'secret',
});
7 changes: 5 additions & 2 deletions src/feedback/feedback.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import { SearchFeedbackDto } from './dto/search.feedback.dto';
import { Feedback } from './entities/feedback.entity';
import { FeedbackService } from './feedback.service';
import { AuthenticatedUser, AuthGuard } from 'nest-keycloak-connect';
import { UserGuard } from 'src/auth/user.guard';
import { GetUser } from 'src/auth/get-user.decorator';
@UseGuards(UserGuard)
@Controller('feedback')
export class FeedbackController {
private logger = new Logger('CollectionController');
Expand All @@ -39,7 +42,7 @@ export class FeedbackController {
@Get()
@UsePipes(ValidationPipe)
async getFeedback(
@AuthenticatedUser() user: User,
@GetUser() user: User,
@Query() searchFeedbackDto: SearchFeedbackDto,
): Promise<{ feedbacks: Feedback[]; total_count: number }> {
if (!user.admin) {
Expand All @@ -55,7 +58,7 @@ export class FeedbackController {
@Put('/:id')
@UsePipes(ValidationPipe)
async editFeedback(
@AuthenticatedUser() user: User,
@GetUser() user: User,
@Param('id', ParseIntPipe) id: number,
@Body() editFeedbackDto: EditFeedbackDto,
): Promise<Feedback> {
Expand Down
17 changes: 10 additions & 7 deletions src/picto/picto.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ import { deletePictoDto } from './dto/picto.delete.dto';
import { copyPictoDto } from './dto/picto.copy.dto';
import { Collection } from 'src/entities/collection.entity';
import { AuthenticatedUser, Public, AuthGuard } from 'nest-keycloak-connect';
import { UserGuard } from 'src/auth/user.guard';
import { GetUser } from 'src/auth/get-user.decorator';
@UseGuards(UserGuard)
@Controller('picto')
export class PictoController {
private logger = new Logger('PictosController');
Expand All @@ -56,15 +59,15 @@ export class PictoController {
@Get('/:id')
getPictoById(
@Param('id', ParseIntPipe) id: number,
@AuthenticatedUser() user: User,
@GetUser() user: User,
): Promise<Picto> {
this.logger.verbose(`User "${user.username}" getting Picto with id ${id}`);
return this.pictoService.getPictoById(id, user);
}

@Get()
@ApiOperation({ summary: 'get all your pictos' })
getAllUserPictos(@AuthenticatedUser() user: User): Promise<Picto[]> {
getAllUserPictos(@GetUser() user: User): Promise<Picto[]> {
this.logger.verbose(`User "${user.username}" getting all Picto`);
return this.pictoService.getAllUserPictos(user);
}
Expand All @@ -77,7 +80,7 @@ export class PictoController {
async sharePictoById(
@Param('id', ParseIntPipe) id: number,
@Body() multipleSharePictoDto: multipleSharePictoDto,
@AuthenticatedUser() user: User,
@GetUser() user: User,
): Promise<Picto> {
let picto: Picto;
if (!multipleSharePictoDto.role) {
Expand Down Expand Up @@ -121,7 +124,7 @@ export class PictoController {
)
async createPicto(
@Body() createPictoDto: createPictoDto,
@AuthenticatedUser() user: User,
@GetUser() user: User,
@UploadedFile() file: Express.Multer.File,
): Promise<Picto> {
if (!file) {
Expand Down Expand Up @@ -192,7 +195,7 @@ export class PictoController {
@Delete()
deletePicto(
@Query(ValidationPipe) deletePictoDto: deletePictoDto,
@AuthenticatedUser() user: User,
@GetUser() user: User,
): Promise<void> {
deletePictoDto.pictoId = Number(deletePictoDto.pictoId);
this.logger.verbose(
Expand All @@ -215,7 +218,7 @@ export class PictoController {
)
async modifyPicto(
@Param('id', ParseIntPipe) id: number,
@AuthenticatedUser() user: User,
@GetUser() user: User,
@Body() modifyPictoDto: modifyPictoDto,
@UploadedFile() file: Express.Multer.File,
): Promise<Picto> {
Expand Down Expand Up @@ -247,7 +250,7 @@ export class PictoController {
@Post('copy')
async copyPicto(
@Body() copyPictoDto: copyPictoDto,
@AuthenticatedUser() user: User,
@GetUser() user: User,
): Promise<Collection> {
this.logger.verbose(
`User "${user.username}" copying Picto with id ${copyPictoDto.pictoId}`,
Expand Down

0 comments on commit f0e04f8

Please sign in to comment.