feat(cli): add command to show qr code (#2518)
* refactor cli, add commands * add docs * improve * fix ec mode order
This commit is contained in:
+26
-74
@@ -1,84 +1,38 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// ! Auto Imports are not supported in this file
|
||||
|
||||
import { drizzle } from 'drizzle-orm/libsql';
|
||||
import { createClient } from '@libsql/client';
|
||||
import type { Resolvable, SubCommandsDef } from 'citty';
|
||||
import { defineCommand, runMain } from 'citty';
|
||||
import { consola } from 'consola';
|
||||
import { eq } from 'drizzle-orm';
|
||||
|
||||
import packageJson from '../package.json';
|
||||
import * as schema from '../server/database/schema';
|
||||
import { hashPassword } from '../server/utils/password';
|
||||
|
||||
const client = createClient({ url: 'file:/etc/wireguard/wg-easy.db' });
|
||||
const db = drizzle({ client, schema });
|
||||
// Commands
|
||||
import dbAdminReset from './admin/reset';
|
||||
import clientsList from './clients/list';
|
||||
import clientsQr from './clients/qr';
|
||||
const subCommands = [dbAdminReset, clientsList, clientsQr] as const;
|
||||
|
||||
const dbAdminReset = defineCommand({
|
||||
meta: {
|
||||
name: 'db:admin:reset',
|
||||
description: 'Reset the admin user password and TOTP settings',
|
||||
},
|
||||
args: {
|
||||
password: {
|
||||
type: 'string',
|
||||
description: 'New password for the admin user',
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
async run(ctx) {
|
||||
let password = ctx.args.password || undefined;
|
||||
if (!password) {
|
||||
password = await consola.prompt('Please enter a new password:', {
|
||||
type: 'text',
|
||||
});
|
||||
// from citty
|
||||
function resolveValue<T>(input: Resolvable<T>): T | Promise<T> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return typeof input === 'function' ? (input as any)() : input;
|
||||
}
|
||||
|
||||
async function generateSubCommands(): Promise<SubCommandsDef> {
|
||||
const subCommandsMap: Record<string, SubCommandsDef[string]> = {};
|
||||
|
||||
for (const cmd of subCommands) {
|
||||
const cmdMeta = await resolveValue(cmd.meta || {});
|
||||
if (!cmdMeta.name) {
|
||||
console.warn('Skipping command without name:', cmd);
|
||||
continue;
|
||||
}
|
||||
if (!password) {
|
||||
consola.error('Password is required');
|
||||
return;
|
||||
}
|
||||
if (password.length < 12) {
|
||||
consola.error('Password must be at least 12 characters long');
|
||||
return;
|
||||
}
|
||||
console.info('Setting new password for admin user...');
|
||||
const hash = await hashPassword(password);
|
||||
subCommandsMap[cmdMeta.name] = cmd;
|
||||
}
|
||||
|
||||
const user = await db.transaction(async (tx) => {
|
||||
const user = await tx
|
||||
.select()
|
||||
.from(schema.user)
|
||||
.where(eq(schema.user.id, 1))
|
||||
.get();
|
||||
return subCommandsMap;
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
consola.error('Admin user not found');
|
||||
return;
|
||||
}
|
||||
|
||||
await tx
|
||||
.update(schema.user)
|
||||
.set({
|
||||
password: hash,
|
||||
totpVerified: false,
|
||||
totpKey: null,
|
||||
})
|
||||
.where(eq(schema.user.id, 1));
|
||||
|
||||
return user;
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
consola.error('Failed to update admin user');
|
||||
return;
|
||||
}
|
||||
|
||||
consola.success(
|
||||
`Successfully updated admin user ${user.id} (${user.username})`
|
||||
);
|
||||
},
|
||||
});
|
||||
const subCommandsMap = await generateSubCommands();
|
||||
|
||||
const main = defineCommand({
|
||||
meta: {
|
||||
@@ -86,9 +40,7 @@ const main = defineCommand({
|
||||
version: packageJson.version,
|
||||
description: 'Command Line Interface',
|
||||
},
|
||||
subCommands: {
|
||||
'db:admin:reset': dbAdminReset,
|
||||
},
|
||||
subCommands: subCommandsMap,
|
||||
});
|
||||
|
||||
runMain(main);
|
||||
|
||||
Reference in New Issue
Block a user