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:

  1. Ability to split and merge based on network connectivity.

  2. History synchronization. Every participant must be able to send a message to the entire group.

  3. Nie ma centralnej władzy, nie może polegać na serwerach.

  4. Non-repudiation. Devices must be able to verify past messages» validity and to replay the entire history.

  5. 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

  1. Bob creates a local Git repository.

  2. 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`

  3. Hash pierwszego zdania staje się identyfikatorem rozmowy.

  4. 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

  1. Bob adds Alice to the repo:

    • Dodaje zaproszony URI w /invited

    • Dodaje CRL do /crls

  2. Bob sends a request on the DHT.

Przyjmując zaproszenie

Alice gets the invite to join the previously created swarm

  1. Alice accepts the invite (if she declines, nothing happens; she will remain in the „invited” list, and will never receive any messages)

  2. A peer-to-peer connection is established between Alice and Bob.

  3. Alice pulls the Git repository from Bob. WARNING this means that messages require a connection, not from the DHT as it is today.

  4. Alice validates the commits from Bob.

  5. To validate that Alice is a member, she removes the invite from /invited directory, then adds her certificate to the /members directory

  6. Once 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

  1. Alice creates a commit message. She constructs a JSON payload containing the MIME type and message body. For example:

{
    "type": "text/plain",
    "body": "hello"
}
  1. 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.

  2. 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).

  3. 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

  1. Bob performs a Git pull on Alice’s repository.

  2. All incoming commits MUST be verified by a hook.

  3. If all commits are valid, commits are stored and displayed.Bob then announces the message via the DRT for other devices.

  4. 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

  1. 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.

  2. 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 each type 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:

  1. Untrusted Timestamps: Commit timestamps cannot be relied upon for ordering ban events, as any device can forge or replay commits with arbitrary dates.

  2. 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.

  3. 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ę

  1. 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

  2. Jeśli otrzyma się nowy komunikat, to zostanie zignorowany.

  3. Jeśli start Jami i repo są nadal obecne, rozmowa nie zostanie ogłoszona klientom.

  4. 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.

  5. Kiedy jesteśmy pewni, że ktoś jest synchronizowany, usuwać usunięte=time::now() i synchronizować z urządzenia innych użytkowników

  6. 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.

  1. TrustRequest włącza „conversationId” informując rówieśnika, jaką rozmowę klonować przy przyjmowaniu wniosku

  2. 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.

  1. Alice adds Bob.

  2. Bob accepts.

  3. Alice removes Bob.

  4. Alice adds Bob.

lub

  1. 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

Używane protokoły

Git

Dlaczego ten wybór

Each conversation will be a Git repository. This choice is motivated by:

  1. Trzeba synchronizować i zamówić wiadomości. Drzewo Merkle jest idealną strukturą do tego i może być linearyzowane poprzez połączenie gałęzi.

  2. Wyróżnione przez naturę, używane w masie, wiele backendów i włączalne.

  3. Może sprawdzić zobowiązania za pomocą haków i masowo używanych krypto

  4. Można je przechowywać w bazie danych w razie potrzeby

  5. 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ć niska

  • Haky 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:

  1. Alice dodaje Boba do rozmowy

  2. Alicja generuje zaproszenie: { „application/invite+json” : { „conversationId”: „$id”, »members«: [{…}] }}

  3. 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

  4. 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:

  1. Alice doda wiadomość do repo, podając tożsamość

  2. Alice otrzymuje wiadomość (od siebie) jeśli jest skuteczna

  3. 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.

  4. 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:

  1. 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).

  2. 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).

  1. To musi przenieść bazę danych z klienta do demona.

  2. 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