mirror of
https://github.com/immich-app/immich.git
synced 2024-12-29 15:11:58 +00:00
feat(server): storage label claim (#3278)
* feat: storage label claim * chore: open api
This commit is contained in:
parent
ed594c1987
commit
f55d63fae8
13 changed files with 49 additions and 5 deletions
6
cli/src/api/open-api/api.ts
generated
6
cli/src/api/open-api/api.ts
generated
|
@ -2596,6 +2596,12 @@ export interface SystemConfigOAuthDto {
|
|||
* @memberof SystemConfigOAuthDto
|
||||
*/
|
||||
'scope': string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof SystemConfigOAuthDto
|
||||
*/
|
||||
'storageLabelClaim': string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
|
|
BIN
mobile/openapi/doc/SystemConfigOAuthDto.md
generated
BIN
mobile/openapi/doc/SystemConfigOAuthDto.md
generated
Binary file not shown.
BIN
mobile/openapi/lib/model/system_config_o_auth_dto.dart
generated
BIN
mobile/openapi/lib/model/system_config_o_auth_dto.dart
generated
Binary file not shown.
BIN
mobile/openapi/test/system_config_o_auth_dto_test.dart
generated
BIN
mobile/openapi/test/system_config_o_auth_dto_test.dart
generated
Binary file not shown.
|
@ -6503,6 +6503,9 @@
|
|||
"scope": {
|
||||
"type": "string"
|
||||
},
|
||||
"storageLabelClaim": {
|
||||
"type": "string"
|
||||
},
|
||||
"buttonText": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -6525,6 +6528,7 @@
|
|||
"clientId",
|
||||
"clientSecret",
|
||||
"scope",
|
||||
"storageLabelClaim",
|
||||
"buttonText",
|
||||
"autoRegister",
|
||||
"autoLaunch",
|
||||
|
|
|
@ -240,11 +240,19 @@ export class AuthService {
|
|||
}
|
||||
|
||||
this.logger.log(`Registering new user: ${profile.email}/${profile.sub}`);
|
||||
this.logger.verbose(`OAuth Profile: ${JSON.stringify(profile)}`);
|
||||
|
||||
let storageLabel: string | null = profile[config.oauth.storageLabelClaim as keyof OAuthProfile] as string;
|
||||
if (typeof storageLabel !== 'string') {
|
||||
storageLabel = null;
|
||||
}
|
||||
|
||||
user = await this.userCore.createUser({
|
||||
firstName: profile.given_name || '',
|
||||
lastName: profile.family_name || '',
|
||||
email: profile.email,
|
||||
oauthId: profile.sub,
|
||||
storageLabel,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,9 @@ export class SystemConfigOAuthDto {
|
|||
@IsString()
|
||||
scope!: string;
|
||||
|
||||
@IsString()
|
||||
storageLabelClaim!: string;
|
||||
|
||||
@IsString()
|
||||
buttonText!: string;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ export const defaults = Object.freeze<SystemConfig>({
|
|||
mobileOverrideEnabled: false,
|
||||
mobileRedirectUri: '',
|
||||
scope: 'openid email profile',
|
||||
storageLabelClaim: 'preferred_username',
|
||||
buttonText: 'Login with OAuth',
|
||||
autoRegister: true,
|
||||
autoLaunch: false,
|
||||
|
|
|
@ -53,6 +53,7 @@ const updatedConfig = Object.freeze<SystemConfig>({
|
|||
mobileOverrideEnabled: false,
|
||||
mobileRedirectUri: '',
|
||||
scope: 'openid email profile',
|
||||
storageLabelClaim: 'preferred_username',
|
||||
},
|
||||
passwordLogin: {
|
||||
enabled: true,
|
||||
|
|
|
@ -8,9 +8,9 @@ import {
|
|||
} from '@nestjs/common';
|
||||
import { constants, createReadStream, ReadStream } from 'fs';
|
||||
import fs from 'fs/promises';
|
||||
import sanitize from 'sanitize-filename';
|
||||
import { AuthUserDto } from '../auth';
|
||||
import { ICryptoRepository } from '../crypto';
|
||||
import { CreateAdminDto, CreateUserDto, CreateUserOAuthDto } from './dto/create-user.dto';
|
||||
import { IUserRepository, UserListFilter } from './user.repository';
|
||||
|
||||
const SALT_ROUNDS = 10;
|
||||
|
@ -67,13 +67,13 @@ export class UserCore {
|
|||
}
|
||||
}
|
||||
|
||||
async createUser(createUserDto: CreateUserDto | CreateAdminDto | CreateUserOAuthDto): Promise<UserEntity> {
|
||||
const user = await this.userRepository.getByEmail(createUserDto.email);
|
||||
async createUser(dto: Partial<UserEntity> & { email: string }): Promise<UserEntity> {
|
||||
const user = await this.userRepository.getByEmail(dto.email);
|
||||
if (user) {
|
||||
throw new BadRequestException('User exists');
|
||||
}
|
||||
|
||||
if (!(createUserDto as CreateAdminDto).isAdmin) {
|
||||
if (!dto.isAdmin) {
|
||||
const localAdmin = await this.userRepository.getAdmin();
|
||||
if (!localAdmin) {
|
||||
throw new BadRequestException('The first registered account must the administrator.');
|
||||
|
@ -81,10 +81,13 @@ export class UserCore {
|
|||
}
|
||||
|
||||
try {
|
||||
const payload: Partial<UserEntity> = { ...createUserDto };
|
||||
const payload: Partial<UserEntity> = { ...dto };
|
||||
if (payload.password) {
|
||||
payload.password = await this.cryptoRepository.hashBcrypt(payload.password, SALT_ROUNDS);
|
||||
}
|
||||
if (payload.storageLabel) {
|
||||
payload.storageLabel = sanitize(payload.storageLabel);
|
||||
}
|
||||
return this.userRepository.create(payload);
|
||||
} catch (e) {
|
||||
Logger.error(e, 'Create new user');
|
||||
|
|
|
@ -40,6 +40,7 @@ export enum SystemConfigKey {
|
|||
OAUTH_CLIENT_ID = 'oauth.clientId',
|
||||
OAUTH_CLIENT_SECRET = 'oauth.clientSecret',
|
||||
OAUTH_SCOPE = 'oauth.scope',
|
||||
OAUTH_STORAGE_LABEL_CLAIM = 'oauth.storageLabelClaim',
|
||||
OAUTH_AUTO_LAUNCH = 'oauth.autoLaunch',
|
||||
OAUTH_BUTTON_TEXT = 'oauth.buttonText',
|
||||
OAUTH_AUTO_REGISTER = 'oauth.autoRegister',
|
||||
|
@ -89,6 +90,7 @@ export interface SystemConfig {
|
|||
clientId: string;
|
||||
clientSecret: string;
|
||||
scope: string;
|
||||
storageLabelClaim: string;
|
||||
buttonText: string;
|
||||
autoRegister: boolean;
|
||||
autoLaunch: boolean;
|
||||
|
|
6
web/src/api/open-api/api.ts
generated
6
web/src/api/open-api/api.ts
generated
|
@ -2596,6 +2596,12 @@ export interface SystemConfigOAuthDto {
|
|||
* @memberof SystemConfigOAuthDto
|
||||
*/
|
||||
'scope': string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof SystemConfigOAuthDto
|
||||
*/
|
||||
'storageLabelClaim': string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
|
|
|
@ -155,6 +155,16 @@
|
|||
isEdited={!(oauthConfig.scope == savedConfig.scope)}
|
||||
/>
|
||||
|
||||
<SettingInputField
|
||||
inputType={SettingInputFieldType.TEXT}
|
||||
label="STORAGE LABEL CLAIM"
|
||||
desc="Automatically set the user's storage label to the value of this claim."
|
||||
bind:value={oauthConfig.storageLabelClaim}
|
||||
required={true}
|
||||
disabled={!oauthConfig.storageLabelClaim}
|
||||
isEdited={!(oauthConfig.storageLabelClaim == savedConfig.storageLabelClaim)}
|
||||
/>
|
||||
|
||||
<SettingInputField
|
||||
inputType={SettingInputFieldType.TEXT}
|
||||
label="BUTTON TEXT"
|
||||
|
|
Loading…
Reference in a new issue