mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-10-29 17:40:28 +00:00
feat(server): reset admin password using cli command in the server container (#928)
This commit is contained in:
11
server/apps/cli/src/app.module.ts
Normal file
11
server/apps/cli/src/app.module.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { DatabaseModule } from '@app/database';
|
||||
import { UserEntity } from '@app/database/entities/user.entity';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { PromptPasswordQuestions, ResetAdminPasswordCommand } from './commands/reset-admin-password.command';
|
||||
|
||||
@Module({
|
||||
imports: [DatabaseModule, TypeOrmModule.forFeature([UserEntity])],
|
||||
providers: [ResetAdminPasswordCommand, PromptPasswordQuestions],
|
||||
})
|
||||
export class AppModule {}
|
||||
52
server/apps/cli/src/commands/reset-admin-password.command.ts
Normal file
52
server/apps/cli/src/commands/reset-admin-password.command.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { UserEntity } from '@app/database/entities/user.entity';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import bcrypt from 'bcrypt';
|
||||
import { Command, CommandRunner, InquirerService, Question, QuestionSet } from 'nest-commander';
|
||||
import { randomBytes } from 'node:crypto';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
@Command({
|
||||
name: 'reset-admin-password',
|
||||
description: 'Reset the admin password',
|
||||
})
|
||||
export class ResetAdminPasswordCommand extends CommandRunner {
|
||||
constructor(
|
||||
private readonly inquirer: InquirerService,
|
||||
@InjectRepository(UserEntity) private userRepository: Repository<UserEntity>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
let { password } = await this.inquirer.ask<{ password: string }>('prompt-password', undefined);
|
||||
password = password || randomBytes(24).toString('base64').replace(/\W/g, '');
|
||||
|
||||
const salt = await bcrypt.genSalt();
|
||||
const hashedPassword = await bcrypt.hash(password, salt);
|
||||
|
||||
const user = await this.userRepository.findOne({ where: { isAdmin: true } });
|
||||
if (!user) {
|
||||
console.log('Unable to reset password: no admin user.');
|
||||
return;
|
||||
}
|
||||
|
||||
user.salt = salt;
|
||||
user.password = hashedPassword;
|
||||
user.shouldChangePassword = true;
|
||||
|
||||
await this.userRepository.save(user);
|
||||
|
||||
console.log(`New password:\n${password}`);
|
||||
}
|
||||
}
|
||||
|
||||
@QuestionSet({ name: 'prompt-password' })
|
||||
export class PromptPasswordQuestions {
|
||||
@Question({
|
||||
message: 'Please choose a new password (optional)',
|
||||
name: 'password',
|
||||
})
|
||||
parsePassword(val: string) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
7
server/apps/cli/src/immich.ts
Executable file
7
server/apps/cli/src/immich.ts
Executable file
@@ -0,0 +1,7 @@
|
||||
import { CommandFactory } from 'nest-commander';
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
async function bootstrap() {
|
||||
await CommandFactory.run(AppModule, ['warn', 'error']);
|
||||
}
|
||||
bootstrap();
|
||||
9
server/apps/cli/tsconfig.app.json
Normal file
9
server/apps/cli/tsconfig.app.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"declaration": false,
|
||||
"outDir": "../../dist/apps/cli"
|
||||
},
|
||||
"include": ["src/**/*", "../../libs/**/*"],
|
||||
"exclude": ["node_modules", "dist", "test", "**/*spec.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user