diff --git a/.gitignore b/.gitignore index 20848db..1dbe92e 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ # Clés utilisateur et données sensibles **/_keys/ **/keys.json* + +# Dossiers de synchronisation de test +**/confs*/ diff --git a/debug_circular_vars.py b/debug_circular_vars.py deleted file mode 100644 index 3f6abb9..0000000 --- a/debug_circular_vars.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python3 -"""Script de debug pour les variables circulaires""" - -import sys -import os -sys.path.append('/home/debian/4NK_vault') - -from pathlib import Path -from api_server import EnvProcessor - -def test_circular_variables(): - print("🔍 Test des variables circulaires HOST/DOMAIN") - - # Test avec le fichier .env de dev - env_file = Path('/home/debian/4NK_vault/storage/dev/.env') - processor = EnvProcessor(env_file) - - # Test de résolution des variables problématiques - test_variables = ['HOST', 'DOMAIN', 'ROOT_HOST', 'ROOT_URL'] - - print(f"\n🔍 Test de résolution des variables:") - for var in test_variables: - if var in processor.variables: - original_value = processor.variables[var] - try: - resolved = processor._resolve_variable(var) - print(f" {var}: {original_value} → {resolved}") - except Exception as e: - print(f" {var}: {original_value} → ERREUR: {e}") - else: - print(f" {var}: NON TROVÉE") - - # Test avec un contenu qui utilise ces variables - test_content = """ -GF_SERVER_ROOT_URL=https://dev4.$HOST/grafana -ROOT_URL=https://$ROOT_HOST -GRAFANA_URL=$ROOT_URL/grafana -""" - - print(f"\n📄 Contenu de test:") - print(test_content) - - processed_content = processor.process_content(test_content) - - print(f"\n📄 Contenu traité:") - print(processed_content) - - # Vérifier si des variables sont encore présentes - if '$' in processed_content: - print("\n⚠️ Variables non résolues détectées!") - import re - remaining_vars = re.findall(r'\$[A-Za-z_][A-Za-z0-9_]*', processed_content) - print(f"Variables restantes: {remaining_vars}") - else: - print("\n✅ Toutes les variables ont été résolues!") - -if __name__ == "__main__": - test_circular_variables() diff --git a/sdk-client/debug-api-response.js b/sdk-client/debug-api-response.js deleted file mode 100644 index 2f5c7c2..0000000 --- a/sdk-client/debug-api-response.js +++ /dev/null @@ -1,58 +0,0 @@ -const https = require('https'); - -async function debugApiResponse() { - console.log('🔍 Debug de la réponse API...'); - - const options = { - hostname: 'vault.4nkweb.com', - port: 6666, - path: '/dev/bitcoin/bitcoin.conf', - method: 'GET', - headers: { - 'X-User-ID': 'demo_user_001' - }, - rejectUnauthorized: false // Pour accepter les certificats auto-signés - }; - - const req = https.request(options, (res) => { - console.log('Status:', res.statusCode); - console.log('Headers:', res.headers); - - let data = ''; - res.on('data', (chunk) => { - data += chunk; - }); - - res.on('end', () => { - console.log('Response length:', data.length); - console.log('First 200 chars:', data.substring(0, 200)); - - // Essayer de décoder base64 - try { - const decoded = Buffer.from(data, 'base64'); - console.log('Decoded length:', decoded.length); - console.log('First 50 bytes (hex):', decoded.subarray(0, 50).toString('hex')); - - if (decoded.length >= 16) { - const nonce = decoded.subarray(0, 12); - const metadataSize = decoded.readUInt32BE(12); - const metadataJson = decoded.subarray(16, 16 + metadataSize); - - console.log('Nonce (hex):', nonce.toString('hex')); - console.log('Metadata size:', metadataSize); - console.log('Metadata:', metadataJson.toString('utf-8')); - } - } catch (e) { - console.log('Error decoding:', e.message); - } - }); - }); - - req.on('error', (e) => { - console.error('Request error:', e); - }); - - req.end(); -} - -debugApiResponse(); diff --git a/sdk-client/debug-test.js b/sdk-client/debug-test.js deleted file mode 100644 index b15d017..0000000 --- a/sdk-client/debug-test.js +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env node - -/** - * Test de débogage du SDK client - */ - -const { createSecureVaultClient } = require('./dist/index.js'); - -async function debugTest() { - console.log('🔍 Test de débogage du SDK client'); - console.log('='.repeat(50)); - - try { - // 1. Création du client avec ID utilisateur - console.log('📝 Création du client...'); - const client = createSecureVaultClient( - 'https://vault.4nkweb.com:6666', - 'demo_user_001' - ); - console.log('✅ Client créé avec succès'); - - // 2. Test direct de getRoutes() - console.log('\n🛣️ Test direct de getRoutes()...'); - const routes = await client.getRoutes(); - - console.log(`\n📋 Résultats:`); - console.log(` Total des routes: ${routes.total_routes}`); - console.log(` Utilisateur: ${routes.user_id}`); - console.log(` Timestamp: ${routes.timestamp}`); - - console.log('\n📝 Routes disponibles:'); - routes.routes.forEach((route, index) => { - console.log(` ${index + 1}. ${route.method} ${route.path}`); - console.log(` ${route.description}`); - }); - - console.log('\n✅ Test réussi !'); - - } catch (error) { - console.error('\n❌ Erreur lors du test:'); - console.error(` Type: ${error.name}`); - console.error(` Message: ${error.message}`); - if (error.statusCode) { - console.error(` Code HTTP: ${error.statusCode}`); - } - if (error.code) { - console.error(` Code d'erreur: ${error.code}`); - } - console.error(` Stack: ${error.stack}`); - } -} - -// Exécution du test -debugTest().catch(console.error); diff --git a/sdk-client/examples/examples/usage.js b/sdk-client/examples/examples/usage.js new file mode 100644 index 0000000..dc69675 --- /dev/null +++ b/sdk-client/examples/examples/usage.js @@ -0,0 +1,387 @@ +"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 // + if (route.path.includes('') && route.path.includes('')) { + 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(' Mapping: /// -> ../confs//'); + // Synchronisation avec options détaillées + const syncResult = await client.syncLocalFiles({ + environment: 'dev', + localDir: '../confs', + 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); +} diff --git a/sdk-client/examples/src/index.js b/sdk-client/examples/src/index.js new file mode 100644 index 0000000..c5c9eb1 --- /dev/null +++ b/sdk-client/examples/src/index.js @@ -0,0 +1,555 @@ +"use strict"; +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 = require("node-fetch"); +const https_1 = require("https"); +const dotenv_1 = require("dotenv"); +const { chacha20poly1305 } = require('@noble/ciphers/chacha.js'); +const fs_1 = require("fs"); +const path_1 = 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 /// -> ../confs// + * 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('') && route.path.includes('')); + 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); +} diff --git a/sdk-client/examples/usage.js b/sdk-client/examples/usage.js index 7105d9b..edfb585 100644 --- a/sdk-client/examples/usage.js +++ b/sdk-client/examples/usage.js @@ -8,7 +8,7 @@ exports.step1_Initialization = step1_Initialization; exports.step2_GetRoutes = step2_GetRoutes; exports.step3_ParseRoutes = step3_ParseRoutes; exports.step4_DecryptContents = step4_DecryptContents; -const index_1 = require("../src/index"); +const index_1 = require("../dist/src/index"); /** * ÉTAPE 1: Initialisation + Gestion des erreurs */ diff --git a/sdk-client/examples/usage.js.map b/sdk-client/examples/usage.js.map deleted file mode 100644 index f27d545..0000000 --- a/sdk-client/examples/usage.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"usage.js","sourceRoot":"","sources":["usage.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk-client/examples/usage.ts b/sdk-client/examples/usage.ts index 75f91a4..8c3a63a 100644 --- a/sdk-client/examples/usage.ts +++ b/sdk-client/examples/usage.ts @@ -253,12 +253,12 @@ async function step4_SyncLocalFiles(client: SecureVaultClient) { try { console.log('\n🔄 Synchronisation des fichiers vers le dossier local...'); - console.log(' Mapping: /// -> ../confs//'); + 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', - localDir: '../confs', verbose: true }); diff --git a/sdk-client/simple-test.js b/sdk-client/simple-test.js deleted file mode 100644 index 249a7be..0000000 --- a/sdk-client/simple-test.js +++ /dev/null @@ -1,25 +0,0 @@ -const fetch = require('node-fetch'); - -async function test() { - try { - console.log('Test simple de l\'API...'); - - const response = await fetch('https://127.0.0.1:6666/health', { - method: 'GET', - headers: { - 'Accept': 'application/json', - } - }); - - if (response.ok) { - const data = await response.json(); - console.log('✅ API fonctionne:', data); - } else { - console.log('❌ Erreur HTTP:', response.status, response.statusText); - } - } catch (error) { - console.log('❌ Erreur:', error.message); - } -} - -test(); diff --git a/sdk-client/test-connection.js b/sdk-client/test-connection.js deleted file mode 100644 index 6b02a43..0000000 --- a/sdk-client/test-connection.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Test de connexion au SDK Vault - * Affiche l'URL utilisée et teste la connectivité - */ - -const { SecureVaultClient } = require('./dist/src/index.js'); - -async function testConnection() { - console.log('🔍 Test de connexion au SDK Vault'); - console.log('==================================='); - - try { - // Afficher les variables d'environnement chargées - console.log('\n📋 Variables d\'environnement:'); - console.log(` VAULT_USER: ${process.env.VAULT_USER || 'NON DÉFINI'}`); - console.log(` VAULT_ENV: ${process.env.VAULT_ENV || 'NON DÉFINI'}`); - console.log(` VAULT_URL: ${process.env.VAULT_URL || 'NON DÉFINI'}`); - console.log(` VAULT_CONFS_DIR: ${process.env.VAULT_CONFS_DIR || 'NON DÉFINI'}`); - - // Créer le client - const client = new SecureVaultClient(); - - // Afficher l'URL configurée - console.log('\n🌐 Configuration du client:'); - console.log(` URL de base: ${client.config?.baseUrl || 'NON DÉFINI'}`); - console.log(` Utilisateur: ${client.config?.userId || 'NON DÉFINI'}`); - - // Test de connectivité - console.log('\n🔌 Test de connectivité...'); - const isConnected = await client.ping(); - - if (isConnected) { - console.log(' ✅ Connexion réussie !'); - - // Test de récupération des routes - console.log('\n📁 Test de récupération des routes...'); - const routes = await client.getRoutes('dev'); - console.log(` ✅ ${routes.length} routes récupérées`); - - // Test de synchronisation - console.log('\n📂 Test de synchronisation...'); - const syncResult = await client.syncLocalFiles({ - environment: 'dev', - localDir: './test-confs', - verbose: true - }); - - console.log(` ✅ Synchronisation terminée:`); - console.log(` - Fichiers synchronisés: ${syncResult.synced}`); - console.log(` - Fichiers ignorés: ${syncResult.skipped}`); - console.log(` - Erreurs: ${syncResult.errors}`); - - } else { - console.log(' ❌ Connexion échouée !'); - } - - } catch (error) { - console.error('\n❌ Erreur:', error.message); - - if (error.message.includes('Variables d\'environnement requises')) { - console.log('\n💡 Solution:'); - console.log(' 1. Créez un fichier .env dans le dossier sdk-client/'); - console.log(' 2. Copiez .env.example vers .env'); - console.log(' 3. Modifiez les valeurs dans .env'); - console.log('\n Exemple de .env:'); - console.log(' VAULT_USER=demo_user_001'); - console.log(' VAULT_KEY=JYyybYFXe9hghRI9d1mpoQ1uYYxpt/6lzYPOWrxruG0='); - console.log(' VAULT_ENV=dev'); - console.log(' VAULT_URL=https://vault.4nkweb.com:6666'); - } - } -} - -testConnection(); diff --git a/sdk-client/test-decrypt.js b/sdk-client/test-decrypt.js deleted file mode 100644 index 2170a12..0000000 --- a/sdk-client/test-decrypt.js +++ /dev/null @@ -1,21 +0,0 @@ -const { SecureVaultClient } = require('./dist/src/index.js'); -const fs = require('fs'); - -async function testDecryption() { - console.log('🔍 Test de déchiffrement simple...'); - - try { - const client = new SecureVaultClient(); - console.log('✅ Client créé'); - - // Test avec un fichier simple - const result = await client.getFile('dev', 'bitcoin/bitcoin.conf'); - console.log('✅ Fichier récupéré:', result.content.substring(0, 100) + '...'); - - } catch (error) { - console.error('❌ Erreur:', error.message); - console.error('Stack:', error.stack); - } -} - -testDecryption(); diff --git a/sdk-client/test-multiple-files.js b/sdk-client/test-multiple-files.js deleted file mode 100644 index 8b7578e..0000000 --- a/sdk-client/test-multiple-files.js +++ /dev/null @@ -1,47 +0,0 @@ -const { SecureVaultClient } = require('./dist/src/index.js'); -const fs = require('fs'); - -async function testMultipleFiles() { - console.log('🔍 Test de chiffrement/déchiffrement sur plusieurs fichiers'); - - const testFiles = [ - 'bitcoin/bitcoin.conf', - 'tor/torrc', - 'grafana/grafana.ini' - ]; - - const client = new SecureVaultClient(); - - for (const filePath of testFiles) { - try { - console.log(`\n📁 Test du fichier: ${filePath}`); - - // 1. Lire le fichier original - const originalFile = `/home/debian/4NK_vault/storage/dev/${filePath}`; - const originalContent = fs.readFileSync(originalFile, 'utf8'); - - // 2. Récupérer via API (chiffré) - const result = await client.getFile('dev', filePath); - - // 3. Comparer - if (originalContent === result.content) { - console.log(`✅ ${filePath}: Chiffrement/déchiffrement réussi`); - console.log(` Taille: ${originalContent.length} → ${result.content.length} caractères`); - } else { - console.log(`❌ ${filePath}: Échec du chiffrement/déchiffrement`); - console.log(` Différences détectées !`); - } - - } catch (error) { - console.log(`❌ ${filePath}: Erreur - ${error.message}`); - } - } - - console.log('\n🎯 Résumé:'); - console.log('✅ Chiffrement réel par l\'API Python (ChaCha20-Poly1305)'); - console.log('✅ Déchiffrement réel par le SDK Node.js (@noble/ciphers)'); - console.log('✅ Contenu identique après chiffrement/déchiffrement'); - console.log('✅ Flux de données sécurisé et fonctionnel'); -} - -testMultipleFiles(); diff --git a/sdk-client/test-routes.js b/sdk-client/test-routes.js deleted file mode 100644 index 706d62a..0000000 --- a/sdk-client/test-routes.js +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env node - -/** - * Test de la nouvelle fonctionnalité getRoutes() du SDK client - */ - -const { createSecureVaultClient } = require('./dist/index.js'); - -async function testRoutes() { - console.log('🔐 Test de la fonctionnalité getRoutes()'); - console.log('='.repeat(60)); - - try { - // 1. Création du client avec ID utilisateur - const client = createSecureVaultClient( - 'https://vault.4nkweb.com:6666', - 'demo_user_001' // ID utilisateur obligatoire - ); - - // 2. Test de connectivité via health - console.log('🔍 Test de connectivité...'); - try { - await client.health(); - console.log('✅ Connecté avec succès'); - } catch (error) { - throw new Error('❌ Impossible de se connecter à l\'API'); - } - - // 3. Test de la nouvelle méthode getRoutes() - console.log('\n🛣️ Récupération des routes disponibles...'); - const routes = await client.getRoutes(); - - console.log(`\n📋 Résultats:`); - console.log(` Total des routes: ${routes.total_routes}`); - console.log(` Utilisateur: ${routes.user_id}`); - console.log(` Timestamp: ${routes.timestamp}`); - console.log(` Type d'authentification: ${routes.authentication.type}`); - - console.log('\n📝 Routes disponibles:'); - routes.routes.forEach((route, index) => { - console.log(`\n ${index + 1}. ${route.method} ${route.path}`); - console.log(` Description: ${route.description}`); - console.log(` Authentification: ${route.authentication}`); - console.log(` Headers requis: ${route.headers_required.join(', ')}`); - 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('\n✅ Test réussi - Toutes les routes ont été récupérées'); - - } catch (error) { - console.error('\n❌ Erreur lors du test:'); - console.error(` Type: ${error.name}`); - console.error(` Message: ${error.message}`); - if (error.statusCode) { - console.error(` Code HTTP: ${error.statusCode}`); - } - if (error.code) { - console.error(` Code d'erreur: ${error.code}`); - } - process.exit(1); - } -} - -// Exécution du test -testRoutes().catch(console.error); diff --git a/sdk-client/test-usage.js b/sdk-client/test-usage.js new file mode 100644 index 0000000..91ed3a4 --- /dev/null +++ b/sdk-client/test-usage.js @@ -0,0 +1,58 @@ +#!/usr/bin/env node + +/** + * Script de test simple qui respecte VAULT_CONFS_DIR + */ + +const { SecureVaultClient } = require('./dist/src/index.js'); + +async function main() { + console.log('🧪 Test du SDK avec VAULT_CONFS_DIR'); + console.log('='.repeat(50)); + + try { + // Initialiser le client (charge automatiquement .env) + const client = new SecureVaultClient(); + + // Afficher les variables chargées + console.log('📄 Variables d\'environnement:'); + console.log(` VAULT_CONFS_DIR: ${process.env.VAULT_CONFS_DIR}`); + console.log(` VAULT_USER: ${process.env.VAULT_USER}`); + console.log(` VAULT_ENV: ${process.env.VAULT_ENV}`); + + // Test de connectivité + console.log('\n🔍 Test de connectivité...'); + const isConnected = await client.ping(); + console.log(` ✅ Connecté: ${isConnected}`); + + // Récupération des routes + console.log('\n🛣️ Récupération des routes...'); + const routes = await client.getRoutes(); + console.log(` ✅ ${routes.total_routes} routes disponibles`); + + // Synchronisation (utilise VAULT_CONFS_DIR automatiquement) + console.log('\n💾 Synchronisation des fichiers...'); + console.log(' Utilise VAULT_CONFS_DIR depuis .env'); + + const syncResult = await client.syncLocalFiles({ + environment: 'dev', + verbose: true + }); + + console.log('\n📊 Résultats:'); + console.log(` ✅ Fichiers synchronisés: ${syncResult.synced}`); + console.log(` ⏭️ Fichiers ignorés: ${syncResult.skipped}`); + console.log(` ❌ Erreurs: ${syncResult.errors}`); + + console.log('\n🎉 Test terminé avec succès !'); + + } catch (error) { + console.error('\n❌ Erreur:', error.message); + process.exit(1); + } +} + +// Exécution +if (require.main === module) { + main().catch(console.error); +} diff --git a/sdk-client/test.js b/sdk-client/test.js deleted file mode 100644 index 73e5b06..0000000 --- a/sdk-client/test.js +++ /dev/null @@ -1 +0,0 @@ -const { createSecureVaultClient } = require('./dist/index.js'); const client = createSecureVaultClient('https://localhost:6666', 'demo_user_001'); client.getFile('dev', 'bitcoin/bitcoin.conf').then(result => { console.log('✅ Succès:', result.filename); console.log('🔑 Contenu:', result.content.substring(0, 200)); console.log('📊 Métadonnées:', { algorithm: result.algorithm, user_id: result.user_id, key_version: result.key_version }); }).catch(err => console.error('❌ Erreur:', err.message)); diff --git a/test_api.py b/test_api.py deleted file mode 100644 index f6d7aba..0000000 --- a/test_api.py +++ /dev/null @@ -1,273 +0,0 @@ -#!/usr/bin/env python3 -""" -Test de l'API Vault sécurisée avec authentification par clés utilisateur -""" - -import requests -import json -import base64 -from datetime import datetime - -# Configuration -BASE_URL = 'https://127.0.0.1:6666' -USER_ID = 'demo_user_001' # ID utilisateur de test -VERIFY_SSL = False # Certificats auto-signés - -def test_health(): - """Test de l'endpoint de santé""" - print("🔍 Test de santé de l'API...") - - try: - response = requests.get( - f"{BASE_URL}/health", - verify=VERIFY_SSL, - headers={'X-User-ID': USER_ID} - ) - - if response.status_code == 200: - health_data = response.json() - print(f"✅ API en bonne santé") - print(f" Service: {health_data.get('service')}") - print(f" Chiffrement: {health_data.get('encryption')}") - print(f" Algorithme: {health_data.get('algorithm')}") - print(f" Authentification: {health_data.get('authentication')}") - print(f" Rotation des clés: {health_data.get('key_rotation')}") - return True - else: - print(f"❌ Erreur de santé: {response.status_code}") - print(f" Réponse: {response.text}") - return False - - except Exception as e: - print(f"❌ Erreur de connexion: {e}") - return False - -def test_info(): - """Test de l'endpoint d'informations""" - print("\n📋 Test des informations API...") - - try: - response = requests.get( - f"{BASE_URL}/info", - verify=VERIFY_SSL, - headers={'X-User-ID': USER_ID} - ) - - if response.status_code == 200: - info_data = response.json() - print(f"✅ Informations récupérées") - print(f" Nom: {info_data.get('name')}") - print(f" Version: {info_data.get('version')}") - print(f" Domaine: {info_data.get('domain')}") - print(f" Protocole: {info_data.get('protocol')}") - print(f" Authentification: {info_data.get('authentication')}") - return True - else: - print(f"❌ Erreur d'informations: {response.status_code}") - print(f" Réponse: {response.text}") - return False - - except Exception as e: - print(f"❌ Erreur de connexion: {e}") - return False - -def test_file_access(): - """Test d'accès à un fichier""" - print("\n📁 Test d'accès au fichier...") - - try: - # Test avec l'environnement dev qui existe - response = requests.get( - f"{BASE_URL}/dev/bitcoin/bitcoin.conf", - verify=VERIFY_SSL, - headers={'X-User-ID': USER_ID} - ) - - if response.status_code == 200: - print(f"✅ Fichier récupéré avec succès") - print(f" Taille: {len(response.content)} bytes") - print(f" Type de contenu: {response.headers.get('Content-Type')}") - print(f" Type de chiffrement: {response.headers.get('X-Encryption-Type')}") - print(f" Algorithme: {response.headers.get('X-Algorithm')}") - print(f" ID utilisateur: {response.headers.get('X-User-ID')}") - print(f" Rotation des clés: {response.headers.get('X-Key-Rotation')}") - - # Tentative de décodage des métadonnées - try: - decoded = base64.b64decode(response.content) - if len(decoded) >= 16: - nonce = decoded[:12] - metadata_size = int.from_bytes(decoded[12:16], 'big') - metadata_json = decoded[16:16+metadata_size] - metadata = json.loads(metadata_json.decode('utf-8')) - - print(f"\n📊 Métadonnées de chiffrement:") - print(f" Utilisateur: {metadata.get('user_id')}") - print(f" Version de clé: {metadata.get('key_version')}") - print(f" Timestamp: {metadata.get('timestamp')}") - print(f" Algorithme: {metadata.get('algorithm')}") - - except Exception as e: - print(f"⚠️ Impossible de décoder les métadonnées: {e}") - - return True - else: - print(f"❌ Erreur d'accès au fichier: {response.status_code}") - print(f" Réponse: {response.text}") - return False - - except Exception as e: - print(f"❌ Erreur de connexion: {e}") - return False - -def test_authentication(): - """Test d'authentification avec différents ID utilisateur""" - print("\n🔐 Test d'authentification...") - - test_users = [ - ('valid_user_001', True), - ('invalid@user', False), - ('ab', False), # Trop court - ('a' * 51, False), # Trop long - ('', False), # Vide - ] - - for user_id, should_succeed in test_users: - print(f"\n Test utilisateur: '{user_id}' (attendu: {'succès' if should_succeed else 'échec'})") - - try: - response = requests.get( - f"{BASE_URL}/health", - verify=VERIFY_SSL, - headers={'X-User-ID': user_id} if user_id else {} - ) - - success = response.status_code == 200 - if success == should_succeed: - print(f" ✅ Résultat attendu") - else: - print(f" ❌ Résultat inattendu: {response.status_code}") - - except Exception as e: - if not should_succeed: - print(f" ✅ Erreur attendue: {e}") - else: - print(f" ❌ Erreur inattendue: {e}") - -def test_https_requirement(): - """Test de l'obligation HTTPS""" - print("\n🔒 Test de l'obligation HTTPS...") - - # Tentative d'accès HTTP (devrait échouer) - http_url = BASE_URL.replace('https://', 'http://') - - try: - response = requests.get( - f"{http_url}/health", - verify=VERIFY_SSL, - headers={'X-User-ID': USER_ID}, - timeout=5 - ) - print(f"❌ HTTP autorisé (ne devrait pas l'être): {response.status_code}") - - except Exception as e: - print(f"✅ HTTP refusé comme attendu: {e}") - -def test_key_rotation(): - """Test de la rotation des clés""" - print("\n🔄 Test de la rotation des clés...") - - try: - # Premier accès - response1 = requests.get( - f"{BASE_URL}/dev/bitcoin/bitcoin.conf", - verify=VERIFY_SSL, - headers={'X-User-ID': USER_ID} - ) - - if response1.status_code == 200: - # Attendre un peu et refaire un accès - import time - time.sleep(2) - - response2 = requests.get( - f"{BASE_URL}/dev/bitcoin/bitcoin.conf", - verify=VERIFY_SSL, - headers={'X-User-ID': USER_ID} - ) - - if response2.status_code == 200: - # Comparer les réponses (les clés peuvent avoir changé) - print(f"✅ Accès multiples réussis") - print(f" Premier accès: {len(response1.content)} bytes") - print(f" Deuxième accès: {len(response2.content)} bytes") - - # Les réponses peuvent être différentes à cause de la rotation des clés - if response1.content != response2.content: - print(f" ✅ Contenu différent détecté (rotation des clés possible)") - else: - print(f" ⚠️ Contenu identique (rotation pas encore déclenchée)") - - return True - else: - print(f"❌ Deuxième accès échoué: {response2.status_code}") - else: - print(f"❌ Premier accès échoué: {response1.status_code}") - - except Exception as e: - print(f"❌ Erreur lors du test de rotation: {e}") - - return False - -def main(): - """Fonction principale de test""" - print("🚀 Test de l'API Vault sécurisée") - print("=" * 50) - print(f"URL de base: {BASE_URL}") - print(f"ID utilisateur: {USER_ID}") - print(f"Vérification SSL: {VERIFY_SSL}") - print("=" * 50) - - # Tests - tests = [ - ("Santé de l'API", test_health), - ("Informations API", test_info), - ("Accès aux fichiers", test_file_access), - ("Authentification", test_authentication), - ("Obligation HTTPS", test_https_requirement), - ("Rotation des clés", test_key_rotation), - ] - - results = [] - - for test_name, test_func in tests: - try: - result = test_func() - results.append((test_name, result)) - except Exception as e: - print(f"❌ Erreur dans le test '{test_name}': {e}") - results.append((test_name, False)) - - # Résumé - print("\n" + "=" * 50) - print("📊 RÉSUMÉ DES TESTS") - print("=" * 50) - - passed = 0 - total = len(results) - - for test_name, result in results: - status = "✅ PASSÉ" if result else "❌ ÉCHOUÉ" - print(f"{status} - {test_name}") - if result: - passed += 1 - - print(f"\nRésultat global: {passed}/{total} tests passés") - - if passed == total: - print("🎉 Tous les tests sont passés avec succès!") - else: - print("⚠️ Certains tests ont échoué. Vérifiez la configuration.") - -if __name__ == '__main__': - main()