Złoto
A swarm (group chat) is a set of participants capable of resilient, decentralized communication. For example, if two participants lose connectivity with the rest of the group (e.g., during an Internet outage) but can still reach each other over a LAN or subnetwork, they can exchange messages locally and then synchronize with the rest of the group once connectivity is restored.
A swarm is defined by the following properties:
Ability to split and merge based on network connectivity.
History synchronization. Every participant must be able to send a message to the entire group.
Nie ma centralnej władzy, nie może polegać na serwerach.
Non-repudiation. Devices must be able to verify past messages» validity and to replay the entire history.
Perfect Forward Secrecy (PFS) is provided on the transport channels. Storage is handled by each device.
Głównym pomysłem jest synchronizowanie drzewa Merkle z uczestnikami.
We identified four modes for swarms that we want to implement:
ONE_TO_ONE: A private conversation between two endpoints—either between two users or with yourself.
ADMIN_INVITES_ONLY: A swarm in which only the administrator can invite members (for example, a teacher-managed classroom).
INVITES_ONLY: A closed swarm that admits members strictly by invitation; no one may join without explicit approval.
PUBLIC: A public swarm that anyone can join without prior invitation (For example a forum).
Scenariusze
Stwórz grupę
Bob chce stworzyć nowy ród
Bob creates a local Git repository.
Następnie tworzy pierwotny podpisany zobowiązanie z następującymi:
Jego klucz publiczny w
/admins
Jego certyfikat urządzenia w ̀ /devices `
Jego CRL w ̀ /crls`
Hash pierwszego zdania staje się identyfikatorem rozmowy.
Bob announces to his other devices that he created a new conversation. This is done via an invite to join the group sent through the DHT to other devices linked to that account.
Dodawanie kogoś
Bob adds Alice
Bob adds Alice to the repo:
Dodaje zaproszony URI w
/invited
Dodaje CRL do
/crls
Bob sends a request on the DHT.
Przyjmując zaproszenie
Alice gets the invite to join the previously created swarm
Alice accepts the invite (if she declines, nothing happens; she will remain in the „invited” list, and will never receive any messages)
A peer-to-peer connection is established between Alice and Bob.
Alice pulls the Git repository from Bob. WARNING this means that messages require a connection, not from the DHT as it is today.
Alice validates the commits from Bob.
To validate that Alice is a member, she removes the invite from
/invited
directory, then adds her certificate to the/members
directoryOnce all commits are validated and syncronized to her device, Alice discovers other members of the group. with these peers, she will then construct the DRT with Bob as a bootstrap.
Wysyłanie wiadomości
Alice sends a message to Bob
Alice creates a commit message. She constructs a JSON payload containing the MIME type and message body. For example:
{
"type": "text/plain",
"body": "hello"
}
Alice ensure her device credentials are present. If Alice’s device certificate or its associated CRL isn’t already stored in the repository, she adds them so that other participants can verify the commit.
Alice commits to the repository (Because Jami relies primarily on commit-message metadata rather than file contents, merge conflicts are rare; the only potential conflicts would involve CRLs or certificates, which are versioned in a dedicated location).
Alice announces the commit via the DRT with a service message and pings the DHT for mobile devices (they must receive a push notification).
Informacja
To notify other devices, the sender transmits a SIP message with type: application/im-gitmessage-id
.
The JSON payload includes the deviceId (the sender’s), the conversationId and the reference (hash) of the new commit.
Otrzymując wiadomość
Bob receives a message from Alice
Bob performs a Git pull on Alice’s repository.
All incoming commits MUST be verified by a hook.
If all commits are valid, commits are stored and displayed.Bob then announces the message via the DRT for other devices.
If any commit is invalid, pull is aborted. Alice must restore her repository to a correct state before retrying.
Wydanie warunków
Aby uniknąć, że użytkownicy będą wysyłać niepożądane zobowiązania (z konfliktami, fałszywymi wiadomościami itp.), każdy zobowiązanie (od najstarszego do najnowszego) musi być zatwierdzone przed połączeniem odległego oddziału:
Informacja
If the validation fails, the fetch is ignored and we do not merge the branch (and remove the data), and the user should be notified.
If a fetch is too big, it’s not merged.
For each incoming commit, ensure that the sending device is currently authorized and that the issuer’s certificate exists under /members or /admins, and the device’s certificate under /devices.
Then handle one of three cases, based on the commit’s parent count:
Merge Commit (2 parents). No further validation is required, merges are always accepted.
Initial Commit (0 parents). Validate that this is the very first repository snapshot:
Admin certificate is added.
Device certificate is added.
CRLs (Certificate Revocation Lists) are added.
No other files are present.
Ordinary Commit (1 parent). The commit message must be JSON with a top‑level
type
field. Handle eachtype
as follows:If
text
(or any non–file‑modifying MIME type)Signature is valid against the author’s certificate in the repo.
No unexpected files are added or removed.
If
vote
voteType
is one of the supported values (e.g. „ban”, „unban”).The vote matches the signing user.
The signer is an admin, their device is present, and not themselves banned.
No unexpected files are added or removed.
If
member
If
adds
Properly signed by the inviter.
New member’s URI appears under
/invited
.No unexpected files are added or removed.
If ONE_TO_ONE, ensure exactly one admin and one member.
If ADMIN_INVITES_ONLY, the inviter must be an admin.
If
joins
Properly signed by the joining device.
Device certificate added under
/devices
.Corresponding invite removed from
/invited
and certificate added to/members
.No unexpected files are added or removed.
If
banned
Vote is valid per the
vote
rules above.Ban is issued by an admin.
Target’s certificate moved to /banned.
Only files related to the ban vote are removed.
No unexpected files are added or removed.
Fallback. If the commit’s type or structure is unrecognized, reject it and notify the peer (or user) that they may be running an outdated version or attempting unauthorized changes.
Zakaz urządzenia
Ważne
Jami source code tends to use the terms (un)ban, while the user interface uses the terms (un)block.
Alice, Bob, Carla, Denys are in a swarm. Alice issues a ban against Denys.
In a fully peer‑to‑peer system with no central authority, this simple action exposes three core challenges:
Untrusted Timestamps: Commit timestamps cannot be relied upon for ordering ban events, as any device can forge or replay commits with arbitrary dates.
Conflicting bans: In cases where multiple admin devices exist, network partitions can result in conflicting ban decisions. For instance, if Alice can communicate with Bob but not with Denys and Carla, while Carla can communicate with Denys, conflicting bans may occur. If Denys bans Alice while Alice bans Denys, the group’s state becomes unclear when all members eventually reconnect and merge their conversation histories.
Compromised or expired devices: Devices can be compromised, stolen, or have their certificates expire. The system must allow banning such devices and ensure they cannot manipulate their certificate or commit timestamps to send unauthorized messages or falsify their expiration status.
Podobne systemy (z systemami rozproszonym grupami) nie są tak duże, ale oto kilka przykładów:
[mpOTR nie definiuje jak zakazać kogoś]
Signal, bez żadnego centralnego serwera do rozmowy grupowej (EDIT: niedawno zmienili ten punkt), nie daje możliwości zakazania kogoś z grupy.
This voting system needs a human action to ban someone or must be based on the CRLs info from the repository (because we can not trust external CRLs).
Wyjąć urządzenie z rozmowy
To jedyna część, w której musi być konsensus, aby uniknąć rozpadu rozmowy, jak gdyby dwóch członków kopnąło się z rozmowy, co zobaczy trzecie?
Jest to niezbędne do wykrycia odwołanych urządzeń lub po prostu uniknięcia niepożądanych osób w pokoju publicznym.
Alice usuwa Boba
Ważne
Alice MUST be an admin to vote.
W pierwszej kolejności głosowała za zakazem pracy Boba. Aby to zrobić, tworzy plik w /votes/ban/members/uri_bob/uri_alice (młody mogą być zastąpieni przez urządzenia dla urządzenia, lub zaproszeni do zaproszeń lub administratorów dla administratorów) i zobowiązuje się do
Następnie sprawdza, czy głosowanie zostało rozwiązane. To oznacza, że > 50% administratorów zgodzi się zakazać Bob (jeśli jest sama, to na pewno więcej niż 50%).
Jeśli głosowanie zostanie rozwiązane, pliki w /votes/ban mogą być usunięte, wszystkie pliki dla Boba w /members, /admins, /invited, /CRLs, /devices mogą być usunięte (lub tylko w /devices jeśli jest to urządzenie, które jest zakazane) i certyfikat Boba może być umieszczony w /banned/members/bob_uri.crt (lub /banned/devices/uri.crt jeśli urządzenie jest zakazane) i przekazany do repo
Następnie Alice informuje innych użytkowników (poza Bobem)
Alice (admin) re-adds Bob (banned member)
If she votes for unbanning Bob. To do that, she creates the file in /votes/unban/members/uri_bob/uri_alice (members can be replaced by devices for a device, or invited for invites or admins for admins) and commits
Następnie sprawdza, czy głosowanie zostało rozwiązane. To oznacza, że > 50% administratorów zgodzi się zakazać Bob (jeśli jest sama, to na pewno więcej niż 50%).
Jeśli głosowanie zostanie rozwiązane, pliki w /votes/unban mogą być usunięte, wszystkie pliki dla Bob w /members, /admins, /invited, /CRLs, mogą być ponownie dodane (lub tylko w /devices jeśli jest to urządzenie, które jest nie zabronione) i zobowiązane do repo
/Zdejmij rozmowę
Zapisz w convInfos removed=time::now() (jak zapiszContact save w kontaktach) że rozmowa jest usunięta i synchronizowana z urządzeniach innych użytkowników
Jeśli otrzyma się nowy komunikat, to zostanie zignorowany.
Jeśli start Jami i repo są nadal obecne, rozmowa nie zostanie ogłoszona klientom.
Two cases: a. If no other member in the conversation we can immediately remove the repository b. If still other members, commit that we leave the conversation, and now wait that at least another device sync this message. This avoids the fact that other members will still detect the user as a valid member and still sends new message notifications.
Kiedy jesteśmy pewni, że ktoś jest synchronizowany, usuwać usunięte=time::now() i synchronizować z urządzenia innych użytkowników
Wszystkie urządzenia posiadane przez użytkownika mogą teraz usunąć repozytorium i powiązane pliki
Jak określić tryb
Nie można zmieniać trybu w czasie, albo jest to inna rozmowa.
{
"type": "initial",
"mode": 0,
}
Na razie „mode” przyjmuje wartości 0 (ONE_TO_ONE), 1 (ADMIN_INVITES_ONLY), 2 (INVITES_ONLY), 3 (PUBLIC)
Processes for 1:1 chats
The goal here is to keep the old API (addContact/removeContact, sendTrustRequest/acceptTrustRequest/discardTrustRequest) to create a chat with a peer and its contact. This still implies some changes that we cannot ignore:
Proces jest nadal taki sam, konto może dodać kontakt za pośrednictwem addContact, a następnie wysłać TrustRequest za pośrednictwem DHT.
TrustRequest włącza „conversationId” informując rówieśnika, jaką rozmowę klonować przy przyjmowaniu wniosku
TrustRequest jest ponownie próbowany, gdy kontakt wraca do sieci. Nie jest to dziś możliwe (nie chcemy generować nowego TrustRequest, jeśli rówieśnik odrzuca pierwszy).
Następnie, gdy kontakt przyjmuje prośbę, potrzebny jest okres synchronizacji, ponieważ kontakt musi teraz klonować rozmowę.
RemoveContact() usunie kontakt i związane z nim rozmowy 1:1 (w tym samym procesie, co „Suspiesz rozmowę”). jedyną notą jest to, że jeśli zakażemy kontaktu, nie będziemy czekać na synchronizację, po prostu usuniemy wszystkie związane pliki.
Scenariusze trudne
W niektórych przypadkach można stworzyć dwie rozmowy.
Alice adds Bob.
Bob accepts.
Alice removes Bob.
Alice adds Bob.
lub
Alice adds Bob and Bob adds Alice at the same time, but both are not connected together.
In this case, two conversations are generated. We don’t want to remove messages from users or choose one conversation here. So, sometimes two conversations between the same members will be shown. It will generate some bugs during the transition time (as we don’t want to break API, the inferred conversation will be one of the two shown conversations, but for now it’s „ok-ish”, will be fixed when clients will fully handle conversationId for all APIs (calls, file transfer, etc)).
Ważne
After accepting a conversation’s request, there is a time the daemon needs to retrieve the distant repository. During this time, clients MUST show a syncing view to give informations to the user. While syncing:
ConfigurationManager::getConversations() will return the conversation’s id even while syncing.
ConfigurationManager::conversationInfos() zwrócą {{„synchronizacja”: „prawdziwa”}} w przypadku synchronizacji.
ConfigurationManager::getConversationMembers() will return a map of two URIs (the current account and the peer who sent the request).
Rozmowy o specyfikację
Wnioski o rozmowy są przedstawiane przez Map<String, String> z następującymi klawiszami:
id: the conversation ID
from: URI of the sender
otrzymał: certyfikat czasu
tytuł: (opcjonalnie) nazwa rozmowy
opis: (opcjonalny)
avatar: (opcjonalny)
Synchronizacja profilu rozmowy
Aby być identyfikowalna, rozmowa wymaga zazwyczaj metadanych, takich jak tytuł (np. Jami), opis (np. niektóre linki, co jest projekt, itp.), oraz obraz (logo projektu).
Przechowywanie w magazynie
Profil rozmowy jest przechowywany w klasycznym pliku vCard w korzeni (/profile.vcf
) np.:
BEGIN:VCARD
VERSION:2.1
FN:TITLE
DESCRIPTION:DESC
END:VCARD
Synchronizacja
To update the vCard, a user with enough permissions (by default: =ADMIN) needs to edit /profile.vcf
and will commit the file with the mimetype application/update-profile
.
The new message is sent via the same mechanism and all peers will receive the MessageReceived signal from the daemon.
The branch is dropped if the commit contains other files or too big or if done by a non-authorized member (by default: <ADMIN).
Ostatnie wyświetlane
W danych zsynchronizowanych, każde urządzenie wysyła do innych urządzeń stan rozmów. W tym stanie jest wysłany ostatni wyświetlany. Jednakże, ponieważ każde urządzenie może mieć swój własny stan dla każdej rozmowy, a prawdopodobnie bez tego samego ostatniego zobowiązania w pewnym momencie, istnieje kilka scenariuszy, które należy wziąć pod uwagę:
Wspierane są pięć scenariuszy:
Jeśli ostatni wyświetlany przez inne urządzenia jest taki sam jak obecny, nie ma co robić.
jeżeli nie ma ostatniego wyświetlania dla bieżącego urządzenia, używane jest wiadomość wyświetlana zdalnie.
Jeśli ostatni wyświetlony odległy nie jest obecny w repo, oznacza to, że commit zostanie pobrany później, więc zapasowy wynik
Jeśli zdalny już jest wyświetlany, sprawdzamy, czy ostatni wyświetlony lokal jest wcześniej w historii, aby go zastąpić
Wreszcie, jeśli wiadomość jest ogłoszona od tego samego autora, oznacza to, że musimy zaktualizować ostatni wyświetlane.
Preferencje
W każdym rozmowie są załączone preferencje ustawione przez użytkownika.
„color” - kolor konwersacji (format #RRGGBB)
„ignoreNotifications” - ignorować powiadomienia o nowych wiadomościach w tej rozmowie
„symbol” - określa domyślny emoji.
Preferencje te są przechowywane w pakicie MapStringString, przechowywane w accountDir/conversation_data/conversationId/preferences
i przesyłane tylko przez urządzenia tego samego użytkownika za pośrednictwem SyncMsg.
API do interakcji z preferencjami to:
// Update preferences
void setConversationPreferences(const std::string& accountId,
const std::string& conversationId,
const std::map<std::string, std::string>& prefs);
// Retrieve preferences
std::map<std::string, std::string> getConversationPreferences(const std::string& accountId,
const std::string& conversationId);
// Emitted when preferences are updated (via setConversationPreferences or by syncing with other devices)
struct ConversationPreferencesUpdated
{
constexpr static const char* name = "ConversationPreferencesUpdated";
using cb_type = void(const std::string& /*accountId*/,
const std::string& /*conversationId*/,
std::map<std::string, std::string> /*preferences*/);
};
Zarządzanie konfliktami w zakresie fuzji
Ponieważ dwaj administratorzy mogą zmienić opis jednocześnie, może wystąpić konflikt fuzji na profile.vcf
. W tym przypadku zostanie wybrany commit z wyższym hashem (np. ffffff > 000000).
API
Użytkownik ma 2 metody uzyskania i ustawienia metadanych rozmowy:
<method name="updateConversationInfos" tp:name-for-bindings="updateConversationInfos">
<tp:added version="10.0.0"/>
<tp:docstring>
Update conversation's infos (supported keys: title, description, avatar)
</tp:docstring>
<arg type="s" name="accountId" direction="in"/>
<arg type="s" name="conversationId" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="VectorMapStringString"/>
<arg type="a{ss}" name="infos" direction="in"/>
</method>
<method name="conversationInfos" tp:name-for-bindings="conversationInfos">
<tp:added version="10.0.0"/>
<tp:docstring>
Get conversation's infos (mode, title, description, avatar)
</tp:docstring>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorMapStringString"/>
<arg type="a{ss}" name="infos" direction="out"/>
<arg type="s" name="accountId" direction="in"/>
<arg type="s" name="conversationId" direction="in"/>
</method>
gdzie infos
jest map<str, str>
z następującymi kluczami:
tryb: WYJĄCY
tytuł
opis
avatar
Powtórny import konta (połączenie/wywóz)
Arkiw musi zawierać conversationId, aby móc odzyskać rozmowy na nowych commitów po ponownym przywozie (ponieważ w tym momencie nie ma zaproszenia).
Rozmowa jest tam, w tym przypadku, demon jest w stanie ponownie sklować tę rozmowę
Konwersacja Id jest brakująca, więc demon prosi (poprzez wiadomość
{{"aplikacja/zaproszenie", rozmowa Id}}
) nowy zaproszenie, które użytkownik musi (ponownie) zaakceptować
Ważne
A conversation can only be retrieved if a contact or another device is there, else it will be lost. There is no magic.
Używane protokoły
Git
Dlaczego ten wybór
Each conversation will be a Git repository. This choice is motivated by:
Trzeba synchronizować i zamówić wiadomości. Drzewo Merkle jest idealną strukturą do tego i może być linearyzowane poprzez połączenie gałęzi.
Wyróżnione przez naturę, używane w masie, wiele backendów i włączalne.
Może sprawdzić zobowiązania za pomocą haków i masowo używanych krypto
Można je przechowywać w bazie danych w razie potrzeby
W przypadku konfliktów można uniknąć używając wiadomości commit, a nie plików.
Co musimy potwierdzić
Wydajność?
git.lock
może być niskaHaky w libgit2
Wielokrotne ciągnięcie w tym samym czasie?
Limity
Aby usunąć rozmowę, urządzenie musi opuścić rozmowę i utworzyć inną.
Jednakże nieprzestronne wiadomości (takie jak wiadomości czytelne tylko przez kilka minut) mogą być wysyłane za pośrednictwem specjalnego wiadomości za pośrednictwem DRT (takie jak powiadomienia o wpisaniu lub odczytaniu).
Struktura
/
- invited
- admins (public keys)
- members (public keys)
- devices (certificates of authors to verify commits)
- banned
- devices
- invited
- admins
- members
- votes
- ban
- members
- uri
- uriAdmin
- devices
- uri
- uriAdmin
- unban
- members
- uri
- uriAdmin
- CRLs
Przekazanie plików
This new system overhauls file sharing: the entire history is now kept in sync, so any device in the conversation can instantly access past files. Rather than forcing the sender to push files directly—an approach that was fragile in the face of connection drops and often required manual retries—devices simply download files when they need them. Moreover, once one device has downloaded a file, it can act as a host for others, ensuring files remain available even if the original sender goes offline.
Protokół
Odesłaniec dodaje nowe zobowiązanie do rozmowy w następującym formacie:
value["tid"] = "RANDOMID";
value["displayName"] = "DISPLAYNAME";
value["totalSize"] = "SIZE OF THE FILE";
value["sha3sum"] = "SHA3SUM OF THE FILE";
value["type"] = "application/data-transfer+json";
i tworzy link w ${data_path}/conversation_data/${conversation_id}/${file_id}
gdzie file_id=${commitid}_${value["tyd"]}.${extension}
Następnie odbiorca może teraz pobrać pliki, skontaktując się z urządzeniami obsługującymi plik otwierając kanał z name="data-transfer://" + conversationId + "/" + currentDeviceId() + "/" + fileId
i przechowywać informacje, że plik czeka w ${data_path}/conversation_data/${conversation_id}/waiting
Urządzenie otrzymujące połączenie przyjmie kanał, sprawdzając, czy plik może zostać wysłany (jeśli sha3sum jest prawidłowy i jeśli istnieje plik). Odbiorca zachowa pierwszy otwarty kanał, zamyka pozostałe i zapisze w plik (z tą samą ścieżką jak nadawca: ${data_path}/conversation_data/${conversation_id}/${file_id}
) wszystkie przychodzące dane.
Kiedy transfer jest zakończony lub kanał zamknięty, sha3sum jest weryfikowany, aby zweryfikować, że plik jest prawidłowy (a jeśli nie jest usunięty).
W przypadku awarii, gdy urządzenie rozmowy zostanie ponownie włączone, poprosiemy o wszystkie pliky oczekujące w ten sam sposób.
Call in Swarm
Pomysł
A swarm conversation can have multiple rendez-vous. A rendez-vous is defined by the following URI:
„accountUri/deviceId/conversationId/confId” gdzie accountUri/deviceId opisuje host.
Właściciel może być określony w dwóch różnych formach:
W metadanych, gdzie są przechowywane jak tytuł / desk / avatar pokoju
Albo początkowy dzwoniciel.
When starting a call, the host will add a new commit to the repository, with the URI to join (accountUri/deviceId/conversationId/confId). This will be valid till the end of the call (announced by a commit with the duration to show)
Każda część otrzyma informacje, że połączenie zostało rozpoczęte i będzie mogła dołączyć do niego połącząc go.
Ataki?
Avoid Git bombs
Wpis
Odkład czasu można zaufać, ponieważ jest edytowalny.
TLS
Operacje Git, wiadomości kontrolne, pliki i inne rzeczy będą używać p2p TLS v1.3 link z tylko szyframi, które gwarantują PFS.
DHT (UDP)
Używane do wysyłania wiadomości do telefonów komórkowych (do uruchomienia powiadomień push) i inicjowania połączeń TCP.
Działalność sieci
Proces zaproszenia kogoś
Alice chce zaprosić Boba:
Alice dodaje Boba do rozmowy
Alicja generuje zaproszenie: { „application/invite+json” : { „conversationId”: „$id”, »members«: [{…}] }}
Dwie możliwości wysyłania wiadomości a. Jeśli nie jest podłączony, za pośrednictwem DHT b. Inne, Alice wysyła na kanale SIP
A. otrzymuje zaproszenie, jest wysłany sygnał dla klienta b. Nie jest podłączony, więc nigdy nie otrzyma zapytania, ponieważ Alice nie musi wiedzieć, czy Bob właśnie zignorował lub zablokował Alice.
Proces wysyłania wiadomości do kogoś
Alice chce wysłać wiadomość do Boba:
Alice doda wiadomość do repo, podając tożsamość
Alice otrzymuje wiadomość (od siebie) jeśli jest skuteczna
W obu przypadkach tworzy się wiadomość: { „aplikacja/im-gitmessage-id” : „{„id”:”\(convId", "commit":"\)commitId”, „deviceId”: „$alice_device_hash”}”}. a. Jeśli nie jest podłączona, za pośrednictwem DHT b.
Cztery możliwości dla Boba: a. Bob nie jest połączony z Alice, więc jeśli ufa Alice, poproś o nowe połączenie i przejdź do b. b. Jeśli jest połączony, weź od Alice i ogłaszaj nowe wiadomości c. Bob nie zna tej rozmowy. Poproś przez DHT o zaproszenie, aby najpierw móc zaakceptować tę rozmowę ({„aplikacja/zaproszenie”, rozmowaId}) d. Bob jest odłączony (brak sieci, lub po prostu zamknięty).
Wdrożenie
! [Diagram: klasy czatu z rzędu]
Obsługiwane wiadomości
Wiadomość początkowa
{
"type": "initial",
"mode": 0,
"invited": "URI"
}
Reprezentuje pierwsze zatwierdzenie repozytorium i zawiera tryb:
enum class ConversationMode : int { ONE_TO_ONE = 0, ADMIN_INVITES_ONLY, INVITES_ONLY, PUBLIC }
i zaproszony
, jeśli tryb = 0.
Wiadomość tekstowa
{
"type": "text/plain",
"body": "content",
"react-to": "id (optional)"
}
Lub do edycji:
{
"type": "application/edited-message",
"body": "content",
"edit": "id of the edited commit"
}
Rozmowy
Pokazuje koniec połączenia (czas trwania w milisekundach):
{
"type": "application/call-history+json",
"to": "URI",
"duration": "3000"
}
Lub do prowadzenia rozmowy w grupie (po jej rozpoczęciu)
{
"type": "application/call-history+json",
"uri": "host URI",
"device": "device of the host",
"confId": "hosted confId"
}
Drugie zatwierdzenie z tym samym JSON + duration
jest dodawane na końcu wywołania, gdy jest hostowane.
Dodawanie pliku
{
"type": "application/data-transfer+json",
"tid": "unique identifier of the file",
"displayName": "File name",
"totalSize": "3000",
"sha3sum": "a sha3 sum"
}
totalSize
jest wyrażony w bitach,
Aktualizacja profilu
{
"type": "application/update-profile",
}
Wydarzenie członkowskie
{
"type": "member",
"uri": "member URI",
"action": "add/join/remove/ban"
}
Gdy użytkownik zostanie zaproszony, dołączy, opuści lub zostanie wyrzucony z konwersacji
Głosowanie
Generowane przez administratorów w celu dodania głosu za wyrzuceniem lub usunięciem kogoś.
{
"type": "vote",
"uri": "member URI",
"action": "ban/unban"
}
!! Stary projekt!!
Informacja
Following notes are not organized yet. Just some line of thoughts.
Poprawki w kryptowalutach.
W przypadku poważnej funkcji czatu grupowego potrzebujemy również poważnej krypto. W obecnym projekcie, jeśli certyfikat zostanie skradziony jako poprzednie wartości DHT w rozmowie, rozmowa może zostać zdecyfrowana.
Informacja
A lib might exist to implement group conversations.
Potrzeba wsparcia ECC w OpenDHT
Użycie
Dodać role?
Istnieją dwa główne przypadki użycia rozmów grupowych:
Coś jak Mattermost w firmie, z prywatnymi kanałami i niektórymi rolami (admin/spectator/bot/etc) lub dla edukacji (gdzie tylko nieliczni są aktywni).
Rozmowy horyzontalne, jak rozmowy między przyjaciółmi.
Dla którego z nich będzie Jami?
Idea wdrożenia
Certyfikat dla grupy, która podpisuje użytkownika flagą dla roli.
Dołącz do rozmowy
Tylko za pośrednictwem bezpośredniego zaproszenia
Za pośrednictwem linku/kod QR/co
Via a room name? (a hash on the DHT)
Co nam potrzeba
Konfidencjalizm: członkowie poza grupą rozmowy nie powinni być w stanie czytać wiadomości w grupie
Pozycja: jeśli jakiś klucz z grupy zostanie zagrożony, poprzednie wiadomości powinny pozostać poufne (jak to możliwe)
Zleczenie wiadomości: Potrzeba mieć wiadomości w odpowiedniej kolejności
Synchronizacja: Trzeba również upewnić się, że wszystkie wiadomości są dostępne tak szybko, jak to możliwe.
Persistencja: W rzeczywistości wiadomość na DHT żyje tylko 10 minut. Ponieważ jest to najlepsze obliczone czasopismo dla tego rodzaju DHT. Aby przetrwać dane, węzeł musi ponownie wstawiać wartość na DHT co 10 minut. Innym sposobem, aby zrobić, gdy węzeł jest offline, jest pozwalać węzłom ponownie wstawić dane. Ale jeśli po 10 minutach, 8 węzłów są nadal tutaj, wykonują 64 żądania (i to jest eksponencyjne).
Inne rozmieszczone sposoby
Potrzebuję trochę badań.
Potrzebuję trochę dochodzenia
Potrzebuję trochę śledztwa.
Na podstawie obecnej pracy, którą mamy
Rozmowa grupowa może być oparta na tej samej pracy, którą mamy już dla wielu urządzeń (ale tutaj, z certyfikatem grupowym).
To musi przenieść bazę danych z klienta do demona.
Jeśli nikt nie jest podłączony, synchronizacja nie może być wykonana, a osoba nigdy nie zobaczy rozmowy
Kolejny DHT
Jak DHT z superużytkownikiem.
Przekazanie plików
Obecnie algorytm transferu plików opiera się na połączeniu TURN (patrz Przekazanie plików). W przypadku dużej grupy będzie to złe. Najpierw potrzebujemy implement p2p do transferu p2p. Wdroż RFC do transferu p2p.
Other problem: currently there is no implementation for TCP support for ICE in PJSIP. This is mandatory for this point (in PJSIP or homemade)
Zasoby
Robustna dystrybuowana synchronizacja sieciowych systemów liniowych z informacjami przerywanymi (Sean Phillips i Ricardo G.Sanfelice)