Jak to działa
Od startu na orbitę
Krok po kroku: administrator zakłada tenanta MindooDB, dwóch użytkowników wymienia zaszyfrowane dane i pracuje razem — a serwer ani razu nie widzi tekstu jawnego.
Start
Administrator uruchamia tenanta
Utwórz tenanta
Administrator zakłada nowego tenanta jednym wywołaniem. Powstają przy tym wszystkie klucze, tenant zostaje otwarty, a pierwszy użytkownik — Alice — zarejestrowany w katalogu.
const { tenant, adminUser, appUser, keyBag }
= await factory.createTenant({
tenantId: "acme",
adminName: "cn=admin/o=acme",
adminPassword: "••••••••",
userName: "cn=alice/o=acme",
userPassword: "••••••••",
}); Opublikuj na serwerze
Administrator rejestruje tenanta na serwerze MindooDB. Serwer przechowuje tylko zaszyfrowane dane i klucze publiczne.
await tenant.publishToServer(
"https://sync.acme.com",
{ registerUsers: [appUser] }
); Utwórz i zsynchronizuj dokument
Alice zakłada dokument z zadaniem i wypycha zaszyfrowane zmiany na serwer.
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); Sygnał
Nowy użytkownik prosi o dołączenie
Utwórz prośbę o dołączenie
Bob tworzy swoją tożsamość lokalnie — jego klucze prywatne nigdy nie opuszczają urządzenia. Generuje prośbę o dołączenie, która zawiera wyłącznie klucze publiczne.
const bob = await factory.createUserId(
"cn=bob/o=acme", "••••••••"
);
const joinRequestURI = factory.createJoinRequest(
bob, { format: "uri" }
);
// → mdb://join-request/eyJ2IjoxLCJ1c2Vy... Dokowanie
Administrator zatwierdza prośbę o dołączenie
Zatwierdź prośbę o dołączenie
Administrator zatwierdza prośbę Boba. Bob zostaje przez to zarejestrowany w katalogu, a klucze symetryczne zaszyfrowane wspólnym hasłem.
const joinResponseURI =
await tenant.approveJoinRequest(
joinRequestURI,
{
adminSigningKey: adminUser
.userSigningKeyPair.privateKey,
adminPassword: "••••••••",
sharePassword: "one-time-secret",
format: "uri",
}
);
// → mdb://join-response/eyJ2IjoxLCJ0ZW5h... Orbita
Zaczyna się współpraca w czasie rzeczywistym
Dołącz, pobierz, zmień, wypchnij
Bob dołącza do tenanta, pobiera najnowsze dane, oznacza zadanie jako zrobione i wypycha zmianę z powrotem.
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); Pobierz zmiany
Alice pobiera najnowsze zmiany i widzi, że zadanie jest zrobione.
await db.pullChangesFrom(remote);
await db.syncStoreChanges();
const updated = await db.getDocument(todoDocId);
console.log(updated.getData().done);
// → true ✓ Zadanie zrobione ✓ Co serwer widzi, a czego nie
Serwer widzi
- Publiczne klucze podpisujące (Ed25519)
- Publiczne klucze szyfrujące (RSA-OAEP)
- Zaszyfrowane bloby (szyfrogram AES-256-GCM)
- Metadane wpisów (znaczniki czasu, skróty treści)
- Hashe nazw użytkowników (SHA-256 — nie same nazwy)
Serwer nie widzi nigdy
- Nazw użytkowników (szyfrowanych kluczem RSA administratora)
- Treści dokumentów (szyfrowanych end-to-end)
- Kluczy prywatnych (zostają na urządzeniu)
- Wspólnych haseł (tylko poza pasmem)
- Symetrycznych kluczy szyfrujących