docs+ops: vault sync workflow; deploy-all with live progress and URL checks; prompt updates

This commit is contained in:
4NK Dev 2025-10-01 22:17:40 +00:00
parent d48ccc8fbc
commit e90c0fe2f2
14 changed files with 1178 additions and 0 deletions

Binary file not shown.

27
sdk-client/dist/examples/usage.d.ts vendored Normal file
View File

@ -0,0 +1,27 @@
/**
* Exemple d'utilisation du client Vault
* Scénario complet : Initialisation Routes Parcours Déchiffrement
*/
import { SecureVaultClient } from '../src/index';
/**
* ÉTAPE 1: Initialisation + Gestion des erreurs
*/
declare function step1_Initialization(): Promise<SecureVaultClient>;
/**
* ÉTAPE 2: Récupération de toutes les routes + Gestion des erreurs
*/
declare function step2_GetRoutes(client: SecureVaultClient): Promise<import("../src/index").VaultRoutes>;
/**
* ÉTAPE 3: Parcours de toutes les routes pour récupération du contenu + Gestion des erreurs
*/
declare function step3_ParseRoutes(routes: any, client: SecureVaultClient): Promise<any[]>;
/**
* ÉTAPE 4: Synchronisation locale des fichiers déchiffrés + Gestion des erreurs
*/
declare function step4_SyncLocalFiles(client: SecureVaultClient): Promise<void>;
/**
* ÉTAPE 5: Déchiffrement des contenus récupérés (non stocké) + Gestion des erreurs
*/
declare function step5_DecryptContents(results: any[]): Promise<void>;
export { step1_Initialization, step2_GetRoutes, step3_ParseRoutes, step4_SyncLocalFiles, step5_DecryptContents };
//# sourceMappingURL=usage.d.ts.map

View File

@ -0,0 +1 @@
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../examples/usage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAiE,MAAM,cAAc,CAAC;AAEhH;;GAEG;AACH,iBAAe,oBAAoB,+BA+DlC;AAED;;GAEG;AACH,iBAAe,eAAe,CAAC,MAAM,EAAE,iBAAiB,+CAuDvD;AAED;;GAEG;AACH,iBAAe,iBAAiB,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,iBAAiB,kBA0GtE;AAED;;GAEG;AACH,iBAAe,oBAAoB,CAAC,MAAM,EAAE,iBAAiB,iBAiD5D;AAED;;GAEG;AACH,iBAAe,qBAAqB,CAAC,OAAO,EAAE,GAAG,EAAE,iBA+ElD;AAgDD,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACtB,CAAC"}

388
sdk-client/dist/examples/usage.js vendored Normal file
View File

@ -0,0 +1,388 @@
"use strict";
/**
* Exemple d'utilisation du client Vault
* Scénario complet : Initialisation Routes Parcours Déchiffrement
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.step1_Initialization = step1_Initialization;
exports.step2_GetRoutes = step2_GetRoutes;
exports.step3_ParseRoutes = step3_ParseRoutes;
exports.step4_SyncLocalFiles = step4_SyncLocalFiles;
exports.step5_DecryptContents = step5_DecryptContents;
const index_1 = require("../src/index");
/**
* ÉTAPE 1: Initialisation + Gestion des erreurs
*/
async function step1_Initialization() {
console.log('🚀 ÉTAPE 1: Initialisation du client + Gestion des erreurs');
console.log('='.repeat(70));
try {
// Test avec différents IDs utilisateur
const testUserIds = [
'demo_user_001', // ID existant
'invalid@user', // ID invalide (caractères interdits)
'ab', // ID trop court
'a'.repeat(129), // ID trop long
'3506ea43d9207038eea58caca84d51e4ccc01c496b6572bbf4dfda7fa03085b8' // Votre clé
];
let validClient = null;
for (const userId of testUserIds) {
try {
console.log(`\n🔍 Test avec l'ID: ${userId.substring(0, 20)}${userId.length > 20 ? '...' : ''}`);
// Utiliser le constructeur avec chargement automatique des clés .env
// Pour le test avec les vraies clés, utiliser le constructeur sans paramètres
const client = userId === 'demo_user_001' ? new index_1.SecureVaultClient() : new index_1.SecureVaultClient({
baseUrl: 'https://vault.4nkweb.com:6666',
userId: userId,
timeout: 30000,
verifySsl: false
});
// Test de connectivité
const isConnected = await client.ping();
if (isConnected) {
console.log(` ✅ ID valide et connecté: ${userId}`);
if (!validClient) {
validClient = client;
}
}
else {
console.log(` ❌ ID valide mais non connecté: ${userId}`);
}
}
catch (error) {
if (error instanceof index_1.VaultAuthenticationError) {
console.log(` 🔑 Erreur d'authentification: ${error.message}`);
}
else if (error.message.includes('ID utilisateur requis') || error.message.includes('invalide')) {
console.log(` ⚠️ ID invalide: ${error.message}`);
}
else {
console.log(` ❌ Erreur inattendue: ${error.message}`);
}
}
}
if (!validClient) {
throw new Error('Aucun client valide trouvé - impossible de continuer');
}
console.log('\n✅ ÉTAPE 1 TERMINÉE: Client initialisé avec succès');
return validClient;
}
catch (error) {
console.error('\n❌ ÉTAPE 1 ÉCHOUÉE:', error);
throw error;
}
}
/**
* ÉTAPE 2: Récupération de toutes les routes + Gestion des erreurs
*/
async function step2_GetRoutes(client) {
console.log('\n🛣 ÉTAPE 2: Récupération de toutes les routes + Gestion des erreurs');
console.log('='.repeat(70));
try {
// Test de récupération des routes
console.log('\n📋 Récupération des routes disponibles...');
const routes = await client.getRoutes();
console.log(` ✅ Total des routes: ${routes.total_routes}`);
console.log(` ✅ Utilisateur: ${routes.user_id}`);
console.log(` ✅ Type d'authentification: ${routes.authentication.type}`);
console.log('\n📝 Routes disponibles:');
routes.routes.forEach((route, index) => {
console.log(` ${index + 1}. ${route.method} ${route.path}`);
console.log(`${route.description}`);
console.log(` → Authentification: ${route.authentication}`);
console.log(` → Type de réponse: ${route.response_type}`);
if (route.parameters) {
console.log(` → Paramètres:`);
Object.entries(route.parameters).forEach(([key, value]) => {
console.log(`${key}: ${value}`);
});
}
if (route.examples && route.examples.length > 0) {
console.log(` → Exemples:`);
route.examples.forEach(example => {
console.log(`${example}`);
});
}
console.log('');
});
console.log('✅ ÉTAPE 2 TERMINÉE: Routes récupérées avec succès');
return routes;
}
catch (error) {
console.error('\n❌ ÉTAPE 2 ÉCHOUÉE:');
if (error instanceof index_1.VaultApiError) {
console.error(` Erreur API: ${error.message}`);
console.error(` Code HTTP: ${error.statusCode}`);
console.error(` Code d'erreur: ${error.code}`);
}
else if (error instanceof index_1.VaultAuthenticationError) {
console.error(` Erreur d'authentification: ${error.message}`);
console.error(` Code HTTP: ${error.statusCode}`);
}
else {
console.error(` Erreur inattendue: ${error.message}`);
}
throw error;
}
}
/**
* ÉTAPE 3: Parcours de toutes les routes pour récupération du contenu + Gestion des erreurs
*/
async function step3_ParseRoutes(routes, client) {
console.log('\n📁 ÉTAPE 3: Parcours des routes pour récupération du contenu + Gestion des erreurs');
console.log('='.repeat(70));
const results = [];
try {
for (const route of routes.routes) {
console.log(`\n🔍 Test de la route: ${route.method} ${route.path}`);
try {
let result = null;
switch (route.path) {
case '/health':
result = await client.health();
console.log(` ✅ Health: ${result.status} - ${result.service}`);
break;
case '/info':
result = await client.info();
console.log(` ✅ Info: ${result.name} v${result.version}`);
break;
case '/routes':
result = await client.getRoutes();
console.log(` ✅ Routes: ${result.total_routes} routes disponibles`);
break;
default:
// Route dynamique /<env>/<file_path>
if (route.path.includes('<env>') && route.path.includes('<file_path>')) {
console.log(` 📂 Test des fichiers de configuration...`);
// Tester quelques fichiers de configuration connus
const testFiles = [
'bitcoin/bitcoin.conf',
'nginx/nginx.conf',
'grafana/grafana.ini'
];
for (const filePath of testFiles) {
try {
const fileResult = await client.getFile('dev', filePath);
console.log(`${filePath}: ${fileResult.size} caractères`);
results.push({
route: `${route.method} /dev/${filePath}`,
success: true,
data: fileResult
});
}
catch (fileError) {
console.log(`${filePath}: ${fileError.message}`);
results.push({
route: `${route.method} /dev/${filePath}`,
success: false,
error: fileError.message
});
}
}
}
break;
}
if (result) {
results.push({
route: `${route.method} ${route.path}`,
success: true,
data: result
});
}
}
catch (error) {
console.log(` ❌ Erreur: ${error.message}`);
if (error instanceof index_1.VaultApiError) {
console.log(` → Code HTTP: ${error.statusCode}`);
console.log(` → Code d'erreur: ${error.code}`);
}
else if (error instanceof index_1.VaultAuthenticationError) {
console.log(` → Erreur d'authentification`);
}
else if (error instanceof index_1.VaultDecryptionError) {
console.log(` → Erreur de déchiffrement`);
}
results.push({
route: `${route.method} ${route.path}`,
success: false,
error: error.message,
errorType: error.name
});
}
}
console.log(`\n📊 Résumé des tests:`);
const successCount = results.filter(r => r.success).length;
const errorCount = results.filter(r => !r.success).length;
console.log(` ✅ Succès: ${successCount}/${results.length}`);
console.log(` ❌ Erreurs: ${errorCount}/${results.length}`);
console.log('\n✅ ÉTAPE 3 TERMINÉE: Parcours des routes terminé');
return results;
}
catch (error) {
console.error('\n❌ ÉTAPE 3 ÉCHOUÉE:', error);
throw error;
}
}
/**
* ÉTAPE 4: Synchronisation locale des fichiers déchiffrés + Gestion des erreurs
*/
async function step4_SyncLocalFiles(client) {
console.log('\n💾 ÉTAPE 4: Synchronisation locale des fichiers déchiffrés + Gestion des erreurs');
console.log('='.repeat(70));
try {
console.log('\n🔄 Synchronisation des fichiers vers le dossier local...');
console.log(' Utilise VAULT_CONFS_DIR depuis le fichier .env');
// Synchronisation avec options détaillées
// Ne pas spécifier localDir pour utiliser VAULT_CONFS_DIR du .env
const syncResult = await client.syncLocalFiles({
environment: 'dev',
verbose: true
});
console.log(`\n📊 Résultats de synchronisation:`);
console.log(` ✅ Fichiers synchronisés: ${syncResult.synced}`);
console.log(` ⏭️ Fichiers ignorés: ${syncResult.skipped}`);
console.log(` ❌ Erreurs: ${syncResult.errors}`);
// Affichage détaillé des résultats
if (syncResult.details.length > 0) {
console.log('\n📋 Détails par fichier:');
syncResult.details.forEach(detail => {
const icon = detail.status === 'synced' ? '✅' :
detail.status === 'skipped' ? '⏭️' : '❌';
console.log(` ${icon} ${detail.file}: ${detail.status}`);
if (detail.message) {
console.log(`${detail.message}`);
}
});
}
console.log('\n✅ ÉTAPE 4 TERMINÉE: Synchronisation locale terminée');
}
catch (error) {
console.error('\n❌ ÉTAPE 4 ÉCHOUÉE:');
if (error instanceof index_1.VaultApiError) {
console.error(` Erreur API: ${error.message}`);
console.error(` Code HTTP: ${error.statusCode}`);
}
else if (error.message.includes('synchronisation')) {
console.error(` Erreur de synchronisation: ${error.message}`);
}
else {
console.error(` Erreur inattendue: ${error.message}`);
}
throw error;
}
}
/**
* ÉTAPE 5: Déchiffrement des contenus récupérés (non stocké) + Gestion des erreurs
*/
async function step5_DecryptContents(results) {
console.log('\n🔓 ÉTAPE 5: Déchiffrement des contenus récupérés + Gestion des erreurs');
console.log('='.repeat(70));
try {
const fileResults = results.filter(r => r.success && r.data && r.data.content);
if (fileResults.length === 0) {
console.log(' ⚠️ Aucun fichier récupéré pour déchiffrement');
return;
}
console.log(`\n🔍 Déchiffrement de ${fileResults.length} fichier(s)...`);
for (const fileResult of fileResults) {
console.log(`\n📄 Fichier: ${fileResult.route}`);
try {
const content = fileResult.data.content;
// Vérifier si le contenu est chiffré (format de démonstration)
if (content.includes('[CONTENU CHIFFRÉ - DÉCHIFFREMENT NÉCESSAIRE]')) {
console.log(' 🔐 Contenu chiffré détecté (format de démonstration)');
// Extraire les métadonnées du format de démonstration
const lines = content.split('\n');
const metadata = {};
lines.forEach((line) => {
if (line.includes('Utilisateur:')) {
metadata.user = line.split('Utilisateur:')[1]?.trim() || '';
}
else if (line.includes('Version de clé:')) {
metadata.keyVersion = line.split('Version de clé:')[1]?.trim() || '';
}
else if (line.includes('Algorithme:')) {
metadata.algorithm = line.split('Algorithme:')[1]?.trim() || '';
}
else if (line.includes('Rotation:')) {
metadata.rotation = line.split('Rotation:')[1]?.trim() || '';
}
else if (line.includes('Taille chiffrée:')) {
metadata.encryptedSize = line.split('Taille chiffrée:')[1]?.trim() || '';
}
});
console.log(` 📋 Métadonnées extraites:`);
console.log(` → Utilisateur: ${metadata.user}`);
console.log(` → Version de clé: ${metadata.keyVersion}`);
console.log(` → Algorithme: ${metadata.algorithm}`);
console.log(` → Rotation: ${metadata.rotation}`);
console.log(` → Taille chiffrée: ${metadata.encryptedSize}`);
// Dans un vrai déchiffrement, on utiliserait la clé utilisateur
console.log(` 🔑 Déchiffrement simulé: Contenu accessible avec la clé utilisateur`);
}
else {
console.log(' 📝 Contenu non chiffré détecté');
console.log(` 📄 Aperçu: ${content.substring(0, 100)}${content.length > 100 ? '...' : ''}`);
}
console.log(` ✅ Déchiffrement traité avec succès`);
}
catch (error) {
console.log(` ❌ Erreur de déchiffrement: ${error.message}`);
if (error instanceof index_1.VaultDecryptionError) {
console.log(` → Erreur de déchiffrement spécifique`);
console.log(` → Code: ${error.code}`);
}
else if (error.message.includes('déchiffrement')) {
console.log(` → Erreur de traitement du contenu`);
}
else {
console.log(` → Erreur inattendue lors du déchiffrement`);
}
}
}
console.log('\n✅ ÉTAPE 5 TERMINÉE: Déchiffrement des contenus terminé');
}
catch (error) {
console.error('\n❌ ÉTAPE 5 ÉCHOUÉE:', error);
throw error;
}
}
/**
* Fonction principale - Exécute le scénario complet
*/
async function main() {
console.log('🚀 DÉMONSTRATION COMPLÈTE DU CLIENT VAULT');
console.log('Scénario: Initialisation → Routes → Parcours → Synchronisation → Déchiffrement');
console.log('='.repeat(80));
try {
// ÉTAPE 1: Initialisation
const client = await step1_Initialization();
// ÉTAPE 2: Récupération des routes
const routes = await step2_GetRoutes(client);
// ÉTAPE 3: Parcours des routes
const results = await step3_ParseRoutes(routes, client);
// ÉTAPE 4: Synchronisation locale
await step4_SyncLocalFiles(client);
// ÉTAPE 5: Déchiffrement
await step5_DecryptContents(results);
console.log('\n🎉 SCÉNARIO COMPLET TERMINÉ AVEC SUCCÈS!');
console.log('\n📝 Résumé du système sécurisé:');
console.log(' • ✅ Authentification par ID utilisateur validée');
console.log(' • ✅ Récupération des routes API fonctionnelle');
console.log(' • ✅ Parcours de toutes les routes testé');
console.log(' • ✅ Synchronisation locale des fichiers déchiffrés');
console.log(' • ✅ Déchiffrement des contenus géré');
console.log(' • ✅ Gestion d\'erreurs complète à chaque étape');
console.log(' • ✅ Rotation automatique des clés active');
console.log(' • ✅ Chiffrement quantum-résistant (ChaCha20-Poly1305)');
}
catch (error) {
console.error('\n💥 ÉCHEC DU SCÉNARIO:', error);
process.exit(1);
}
}
// Exécution si appelé directement
if (require.main === module) {
main().catch(console.error);
}
//# sourceMappingURL=usage.js.map

1
sdk-client/dist/examples/usage.js.map vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,4 @@
/**
* Configuration des tests pour le SDK Vault Client
*/
//# sourceMappingURL=setup.d.ts.map

View File

@ -0,0 +1 @@
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/__tests__/setup.ts"],"names":[],"mappings":"AAAA;;GAEG"}

26
sdk-client/dist/src/__tests__/setup.js vendored Normal file
View File

@ -0,0 +1,26 @@
"use strict";
/**
* Configuration des tests pour le SDK Vault Client
*/
// Configuration globale pour les tests
beforeAll(() => {
// Configuration des timeouts pour les tests
jest.setTimeout(30000);
});
beforeEach(() => {
// Reset des mocks avant chaque test
jest.clearAllMocks();
});
afterEach(() => {
// Nettoyage après chaque test
jest.restoreAllMocks();
});
// Mock des modules Node.js si nécessaire
jest.mock('crypto', () => ({
...jest.requireActual('crypto'),
createDecipher: jest.fn(),
}));
// Variables d'environnement pour les tests
process.env['NODE_ENV'] = 'test';
process.env['TZ'] = 'UTC';
//# sourceMappingURL=setup.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/__tests__/setup.ts"],"names":[],"mappings":";AAAA;;GAEG;AAEH,uCAAuC;AACvC,SAAS,CAAC,GAAG,EAAE;IACb,4CAA4C;IAC5C,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AACzB,CAAC,CAAC,CAAC;AAEH,UAAU,CAAC,GAAG,EAAE;IACd,oCAAoC;IACpC,IAAI,CAAC,aAAa,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,8BAA8B;IAC9B,IAAI,CAAC,eAAe,EAAE,CAAC;AACzB,CAAC,CAAC,CAAC;AAEH,yCAAyC;AACzC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IACzB,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;IAC/B,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE;CAC1B,CAAC,CAAC,CAAC;AAEJ,2CAA2C;AAC3C,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC;AACjC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC"}

167
sdk-client/dist/src/index.d.ts vendored Normal file
View File

@ -0,0 +1,167 @@
export interface VaultConfig {
baseUrl: string;
verifySsl?: boolean;
timeout?: number;
userId: string;
}
export interface VaultFile {
content: string;
filename: string;
size: number;
encrypted: boolean;
algorithm?: string | undefined;
user_id?: string | undefined;
key_version?: string | undefined;
timestamp?: string | undefined;
}
export interface VaultHealth {
status: string;
service: string;
encryption: string;
algorithm: string;
authentication?: string;
key_rotation?: string;
timestamp?: string;
}
export interface VaultInfo {
name: string;
version: string;
domain: string;
port: number;
protocol: string;
encryption: string;
authentication?: string;
key_rotation?: string;
endpoints?: Record<string, string>;
}
export interface VaultRoute {
method: string;
path: string;
description: string;
authentication: string;
headers_required: string[];
response_type: string;
parameters?: Record<string, string>;
examples?: string[];
}
export interface VaultRoutes {
routes: VaultRoute[];
total_routes: number;
authentication: {
type: string;
header: string;
description: string;
};
user_id: string;
timestamp: string;
}
export interface SyncOptions {
environment: string;
localDir?: string;
verbose?: boolean;
}
export interface SyncResult {
synced: number;
skipped: number;
errors: number;
details: Array<{
file: string;
status: 'synced' | 'skipped' | 'error';
message?: string;
}>;
}
export interface VaultError {
message: string;
code?: string | undefined;
statusCode?: number | undefined;
}
export declare class VaultApiError extends Error implements VaultError {
readonly code?: string | undefined;
readonly statusCode?: number | undefined;
constructor(message: string, code?: string, statusCode?: number);
}
export declare class VaultDecryptionError extends Error implements VaultError {
readonly code?: string | undefined;
constructor(message: string, code?: string);
}
export declare class VaultAuthenticationError extends Error implements VaultError {
readonly code?: string | undefined;
readonly statusCode?: number | undefined;
constructor(message: string, code?: string, statusCode?: number);
}
/**
* Client sécurisé pour l'API Vault avec authentification par clés utilisateur
* Les clés sont gérées côté serveur avec rotation automatique
*/
export declare class SecureVaultClient {
private config;
private vaultKey;
constructor(config?: VaultConfig);
/**
* Récupère un fichier depuis l'API Vault
*/
getFile(env: string, filePath: string): Promise<VaultFile>;
/**
* Récupère plusieurs fichiers en parallèle
*/
getFiles(env: string, filePaths: string[]): Promise<VaultFile[]>;
/**
* Recherche des fichiers correspondant à un pattern
*/
searchFiles(_env: string, _pattern: string): Promise<VaultFile[]>;
/**
* Vérifie l'état de santé de l'API
*/
health(): Promise<VaultHealth>;
/**
* Récupère les informations sur l'API
*/
info(): Promise<VaultInfo>;
/**
* Test de connectivité simple
*/
ping(): Promise<boolean>;
/**
* Récupère toutes les routes disponibles de l'API
*/
getRoutes(): Promise<VaultRoutes>;
/**
* Synchronise les fichiers déchiffrés localement
* Route vault /<env>/<project>/<file_name> -> ../confs/<project>/<file_name>
* Les fichiers existants dans confs/ sont toujours écrasés pour avoir le contenu le plus récent
*/
syncLocalFiles(options: SyncOptions): Promise<SyncResult>;
/**
* Déchiffre le contenu avec les métadonnées utilisateur et gère la prochaine clé
*/
private decryptContent;
/**
* Met à jour la prochaine clé pour les requêtes suivantes et le fichier .env
*/
private updateNextKey;
/**
* Retourne le répertoire du fichier .env trouvé
*/
private _getEnvFileDirectory;
/**
* Charge les variables d'environnement depuis plusieurs emplacements possibles
*/
private _loadEnvironmentVariables;
/**
* Met à jour le fichier .env avec la nouvelle clé
*/
private updateEnvFile;
/**
* Effectue une requête vers l'API avec authentification
*/
private _fetchApi;
}
/**
* Fonction utilitaire pour créer un client sécurisé
*/
export declare function createSecureVaultClient(baseUrl: string, userId: string): SecureVaultClient;
/**
* Fonction utilitaire pour créer un client sécurisé avec configuration complète
*/
export declare function createSecureVaultClientWithConfig(config: VaultConfig): SecureVaultClient;
//# sourceMappingURL=index.d.ts.map

1
sdk-client/dist/src/index.d.ts.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}

559
sdk-client/dist/src/index.js vendored Normal file
View File

@ -0,0 +1,559 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SecureVaultClient = exports.VaultAuthenticationError = exports.VaultDecryptionError = exports.VaultApiError = void 0;
exports.createSecureVaultClient = createSecureVaultClient;
exports.createSecureVaultClientWithConfig = createSecureVaultClientWithConfig;
const node_fetch_1 = __importDefault(require("node-fetch"));
const https_1 = __importDefault(require("https"));
const dotenv_1 = __importDefault(require("dotenv"));
const { chacha20poly1305 } = require('@noble/ciphers/chacha.js');
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
class VaultApiError extends Error {
constructor(message, code, statusCode) {
super(message);
this.name = 'VaultApiError';
this.code = code;
this.statusCode = statusCode;
}
}
exports.VaultApiError = VaultApiError;
class VaultDecryptionError extends Error {
constructor(message, code) {
super(message);
this.name = 'VaultDecryptionError';
this.code = code;
}
}
exports.VaultDecryptionError = VaultDecryptionError;
class VaultAuthenticationError extends Error {
constructor(message, code, statusCode) {
super(message);
this.name = 'VaultAuthenticationError';
this.code = code;
this.statusCode = statusCode;
}
}
exports.VaultAuthenticationError = VaultAuthenticationError;
/**
* Client sécurisé pour l'API Vault avec authentification par clés utilisateur
* Les clés sont gérées côté serveur avec rotation automatique
*/
class SecureVaultClient {
constructor(config) {
this.vaultKey = null;
// Charger les variables d'environnement depuis .env
// Essayer plusieurs emplacements pour le fichier .env
this._loadEnvironmentVariables();
// Si pas de config fournie, utiliser les variables d'environnement
if (!config) {
const envUser = process.env['VAULT_USER'];
const envKey = process.env['VAULT_KEY'];
const envEnv = process.env['VAULT_ENV'];
if (!envUser || !envKey || !envEnv) {
throw new Error('Variables d\'environnement requises: VAULT_USER, VAULT_KEY, VAULT_ENV');
}
config = {
baseUrl: 'https://vault.4nkweb.com:6666',
userId: envUser,
timeout: 30000,
verifySsl: false
};
this.vaultKey = envKey;
}
this.config = {
verifySsl: false,
timeout: 30000,
...config,
};
// Validation de l'ID utilisateur
if (!this.config.userId || this.config.userId.length < 3 || this.config.userId.length > 128) {
throw new Error('ID utilisateur requis (3-128 caractères)');
}
if (!/^[a-zA-Z0-9_-]+$/.test(this.config.userId)) {
throw new Error('ID utilisateur invalide - caractères autorisés: a-z, A-Z, 0-9, _, -');
}
}
/**
* Récupère un fichier depuis l'API Vault
*/
async getFile(env, filePath) {
const url = `${this.config.baseUrl}/${env}/${filePath}`;
try {
const response = await this._fetchApi(url);
if (!response.ok) {
if (response.status === 401) {
throw new VaultAuthenticationError('Authentification échouée - vérifiez votre ID utilisateur', 'AUTH_FAILED', response.status);
}
if (response.status === 403) {
throw new VaultApiError('Accès non autorisé à ce fichier', 'ACCESS_DENIED', response.status);
}
throw new VaultApiError(`Erreur API: ${response.status} ${response.statusText}`, 'API_ERROR', response.status);
}
const encryptedData = await response.arrayBuffer();
// Extraction des métadonnées depuis les headers
const user_id = response.headers.get('X-User-ID') || undefined;
const keyRotation = response.headers.get('X-Key-Rotation') || undefined;
const algorithm = response.headers.get('X-Algorithm') || undefined;
// Déchiffrement du contenu avec les headers pour la prochaine clé
const decryptedContent = this.decryptContent(Buffer.from(encryptedData), response.headers);
return {
content: decryptedContent,
filename: filePath.split('/').pop() || filePath,
size: decryptedContent.length,
encrypted: true,
algorithm,
user_id,
key_version: keyRotation,
timestamp: new Date().toISOString()
};
}
catch (error) {
if (error instanceof VaultApiError || error instanceof VaultAuthenticationError) {
throw error;
}
throw new VaultApiError(`Erreur lors de la récupération du fichier: ${error instanceof Error ? error.message : 'Inconnue'}`);
}
}
/**
* Récupère plusieurs fichiers en parallèle
*/
async getFiles(env, filePaths) {
const promises = filePaths.map(filePath => this.getFile(env, filePath));
return Promise.all(promises);
}
/**
* Recherche des fichiers correspondant à un pattern
*/
async searchFiles(_env, _pattern) {
// Cette fonctionnalité nécessiterait une implémentation côté serveur
// Pour l'instant, retour d'une erreur explicative
throw new VaultApiError('Recherche de fichiers non implémentée - contactez l\'administrateur', 'NOT_IMPLEMENTED');
}
/**
* Vérifie l'état de santé de l'API
*/
async health() {
const url = `${this.config.baseUrl}/health`;
try {
const response = await this._fetchApi(url);
if (!response.ok) {
throw new VaultApiError(`Erreur de santé API: ${response.status}`, 'HEALTH_CHECK_FAILED', response.status);
}
return await response.json();
}
catch (error) {
if (error instanceof VaultApiError) {
throw error;
}
throw new VaultApiError(`Erreur lors du contrôle de santé: ${error instanceof Error ? error.message : 'Inconnue'}`);
}
}
/**
* Récupère les informations sur l'API
*/
async info() {
const url = `${this.config.baseUrl}/info`;
try {
const response = await this._fetchApi(url);
if (!response.ok) {
throw new VaultApiError(`Erreur info API: ${response.status}`, 'INFO_ERROR', response.status);
}
return await response.json();
}
catch (error) {
if (error instanceof VaultApiError) {
throw error;
}
throw new VaultApiError(`Erreur lors de la récupération des informations: ${error instanceof Error ? error.message : 'Inconnue'}`);
}
}
/**
* Test de connectivité simple
*/
async ping() {
try {
await this.health();
return true;
}
catch (error) {
return false;
}
}
/**
* Récupère toutes les routes disponibles de l'API
*/
async getRoutes() {
const url = `${this.config.baseUrl}/routes`;
try {
const response = await this._fetchApi(url);
if (!response.ok) {
if (response.status === 401) {
throw new VaultAuthenticationError('Authentification échouée - vérifiez votre ID utilisateur', 'AUTH_FAILED', response.status);
}
throw new VaultApiError(`Erreur API routes: ${response.status} ${response.statusText}`, 'ROUTES_API_ERROR', response.status);
}
return await response.json();
}
catch (error) {
if (error instanceof VaultApiError || error instanceof VaultAuthenticationError) {
throw error;
}
throw new VaultApiError(`Erreur lors de la récupération des routes: ${error instanceof Error ? error.message : 'Inconnue'}`);
}
}
/**
* Synchronise les fichiers déchiffrés localement
* Route vault /<env>/<project>/<file_name> -> ../confs/<project>/<file_name>
* Les fichiers existants dans confs/ sont toujours écrasés pour avoir le contenu le plus récent
*/
async syncLocalFiles(options) {
// Recharger les variables d'environnement au cas où elles auraient changé
this._loadEnvironmentVariables();
// Récupérer le dossier de destination depuis les variables d'environnement
const defaultConfsDir = process.env['VAULT_CONFS_DIR'] || '../confs';
const { environment, localDir = defaultConfsDir, verbose = false } = options;
const result = {
synced: 0,
skipped: 0,
errors: 0,
details: []
};
try {
// 1. Créer le dossier de destination s'il n'existe pas
// Résoudre le chemin par rapport au répertoire du fichier .env
let targetDir;
if (path_1.default.isAbsolute(localDir)) {
targetDir = localDir;
}
else {
// Pour les chemins relatifs, partir du répertoire du fichier .env
const envFileDir = this._getEnvFileDirectory();
targetDir = path_1.default.resolve(envFileDir, localDir);
}
if (!fs_1.default.existsSync(targetDir)) {
fs_1.default.mkdirSync(targetDir, { recursive: true });
if (verbose) {
console.log(`📁 Dossier créé: ${targetDir}`);
}
}
// 2. Récupérer la liste des routes pour identifier les fichiers
const routes = await this.getRoutes();
// 3. Extraire les fichiers disponibles depuis les exemples de routes
const fileRoute = routes.routes.find(route => route.path.includes('<env>') && route.path.includes('<file_path>'));
if (!fileRoute || !fileRoute.examples) {
throw new VaultApiError('Impossible de déterminer les fichiers disponibles');
}
// 4. Parser les exemples pour extraire les projets et fichiers
const filesToSync = [];
for (const example of fileRoute.examples) {
// Format: /dev/bitcoin/bitcoin.conf -> project: bitcoin, fileName: bitcoin.conf
const pathParts = example.split('/').filter(part => part && part !== environment);
if (pathParts.length >= 2) {
const project = pathParts[0] || 'unknown';
const fileName = pathParts[pathParts.length - 1] || 'unknown';
const vaultPath = pathParts.join('/');
filesToSync.push({
project,
fileName,
vaultPath
});
}
}
// 5. Synchroniser chaque fichier
for (const file of filesToSync) {
try {
const localProjectDir = path_1.default.join(targetDir, file.project);
const localFilePath = path_1.default.join(localProjectDir, file.fileName);
// Créer le dossier du projet s'il n'existe pas
if (!fs_1.default.existsSync(localProjectDir)) {
fs_1.default.mkdirSync(localProjectDir, { recursive: true });
if (verbose) {
console.log(`📁 Dossier projet créé: ${localProjectDir}`);
}
}
// Toujours écraser les fichiers dans confs/ pour avoir le contenu le plus récent
// La vérification d'existence est conservée pour le logging uniquement
const fileExists = fs_1.default.existsSync(localFilePath);
if (fileExists && verbose) {
console.log(`🔄 Écrasement du fichier existant: ${file.vaultPath}`);
}
// Récupérer le fichier depuis le vault
const vaultFile = await this.getFile(environment, file.vaultPath);
// Extraire le contenu déchiffré (simulation pour le format de démonstration)
let content = vaultFile.content;
// Le contenu est maintenant déchiffré automatiquement par decryptContent
// Pas besoin de récupérer depuis le storage, le contenu vient de l'API déchiffrée
// Écrire le fichier local
fs_1.default.writeFileSync(localFilePath, content, 'utf8');
result.synced++;
result.details.push({
file: file.vaultPath,
status: 'synced',
message: `Synchronisé vers ${localFilePath}`
});
if (verbose) {
console.log(`✅ Synchronisé: ${file.vaultPath} -> ${localFilePath}`);
}
}
catch (error) {
result.errors++;
const errorMessage = error instanceof Error ? error.message : 'Erreur inconnue';
result.details.push({
file: file.vaultPath,
status: 'error',
message: errorMessage
});
if (verbose) {
console.log(`❌ Erreur: ${file.vaultPath} - ${errorMessage}`);
}
}
}
if (verbose) {
console.log(`\n📊 Résumé de synchronisation:`);
console.log(` ✅ Synchronisés: ${result.synced}`);
console.log(` ⏭️ Ignorés: ${result.skipped}`);
console.log(` ❌ Erreurs: ${result.errors}`);
}
return result;
}
catch (error) {
throw new VaultApiError(`Erreur lors de la synchronisation: ${error instanceof Error ? error.message : 'Inconnue'}`);
}
}
/**
* Déchiffre le contenu avec les métadonnées utilisateur et gère la prochaine clé
*/
decryptContent(encryptedData, responseHeaders) {
try {
// Décoder le base64
const decoded = Buffer.from(encryptedData.toString(), 'base64');
// Nouveau format: nonce (12 bytes) + taille_métadonnées (4 bytes) + métadonnées + contenu chiffré
if (decoded.length < 16) {
throw new Error('Données chiffrées invalides - format incorrect');
}
const nonce = decoded.subarray(0, 12);
const metadataSize = decoded.readUInt32BE(12);
const metadataJson = decoded.subarray(16, 16 + metadataSize);
const ciphertext = decoded.subarray(16 + metadataSize);
// Parse des métadonnées
const metadata = JSON.parse(metadataJson.toString('utf-8'));
// Vérification de l'utilisateur
if (metadata.user_id !== this.config.userId) {
throw new VaultAuthenticationError('Métadonnées utilisateur ne correspondent pas', 'USER_MISMATCH');
}
// Récupération de la prochaine clé depuis les headers ou les métadonnées
const nextKey = responseHeaders?.get('X-Next-Key') || metadata.next_key;
// Pour le déchiffrement, utiliser la clé courante d'abord
const keyToUse = this.vaultKey;
if (!keyToUse) {
throw new VaultDecryptionError('Clé de déchiffrement non disponible');
}
console.log(`🔑 Utilisation de la clé courante pour déchiffrement: ${keyToUse.substring(0, 20)}...`);
// Ne pas mettre à jour la clé immédiatement, attendre un déchiffrement réussi
try {
// Convertir la clé base64 en Uint8Array
const key = Buffer.from(keyToUse, 'base64');
// Déchiffrement ChaCha20-Poly1305 avec @noble/ciphers
const cipher = chacha20poly1305(key, nonce);
const decrypted = cipher.decrypt(ciphertext);
// Déchiffrement réussi, mettre à jour la clé pour la prochaine requête
if (nextKey) {
this.updateNextKey(nextKey);
}
// Retourner le contenu déchiffré
return Buffer.from(decrypted).toString('utf-8');
}
catch (decryptError) {
// Si le déchiffrement échoue, essayer avec la prochaine clé si elle est différente
if (nextKey && nextKey !== keyToUse) {
console.log(`🔄 Tentative de déchiffrement avec la prochaine clé...`);
try {
const nextKeyBuffer = Buffer.from(nextKey, 'base64');
const cipherNext = chacha20poly1305(nextKeyBuffer, nonce);
const decryptedNext = cipherNext.decrypt(ciphertext);
console.log(`✅ Déchiffrement réussi avec la prochaine clé !`);
// Déchiffrement réussi avec la prochaine clé, mettre à jour
this.updateNextKey(nextKey);
return Buffer.from(decryptedNext).toString('utf-8');
}
catch (nextDecryptError) {
console.warn(`⚠️ Déchiffrement avec la prochaine clé échoué: ${nextDecryptError instanceof Error ? nextDecryptError.message : 'Erreur inconnue'}`);
}
}
throw new VaultDecryptionError(`Erreur de déchiffrement ChaCha20-Poly1305: ${decryptError instanceof Error ? decryptError.message : 'Inconnue'}`);
}
}
catch (error) {
if (error instanceof VaultAuthenticationError || error instanceof VaultDecryptionError) {
throw error;
}
throw new VaultDecryptionError(`Erreur de déchiffrement: ${error instanceof Error ? error.message : 'Inconnue'}`);
}
}
/**
* Met à jour la prochaine clé pour les requêtes suivantes et le fichier .env
*/
updateNextKey(nextKey) {
if (nextKey) {
this.vaultKey = nextKey; // Mettre à jour la clé courante
// Mettre à jour le fichier .env avec la nouvelle clé
this.updateEnvFile(nextKey);
console.log(`🔑 Prochaine clé mise à jour: ${nextKey.substring(0, 20)}...`);
}
}
/**
* Retourne le répertoire du fichier .env trouvé
*/
_getEnvFileDirectory() {
// Chercher le fichier .env dans l'ordre de priorité
const possibleEnvPaths = [
path_1.default.join(__dirname, '.env'), // Répertoire du SDK (priorité 1)
path_1.default.join(process.cwd(), '.env'), // Répertoire de travail (priorité 2)
'.env', // Répertoire courant (priorité 3)
'../.env', // Répertoire parent (priorité 4)
'../../.env', // Répertoire grand-parent (priorité 5)
path_1.default.join(__dirname, '../.env'), // Parent du SDK (priorité 6)
path_1.default.join(__dirname, '../../.env'), // Grand-parent du SDK (priorité 7)
];
for (const envPath of possibleEnvPaths) {
try {
if (fs_1.default.existsSync(envPath)) {
// Retourner le répertoire du fichier .env
const envDir = path_1.default.dirname(path_1.default.resolve(envPath));
return envDir;
}
}
catch (error) {
// Ignorer les erreurs et continuer avec le chemin suivant
continue;
}
}
// Fallback vers le répertoire du SDK si aucun .env n'est trouvé
return __dirname;
}
/**
* Charge les variables d'environnement depuis plusieurs emplacements possibles
*/
_loadEnvironmentVariables() {
const possibleEnvPaths = [
'.env', // Répertoire courant
'../.env', // Répertoire parent
'../../.env', // Répertoire grand-parent
path_1.default.join(__dirname, '.env'), // Répertoire du SDK
path_1.default.join(__dirname, '../.env'), // Parent du SDK
path_1.default.join(__dirname, '../../.env'), // Grand-parent du SDK
path_1.default.join(process.cwd(), '.env'), // Répertoire de travail
];
let envLoaded = false;
for (const envPath of possibleEnvPaths) {
try {
if (fs_1.default.existsSync(envPath)) {
const result = dotenv_1.default.config({ path: envPath });
if (!result.error) {
console.log(`📄 Variables d'environnement chargées depuis: ${envPath}`);
envLoaded = true;
break;
}
}
}
catch (error) {
// Ignorer les erreurs et continuer avec le chemin suivant
continue;
}
}
// Si aucun fichier .env n'a été trouvé, essayer le chargement par défaut
if (!envLoaded) {
try {
dotenv_1.default.config();
console.log('📄 Variables d\'environnement chargées depuis .env par défaut');
}
catch (error) {
console.log('⚠️ Aucun fichier .env trouvé, utilisation des variables système uniquement');
}
}
}
/**
* Met à jour le fichier .env avec la nouvelle clé
*/
updateEnvFile(newKey) {
try {
const envPath = path_1.default.join(__dirname, '../../.env');
// Lire le fichier .env actuel
let envContent = '';
if (fs_1.default.existsSync(envPath)) {
envContent = fs_1.default.readFileSync(envPath, 'utf8');
}
// Mettre à jour ou ajouter la clé VAULT_KEY
const keyRegex = /^VAULT_KEY=.*$/m;
if (keyRegex.test(envContent)) {
envContent = envContent.replace(keyRegex, `VAULT_KEY="${newKey}"`);
}
else {
envContent += `\nVAULT_KEY="${newKey}"\n`;
}
// Écrire le fichier .env mis à jour
fs_1.default.writeFileSync(envPath, envContent, 'utf8');
console.log(`📝 Fichier .env mis à jour avec la nouvelle clé`);
}
catch (error) {
console.warn(`⚠️ Impossible de mettre à jour le fichier .env: ${error instanceof Error ? error.message : 'Erreur inconnue'}`);
}
}
/**
* Effectue une requête vers l'API avec authentification
*/
async _fetchApi(url) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
try {
const mergedOptions = {
method: 'GET',
headers: {
'User-Agent': 'SecureVaultClient/2.0.0',
'X-User-ID': this.config.userId,
'Accept': 'application/octet-stream'
},
signal: controller.signal
};
// Configuration SSL pour les certificats auto-signés
if (this.config.verifySsl === false) {
mergedOptions.agent = new https_1.default.Agent({
rejectUnauthorized: false
});
}
const response = await (0, node_fetch_1.default)(url, mergedOptions);
clearTimeout(timeoutId);
return response;
}
catch (error) {
clearTimeout(timeoutId);
if (error instanceof Error && error.name === 'AbortError') {
throw new VaultApiError(`Timeout de la requête (${this.config.timeout}ms)`, 'TIMEOUT');
}
throw new VaultApiError(`Erreur de connexion: ${error instanceof Error ? error.message : 'Inconnue'}`);
}
}
}
exports.SecureVaultClient = SecureVaultClient;
/**
* Fonction utilitaire pour créer un client sécurisé
*/
function createSecureVaultClient(baseUrl, userId) {
return new SecureVaultClient({
baseUrl,
userId,
verifySsl: false, // Pour les certificats auto-signés en développement
timeout: 15000
});
}
/**
* Fonction utilitaire pour créer un client sécurisé avec configuration complète
*/
function createSecureVaultClientWithConfig(config) {
return new SecureVaultClient(config);
}
//# sourceMappingURL=index.js.map

1
sdk-client/dist/src/index.js.map vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
./