bgipfs
Version:
BuidlGuidl IPFS CLI
52 lines (51 loc) • 2.06 kB
JavaScript
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');
}
}
}