Fonctionnement
Du décollage à l'orbite
Pas à pas : un admin met en place un tenant MindooDB, puis deux utilisateurs échangent des données chiffrées et travaillent ensemble — sans que le serveur voie jamais de texte en clair.
Décollage
L'admin met le tenant en place
Créer le tenant
L'admin crée un nouveau tenant en un seul appel. Toutes les clés sont générées, le tenant est ouvert et Alice est enregistrée dans l'annuaire comme première utilisatrice.
const { tenant, adminUser, appUser, keyBag }
= await factory.createTenant({
tenantId: "acme",
adminName: "cn=admin/o=acme",
adminPassword: "••••••••",
userName: "cn=alice/o=acme",
userPassword: "••••••••",
}); Publier sur le serveur
L'admin enregistre le tenant sur un serveur MindooDB. Le serveur ne stocke que des données chiffrées et des clés publiques.
await tenant.publishToServer(
"https://sync.acme.com",
{ registerUsers: [appUser] }
); Créer & synchroniser un document
Alice crée un document todo et envoie les modifications chiffrées au serveur.
const db = await tenant.openDB("todos");
const doc = await db.createDocument();
await db.changeDoc(doc, (d) => {
const data = d.getData();
data.title = "Buy groceries";
data.done = false;
});
const remote = await tenant.connectToServer(
"https://sync.acme.com", "todos"
);
await db.pushChangesTo(remote); Signal
Un nouvel utilisateur demande à rejoindre le tenant
Créer une demande d'adhésion
Bob crée son identité en local — ses clés privées ne quittent jamais son appareil. Il génère une demande d'adhésion qui ne contient que des clés publiques.
const bob = await factory.createUserId(
"cn=bob/o=acme", "••••••••"
);
const joinRequestURI = factory.createJoinRequest(
bob, { format: "uri" }
);
// → mdb://join-request/eyJ2IjoxLCJ1c2Vy... Amarrage
L'admin approuve la demande d'adhésion
Approuver la demande d'adhésion
L'admin approuve la demande de Bob. Bob est ainsi enregistré dans l'annuaire, et les clés symétriques sont chiffrées avec un mot de passe de partage.
const joinResponseURI =
await tenant.approveJoinRequest(
joinRequestURI,
{
adminSigningKey: adminUser
.userSigningKeyPair.privateKey,
adminPassword: "••••••••",
sharePassword: "one-time-secret",
format: "uri",
}
);
// → mdb://join-response/eyJ2IjoxLCJ0ZW5h... Orbite
La collaboration en temps réel commence
Rejoindre, pull, modifier, push
Bob rejoint le tenant, récupère les données les plus récentes, marque le todo comme terminé et renvoie sa modification.
const { tenant: bobTenant } =
await factory.joinTenant(
joinResponseURI,
{
user: bob,
password: "••••••••",
sharePassword: "one-time-secret",
}
);
const remote = await bobTenant.connectToServer(
"https://sync.acme.com", "todos"
);
const db = await bobTenant.openDB("todos");
await db.pullChangesFrom(remote);
await db.syncStoreChanges();
const todo = await db.getDocument(todoDocId);
await db.changeDoc(todo, (d) => {
d.getData().done = true;
});
await db.pushChangesTo(remote); Récupérer les modifications
Alice récupère les dernières modifications et voit que le todo est terminé.
await db.pullChangesFrom(remote);
await db.syncStoreChanges();
const updated = await db.getDocument(todoDocId);
console.log(updated.getData().done);
// → true ✓ Le todo est terminé ✓ Ce que le serveur voit et ce qu'il ne voit pas
Le serveur voit
- Les clés de signature publiques (Ed25519)
- Les clés de chiffrement publiques (RSA-OAEP)
- Les blobs chiffrés (texte chiffré AES-256-GCM)
- Les métadonnées des entrées (horodatages, empreintes de contenu)
- Les hachages des noms d'utilisateur (SHA-256 — pas les noms eux-mêmes)
Le serveur ne voit jamais
- Les noms d'utilisateur (chiffrés avec la clé RSA de l'admin)
- Le contenu des documents (chiffré de bout en bout)
- Les clés privées (elles restent sur l'appareil)
- Les mots de passe partagés (hors bande uniquement)
- Les clés de chiffrement symétriques