app-wizard-cli
Version:
CLI pour gérer votre projet Nest/Angular
152 lines (151 loc) • 5.43 kB
JavaScript
/**
* @module commands/login
* Implémente la commande `appwizard login` :
* - saisie manuelle,
* - import de fichier JSON (sélection parmi ~/Downloads, filtré),
* - ouverture du navigateur + import.
*/
import open from 'open';
import prompts from 'prompts';
import fs from 'fs-extra';
import * as path from 'path';
import os from 'os';
import { AuthService } from '../services/auth-service.js';
import { ConfigService } from '../services/config-service.js';
export async function loginCommand() {
const auth = new AuthService();
const config = await new ConfigService().getConfig();
const { frontendUrl } = config.endpoints;
// 1) Choix du mode
const modeResp = await prompts({
type: 'select',
name: 'mode',
message: 'Mode de récupération des credentials Service Account :',
choices: [
{ title: 'Manuel (saisie)', value: 'manual' },
{ title: 'Fichier JSON (Downloads)', value: 'file' },
{ title: 'Via navigateur (download)', value: 'web' },
],
initial: 0,
});
const mode = modeResp.mode;
let sa;
// 2) Selon le mode, on récupère clientId/secret
if (mode === 'manual') {
// Saisie manuelle
const resp = await prompts([
{ type: 'text', name: 'clientId', message: 'Client ID :' },
{ type: 'password', name: 'clientSecret', message: 'Client Secret :' },
]);
const clientId = resp.clientId;
const clientSecret = resp.clientSecret;
if (!clientId || !clientSecret) {
console.error('❌ Les deux champs sont requis.');
return;
}
sa = { clientId, clientSecret };
}
else {
// Mode file ou web
if (mode === 'web') {
console.log('🌐 Ouverture du navigateur pour créer votre Service Account…');
await open(`${frontendUrl}/service-account-creation`);
// Prompt pour attendre la création du Service Account
const resp = await prompts({
type: 'confirm',
name: 'confirm',
message: 'Avez-vous créé le Service Account ?',
initial: true,
});
console.log('→ Une fois le JSON téléchargé, choisissez-le ci-dessous.');
}
const downloadDir = path.join(os.homedir(), 'Downloads');
let files = [];
try {
files = (await fs.readdir(downloadDir))
.filter(f => f.toLowerCase().endsWith('.json'));
}
catch {
/* ignore */
}
// Séparer les JSON contenant "credential"
const credFiles = files.filter(f => f.toLowerCase().includes('credential'));
const otherFiles = files.filter(f => !f.toLowerCase().includes('credential'));
// Construire la liste de choix
const choices = [];
// Priorité aux fichiers credentials*
for (const f of credFiles) {
choices.push({
title: f,
value: path.join(downloadDir, f)
});
}
if (otherFiles.length > 0) {
// Séparateur non sélectionnable
choices.push({ title: '--- Autres JSON trouvés ---', value: '' });
for (const f of otherFiles) {
choices.push({
title: f,
value: path.join(downloadDir, f)
});
}
}
// Option manuelle en dernier
choices.push({
title: 'Entrer un chemin manuellement',
value: '__manual'
});
// Prompt de sélection
const sel = await prompts({
type: 'select',
name: 'choice',
message: `Sélectionnez le fichier JSON dans ${downloadDir}:`,
choices,
initial: 0,
});
let filePath = sel.choice;
if (!filePath) {
// Peut être le séparateur vide => fallback manuel
const resp = await prompts({
type: 'text',
name: 'manual',
message: 'Chemin complet vers le JSON :'
});
filePath = resp.manual;
}
else if (filePath === '__manual') {
// Choisi l’option manuelle
const resp = await prompts({
type: 'text',
name: 'manual',
message: 'Chemin complet vers le JSON :'
});
filePath = resp.manual;
}
if (!filePath || !(await fs.pathExists(filePath))) {
console.error('❌ Fichier introuvable ou chemin invalide.');
return;
}
// Lecture et validation du JSON
const json = await fs.readJSON(filePath);
if (!json.clientId || !json.clientSecret) {
console.error('❌ Le JSON ne contient pas clientId/clientSecret.');
return;
}
sa = {
clientId: json.clientId,
clientSecret: json.clientSecret,
};
}
// 3) Persistance et test du token
if (sa) {
await auth.setServiceAccount(sa);
try {
await auth.getAccessToken();
console.log('🎉 Authentification réussie !');
}
catch (err) {
console.error('❌ Impossible de récupérer le token :', err.message || err);
}
}
}