mirror of
https://github.com/immich-app/immich.git
synced 2024-11-15 09:59:00 -07:00
feat(server): storage label claim (#3278)
* feat: storage label claim * chore: open api
This commit is contained in:
parent
ed594c1987
commit
f55d63fae8
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}
|
||||
|
1
mobile/openapi/doc/SystemConfigOAuthDto.md
generated
1
mobile/openapi/doc/SystemConfigOAuthDto.md
generated
@ -13,6 +13,7 @@ Name | Type | Description | Notes
|
||||
**clientId** | **String** | |
|
||||
**clientSecret** | **String** | |
|
||||
**scope** | **String** | |
|
||||
**storageLabelClaim** | **String** | |
|
||||
**buttonText** | **String** | |
|
||||
**autoRegister** | **bool** | |
|
||||
**autoLaunch** | **bool** | |
|
||||
|
@ -18,6 +18,7 @@ class SystemConfigOAuthDto {
|
||||
required this.clientId,
|
||||
required this.clientSecret,
|
||||
required this.scope,
|
||||
required this.storageLabelClaim,
|
||||
required this.buttonText,
|
||||
required this.autoRegister,
|
||||
required this.autoLaunch,
|
||||
@ -35,6 +36,8 @@ class SystemConfigOAuthDto {
|
||||
|
||||
String scope;
|
||||
|
||||
String storageLabelClaim;
|
||||
|
||||
String buttonText;
|
||||
|
||||
bool autoRegister;
|
||||
@ -52,6 +55,7 @@ class SystemConfigOAuthDto {
|
||||
other.clientId == clientId &&
|
||||
other.clientSecret == clientSecret &&
|
||||
other.scope == scope &&
|
||||
other.storageLabelClaim == storageLabelClaim &&
|
||||
other.buttonText == buttonText &&
|
||||
other.autoRegister == autoRegister &&
|
||||
other.autoLaunch == autoLaunch &&
|
||||
@ -66,6 +70,7 @@ class SystemConfigOAuthDto {
|
||||
(clientId.hashCode) +
|
||||
(clientSecret.hashCode) +
|
||||
(scope.hashCode) +
|
||||
(storageLabelClaim.hashCode) +
|
||||
(buttonText.hashCode) +
|
||||
(autoRegister.hashCode) +
|
||||
(autoLaunch.hashCode) +
|
||||
@ -73,7 +78,7 @@ class SystemConfigOAuthDto {
|
||||
(mobileRedirectUri.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'SystemConfigOAuthDto[enabled=$enabled, issuerUrl=$issuerUrl, clientId=$clientId, clientSecret=$clientSecret, scope=$scope, buttonText=$buttonText, autoRegister=$autoRegister, autoLaunch=$autoLaunch, mobileOverrideEnabled=$mobileOverrideEnabled, mobileRedirectUri=$mobileRedirectUri]';
|
||||
String toString() => 'SystemConfigOAuthDto[enabled=$enabled, issuerUrl=$issuerUrl, clientId=$clientId, clientSecret=$clientSecret, scope=$scope, storageLabelClaim=$storageLabelClaim, buttonText=$buttonText, autoRegister=$autoRegister, autoLaunch=$autoLaunch, mobileOverrideEnabled=$mobileOverrideEnabled, mobileRedirectUri=$mobileRedirectUri]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
@ -82,6 +87,7 @@ class SystemConfigOAuthDto {
|
||||
json[r'clientId'] = this.clientId;
|
||||
json[r'clientSecret'] = this.clientSecret;
|
||||
json[r'scope'] = this.scope;
|
||||
json[r'storageLabelClaim'] = this.storageLabelClaim;
|
||||
json[r'buttonText'] = this.buttonText;
|
||||
json[r'autoRegister'] = this.autoRegister;
|
||||
json[r'autoLaunch'] = this.autoLaunch;
|
||||
@ -103,6 +109,7 @@ class SystemConfigOAuthDto {
|
||||
clientId: mapValueOfType<String>(json, r'clientId')!,
|
||||
clientSecret: mapValueOfType<String>(json, r'clientSecret')!,
|
||||
scope: mapValueOfType<String>(json, r'scope')!,
|
||||
storageLabelClaim: mapValueOfType<String>(json, r'storageLabelClaim')!,
|
||||
buttonText: mapValueOfType<String>(json, r'buttonText')!,
|
||||
autoRegister: mapValueOfType<bool>(json, r'autoRegister')!,
|
||||
autoLaunch: mapValueOfType<bool>(json, r'autoLaunch')!,
|
||||
@ -160,6 +167,7 @@ class SystemConfigOAuthDto {
|
||||
'clientId',
|
||||
'clientSecret',
|
||||
'scope',
|
||||
'storageLabelClaim',
|
||||
'buttonText',
|
||||
'autoRegister',
|
||||
'autoLaunch',
|
||||
|
@ -41,6 +41,11 @@ void main() {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// String storageLabelClaim
|
||||
test('to test the property `storageLabelClaim`', () async {
|
||||
// TODO
|
||||
});
|
||||
|
||||
// String buttonText
|
||||
test('to test the property `buttonText`', () async {
|
||||
// TODO
|
||||
|
@ -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 New Issue
Block a user