mirror of
https://github.com/immich-app/immich
synced 2026-08-29 13:15:45 +00:00
refactor: always validate login (i.e. check cookie)
This commit is contained in:
parent
35ac0b3269
commit
a597b0edb1
7 changed files with 31 additions and 63 deletions
19
mobile/openapi/lib/model/maintenance_login_dto.dart
generated
19
mobile/openapi/lib/model/maintenance_login_dto.dart
generated
|
|
@ -13,10 +13,16 @@ part of openapi.api;
|
|||
class MaintenanceLoginDto {
|
||||
/// Returns a new [MaintenanceLoginDto] instance.
|
||||
MaintenanceLoginDto({
|
||||
required this.token,
|
||||
this.token,
|
||||
});
|
||||
|
||||
String token;
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
String? token;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is MaintenanceLoginDto &&
|
||||
|
|
@ -25,14 +31,18 @@ class MaintenanceLoginDto {
|
|||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(token.hashCode);
|
||||
(token == null ? 0 : token!.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'MaintenanceLoginDto[token=$token]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
if (this.token != null) {
|
||||
json[r'token'] = this.token;
|
||||
} else {
|
||||
// json[r'token'] = null;
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +55,7 @@ class MaintenanceLoginDto {
|
|||
final json = value.cast<String, dynamic>();
|
||||
|
||||
return MaintenanceLoginDto(
|
||||
token: mapValueOfType<String>(json, r'token')!,
|
||||
token: mapValueOfType<String>(json, r'token'),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
|
@ -93,7 +103,6 @@ class MaintenanceLoginDto {
|
|||
|
||||
/// The list of required keys that must be present in a JSON.
|
||||
static const requiredKeys = <String>{
|
||||
'token',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -248,13 +248,6 @@
|
|||
"parameters": [],
|
||||
"responses": {
|
||||
"201": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/MaintenanceModeResponseDto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
|
|
@ -314,13 +307,6 @@
|
|||
"parameters": [],
|
||||
"responses": {
|
||||
"201": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/MaintenanceModeResponseDto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
|
|
@ -12695,17 +12681,6 @@
|
|||
},
|
||||
"type": "object"
|
||||
},
|
||||
"MaintenanceModeResponseDto": {
|
||||
"properties": {
|
||||
"isMaintenanceMode": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"isMaintenanceMode"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ManualJobName": {
|
||||
"enum": [
|
||||
"person-cleanup",
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ export type MaintenanceModeResponseDto = {
|
|||
isMaintenanceMode: boolean;
|
||||
};
|
||||
export type MaintenanceLoginDto = {
|
||||
token: string;
|
||||
token?: string;
|
||||
};
|
||||
export type MaintenanceAuthDto = {
|
||||
username: string;
|
||||
|
|
|
|||
|
|
@ -23,8 +23,9 @@ export class MaintenanceWorkerController {
|
|||
@Body() dto: MaintenanceLoginDto,
|
||||
@Res({ passthrough: true }) response: Response,
|
||||
): Promise<MaintenanceAuthDto> {
|
||||
const auth = await this.service.login(dto.token ?? request.cookies[ImmichCookie.MaintenanceToken]);
|
||||
response.cookie(ImmichCookie.MaintenanceToken, dto.token);
|
||||
const token = dto.token ?? request.cookies[ImmichCookie.MaintenanceToken];
|
||||
const auth = await this.service.login(token);
|
||||
response.cookie(ImmichCookie.MaintenanceToken, token);
|
||||
return auth;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { BadRequestException, Body, Controller, Post, Res } from '@nestjs/common
|
|||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { Response } from 'express';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import { MaintenanceAuthDto, MaintenanceLoginDto, MaintenanceModeResponseDto } from 'src/dtos/maintenance.dto';
|
||||
import { MaintenanceAuthDto, MaintenanceLoginDto } from 'src/dtos/maintenance.dto';
|
||||
import { ImmichCookie, Permission } from 'src/enum';
|
||||
import { Auth, Authenticated } from 'src/middleware/auth.guard';
|
||||
import { MaintenanceRepository } from 'src/repositories/maintenance.repository';
|
||||
|
|
@ -20,22 +20,18 @@ export class MaintenanceController {
|
|||
|
||||
@Post('start')
|
||||
@Authenticated({ permission: Permission.Maintenance, admin: true })
|
||||
async startMaintenance(
|
||||
@Auth() auth: AuthDto,
|
||||
@Res({ passthrough: true }) response: Response,
|
||||
): Promise<MaintenanceModeResponseDto> {
|
||||
async startMaintenance(@Auth() auth: AuthDto, @Res({ passthrough: true }) response: Response): Promise<void> {
|
||||
const { secret } = await this.service.startMaintenance();
|
||||
const jwt = await MaintenanceRepository.createJwt(secret, {
|
||||
username: auth.user.name,
|
||||
});
|
||||
|
||||
response.cookie(ImmichCookie.MaintenanceToken, jwt);
|
||||
return { isMaintenanceMode: true };
|
||||
}
|
||||
|
||||
@Post('end')
|
||||
@Authenticated({ permission: Permission.Maintenance, admin: true })
|
||||
endMaintenance(): Promise<MaintenanceModeResponseDto> {
|
||||
endMaintenance(): void {
|
||||
throw new BadRequestException('Not in maintenance mode');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export class MaintenanceModeResponseDto {
|
|||
}
|
||||
|
||||
export class MaintenanceLoginDto {
|
||||
@ValidateString()
|
||||
@ValidateString({ optional: true })
|
||||
token?: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,31 +20,18 @@ export function maintenanceShouldRedirect(maintenanceMode: boolean, currentUrl:
|
|||
export const loadMaintenanceAuth = async () => {
|
||||
try {
|
||||
const maintenanceAuth = get(maintenanceAuth$);
|
||||
|
||||
const query = new URLSearchParams(location.search);
|
||||
const queryToken = query.get('token');
|
||||
|
||||
if (!maintenanceAuth || queryToken) {
|
||||
const cookie = document.cookie
|
||||
.split(';')
|
||||
.map((cookie) => cookie.split('=', 2).map((value) => value.trim()))
|
||||
.find(([name]) => name === 'immich_maintenance_token');
|
||||
try {
|
||||
const auth = await maintenanceLogin({
|
||||
maintenanceLoginDto: {
|
||||
token: query.get('token') ?? undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const token = queryToken ?? cookie?.[1];
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const auth = await maintenanceLogin({
|
||||
maintenanceLoginDto: {
|
||||
token,
|
||||
},
|
||||
});
|
||||
|
||||
maintenanceAuth$.set(auth);
|
||||
} catch (error) {
|
||||
void error;
|
||||
}
|
||||
}
|
||||
maintenanceAuth$.set(auth);
|
||||
} catch (error) {
|
||||
void error;
|
||||
}
|
||||
|
||||
return maintenanceAuth;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue