4NK_vault/docs/sdk-documentation.md
4NK Dev b13c8745e3 feat: Implémentation système sécurisé avec clés par utilisateur et environnement
-  API sécurisée avec authentification par ID utilisateur
-  HTTPS obligatoire avec rejet des connexions HTTP
-  Clés individuelles par utilisateur ET par environnement
-  Rotation automatique des clés avec sauvegarde de l'ancienne
-  Stockage sécurisé dans storage/<env>/_keys/
-  Client SDK mis à jour sans stockage de clés côté client
-  Documentation complète avec avertissements de sécurité
-  Tests complets du système sécurisé
- 🔒 Protection des fichiers sensibles dans .gitignore
2025-09-29 21:27:09 +00:00

14 KiB

SDK Client TypeScript - Documentation complète

Vue d'ensemble

Le SDK Client TypeScript pour l'API Vault 4NK fournit une interface type-safe et moderne pour interagir avec l'API de stockage sécurisé. Il inclut le déchiffrement côté client, la gestion d'erreurs avancée, et des utilitaires cryptographiques.

Installation

NPM

npm install @4nk/vault-sdk

Depuis les sources

git clone https://git.4nkweb.com/4nk/vault-sdk.git
cd vault-sdk
npm install
npm run build

Configuration

Importation de base

import { VaultClient, createVaultClient, VaultCrypto } from '@4nk/vault-sdk';

Création d'un client

Méthode simple (recommandée)

const client = createVaultClient(
  'https://vault.4nkweb.com:6666'
  // Plus de clé de déchiffrement nécessaire - clés dynamiques utilisées
);

Méthode avancée (recommandée)

const client = new VaultClient(
  {
    baseUrl: 'https://vault.4nkweb.com:6666',
    verifySsl: false, // Pour les certificats auto-signés
    timeout: 15000,   // 15 secondes
  }
  // Plus de clé de déchiffrement nécessaire - clés dynamiques utilisées
);

Méthode compatible (dépréciée)

const client = new VaultClient(
  {
    baseUrl: 'https://vault.4nkweb.com:6666',
    verifySsl: false,
    timeout: 15000,
  },
  'old_demo_key' // Ignorée mais acceptée pour compatibilité
);

API Reference

Classe VaultClient

Constructeur

constructor(config: VaultConfig, decryptionKey?: string)

Paramètres :

  • config : Configuration du client
  • decryptionKey : Clé de déchiffrement optionnelle (32 bytes exactement) - Dépréciée, clés dynamiques utilisées

Configuration :

interface VaultConfig {
  baseUrl: string;           // URL de base de l'API
  verifySsl?: boolean;       // Validation SSL (défaut: true)
  timeout?: number;          // Timeout en ms (défaut: 30000)
}

Méthodes

getFile(env: string, filePath: string): Promise<VaultFile>

Récupère et déchiffre un fichier depuis l'API.

Paramètres :

  • env : Environnement (ex: "dev", "prod")
  • filePath : Chemin du fichier relatif

Retour :

interface VaultFile {
  content: string;           // Contenu déchiffré
  filename: string;          // Nom du fichier
  size: number;              // Taille en caractères
  encrypted: boolean;        // Était chiffré
  algorithm?: string;        // Algorithme utilisé
}

Exemple :

try {
  const file = await client.getFile('dev', 'bitcoin/bitcoin.conf');
  console.log(`Fichier: ${file.filename}`);
  console.log(`Taille: ${file.size} caractères`);
  console.log(`Contenu: ${file.content}`);
} catch (error) {
  console.error('Erreur:', error.message);
}
getFiles(requests: FileRequest[]): Promise<VaultFile[]>

Récupère plusieurs fichiers en parallèle.

Paramètres :

interface FileRequest {
  env: string;
  filePath: string;
}

Exemple :

const files = await client.getFiles([
  { env: 'dev', filePath: 'bitcoin/bitcoin.conf' },
  { env: 'dev', filePath: 'tor/torrc' },
  { env: 'dev', filePath: 'sdk_relay/sdk_relay.conf' }
]);

files.forEach(file => {
  console.log(`${file.filename}: ${file.size} caractères`);
});
health(): Promise<VaultHealth>

Vérifie l'état de santé de l'API.

Retour :

interface VaultHealth {
  status: string;            // "healthy" ou "unhealthy"
  service: string;           // Nom du service
  encryption: string;        // Type de chiffrement
  algorithm: string;         // Algorithme utilisé
}

Exemple :

const health = await client.health();
console.log(`Statut: ${health.status}`);
console.log(`Chiffrement: ${health.encryption}`);
info(): Promise<VaultInfo>

Récupère les informations sur l'API.

Retour :

interface VaultInfo {
  name: string;              // Nom de l'API
  version: string;           // Version
  domain: string;            // Domaine
  port: number;              // Port
  protocol: string;          // Protocole
  encryption: string;        // Type de chiffrement
  endpoints: Record<string, string>; // Endpoints disponibles
}

Exemple :

const info = await client.info();
console.log(`API: ${info.name} v${info.version}`);
console.log(`Domaine: ${info.domain}:${info.port}`);
ping(): Promise<boolean>

Teste la connectivité à l'API.

Retour : true si connecté, false sinon

Exemple :

const isConnected = await client.ping();
if (isConnected) {
  console.log('✅ API accessible');
} else {
  console.log('❌ API inaccessible');
}
searchFiles(env: string, pattern?: RegExp): Promise<string[]>

Recherche des fichiers par pattern (non implémenté côté serveur).

Note : Cette méthode retourne toujours un tableau vide car l'endpoint de recherche n'est pas encore implémenté côté serveur.

Classe VaultCrypto

Utilitaires pour la gestion des clés de chiffrement.

generateKey(): string

Génère une clé de déchiffrement aléatoire de 32 bytes (déprécié).

Retour : Clé de 32 caractères UTF-8

Note : Cette méthode est dépréciée car le système utilise maintenant des clés dynamiques générées automatiquement par le serveur.

hashToKey(password: string): string

Dérive une clé de 32 bytes depuis un mot de passe (déprécié).

Paramètres :

  • password : Mot de passe source

Retour : Clé de 32 bytes dérivée avec SHA-256

Note : Cette méthode est dépréciée car le système utilise maintenant des clés dynamiques générées automatiquement par le serveur.

validateKey(key: string): boolean

Vérifie qu'une clé fait exactement 32 bytes (déprécié).

Paramètres :

  • key : Clé à valider

Retour : true si la clé est valide, false sinon

Note : Cette méthode est dépréciée car le système utilise maintenant des clés dynamiques générées automatiquement par le serveur.

Gestion d'erreurs

Classes d'erreurs

VaultApiError

Erreurs liées aux requêtes HTTP vers l'API.

class VaultApiError extends Error {
  constructor(
    message: string,
    public statusCode?: number,
    public endpoint?: string
  );
}

Propriétés :

  • message : Message d'erreur
  • statusCode : Code HTTP d'erreur
  • endpoint : Endpoint qui a échoué

Exemple :

try {
  await client.getFile('dev', 'fichier-inexistant.conf');
} catch (error) {
  if (error instanceof VaultApiError) {
    console.error(`Erreur API: ${error.message}`);
    console.error(`Code: ${error.statusCode}`);
    console.error(`Endpoint: ${error.endpoint}`);
  }
}

VaultDecryptionError

Erreurs liées au déchiffrement des fichiers.

class VaultDecryptionError extends Error {
  constructor(message: string);
}

Exemple :

try {
  const file = await client.getFile('dev', 'config.conf');
} catch (error) {
  if (error instanceof VaultDecryptionError) {
    console.error(`Erreur de déchiffrement: ${error.message}`);
  }
}

Gestion d'erreurs complète

async function handleFileRequest(env: string, filePath: string) {
  try {
    const file = await client.getFile(env, filePath);
    return file;
  } catch (error) {
    if (error instanceof VaultApiError) {
      switch (error.statusCode) {
        case 404:
          console.error(`Fichier non trouvé: ${filePath}`);
          break;
        case 403:
          console.error(`Accès non autorisé: ${filePath}`);
          break;
        case 500:
          console.error(`Erreur serveur pour: ${filePath}`);
          break;
        default:
          console.error(`Erreur API: ${error.message}`);
      }
    } else if (error instanceof VaultDecryptionError) {
      console.error(`Erreur de déchiffrement: ${error.message}`);
    } else {
      console.error(`Erreur inconnue: ${error.message}`);
    }
    throw error;
  }
}

Exemples d'utilisation

Exemple basique

import { createVaultClient } from '@4nk/vault-sdk';

async function basicExample() {
  // Création du client (plus de clé de déchiffrement nécessaire)
  const client = createVaultClient('https://vault.4nkweb.com:6666');

  // Test de connectivité
  const isConnected = await client.ping();
  if (!isConnected) {
    throw new Error('Impossible de se connecter à l\'API');
  }

  // Récupération d'un fichier
  const file = await client.getFile('dev', 'bitcoin/bitcoin.conf');
  console.log(`Fichier: ${file.filename}`);
  console.log(`Taille: ${file.size} caractères`);
  console.log(`Contenu: ${file.content.substring(0, 100)}...`);
}

Exemple avancé avec gestion d'erreurs

import { VaultClient, VaultApiError, VaultDecryptionError } from '@4nk/vault-sdk';

async function advancedExample() {
  const client = new VaultClient({
    baseUrl: 'https://vault.4nkweb.com:6666',
    timeout: 10000,
  });

  // Informations sur l'API
  try {
    const info = await client.info();
    console.log(`API: ${info.name} v${info.version}`);
  } catch (error) {
    console.error('Erreur info:', error.message);
  }

  // Récupération de plusieurs fichiers
  const requests = [
    { env: 'dev', filePath: 'bitcoin/bitcoin.conf' },
    { env: 'dev', filePath: 'tor/torrc' },
    { env: 'dev', filePath: 'sdk_relay/sdk_relay.conf' }
  ];

  try {
    const files = await client.getFiles(requests);
    console.log(`${files.length} fichiers récupérés`);

    files.forEach((file, index) => {
      console.log(`${index + 1}. ${file.filename}: ${file.size} chars`);
    });
  } catch (error) {
    if (error instanceof VaultApiError) {
      console.error(`Erreur API: ${error.statusCode} - ${error.message}`);
    } else if (error instanceof VaultDecryptionError) {
      console.error(`Erreur de déchiffrement: ${error.message}`);
    }
  }
}

Exemple avec retry automatique

async function retryOperation<T>(
  operation: () => Promise<T>,
  maxRetries: number = 3,
  delay: number = 1000
): Promise<T> {
  let lastError: Error;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await operation();
    } catch (error) {
      lastError = error as Error;
      console.log(`Tentative ${attempt}/${maxRetries} échouée: ${lastError.message}`);

      if (attempt < maxRetries) {
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }

  throw lastError!;
}

// Utilisation
const file = await retryOperation(
  () => client.getFile('dev', 'bitcoin/bitcoin.conf'),
  3,
  500
);

Configuration TypeScript

tsconfig.json recommandé

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020", "DOM"],
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true,
    "sourceMap": true
  }
}

Types personnalisés

// Extension des types existants
interface CustomVaultFile extends VaultFile {
  metadata?: {
    lastModified: Date;
    checksum: string;
  };
}

// Types pour vos applications
interface ConfigFile {
  environment: string;
  services: string[];
  variables: Record<string, string>;
}

Tests

Tests unitaires avec Jest

import { VaultClient, VaultCrypto } from '@4nk/vault-sdk';

describe('VaultClient', () => {
  let client: VaultClient;

  beforeEach(() => {
    client = new VaultClient({
      baseUrl: 'https://vault.4nkweb.com:6666'
    });
  });

  it('devrait récupérer un fichier', async () => {
    const file = await client.getFile('dev', 'bitcoin/bitcoin.conf');
    expect(file).toBeDefined();
    expect(file.filename).toBe('bitcoin.conf');
    expect(file.content).toBeTruthy();
  });

  it('devrait gérer les erreurs 404', async () => {
    await expect(client.getFile('dev', 'fichier-inexistant.conf'))
      .rejects
      .toThrow('Fichier non trouvé');
  });
});

Tests d'intégration

describe('Intégration API', () => {
  it('devrait fonctionner end-to-end', async () => {
    const client = createVaultClient('https://vault.4nkweb.com:6666');

    // Test de santé
    const health = await client.health();
    expect(health.status).toBe('healthy');

    // Test de fichier
    const file = await client.getFile('dev', 'bitcoin/bitcoin.conf');
    expect(file.content).toContain('bitcoin');
  });
});

Performance et optimisation

Récupération parallèle

// ✅ Bon : Récupération parallèle
const files = await client.getFiles(requests);

// ❌ Mauvais : Récupération séquentielle
const files = [];
for (const request of requests) {
  const file = await client.getFile(request.env, request.filePath);
  files.push(file);
}

Cache local

class CachedVaultClient extends VaultClient {
  private cache = new Map<string, VaultFile>();

  async getFile(env: string, filePath: string): Promise<VaultFile> {
    const key = `${env}/${filePath}`;

    if (this.cache.has(key)) {
      return this.cache.get(key)!;
    }

    const file = await super.getFile(env, filePath);
    this.cache.set(key, file);
    return file;
  }
}

Dépannage

Problèmes courants

Erreur de clé de déchiffrement

Error: La clé de déchiffrement doit faire exactement 32 bytes

Solution : Vérifiez que votre clé fait exactement 32 caractères UTF-8.

Erreur de connectivité

Error: fetch failed

Solutions :

  • Vérifiez que l'API est démarrée
  • Vérifiez l'URL de base
  • Désactivez la validation SSL si nécessaire (verifySsl: false)

Erreur de déchiffrement

VaultDecryptionError: Erreur de déchiffrement

Solutions :

  • Vérifiez que la clé correspond à celle utilisée côté serveur
  • Vérifiez que le fichier n'est pas corrompu

Debug

// Activation des logs détaillés
const client = new VaultClient({
  baseUrl: 'https://vault.4nkweb.com:6666',
  timeout: 30000
});

// Test de connectivité
const isConnected = await client.ping();
console.log('Connecté:', isConnected);

// Test d'information
try {
  const info = await client.info();
  console.log('Info API:', info);
} catch (error) {
  console.error('Erreur info:', error);
}

Support


Version SDK : 1.0.0 Compatibilité API : 1.0.0+