Documentation JavaScript CDN
JavaScript CDN Sharokey léger pour intégration rapide dans le navigateur. Fichier unique, aucun processus de build requis - parfait pour les projets simples et le prototypage rapide.
🚀 Démarrage Rapide
Installation
Il suffit d'inclure le script dans votre page HTML :
<!-- Inclure le script CDN Sharokey -->
<script src="sharokey.js"></script><!-- Ou télécharger et utiliser localement -->
<script src="/js/sharokey.js"></script>Configuration de Base
<!DOCTYPE html>
<html>
<head>
<title>Intégration Sharokey</title>
<script src="sharokey.js"></script>
</head>
<body>
<script>
// Configurer une fois
Sharokey.config({
token: 'votre-token-api'
});
</script>
</body>
</html>Premier Secret
// Créer votre premier secret (syntaxe style CLI)
const secret = await Sharokey.create('Mon premier secret', 24, 1);
console.log('URL du Secret :', secret.share_url);
console.log('Slug du Secret :', secret.slug);⚙️ Configuration
Configuration Globale
// Configurer l'objet Sharokey global
Sharokey.config({
token: 'votre-token-api', // Requis : Token d'authentification API
apiUrl: 'https://api.sharokey.com/api/v1' // Optionnel : URL API personnalisée (utilise la valeur par défaut si omis)
});Sécurité du Token
Le token API sera visible dans le code côté client. N'utilisez cette approche que sur des domaines de confiance ou pour des opérations non sensibles.
Configuration Spécifique à l'Environnement
// Développement
if (window.location.hostname === 'localhost') {
Sharokey.config({
token: 'dev-token-ici',
apiUrl: 'https://dev-api.sharokey.com/api/v1'
});
} else {
// Production
Sharokey.config({
token: 'prod-token-ici'
});
}🔐 Créer des Secrets
Création de Secret Basique
Le JavaScript CDN utilise une syntaxe cohérente avec le CLI pour la simplicité :
// Basique : contenu, heures, vues
const secret = await Sharokey.create(
'Mot de passe base de données : secret123',
24, // 24 heures
1 // 1 vue
);
console.log('URL de Partage :', secret.share_url);Avec Options Supplémentaires
// Avec description, mot de passe et OTP
const secret = await Sharokey.create(
'Rapport financier T4',
48, // 48 heures
3, // 3 vues
{
description: 'Données financières trimestrielles',
password: 'ProtectionSupplementaire2024!',
otp_email: '[email protected]'
}
);Limitation OTP
Les OTP par email et SMS sont mutuellement exclusifs - vous ne pouvez en utiliser qu'un par secret.
Avec Pièces Jointes
Depuis un Input Fichier
<input type="file" id="fileInput" multiple>
<button onclick="shareWithFiles()">Partager le Secret</button>
<script>
async function shareWithFiles() {
const fileInput = document.getElementById('fileInput');
const files = Array.from(fileInput.files);
const secret = await Sharokey.create(
'Documents du projet',
72, // 72 heures
5, // 5 vues
{
description: 'Contrat et spécifications',
attachments: files,
password: 'ProjetSecure2024'
}
);
console.log('URL de Partage avec pièces jointes :', secret.share_url);
}
</script>Intégration Glisser-Déposer
<div id="dropZone" ondrop="handleDrop(event)" ondragover="allowDrop(event)">
Déposez les fichiers ici ou cliquez pour sélectionner
</div>
<script>
function allowDrop(event) {
event.preventDefault();
}
async function handleDrop(event) {
event.preventDefault();
const files = Array.from(event.dataTransfer.files);
const secret = await Sharokey.create(
'Fichiers déposés',
24, 1,
{
description: `${files.length} fichier(s) partagé(s)`,
attachments: files
}
);
alert(`Fichiers partagés ! URL : ${secret.share_url}`);
}
</script>Limites des pièces jointes : Identiques aux autres librairies - varie selon l'implémentation
Exemple Complet
// Exemple avec toutes les options
const secret = await Sharokey.create(
'Documents de fusion hautement confidentiels',
72, // 3 jours
2, // 2 vues max
{
description: 'Documents M&A pour révision du conseil',
password: 'ConseilAdministration2024!',
otp_email: '[email protected]',
attachments: attachmentFiles // Depuis input fichier ou glisser-déposer
}
);
// Afficher le résultat
document.getElementById('result').innerHTML = `
<h3>Secret Créé avec Succès !</h3>
<p><strong>URL de Partage :</strong> <a href="${secret.share_url}" target="_blank">${secret.share_url}</a></p>
<p><strong>Expire :</strong> ${secret.expires_at}</p>
<p><strong>Vues Max :</strong> ${secret.maximum_views}</p>
<p><strong>Pièces jointes :</strong> ${secret.attachment_count || 0}</p>
`;📝 Gestion des Secrets
Lister les Secrets
// Listage basique
const secrets = await Sharokey.list();
// Avec filtres
const filtered = await Sharokey.list({
limit: 10,
status: 'active'
});
// Afficher dans un tableau
function displaySecrets(secrets) {
const tableRows = secrets.map(secret => `
<tr>
<td>${secret.slug}</td>
<td>${secret.description || 'Aucune description'}</td>
<td>${secret.status}</td>
<td>${secret.remaining_views}/${secret.maximum_views}</td>
<td>${new Date(secret.expires_at).toLocaleDateString()}</td>
</tr>
`).join('');
document.getElementById('secretsTable').innerHTML = `
<table border="1">
<thead>
<tr>
<th>Slug</th>
<th>Description</th>
<th>Statut</th>
<th>Vues</th>
<th>Expire</th>
</tr>
</thead>
<tbody>
${tableRows}
</tbody>
</table>
`;
}Détails d'un Secret
// Obtenir un secret spécifique
const secret = await Sharokey.get('ABC123XYZ');
// Afficher les détails
document.getElementById('secretDetails').innerHTML = `
<h3>Détails du Secret</h3>
<p><strong>Description :</strong> ${secret.description}</p>
<p><strong>Statut :</strong> ${secret.status}</p>
<p><strong>Créé :</strong> ${new Date(secret.created_at).toLocaleString()}</p>
<p><strong>Expire :</strong> ${new Date(secret.expires_at).toLocaleString()}</p>
<p><strong>Vues Restantes :</strong> ${secret.remaining_views}/${secret.maximum_views}</p>
<p><strong>A un Mot de Passe :</strong> ${secret.has_password ? 'Oui' : 'Non'}</p>
<p><strong>A un OTP :</strong> ${secret.has_otp ? 'Oui' : 'Non'}</p>
<p><strong>Pièces jointes :</strong> ${secret.attachment_count || 0}</p>
`;Supprimer des Secrets
// Supprimer un secret unique
await Sharokey.delete('ABC123XYZ');
alert('Secret supprimé avec succès');
// Supprimer avec confirmation
function confirmDelete(slug) {
if (confirm(`Êtes-vous sûr de vouloir supprimer le secret ${slug} ?`)) {
Sharokey.delete(slug)
.then(() => alert('Secret supprimé'))
.catch(error => alert('Échec de suppression : ' + error.message));
}
}🔧 Fonctions Utilitaires
Génération de Mots de Passe
// Générer un mot de passe sécurisé
const password = await Sharokey.generatePassword();
console.log('Mot de passe généré :', password); // 16 caractères par défaut
// Longueur personnalisée (8-32 caractères)
const longPassword = await Sharokey.generatePassword(24);
// Utiliser dans un formulaire
document.getElementById('passwordField').value = await Sharokey.generatePassword(16);Test de Connectivité
// Tester la connectivité API
try {
const isConnected = await Sharokey.testConnection();
if (isConnected) {
document.getElementById('status').innerHTML = '✅ API Connectée';
document.getElementById('status').className = 'success';
}
} catch (error) {
document.getElementById('status').innerHTML = '❌ Échec de Connexion : ' + error.message;
document.getElementById('status').className = 'error';
}Statistiques
// Obtenir les statistiques du compte
const stats = await Sharokey.stats();
// Afficher dans un tableau de bord
document.getElementById('dashboard').innerHTML = `
<div class="stats-grid">
<div class="stat">
<h3>${stats.total_secrets}</h3>
<p>Total des Secrets</p>
</div>
<div class="stat">
<h3>${stats.active_secrets}</h3>
<p>Secrets Actifs</p>
</div>
<div class="stat">
<h3>${stats.total_views}</h3>
<p>Total des Vues</p>
</div>
<div class="stat">
<h3>${(stats.storage_used / 1024 / 1024).toFixed(1)} Mo</h3>
<p>Stockage Utilisé</p>
</div>
</div>
`;📧 Demandes de Secret
Demander à d'autres personnes de partager des secrets avec vous de manière sécurisée via des URL de demande générées.
Créer une Demande de Secret
// Demande de secret de base
const request = await Sharokey.createRequest({
message: "Merci de partager les identifiants de base de données",
description: "Accès DB production nécessaire",
secretExpirationHours: 24, // Le secret expirera dans 24h
requestExpirationHours: 48, // La demande expire dans 48h
maximumViews: 1, // Le secret peut être vu une seule fois
emailTo: "[email protected]",
emailReply: "[email protected]"
});
console.log('Demande créée:', request.url);
console.log('Envoyer cette URL au destinataire:', request.url);Intégration avec un Formulaire
<form id="requestForm">
<div>
<label for="requestMessage">Message pour le destinataire :</label>
<textarea id="requestMessage" placeholder="Merci de partager les informations demandées"></textarea>
</div>
<div>
<label for="requestDescription">Description interne :</label>
<input type="text" id="requestDescription" placeholder="Description pour votre référence">
</div>
<div>
<label for="emailTo">Email du destinataire :</label>
<input type="email" id="emailTo" placeholder="[email protected]">
</div>
<button type="submit">Créer la Demande</button>
</form>
<div id="requestResult"></div>
<script>
document.getElementById('requestForm').addEventListener('submit', async (e) => {
e.preventDefault();
try {
const request = await Sharokey.createRequest({
message: document.getElementById('requestMessage').value,
description: document.getElementById('requestDescription').value,
emailTo: document.getElementById('emailTo').value,
secretExpirationHours: 24,
requestExpirationHours: 48,
maximumViews: 1
});
document.getElementById('requestResult').innerHTML = `
<div class="success">
<h3>Demande Créée !</h3>
<p><strong>URL de la Demande :</strong> <br>
<input type="text" value="${request.url}" readonly onclick="this.select()"></p>
<button onclick="copyToClipboard('${request.url}')">Copier l'URL</button>
<p><small>Envoyez cette URL au destinataire pour qu'il puisse partager le secret de manière sécurisée.</small></p>
</div>
`;
document.getElementById('requestForm').reset();
} catch (error) {
document.getElementById('requestResult').innerHTML = `
<div class="error">
<h3>Erreur de Création de la Demande</h3>
<p>${error.message}</p>
</div>
`;
}
});
</script>Lister et Gérer les Demandes
// Lister toutes les demandes
const requests = await Sharokey.listRequests({status: 'active', limit: 10});
console.log('Demandes actives:', requests.data.length);
// Afficher dans un tableau
function displayRequests(requests) {
const tableRows = requests.data.map(req => `
<tr>
<td>${req.token}</td>
<td>${req.description || 'Aucune description'}</td>
<td>${req.status}</td>
<td>${new Date(req.request_expiration).toLocaleDateString()}</td>
<td>
<button onclick="deleteRequest(${req.id})">Supprimer</button>
<button onclick="copyToClipboard('${req.url}')">Copier URL</button>
</td>
</tr>
`).join('');
document.getElementById('requestsTable').innerHTML = `
<table border="1">
<thead>
<tr>
<th>Token</th>
<th>Description</th>
<th>Statut</th>
<th>Expire</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
${tableRows}
</tbody>
</table>
`;
}
// Supprimer une demande
async function deleteRequest(requestId) {
if (confirm('Êtes-vous sûr de vouloir supprimer cette demande ?')) {
try {
await Sharokey.deleteRequest(requestId);
alert('Demande supprimée avec succès');
// Recharger la liste
loadRequests();
} catch (error) {
alert('Erreur lors de la suppression : ' + error.message);
}
}
}
// Charger les demandes
async function loadRequests() {
try {
const requests = await Sharokey.listRequests({limit: 20});
displayRequests(requests);
} catch (error) {
document.getElementById('requestsTable').innerHTML = `
<div class="error">Erreur de chargement des demandes : ${error.message}</div>
`;
}
}Statistiques des Demandes
// Obtenir les statistiques des demandes
const stats = await Sharokey.requestStats();
// Afficher dans un tableau de bord
document.getElementById('requestStats').innerHTML = `
<div class="stats-grid">
<div class="stat">
<h3>${stats.total_requests || 0}</h3>
<p>Total Demandes</p>
</div>
<div class="stat">
<h3>${stats.active_requests || 0}</h3>
<p>Demandes Actives</p>
</div>
<div class="stat">
<h3>${stats.expired_requests || 0}</h3>
<p>Demandes Expirées</p>
</div>
<div class="stat">
<h3>${stats.requests_created_today || 0}</h3>
<p>Créées Aujourd'hui</p>
</div>
</div>
`;Tableau de Bord Complet avec Demandes
<div id="fullDashboard">
<div class="tabs">
<button onclick="showTab('secrets')" class="tab-button active">Secrets</button>
<button onclick="showTab('requests')" class="tab-button">Demandes</button>
<button onclick="showTab('stats')" class="tab-button">Statistiques</button>
</div>
<div id="secretsTab" class="tab-content active">
<h3>Mes Secrets</h3>
<div id="secretsList"></div>
</div>
<div id="requestsTab" class="tab-content">
<h3>Mes Demandes de Secret</h3>
<button onclick="loadRequests()">Actualiser</button>
<div id="requestsList"></div>
</div>
<div id="statsTab" class="tab-content">
<h3>Statistiques</h3>
<div id="combinedStats"></div>
</div>
</div>
<script>
function showTab(tabName) {
// Masquer tous les onglets
document.querySelectorAll('.tab-content').forEach(tab => {
tab.classList.remove('active');
});
document.querySelectorAll('.tab-button').forEach(btn => {
btn.classList.remove('active');
});
// Afficher l'onglet sélectionné
document.getElementById(tabName + 'Tab').classList.add('active');
event.target.classList.add('active');
// Charger le contenu si nécessaire
if (tabName === 'requests') {
loadRequests();
} else if (tabName === 'stats') {
loadCombinedStats();
}
}
async function loadCombinedStats() {
try {
const [secretStats, requestStats] = await Promise.all([
Sharokey.stats(),
Sharokey.requestStats()
]);
document.getElementById('combinedStats').innerHTML = `
<div class="stats-section">
<h4>Secrets</h4>
<p>Total : ${secretStats.total_secrets} | Actifs : ${secretStats.active_secrets}</p>
</div>
<div class="stats-section">
<h4>Demandes de Secret</h4>
<p>Total : ${requestStats.total_requests || 0} | Actives : ${requestStats.active_requests || 0}</p>
</div>
`;
} catch (error) {
document.getElementById('combinedStats').innerHTML = `
<div class="error">Erreur de chargement des statistiques : ${error.message}</div>
`;
}
}
</script>
<style>
.tabs {
border-bottom: 1px solid #ccc;
margin-bottom: 20px;
}
.tab-button {
background: none;
border: none;
padding: 10px 20px;
cursor: pointer;
border-bottom: 2px solid transparent;
}
.tab-button.active {
border-bottom-color: #007cba;
font-weight: bold;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
}
.stat {
text-align: center;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
}
</style>🎯 Compatibilité Navigateurs
Le JavaScript CDN prend en charge les navigateurs modernes avec l'API Web Crypto :
- Chrome : 60+
- Firefox : 55+
- Safari : 11+
- Edge : 79+
- Internet Explorer : Non supporté (manque l'API Web Crypto)
Détection de Fonctionnalité
// Vérifier la compatibilité avant utilisation
if (!window.crypto || !window.crypto.subtle) {
document.getElementById('app').innerHTML = `
<div class="error">
<h2>Navigateur Non Supporté</h2>
<p>Cette application nécessite un navigateur moderne avec support de l'API Web Crypto.</p>
<p>Veuillez mettre à niveau vers une version récente de Chrome, Firefox, Safari, ou Edge.</p>
</div>
`;
} else {
// Initialiser Sharokey
Sharokey.config({ token: 'votre-token' });
}🚨 Gestion d'Erreurs
Gestion d'Erreurs Basique
// Gérer les erreurs avec try-catch
try {
const secret = await Sharokey.create('Mon secret', 24, 1);
showSuccess('Secret créé : ' + secret.share_url);
} catch (error) {
showError('Échec de création du secret : ' + error.message);
}
function showSuccess(message) {
document.getElementById('message').innerHTML = `<div class="success">${message}</div>`;
}
function showError(message) {
document.getElementById('message').innerHTML = `<div class="error">${message}</div>`;
}Information d'Erreur Détaillée
// Gestion d'erreurs plus détaillée
async function createSecretSafely(content, hours, views, options = {}) {
try {
return await Sharokey.create(content, hours, views, options);
} catch (error) {
console.error('Erreur Sharokey :', error);
// Vérifier le type d'erreur
if (error.message.includes('Authentication')) {
showError('Échec de l\'authentification. Veuillez vérifier votre token API.');
} else if (error.message.includes('validation')) {
showError('Erreur de validation : ' + error.message);
} else if (error.message.includes('file')) {
showError('Erreur de fichier : ' + error.message);
} else if (error.message.includes('network')) {
showError('Erreur réseau. Veuillez vérifier votre connexion.');
} else {
showError('Une erreur inattendue s\'est produite : ' + error.message);
}
return null;
}
}🔐 Considérations de Sécurité
Gestion des Tokens
// Utiliser des tokens spécifiques à l'environnement
const getApiToken = () => {
if (window.location.hostname === 'localhost') {
return 'dev_token_ici';
} else if (window.location.hostname.includes('staging')) {
return 'staging_token_ici';
} else {
return 'production_token_ici';
}
};
Sharokey.config({ token: getApiToken() });HTTPS Uniquement
// Assurer HTTPS en production
if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
location.replace(`https:${location.href.substring(location.protocol.length)}`);
}Sécurité du Contenu
// Valider le contenu avant partage
function validateSecretContent(content) {
if (!content || content.trim().length === 0) {
throw new Error('Le contenu du secret ne peut pas être vide');
}
if (content.length > 100000) { // Limite 100Ko
throw new Error('Contenu trop volumineux');
}
// Vérifier les motifs potentiellement sensibles
const sensitivePatterns = [
/password\s*[:=]\s*\w+/i,
/api[_-]?key\s*[:=]\s*\w+/i
];
for (const pattern of sensitivePatterns) {
if (pattern.test(content)) {
console.warn('Le contenu semble contenir des informations sensibles');
break;
}
}
return true;
}🎨 Exemples d'Intégration
Intégration de Formulaire Simple
<form id="secretForm">
<div>
<label for="content">Contenu du Secret :</label>
<textarea id="content" required></textarea>
</div>
<div>
<label for="hours">Expire dans (heures) :</label>
<input type="number" id="hours" min="1" max="1000" value="24">
</div>
<div>
<label for="views">Vues maximum :</label>
<input type="number" id="views" min="1" max="10" value="1">
</div>
<div>
<label for="password">Protection par mot de passe (optionnel) :</label>
<input type="password" id="password">
</div>
<div>
<label for="files">Pièces jointes (optionnel) :</label>
<input type="file" id="files" multiple>
</div>
<button type="submit">Créer le Secret</button>
</form>
<div id="result"></div>
<script>
document.getElementById('secretForm').addEventListener('submit', async (e) => {
e.preventDefault();
const content = document.getElementById('content').value;
const hours = parseInt(document.getElementById('hours').value);
const views = parseInt(document.getElementById('views').value);
const password = document.getElementById('password').value;
const files = Array.from(document.getElementById('files').files);
try {
const options = {};
if (password) options.password = password;
if (files.length > 0) options.attachments = files;
const secret = await Sharokey.create(content, hours, views, options);
document.getElementById('result').innerHTML = `
<div class="success">
<h3>Secret Créé !</h3>
<p><strong>URL de Partage :</strong> <br>
<input type="text" value="${secret.share_url}" readonly onclick="this.select()"></p>
<button onclick="copyToClipboard('${secret.share_url}')">Copier l'URL</button>
</div>
`;
// Vider le formulaire
document.getElementById('secretForm').reset();
} catch (error) {
document.getElementById('result').innerHTML = `
<div class="error">
<h3>Erreur de Création du Secret</h3>
<p>${error.message}</p>
</div>
`;
}
});
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
alert('URL copiée dans le presse-papiers !');
});
}
</script>Tableau de Bord de Gestion
<div id="dashboard">
<div class="controls">
<button onclick="loadSecrets()">Actualiser les Secrets</button>
<button onclick="loadStats()">Charger les Statistiques</button>
<button onclick="testConnection()">Tester la Connexion</button>
</div>
<div id="stats"></div>
<div id="secrets"></div>
</div>
<script>
async function loadSecrets() {
try {
const secrets = await Sharokey.list({ limit: 50 });
displaySecrets(secrets);
} catch (error) {
document.getElementById('secrets').innerHTML = `<div class="error">Erreur de chargement des secrets : ${error.message}</div>`;
}
}
async function loadStats() {
try {
const stats = await Sharokey.stats();
document.getElementById('stats').innerHTML = `
<div class="stats">
<h3>Statistiques du Compte</h3>
<p>Total : ${stats.total_secrets} | Actifs : ${stats.active_secrets} | Vues : ${stats.total_views}</p>
</div>
`;
} catch (error) {
document.getElementById('stats').innerHTML = `<div class="error">Erreur de chargement des stats : ${error.message}</div>`;
}
}
async function testConnection() {
try {
const connected = await Sharokey.testConnection();
alert(connected ? 'Connexion réussie !' : 'Échec de connexion !');
} catch (error) {
alert('Test de connexion échoué : ' + error.message);
}
}
// Charger le tableau de bord au chargement de la page
window.addEventListener('load', () => {
loadSecrets();
loadStats();
});
</script>📏 Taille de Fichier et Limites
Le fichier JavaScript CDN est conçu pour la simplicité :
- Taille du fichier : ~150Ko (minifié)
- Dépendances : Aucune (autonome)
- Limitations navigateur : Mêmes limites de pièces jointes que les autres librairies
- Exposition du token : Visible côté client (utiliser des mesures de sécurité appropriées)
🔗 Ressources Associées
- Comparaison des Fonctionnalités - Comparer avec d'autres librairies
- JavaScript SDK - Version complète pour projets complexes
- Référence API - Documentation directe de l'API REST
- Exemples - Plus d'exemples d'utilisation et tutoriels
- CLI C# - Interface en ligne de commande
- Python SDK - Pour les applications Python
📜 License
Le JavaScript CDN Sharokey est distribué sous la Licence MIT.
Voir LICENSE pour plus de détails.
