UNPKG

bgipfs

Version:
52 lines (51 loc) 2.06 kB
import { input } from '@inquirer/prompts'; import { execa } from 'execa'; import { randomBytes } from 'node:crypto'; import { promises as fs } from 'node:fs'; const DEFAULT_OPTIONS = { force: false, save: true }; export class AuthService { env; constructor(env) { this.env = env; } async createAuthFile(username, password, role) { const htpasswd = `${username}:${await execa('openssl', ['passwd', '-apr1', password]).then((r) => r.stdout)}`; await fs.writeFile(`auth/${role}-htpasswd`, htpasswd); } async setupCredentials(role, args, options = DEFAULT_OPTIONS) { const defaultUsername = role === 'admin' ? 'admin' : 'user'; const username = options.force ? args?.username || defaultUsername : await input({ default: defaultUsername, message: `Enter ${role} username`, }); const authPassword = options.force ? args?.password || (await this.generatePassword()) : await input({ default: args?.password, message: `Enter ${role} password (leave blank to generate)`, }).then((p) => p || this.generatePassword()); // Create auth directory if it doesn't exist await fs.mkdir('auth', { recursive: true }); if (options.save) { // Update env file and htpasswd await this.env.updateEnv([ { key: `${role.toUpperCase()}_USERNAME`, value: username }, { key: `${role.toUpperCase()}_PASSWORD`, value: authPassword }, ]); } await this.createAuthFile(username, authPassword, role); return { password: authPassword, username }; } async generatePassword() { try { const { stdout } = await execa('openssl', ['rand', '-base64', '32']); return stdout.trim(); } catch { // Fall back to Node.js crypto if openssl fails return randomBytes(32).toString('hex'); } } }