mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-25 03:06:31 -05:00
feat(api/private/me): include authProvider in UserInfo
This information is supposed to be used by the frontend to identify the login method that was used. The used login method is saved as a string into the session data and extracted via a new SessionAuthProvider decorator. Signed-off-by: David Mehren <git@herrmehren.de>
This commit is contained in:
parent
3f8e3b0589
commit
d6ea4d29fe
7 changed files with 71 additions and 8 deletions
|
@ -75,11 +75,18 @@ export class AuthController {
|
||||||
@Post('local/login')
|
@Post('local/login')
|
||||||
@OpenApi(201, 400, 401)
|
@OpenApi(201, 400, 401)
|
||||||
login(
|
login(
|
||||||
@Req() request: Request & { session: { user: string } },
|
@Req()
|
||||||
|
request: Request & {
|
||||||
|
session: {
|
||||||
|
authProvider: string;
|
||||||
|
user: string;
|
||||||
|
};
|
||||||
|
},
|
||||||
@Body() loginDto: LoginDto,
|
@Body() loginDto: LoginDto,
|
||||||
): void {
|
): void {
|
||||||
// There is no further testing needed as we only get to this point if LocalAuthGuard was successful
|
// There is no further testing needed as we only get to this point if LocalAuthGuard was successful
|
||||||
request.session.user = loginDto.username;
|
request.session.user = loginDto.username;
|
||||||
|
request.session.authProvider = 'local';
|
||||||
}
|
}
|
||||||
|
|
||||||
@UseGuards(SessionGuard)
|
@UseGuards(SessionGuard)
|
||||||
|
|
|
@ -10,11 +10,12 @@ import { SessionGuard } from '../../../identity/session.guard';
|
||||||
import { ConsoleLoggerService } from '../../../logger/console-logger.service';
|
import { ConsoleLoggerService } from '../../../logger/console-logger.service';
|
||||||
import { MediaUploadDto } from '../../../media/media-upload.dto';
|
import { MediaUploadDto } from '../../../media/media-upload.dto';
|
||||||
import { MediaService } from '../../../media/media.service';
|
import { MediaService } from '../../../media/media.service';
|
||||||
import { FullUserInfoDto } from '../../../users/user-info.dto';
|
import { UserLoginInfoDto } from '../../../users/user-info.dto';
|
||||||
import { User } from '../../../users/user.entity';
|
import { User } from '../../../users/user.entity';
|
||||||
import { UsersService } from '../../../users/users.service';
|
import { UsersService } from '../../../users/users.service';
|
||||||
import { OpenApi } from '../../utils/openapi.decorator';
|
import { OpenApi } from '../../utils/openapi.decorator';
|
||||||
import { RequestUser } from '../../utils/request-user.decorator';
|
import { RequestUser } from '../../utils/request-user.decorator';
|
||||||
|
import { SessionAuthProvider } from '../../utils/session-authprovider.decorator';
|
||||||
|
|
||||||
@UseGuards(SessionGuard)
|
@UseGuards(SessionGuard)
|
||||||
@OpenApi(401)
|
@OpenApi(401)
|
||||||
|
@ -31,8 +32,11 @@ export class MeController {
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@OpenApi(200)
|
@OpenApi(200)
|
||||||
getMe(@RequestUser() user: User): FullUserInfoDto {
|
getMe(
|
||||||
return this.userService.toFullUserDto(user);
|
@RequestUser() user: User,
|
||||||
|
@SessionAuthProvider() authProvider: string,
|
||||||
|
): UserInfoDto {
|
||||||
|
return this.userService.toUserLoginInfoDto(user, authProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('media')
|
@Get('media')
|
||||||
|
|
34
src/api/utils/session-authprovider.decorator.ts
Normal file
34
src/api/utils/session-authprovider.decorator.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
createParamDecorator,
|
||||||
|
ExecutionContext,
|
||||||
|
InternalServerErrorException,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { Request } from 'express';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the auth provider identifier from a session inside a request
|
||||||
|
*
|
||||||
|
* Will throw an {@link InternalServerErrorException} if no identifier is present
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
export const SessionAuthProvider = createParamDecorator(
|
||||||
|
(data: unknown, ctx: ExecutionContext) => {
|
||||||
|
const request: Request & {
|
||||||
|
session: {
|
||||||
|
authProvider: string;
|
||||||
|
};
|
||||||
|
} = ctx.switchToHttp().getRequest();
|
||||||
|
if (!request.session?.authProvider) {
|
||||||
|
// We should have an auth provider here, otherwise something is wrong
|
||||||
|
throw new InternalServerErrorException(
|
||||||
|
'Session is missing an auth provider identifier',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return request.session.authProvider;
|
||||||
|
},
|
||||||
|
);
|
|
@ -51,3 +51,12 @@ export class FullUserInfoDto extends UserInfoDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
email: string;
|
email: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class UserLoginInfoDto extends UserInfoDto {
|
||||||
|
/**
|
||||||
|
* Identifier of the auth provider that was used to log in
|
||||||
|
*/
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
authProvider: string;
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,11 @@ import { Repository } from 'typeorm';
|
||||||
|
|
||||||
import { AlreadyInDBError, NotInDBError } from '../errors/errors';
|
import { AlreadyInDBError, NotInDBError } from '../errors/errors';
|
||||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||||
import { FullUserInfoDto, UserInfoDto } from './user-info.dto';
|
import {
|
||||||
|
FullUserInfoDto,
|
||||||
|
UserInfoDto,
|
||||||
|
UserLoginInfoDto,
|
||||||
|
} from './user-info.dto';
|
||||||
import { UserRelationEnum } from './user-relation.enum';
|
import { UserRelationEnum } from './user-relation.enum';
|
||||||
import { User } from './user.entity';
|
import { User } from './user.entity';
|
||||||
|
|
||||||
|
@ -131,4 +135,8 @@ export class UsersService {
|
||||||
email: user.email ?? '',
|
email: user.email ?? '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toUserLoginInfoDto(user: User, authProvider: string): UserLoginInfoDto {
|
||||||
|
return { ...this.toUserDto(user), authProvider };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import request from 'supertest';
|
||||||
|
|
||||||
import { NotInDBError } from '../../src/errors/errors';
|
import { NotInDBError } from '../../src/errors/errors';
|
||||||
import { Note } from '../../src/notes/note.entity';
|
import { Note } from '../../src/notes/note.entity';
|
||||||
import { FullUserInfoDto } from '../../src/users/user-info.dto';
|
import { UserLoginInfoDto } from '../../src/users/user-info.dto';
|
||||||
import { User } from '../../src/users/user.entity';
|
import { User } from '../../src/users/user.entity';
|
||||||
import { TestSetup, TestSetupBuilder } from '../test-setup';
|
import { TestSetup, TestSetupBuilder } from '../test-setup';
|
||||||
|
|
||||||
|
@ -50,12 +50,12 @@ describe('Me', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('GET /me', async () => {
|
it('GET /me', async () => {
|
||||||
const userInfo = testSetup.userService.toFullUserDto(user);
|
const userInfo = testSetup.userService.toUserLoginInfoDto(user, 'local');
|
||||||
const response = await agent
|
const response = await agent
|
||||||
.get('/api/private/me')
|
.get('/api/private/me')
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
const gotUser = response.body as FullUserInfoDto;
|
const gotUser = response.body as UserLoginInfoDto;
|
||||||
expect(gotUser).toEqual(userInfo);
|
expect(gotUser).toEqual(userInfo);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ describe('Register and Login', () => {
|
||||||
const profile = await session.get('/api/private/me').expect(200);
|
const profile = await session.get('/api/private/me').expect(200);
|
||||||
expect(profile.body.username).toEqual(USERNAME);
|
expect(profile.body.username).toEqual(USERNAME);
|
||||||
expect(profile.body.displayName).toEqual(DISPLAYNAME);
|
expect(profile.body.displayName).toEqual(DISPLAYNAME);
|
||||||
|
expect(profile.body.authProvider).toEqual('local');
|
||||||
|
|
||||||
// logout again
|
// logout again
|
||||||
await session.delete('/api/private/auth/logout').expect(204);
|
await session.delete('/api/private/auth/logout').expect(204);
|
||||||
|
|
Loading…
Reference in a new issue