mirror of
https://github.com/immich-app/immich.git
synced 2024-12-29 15:11:58 +00:00
feat(server): reset admin password using cli command in the server container (#928)
This commit is contained in:
parent
dd8a4c0c56
commit
02bc84062e
9 changed files with 300 additions and 277 deletions
|
@ -26,9 +26,10 @@ RUN mkdir -p /usr/src/app/dist \
|
||||||
|
|
||||||
COPY --from=builder /usr/src/app/node_modules ./node_modules
|
COPY --from=builder /usr/src/app/node_modules ./node_modules
|
||||||
COPY --from=builder /usr/src/app/dist ./dist
|
COPY --from=builder /usr/src/app/dist ./dist
|
||||||
|
COPY --from=builder /usr/src/app/bin ./bin
|
||||||
|
|
||||||
RUN npm prune --production
|
RUN npm prune --production
|
||||||
|
|
||||||
VOLUME /usr/src/app/upload
|
VOLUME /usr/src/app/upload
|
||||||
|
|
||||||
EXPOSE 3001
|
EXPOSE 3001
|
||||||
|
|
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"]
|
||||||
|
}
|
1
server/bin/cli.sh
Executable file
1
server/bin/cli.sh
Executable file
|
@ -0,0 +1 @@
|
||||||
|
node ./dist/apps/cli/apps/cli/src/immich "$@"
|
|
@ -6,13 +6,15 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"webpack": false,
|
"webpack": false,
|
||||||
"tsConfigPath": "apps/immich/tsconfig.app.json",
|
"tsConfigPath": "apps/immich/tsconfig.app.json",
|
||||||
"plugins": [ {
|
"plugins": [
|
||||||
"name": "@nestjs/swagger",
|
{
|
||||||
"options": {
|
"name": "@nestjs/swagger",
|
||||||
"classValidatorShim": false,
|
"options": {
|
||||||
"introspectComments": true
|
"classValidatorShim": false,
|
||||||
|
"introspectComments": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}]
|
]
|
||||||
},
|
},
|
||||||
"projects": {
|
"projects": {
|
||||||
"immich": {
|
"immich": {
|
||||||
|
@ -33,6 +35,15 @@
|
||||||
"tsConfigPath": "apps/microservices/tsconfig.app.json"
|
"tsConfigPath": "apps/microservices/tsconfig.app.json"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"cli": {
|
||||||
|
"type": "application",
|
||||||
|
"root": "apps/cli",
|
||||||
|
"entryFile": "immich",
|
||||||
|
"sourceRoot": "apps/cli/src",
|
||||||
|
"compilerOptions": {
|
||||||
|
"tsConfigPath": "apps/cli/tsconfig.app.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"root": "libs/common",
|
"root": "libs/common",
|
||||||
|
|
465
server/package-lock.json
generated
465
server/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -5,9 +5,12 @@
|
||||||
"author": "",
|
"author": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
|
"bin": {
|
||||||
|
"immich": "./bin/cli.sh"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "rimraf dist",
|
"prebuild": "rimraf dist",
|
||||||
"build": "nest build immich && nest build microservices",
|
"build": "nest build immich && nest build microservices && nest build cli",
|
||||||
"format": "prettier --write \"apps/**/*.ts\" \"libs/**/*.ts\"",
|
"format": "prettier --write \"apps/**/*.ts\" \"libs/**/*.ts\"",
|
||||||
"start": "nest start",
|
"start": "nest start",
|
||||||
"start:dev": "nest start --watch",
|
"start:dev": "nest start --watch",
|
||||||
|
@ -59,6 +62,7 @@
|
||||||
"local-reverse-geocoder": "^0.12.5",
|
"local-reverse-geocoder": "^0.12.5",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"luxon": "^3.0.3",
|
"luxon": "^3.0.3",
|
||||||
|
"nest-commander": "^3.3.0",
|
||||||
"passport": "^0.6.0",
|
"passport": "^0.6.0",
|
||||||
"passport-jwt": "^4.0.0",
|
"passport-jwt": "^4.0.0",
|
||||||
"pg": "^8.7.1",
|
"pg": "^8.7.1",
|
||||||
|
|
Loading…
Reference in a new issue