Come funziona
Dal lancio all'orbita
Passo per passo: un admin prepara un tenant MindooDB, poi due utenti si scambiano dati cifrati e collaborano — senza che il server veda mai testo in chiaro.
Lancio
L'admin prepara il tenant
Creare il tenant
Con una sola chiamata l'admin crea un nuovo tenant. L'operazione genera tutte le chiavi, apre il tenant e registra nella directory la prima utente, Alice.
const { tenant, adminUser, appUser, keyBag }
= await factory.createTenant({
tenantId: "acme",
adminName: "cn=admin/o=acme",
adminPassword: "••••••••",
userName: "cn=alice/o=acme",
userPassword: "••••••••",
}); Pubblicare sul server
L'admin registra il tenant su un server MindooDB. Il server archivia soltanto dati cifrati e chiavi pubbliche.
await tenant.publishToServer(
"https://sync.acme.com",
{ registerUsers: [appUser] }
); Creare e sincronizzare un documento
Alice crea un documento todo e invia al server le modifiche cifrate.
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); Segnale
Un nuovo utente chiede di aderire
Creare la richiesta di adesione
Bob crea la propria identità in locale: le sue chiavi private non lasciano mai il dispositivo. Genera una richiesta di adesione che contiene solo chiavi pubbliche.
const bob = await factory.createUserId(
"cn=bob/o=acme", "••••••••"
);
const joinRequestURI = factory.createJoinRequest(
bob, { format: "uri" }
);
// → mdb://join-request/eyJ2IjoxLCJ1c2Vy... Attracco
L'admin approva la richiesta di adesione
Approvare la richiesta di adesione
L'admin approva la richiesta di Bob. Così Bob viene registrato nella directory e le chiavi simmetriche vengono cifrate con una password di condivisione.
const joinResponseURI =
await tenant.approveJoinRequest(
joinRequestURI,
{
adminSigningKey: adminUser
.userSigningKeyPair.privateKey,
adminPassword: "••••••••",
sharePassword: "one-time-secret",
format: "uri",
}
);
// → mdb://join-response/eyJ2IjoxLCJ0ZW5h... Orbita
Inizia la collaborazione in tempo reale
Adesione, pull, modifica, push
Bob aderisce al tenant, scarica i dati più recenti, segna il todo come completato e rimanda indietro la modifica.
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); Recuperare le modifiche
Alice scarica le ultime modifiche e vede che il todo è completato.
await db.pullChangesFrom(remote);
await db.syncStoreChanges();
const updated = await db.getDocument(todoDocId);
console.log(updated.getData().done);
// → true ✓ Todo completato ✓ Cosa vede il server e cosa non vede
Il server vede
- Chiavi di firma pubbliche (Ed25519)
- Chiavi di crittografia pubbliche (RSA-OAEP)
- Blob cifrati (testo cifrato AES-256-GCM)
- Metadati delle voci (marche temporali, hash del contenuto)
- Hash dei nomi utente (SHA-256 — non i nomi veri)
Il server non vede mai
- I nomi utente (cifrati con la chiave RSA dell'admin)
- Il contenuto dei documenti (cifrato end-to-end)
- Le chiavi private (restano sul dispositivo)
- Le password condivise (solo out-of-band)
- Le chiavi di crittografia simmetriche