mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 21:00:58 +03:00
feature/cli-reset-password (#4585)
* feat: add cli to reset password * chore: add information for password reset command * fix: add information for password reset command
This commit is contained in:
@@ -20,6 +20,9 @@
|
|||||||
"start-worker": "run-script-os",
|
"start-worker": "run-script-os",
|
||||||
"start-worker:windows": "cd packages/server/bin && run worker",
|
"start-worker:windows": "cd packages/server/bin && run worker",
|
||||||
"start-worker:default": "cd packages/server/bin && ./run worker",
|
"start-worker:default": "cd packages/server/bin && ./run worker",
|
||||||
|
"user": "run-script-os",
|
||||||
|
"user:windows": "cd packages/server/bin && run user",
|
||||||
|
"user:default": "cd packages/server/bin && ./run user",
|
||||||
"test": "turbo run test",
|
"test": "turbo run test",
|
||||||
"clean": "pnpm --filter \"./packages/**\" clean",
|
"clean": "pnpm --filter \"./packages/**\" clean",
|
||||||
"nuke": "pnpm --filter \"./packages/**\" nuke && rimraf node_modules .turbo",
|
"nuke": "pnpm --filter \"./packages/**\" nuke && rimraf node_modules .turbo",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Command, Flags } from '@oclif/core'
|
import { Command, Flags } from '@oclif/core'
|
||||||
import path from 'path'
|
|
||||||
import dotenv from 'dotenv'
|
import dotenv from 'dotenv'
|
||||||
|
import path from 'path'
|
||||||
import logger from '../utils/logger'
|
import logger from '../utils/logger'
|
||||||
|
|
||||||
dotenv.config({ path: path.join(__dirname, '..', '..', '.env'), override: true })
|
dotenv.config({ path: path.join(__dirname, '..', '..', '.env'), override: true })
|
||||||
@@ -120,7 +120,7 @@ export abstract class BaseCommand extends Command {
|
|||||||
logger.error('unhandledRejection: ', err)
|
logger.error('unhandledRejection: ', err)
|
||||||
})
|
})
|
||||||
|
|
||||||
const { flags } = await this.parse(BaseCommand)
|
const { flags } = await this.parse(this.constructor as any)
|
||||||
if (flags.PORT) process.env.PORT = flags.PORT
|
if (flags.PORT) process.env.PORT = flags.PORT
|
||||||
if (flags.CORS_ORIGINS) process.env.CORS_ORIGINS = flags.CORS_ORIGINS
|
if (flags.CORS_ORIGINS) process.env.CORS_ORIGINS = flags.CORS_ORIGINS
|
||||||
if (flags.IFRAME_ORIGINS) process.env.IFRAME_ORIGINS = flags.IFRAME_ORIGINS
|
if (flags.IFRAME_ORIGINS) process.env.IFRAME_ORIGINS = flags.IFRAME_ORIGINS
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import { Args } from '@oclif/core'
|
||||||
|
import { QueryRunner } from 'typeorm'
|
||||||
|
import * as DataSource from '../DataSource'
|
||||||
|
import { User } from '../enterprise/database/entities/user.entity'
|
||||||
|
import { getHash } from '../enterprise/utils/encryption.util'
|
||||||
|
import { isInvalidPassword } from '../enterprise/utils/validation.util'
|
||||||
|
import logger from '../utils/logger'
|
||||||
|
import { BaseCommand } from './base'
|
||||||
|
|
||||||
|
export default class user extends BaseCommand {
|
||||||
|
static args = {
|
||||||
|
email: Args.string({
|
||||||
|
description: 'Email address to search for in the user database'
|
||||||
|
}),
|
||||||
|
password: Args.string({
|
||||||
|
description: 'New password for that user'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(): Promise<void> {
|
||||||
|
const { args } = await this.parse(user)
|
||||||
|
|
||||||
|
let queryRunner: QueryRunner | undefined
|
||||||
|
try {
|
||||||
|
logger.info('Initializing DataSource')
|
||||||
|
const dataSource = await DataSource.getDataSource()
|
||||||
|
await dataSource.initialize()
|
||||||
|
|
||||||
|
queryRunner = dataSource.createQueryRunner()
|
||||||
|
await queryRunner.connect()
|
||||||
|
|
||||||
|
if (args.email && args.password) {
|
||||||
|
logger.info('Running resetPassword')
|
||||||
|
await this.resetPassword(queryRunner, args.email, args.password)
|
||||||
|
} else {
|
||||||
|
logger.info('Running listUserEmails')
|
||||||
|
await this.listUserEmails(queryRunner)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error)
|
||||||
|
} finally {
|
||||||
|
if (queryRunner && !queryRunner.isReleased) await queryRunner.release()
|
||||||
|
await this.gracefullyExit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async listUserEmails(queryRunner: QueryRunner) {
|
||||||
|
logger.info('Listing all user emails')
|
||||||
|
const users = await queryRunner.manager.find(User, {
|
||||||
|
select: ['email']
|
||||||
|
})
|
||||||
|
|
||||||
|
const emails = users.map((user) => user.email)
|
||||||
|
logger.info(`Email addresses: ${emails.join(', ')}`)
|
||||||
|
logger.info(`Email count: ${emails.length}`)
|
||||||
|
logger.info('To reset user password, run the following command: pnpm user --email "myEmail" --password "myPassword"')
|
||||||
|
}
|
||||||
|
|
||||||
|
async resetPassword(queryRunner: QueryRunner, email: string, password: string) {
|
||||||
|
logger.info(`Finding user by email: ${email}`)
|
||||||
|
const user = await queryRunner.manager.findOne(User, {
|
||||||
|
where: { email }
|
||||||
|
})
|
||||||
|
if (!user) throw new Error(`User not found with email: ${email}`)
|
||||||
|
|
||||||
|
if (isInvalidPassword(password)) {
|
||||||
|
const errors = []
|
||||||
|
if (!/(?=.*[a-z])/.test(password)) errors.push('at least one lowercase letter')
|
||||||
|
if (!/(?=.*[A-Z])/.test(password)) errors.push('at least one uppercase letter')
|
||||||
|
if (!/(?=.*\d)/.test(password)) errors.push('at least one number')
|
||||||
|
if (!/(?=.*[^a-zA-Z0-9])/.test(password)) errors.push('at least one special character')
|
||||||
|
if (password.length < 8) errors.push('minimum length of 8 characters')
|
||||||
|
throw new Error(`Invalid password: Must contain ${errors.join(', ')}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
user.credential = getHash(password)
|
||||||
|
await queryRunner.manager.save(user)
|
||||||
|
logger.info(`Password reset for user: ${email}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user