mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-10-29 17:40:28 +00:00
feat(web,server): manage authorized devices (#2329)
* feat: manage authorized devices * chore: open api * get header from mobile app * write header from mobile app * styling * fix unit test * feat: use relative time * feat: update access time * fix: tests * chore: confirm wording * chore: bump test coverage thresholds * feat: add some icons * chore: icon tweaks --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
AdminSignupResponseDto,
|
||||
AuthDeviceResponseDto,
|
||||
AuthService,
|
||||
AuthType,
|
||||
AuthUserDto,
|
||||
@@ -7,18 +8,20 @@ import {
|
||||
IMMICH_ACCESS_COOKIE,
|
||||
IMMICH_AUTH_TYPE_COOKIE,
|
||||
LoginCredentialDto,
|
||||
LoginDetails,
|
||||
LoginResponseDto,
|
||||
LogoutResponseDto,
|
||||
SignUpDto,
|
||||
UserResponseDto,
|
||||
ValidateAccessTokenResponseDto,
|
||||
} from '@app/domain';
|
||||
import { Body, Controller, Ip, Post, Req, Res } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, Post, Req, Res } from '@nestjs/common';
|
||||
import { ApiBadRequestResponse, ApiTags } from '@nestjs/swagger';
|
||||
import { Request, Response } from 'express';
|
||||
import { GetAuthUser } from '../decorators/auth-user.decorator';
|
||||
import { GetAuthUser, GetLoginDetails } from '../decorators/auth-user.decorator';
|
||||
import { Authenticated } from '../decorators/authenticated.decorator';
|
||||
import { UseValidation } from '../decorators/use-validation.decorator';
|
||||
import { UUIDParamDto } from './dto/uuid-param.dto';
|
||||
|
||||
@ApiTags('Authentication')
|
||||
@Controller('auth')
|
||||
@@ -29,11 +32,10 @@ export class AuthController {
|
||||
@Post('login')
|
||||
async login(
|
||||
@Body() loginCredential: LoginCredentialDto,
|
||||
@Ip() clientIp: string,
|
||||
@Req() req: Request,
|
||||
@Res({ passthrough: true }) res: Response,
|
||||
@GetLoginDetails() loginDetails: LoginDetails,
|
||||
): Promise<LoginResponseDto> {
|
||||
const { response, cookie } = await this.service.login(loginCredential, clientIp, req.secure);
|
||||
const { response, cookie } = await this.service.login(loginCredential, loginDetails);
|
||||
res.header('Set-Cookie', cookie);
|
||||
return response;
|
||||
}
|
||||
@@ -44,6 +46,18 @@ export class AuthController {
|
||||
return this.service.adminSignUp(signUpCredential);
|
||||
}
|
||||
|
||||
@Authenticated()
|
||||
@Get('devices')
|
||||
getAuthDevices(@GetAuthUser() authUser: AuthUserDto): Promise<AuthDeviceResponseDto[]> {
|
||||
return this.service.getDevices(authUser);
|
||||
}
|
||||
|
||||
@Authenticated()
|
||||
@Delete('devices/:id')
|
||||
logoutAuthDevice(@GetAuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise<void> {
|
||||
return this.service.logoutDevice(authUser, id);
|
||||
}
|
||||
|
||||
@Authenticated()
|
||||
@Post('validateToken')
|
||||
validateAccessToken(): ValidateAccessTokenResponseDto {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
AuthUserDto,
|
||||
LoginDetails,
|
||||
LoginResponseDto,
|
||||
OAuthCallbackDto,
|
||||
OAuthConfigDto,
|
||||
@@ -10,7 +11,7 @@ import {
|
||||
import { Body, Controller, Get, HttpStatus, Post, Redirect, Req, Res } from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { Request, Response } from 'express';
|
||||
import { GetAuthUser } from '../decorators/auth-user.decorator';
|
||||
import { GetAuthUser, GetLoginDetails } from '../decorators/auth-user.decorator';
|
||||
import { Authenticated } from '../decorators/authenticated.decorator';
|
||||
import { UseValidation } from '../decorators/use-validation.decorator';
|
||||
|
||||
@@ -38,9 +39,9 @@ export class OAuthController {
|
||||
async callback(
|
||||
@Res({ passthrough: true }) res: Response,
|
||||
@Body() dto: OAuthCallbackDto,
|
||||
@Req() req: Request,
|
||||
@GetLoginDetails() loginDetails: LoginDetails,
|
||||
): Promise<LoginResponseDto> {
|
||||
const { response, cookie } = await this.service.login(dto, req.secure);
|
||||
const { response, cookie } = await this.service.login(dto, loginDetails);
|
||||
res.header('Set-Cookie', cookie);
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
export { AuthUserDto } from '@app/domain';
|
||||
import { AuthUserDto } from '@app/domain';
|
||||
import { AuthUserDto, LoginDetails } from '@app/domain';
|
||||
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||
import { UAParser } from 'ua-parser-js';
|
||||
|
||||
export const GetAuthUser = createParamDecorator((data, ctx: ExecutionContext): AuthUserDto => {
|
||||
return ctx.switchToHttp().getRequest<{ user: AuthUserDto }>().user;
|
||||
});
|
||||
|
||||
export const GetLoginDetails = createParamDecorator((data, ctx: ExecutionContext): LoginDetails => {
|
||||
const req = ctx.switchToHttp().getRequest();
|
||||
const userAgent = UAParser(req.headers['user-agent']);
|
||||
|
||||
return {
|
||||
clientIp: req.clientIp,
|
||||
isSecure: req.secure,
|
||||
deviceType: userAgent.browser.name || userAgent.device.type || req.headers.devicemodel || '',
|
||||
deviceOS: userAgent.os.name || req.headers.devicetype || '',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -21,6 +21,10 @@ export function patchOpenAPI(document: OpenAPIObject) {
|
||||
if (operation.summary === '') {
|
||||
delete operation.summary;
|
||||
}
|
||||
|
||||
if (operation.description === '') {
|
||||
delete operation.description;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user