
- API server with ChaCha20-Poly1305 encryption - TypeScript SDK client with full functionality - Complete documentation in docs/ - Environment variable processing with composite variables - HTTPS-only API on port 6666 - Storage structure for configuration files - Tests and examples included Features: - Quantum-resistant encryption (ChaCha20-Poly1305) - Variable substitution from .env files - Comprehensive TypeScript SDK - Full API documentation and specifications - Deployment guides and security model
636 lines
14 KiB
Markdown
636 lines
14 KiB
Markdown
# 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
|
|
```bash
|
|
npm install @4nk/vault-sdk
|
|
```
|
|
|
|
### Depuis les sources
|
|
```bash
|
|
git clone https://git.4nkweb.com/4nk/vault-sdk.git
|
|
cd vault-sdk
|
|
npm install
|
|
npm run build
|
|
```
|
|
|
|
## Configuration
|
|
|
|
### Importation de base
|
|
|
|
```typescript
|
|
import { VaultClient, createVaultClient, VaultCrypto } from '@4nk/vault-sdk';
|
|
```
|
|
|
|
### Création d'un client
|
|
|
|
#### Méthode simple
|
|
```typescript
|
|
const client = createVaultClient(
|
|
'https://vault.4nkweb.com:6666',
|
|
'quantum_resistant_demo_key_32byt'
|
|
);
|
|
```
|
|
|
|
#### Méthode avancée
|
|
```typescript
|
|
const client = new VaultClient(
|
|
{
|
|
baseUrl: 'https://vault.4nkweb.com:6666',
|
|
verifySsl: false, // Pour les certificats auto-signés
|
|
timeout: 15000, // 15 secondes
|
|
},
|
|
'quantum_resistant_demo_key_32byt'
|
|
);
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### Classe VaultClient
|
|
|
|
#### Constructeur
|
|
|
|
```typescript
|
|
constructor(config: VaultConfig, decryptionKey: string)
|
|
```
|
|
|
|
**Paramètres** :
|
|
- `config` : Configuration du client
|
|
- `decryptionKey` : Clé de déchiffrement (32 bytes exactement)
|
|
|
|
**Configuration** :
|
|
```typescript
|
|
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** :
|
|
```typescript
|
|
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** :
|
|
```typescript
|
|
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** :
|
|
```typescript
|
|
interface FileRequest {
|
|
env: string;
|
|
filePath: string;
|
|
}
|
|
```
|
|
|
|
**Exemple** :
|
|
```typescript
|
|
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** :
|
|
```typescript
|
|
interface VaultHealth {
|
|
status: string; // "healthy" ou "unhealthy"
|
|
service: string; // Nom du service
|
|
encryption: string; // Type de chiffrement
|
|
algorithm: string; // Algorithme utilisé
|
|
}
|
|
```
|
|
|
|
**Exemple** :
|
|
```typescript
|
|
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** :
|
|
```typescript
|
|
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** :
|
|
```typescript
|
|
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** :
|
|
```typescript
|
|
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.
|
|
|
|
**Retour** : Clé de 32 caractères UTF-8
|
|
|
|
**Exemple** :
|
|
```typescript
|
|
const randomKey = VaultCrypto.generateKey();
|
|
console.log(`Clé générée: ${randomKey.substring(0, 10)}...`);
|
|
```
|
|
|
|
#### `hashToKey(password: string): string`
|
|
|
|
Dérive une clé de 32 bytes depuis un mot de passe.
|
|
|
|
**Paramètres** :
|
|
- `password` : Mot de passe source
|
|
|
|
**Retour** : Clé de 32 bytes dérivée avec SHA-256
|
|
|
|
**Exemple** :
|
|
```typescript
|
|
const password = 'mon-mot-de-passe-secret';
|
|
const derivedKey = VaultCrypto.hashToKey(password);
|
|
console.log(`Clé dérivée: ${derivedKey.substring(0, 10)}...`);
|
|
```
|
|
|
|
#### `validateKey(key: string): boolean`
|
|
|
|
Vérifie qu'une clé fait exactement 32 bytes.
|
|
|
|
**Paramètres** :
|
|
- `key` : Clé à valider
|
|
|
|
**Retour** : `true` si la clé est valide, `false` sinon
|
|
|
|
**Exemple** :
|
|
```typescript
|
|
const key = 'quantum_resistant_demo_key_32byt';
|
|
const isValid = VaultCrypto.validateKey(key);
|
|
console.log(`Clé valide: ${isValid}`);
|
|
```
|
|
|
|
## Gestion d'erreurs
|
|
|
|
### Classes d'erreurs
|
|
|
|
#### VaultApiError
|
|
|
|
Erreurs liées aux requêtes HTTP vers l'API.
|
|
|
|
```typescript
|
|
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** :
|
|
```typescript
|
|
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.
|
|
|
|
```typescript
|
|
class VaultDecryptionError extends Error {
|
|
constructor(message: string);
|
|
}
|
|
```
|
|
|
|
**Exemple** :
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
import { createVaultClient } from '@4nk/vault-sdk';
|
|
|
|
async function basicExample() {
|
|
// Création du client
|
|
const client = createVaultClient(
|
|
'https://vault.4nkweb.com:6666',
|
|
'quantum_resistant_demo_key_32byt'
|
|
);
|
|
|
|
// 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
|
|
|
|
```typescript
|
|
import { VaultClient, VaultApiError, VaultDecryptionError } from '@4nk/vault-sdk';
|
|
|
|
async function advancedExample() {
|
|
const client = new VaultClient(
|
|
{
|
|
baseUrl: 'https://vault.4nkweb.com:6666',
|
|
timeout: 10000,
|
|
},
|
|
'quantum_resistant_demo_key_32byt'
|
|
);
|
|
|
|
// 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
|
|
|
|
```typescript
|
|
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é
|
|
|
|
```json
|
|
{
|
|
"compilerOptions": {
|
|
"target": "ES2020",
|
|
"module": "commonjs",
|
|
"lib": ["ES2020", "DOM"],
|
|
"strict": true,
|
|
"esModuleInterop": true,
|
|
"skipLibCheck": true,
|
|
"forceConsistentCasingInFileNames": true,
|
|
"declaration": true,
|
|
"sourceMap": true
|
|
}
|
|
}
|
|
```
|
|
|
|
### Types personnalisés
|
|
|
|
```typescript
|
|
// 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
|
|
|
|
```typescript
|
|
import { VaultClient, VaultCrypto } from '@4nk/vault-sdk';
|
|
|
|
describe('VaultClient', () => {
|
|
let client: VaultClient;
|
|
|
|
beforeEach(() => {
|
|
client = new VaultClient(
|
|
{ baseUrl: 'https://vault.4nkweb.com:6666' },
|
|
'quantum_resistant_demo_key_32byt'
|
|
);
|
|
});
|
|
|
|
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
|
|
|
|
```typescript
|
|
describe('Intégration API', () => {
|
|
it('devrait fonctionner end-to-end', async () => {
|
|
const client = createVaultClient(
|
|
'https://vault.4nkweb.com:6666',
|
|
'quantum_resistant_demo_key_32byt'
|
|
);
|
|
|
|
// 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
|
|
|
|
```typescript
|
|
// ✅ 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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
// Activation des logs détaillés
|
|
const client = new VaultClient(
|
|
{
|
|
baseUrl: 'https://vault.4nkweb.com:6666',
|
|
timeout: 30000
|
|
},
|
|
'quantum_resistant_demo_key_32byt'
|
|
);
|
|
|
|
// 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
|
|
|
|
- **Documentation** : [docs/README.md](README.md)
|
|
- **API Specification** : [docs/api-specification.md](api-specification.md)
|
|
- **Issues** : [Git Issues](https://git.4nkweb.com/4nk/vault-sdk/issues)
|
|
- **Email** : sdk-support@4nkweb.com
|
|
|
|
---
|
|
|
|
**Version SDK** : 1.0.0
|
|
**Compatibilité API** : 1.0.0+
|