Skip to content

Documentation SDK JavaScript

La librairie JavaScript Sharokey permet d'intégrer facilement le partage de secrets sécurisés dans vos applications JavaScript/TypeScript. Elle reproduit toutes les fonctionnalités du CLI Sharokey avec une API moderne et intuitive.

✨ Fonctionnalités principales

  • 🔐 Chiffrement Zero Knowledge : AES-GCM-256 côté client
  • 🌍 Multi-environnement : Node.js et navigateurs
  • 📱 API moderne : Promises, async/await, TypeScript
  • 🔑 Authentification flexible : Token API ou Microsoft SSO
  • 📎 Pièces jointes : Support des fichiers chiffrés
  • 🎛️ Configuration avancée : Retry, timeout, logs
  • 🧪 Tests complets : Coverage et validation

📦 Installation

⚠️ Note importante : Ce package n'est pas encore disponible sur NPM. La documentation décrit l'API future.

NPM (à venir)

bash
# Pas encore disponible
# npm install sharokey-js

Yarn (à venir)

bash
# Pas encore disponible
# yarn add sharokey-js

CDN (navigateur) - Pas encore disponible

html
<!-- Pas encore disponible -->
<!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/sharokey.min.js"></script> -->

🚀 Démarrage rapide

Import ES6/TypeScript

javascript
import { SharokeyClient } from 'sharokey-js';
// ou
import SharokeyClient from 'sharokey-js';

Require CommonJS

javascript
const { SharokeyClient } = require('sharokey-js');

Usage de base

javascript
// Configuration du client
const client = new SharokeyClient({
  token: 'votre-token-api',
  apiUrl: 'https://api.sharokey.com/api/v1'
});

// Créer un secret
const secret = await client.createSecret({
  content: "Mon mot de passe secret",
  expirationHours: 24,
  maximumViews: 1,
  description: "Accès temporaire"
});

console.log('Secret créé:', secret.shareUrl);
console.log('Expire le:', secret.expiration);

⚙️ Configuration

Configuration de base

javascript
const client = new SharokeyClient({
  token: 'votre-token-api',                    // REQUIS
  apiUrl: 'https://api.sharokey.com/api/v1', // Optionnel
  timeout: 30000,                              // 30 secondes
  retries: 3                                   // 3 tentatives
});

Configuration avancée

javascript
const client = new SharokeyClient({
  token: 'votre-token-api',
  apiUrl: 'https://api.sharokey.com/api/v1',
  timeout: 60000,
  retries: 5,
  defaultExpirationHours: 48,
  defaultMaximumViews: 3,
  logLevel: 'info',                    // debug, info, warn, error
  validateSsl: true,
  headers: {
    'X-Custom-Header': 'value'
  }
});

Validation de configuration

javascript
import { validateConfig } from 'sharokey-js';

const errors = validateConfig({
  token: 'test',
  timeout: -1  // Erreur
});

if (errors.length > 0) {
  console.error('Erreurs de configuration:', errors);
}

🔑 Authentification

Avec token API

javascript
const client = new SharokeyClient({
  token: 'sk_live_abcdefghijklmnop1234567890'
});

// Valider le token
const userInfo = await client.validateToken();
if (userInfo) {
  console.log('Connecté en tant que:', userInfo.email);
} else {
  console.error('Token invalide');
}

Test de connectivité

javascript
const isConnected = await client.testConnection();
if (!isConnected) {
  throw new Error('Impossible de se connecter à l\'API Sharokey');
}

Informations utilisateur

javascript
const user = client.getCurrentUser();
console.log('Utilisateur actuel:', user);

📝 Créer des secrets

Création simple

javascript
const secret = await client.createSecret("Mon secret");
console.log('Lien de partage:', secret.shareUrl);

Création avec options

javascript
const secret = await client.createSecret({
  content: "Informations confidentielles",
  description: "Données client importantes",
  message: "Merci de consulter avant demain",
  expirationHours: 48,
  maximumViews: 3,
  password: "protection-additionnelle"
});

Avec pièces jointes

javascript
import fs from 'fs';

const fileData = fs.readFileSync('document.pdf');

const secret = await client.createSecret({
  content: "Voici le document demandé",
  description: "Contrat confidentiel",
  expirationHours: 72,
  maximumViews: 1,
  attachments: [
    {
      name: 'contrat.pdf',
      data: fileData
    },
    {
      name: 'annexe.docx', 
      data: annexeData
    }
  ]
});

Avec protection OTP

javascript
const secret = await client.createSecret({
  content: "Code d'accès critique",
  expirationHours: 1,
  maximumViews: 1,
  otpEmail: "[email protected]",
  // ou
  otpPhone: "+33123456789"
});

Générateur de mot de passe

javascript
// Générer un mot de passe simple
const password = client.generatePassword();
console.log('Mot de passe généré:', password);

// Générer et créer un secret
const result = await client.createPasswordSecret(
  "Accès temporaire serveur", 
  {
    passwordLength: 20,
    includeSymbols: true,
    expirationHours: 2,
    maximumViews: 1
  }
);

console.log('Mot de passe:', result.password);
console.log('Lien:', result.secret.shareUrl);

Builder pattern

javascript
import { createSecretRequest } from 'sharokey-js';

const request = createSecretRequest()
  .setContent("Secret complexe")
  .setDescription("Description détaillée")
  .setExpirationHours(24)
  .setMaximumViews(5)
  .setPassword("motdepasse")
  .addAttachment('fichier1.txt', buffer1)
  .addAttachment('fichier2.pdf', buffer2);

const secret = await client.createSecret(request);

📊 Lister et gérer

Lister tous les secrets

javascript
const result = await client.listSecrets();
console.log(`${result.data.length} secrets trouvés`);

result.data.forEach(secret => {
  console.log(`${secret.slug}: ${secret.description} (${secret.currentViews}/${secret.maximumViews})`);
});

Lister avec filtres

javascript
const secrets = await client.listSecrets({
  status: 'active',
  creator: '[email protected]',
  limit: 10,
  search: 'mot-clé'
});

Détails d'un secret

javascript
const secret = await client.getSecret('ABC123XY');

console.log('Description:', secret.description);
console.log('Créateur:', secret.creator);
console.log('Vues restantes:', secret.getRemainingViews());
console.log('Expire dans:', secret.getTimeRemaining(), 'ms');
console.log('Actif:', secret.isActive());

Supprimer un secret

javascript
const deleted = await client.deleteSecret('ABC123XY');
if (deleted) {
  console.log('Secret supprimé avec succès');
}

Statistiques d'usage

javascript
const stats = await client.getStatistics();

console.log('Statistiques:');
console.log('- Total secrets:', stats.totalSecrets);
console.log('- Secrets actifs:', stats.activeSecrets);
console.log('- Secrets expirés:', stats.expiredSecrets);
console.log('- Total vues:', stats.totalViews);
console.log('- Taux protection:', stats.getPasswordProtectionRate() + '%');
console.log('- Moyenne vues:', stats.getAverageViewsPerSecret());

🔧 Fonctionnalités avancées

Recherche de secrets

javascript
const secrets = await client.searchSecrets("mot-clé", {
  limit: 20,
  status: 'active'
});

console.log(`${secrets.length} secrets trouvés`);

Secrets actifs uniquement

javascript
const activeSecrets = await client.getActiveSecrets(50);
console.log('Secrets encore consultables:', activeSecrets.length);

Mise à jour de configuration

javascript
client.updateConfig({
  timeout: 60000,
  retries: 5,
  logLevel: 'debug'
});

// Chaînable
client.updateConfig({ timeout: 30000 })
      .updateConfig({ retries: 3 });

📖 Référence API

SharokeyClient

Méthodes principales

  • createSecret(content, options?)Promise<Secret>
  • listSecrets(filters?)Promise<ListResponse<Secret>>
  • getSecret(slug)Promise<Secret>
  • deleteSecret(slug)Promise<boolean>
  • getStatistics()Promise<Statistics>

Méthodes utilitaires

  • generatePassword(length?, symbols?)string
  • testConnection()Promise<boolean>
  • validateToken()Promise<Object|null>
  • getCurrentUser()Object|null
  • getInfo()ClientInfo

Méthodes avancées

  • createPasswordSecret(desc, options?)Promise<{secret, password}>
  • searchSecrets(query, options?)Promise<Secret[]>
  • getActiveSecrets(limit?)Promise<Secret[]>

Méthodes de Demandes de Secret

  • createSecretRequest(options?)Promise<SecretRequest>
  • listSecretRequests(filters?)Promise<ListResponse<SecretRequest>>
  • getSecretRequest(id)Promise<SecretRequest>
  • deleteSecretRequest(id)Promise<boolean>
  • getSecretRequestStatistics()Promise<Object>
  • getActiveSecretRequests(limit?)Promise<SecretRequest[]>

Secret

Propriétés

  • slug: string - Identifiant unique
  • description: string - Description
  • creator: string - Email du créateur
  • maximumViews: number - Vues maximum
  • currentViews: number - Vues actuelles
  • expiration: Date - Date d'expiration
  • hasAttachments: boolean - A des pièces jointes
  • shareUrl: string - URL de partage complète

Méthodes

  • isActive()boolean
  • getRemainingViews()number
  • getTimeRemaining()number|null

Statistics

Propriétés

  • totalSecrets: number - Total des secrets
  • activeSecrets: number - Secrets actifs
  • expiredSecrets: number - Secrets expirés
  • totalViews: number - Total des vues

Méthodes

  • getPasswordProtectionRate()number
  • getAverageViewsPerSecret()number

SecretRequest

Propriétés

  • id: number - Identifiant unique
  • token: string - Token de la demande
  • message: string - Message pour le destinataire
  • description: string - Description interne
  • secretExpirationHours: number - Heures avant expiration du secret
  • requestExpirationHours: number - Heures avant expiration de la demande
  • maximumViews: number - Vues maximum pour le secret
  • emailTo: string - Email du destinataire
  • emailReply: string - Email de réponse
  • creator: string - Email du créateur
  • status: string - Statut de la demande (active, expired)
  • url: string - URL de partage de la demande
  • createdAt: Date - Date de création

Méthodes

  • isActive()boolean
  • isExpired()boolean
  • getShareUrl()string

💡 Exemples pratiques

Application web de partage

javascript
class SecretManager {
  constructor(token) {
    this.client = new SharokeyClient({ token });
  }

  async sharePassword(password, recipient) {
    const secret = await this.client.createSecret({
      content: password,
      description: `Mot de passe pour ${recipient}`,
      expirationHours: 1,
      maximumViews: 1,
      otpEmail: recipient
    });

    return secret.shareUrl;
  }

  async shareDocument(filePath, description) {
    const fs = require('fs');
    const fileData = fs.readFileSync(filePath);

    const secret = await this.client.createSecret({
      content: "Document confidentiel ci-joint",
      description: description,
      expirationHours: 48,
      maximumViews: 3,
      attachments: [{
        name: path.basename(filePath),
        data: fileData
      }]
    });

    return secret.shareUrl;
  }

  async requestCredentials(email, description) {
    const request = await this.client.createSecretRequest({
      message: "Merci de partager les identifiants demandés de manière sécurisée",
      description: description,
      secretExpirationHours: 24,
      requestExpirationHours: 48,
      maximumViews: 1,
      emailTo: email,
      emailReply: "[email protected]"
    });

    return request.url;
  }

  async getDashboard() {
    const [stats, activeSecrets, activeRequests] = await Promise.all([
      this.client.getStatistics(),
      this.client.getActiveSecrets(10),
      this.client.getActiveSecretRequests(5)
    ]);

    return { stats, activeSecrets, activeRequests };
  }
}

Script de maintenance

javascript
#!/usr/bin/env node

const { SharokeyClient } = require('sharokey-js');

async function maintenance() {
  const client = new SharokeyClient({
    token: process.env.SHAROKEY_TOKEN,
    logLevel: 'info'
  });

  // Vérifier la connectivité
  const connected = await client.testConnection();
  if (!connected) {
    console.error('❌ Impossible de se connecter');
    process.exit(1);
  }

  // Afficher les secrets actifs
  console.log('📋 Récupération des secrets actifs...');
  const activeSecrets = await client.getActiveSecrets();
  console.log(`✅ ${activeSecrets.length} secrets actifs`);

  // Afficher les statistiques
  const stats = await client.getStatistics();
  console.log('\n📊 Statistiques:');
  console.log(`- Secrets actifs: ${stats.activeSecrets}`);
  console.log(`- Total vues: ${stats.totalViews}`);
  
  process.exit(0);
}

maintenance().catch(console.error);

Intégration Express.js

javascript
const express = require('express');
const { SharokeyClient } = require('sharokey-js');

const app = express();
const client = new SharokeyClient({
  token: process.env.SHAROKEY_TOKEN
});

app.use(express.json());

// Créer un secret via API REST
app.post('/api/secrets', async (req, res) => {
  try {
    const { content, description, hours, views } = req.body;
    
    const secret = await client.createSecret({
      content,
      description,
      expirationHours: hours || 24,
      maximumViews: views || 1
    });

    res.json({
      success: true,
      shareUrl: secret.shareUrl,
      expiresAt: secret.expiration
    });
    
  } catch (error) {
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
});

// Lister les secrets
app.get('/api/secrets', async (req, res) => {
  try {
    const result = await client.listSecrets({
      limit: parseInt(req.query.limit) || 50
    });

    res.json({
      success: true,
      secrets: result.data,
      pagination: result.meta
    });
    
  } catch (error) {
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
});

app.listen(3000, () => {
  console.log('API démarrée sur http://localhost:3000');
});

Usage React Hook

javascript
import { useState, useEffect } from 'react';
import { SharokeyClient } from 'sharokey-js';

function useSharokey(token) {
  const [client] = useState(() => new SharokeyClient({ token }));
  const [secrets, setSecrets] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const createSecret = async (content, options) => {
    setLoading(true);
    try {
      const secret = await client.createSecret(content, options);
      setSecrets(prev => [secret, ...prev]);
      return secret;
    } catch (err) {
      setError(err.message);
      throw err;
    } finally {
      setLoading(false);
    }
  };

  const refreshSecrets = async () => {
    setLoading(true);
    try {
      const result = await client.listSecrets();
      setSecrets(result.data);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    refreshSecrets();
  }, []);

  return {
    secrets,
    loading,
    error,
    createSecret,
    refreshSecrets,
    client
  };
}

// Usage dans un composant
function SecretManager() {
  const { secrets, createSecret, loading } = useSharokey(process.env.REACT_APP_SHAROKEY_TOKEN);

  const handleCreate = async () => {
    await createSecret("Mon nouveau secret", {
      expirationHours: 24,
      maximumViews: 1
    });
  };

  return (
    <div>
      <button onClick={handleCreate} disabled={loading}>
        Créer un secret
      </button>
      
      <ul>
        {secrets.map(secret => (
          <li key={secret.slug}>
            {secret.description} - {secret.getRemainingViews()} vues restantes
          </li>
        ))}
      </ul>
    </div>
  );
}

🚨 Gestion d'erreurs

Types d'erreurs

javascript
import { ApiError } from 'sharokey-js';

try {
  await client.createSecret("test");
} catch (error) {
  if (error instanceof ApiError) {
    switch (error.status) {
      case 401:
        console.error('Token invalide ou expiré');
        break;
      case 403:
        console.error('Accès refusé');
        break;
      case 429:
        console.error('Limite de taux atteinte');
        break;
      case 500:
        console.error('Erreur serveur:', error.message);
        break;
      default:
        console.error(`Erreur API ${error.status}:`, error.message);
    }
  } else {
    console.error('Erreur locale:', error.message);
  }
}

Validation locale

javascript
try {
  const secret = await client.createSecret({
    content: "", // Erreur de validation
    expirationHours: -1 // Erreur de validation
  });
} catch (error) {
  console.error('Erreur de validation:', error.message);
  // "Erreurs de validation : Le contenu est requis, Les heures d'expiration doivent être entre 1 et 1000"
}

Retry automatique

javascript
// Les erreurs réseau sont automatiquement retentées
const client = new SharokeyClient({
  token: 'test',
  retries: 5, // 5 tentatives maximum
  timeout: 60000 // 60 secondes
});

// Les erreurs 4xx ne sont PAS retentées (erreurs client)
// Les erreurs 5xx SONT retentées (erreurs serveur)

Gestion robuste

javascript
async function createSecretSafely(content, options) {
  const maxRetries = 3;
  let lastError;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await client.createSecret(content, options);
    } catch (error) {
      lastError = error;
      
      if (error instanceof ApiError) {
        // Erreurs non récupérables
        if (error.status === 401 || error.status === 403) {
          throw error;
        }
        
        // Erreurs temporaires - attendre avant retry
        if (error.status >= 500) {
          const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
          console.warn(`Tentative ${attempt}/${maxRetries} échouée, retry dans ${delay}ms`);
          await new Promise(resolve => setTimeout(resolve, delay));
          continue;
        }
      }
      
      // Autres erreurs - retry immédiat
      console.warn(`Tentative ${attempt}/${maxRetries} échouée:`, error.message);
    }
  }
  
  throw lastError;
}

🎛️ Configuration avancée

Variables d'environnement

bash
# .env
SHAROKEY_TOKEN=sk_live_abcdefghijklmnop1234567890
SHAROKEY_API_URL=https://api.sharokey.com/api/v1
SHAROKEY_TIMEOUT=60000
SHAROKEY_LOG_LEVEL=info
javascript
const client = new SharokeyClient({
  token: process.env.SHAROKEY_TOKEN,
  apiUrl: process.env.SHAROKEY_API_URL,
  timeout: parseInt(process.env.SHAROKEY_TIMEOUT) || 30000,
  logLevel: process.env.SHAROKEY_LOG_LEVEL || 'info'
});

Configuration par environnement

javascript
const configs = {
  development: {
    apiUrl: 'https://dev.api.sharokey.com/api/v1',
    logLevel: 'debug',
    validateSsl: false
  },
  staging: {
    apiUrl: 'https://staging.api.sharokey.com/api/v1',
    logLevel: 'info'
  },
  production: {
    apiUrl: 'https://api.sharokey.com/api/v1',
    logLevel: 'warn',
    retries: 5
  }
};

const client = new SharokeyClient({
  token: process.env.SHAROKEY_TOKEN,
  ...configs[process.env.NODE_ENV || 'development']
});

Logging personnalisé

javascript
// La librairie log automatiquement selon le niveau configuré
// debug: Requêtes détaillées
// info: Opérations importantes
// warn: Problèmes non critiques  
// error: Erreurs critiques

const client = new SharokeyClient({
  token: 'test',
  logLevel: 'debug' // Voir toutes les requêtes HTTP
});

💬 Support

Documentation technique

Ressources

Contact

FAQ

Q: La librairie fonctionne-t-elle dans les navigateurs ?

R: Oui, elle fonctionne dans tous les navigateurs modernes supportant l'API Web Crypto (Chrome 37+, Firefox 34+, Safari 7+).

Q: Puis-je utiliser des tokens d'entreprise ?

R: Oui, tous les types de tokens API Sharokey sont supportés (utilisateur et entreprise).

Q: Les secrets sont-ils vraiment chiffrés côté client ?

R: Oui, le chiffrement AES-GCM-256 est effectué entièrement côté client. Le serveur ne reçoit que les données chiffrées.

Q: Quelle est la taille maximum des fichiers ?

R: 10MB total pour tous les fichiers combinés, 10 fichiers maximum par secret.

Q: La librairie supporte-t-elle TypeScript ?

R: Oui, les définitions TypeScript sont incluses dans le package.


Documentation générée le 08/01/2025 - Équipe Sharokey

Released under the MIT License.