Schar
Wichtig
Jami source code tends to use the terms (un)ban, while the user interface uses the terms (un)block.
Synospis
Ziel dieses Dokuments ist es, zu beschreiben, wie Gruppenchats (auch bekannt als Schwarm-Chat**) in Jami umgesetzt werden.
Eine swarm ist eine Gruppe, die ohne Zentralautorität auf widerstandsfähige Weise diskutieren kann. Wenn zwei Personen keine Verbindung zum Rest der Gruppe haben (d. h. Internetunterbrochen), aber sie sich gegenseitig kontaktieren können (z. B. in einem LAN oder einem Subnetzwerk), können sie sich gegenseitig Nachrichten senden und dann, wenn möglich, mit dem Rest der Gruppe synchronisieren.
Die Schaum wird also definiert:
Fähigkeit, sich nach der Verbindung zu trennen und zu verschmelzen.
Jeder muss eine Nachricht an die ganze Gruppe senden können.
Keine zentrale Behörde, kann sich nicht auf einen Server verlassen.
Nicht-Verweigerung: Geräte müssen in der Lage sein, die Gültigkeit alter Nachrichten zu überprüfen und die gesamte Geschichte wiederzufinden.
Die Speicherung wird vom Gerät verwaltet.
Die Idee ist, einen synchronisierten Merkle-Baum mit den Teilnehmern zu bekommen.
Wir haben vier Modi für Schwarm-Chat identifiziert, die wir implementieren wollen:
EINER_ZU EINER, im Grunde der Fall, den wir heute haben, wenn Sie mit einem Freund diskutieren
ADMIN_INVITES_ONLY im Allgemeinen eine Klasse, in der der Lehrer Menschen einladen kann, aber nicht die Schüler
INVITES_ONLY eine private Gruppe von Freunden
Publikum ist im Grunde ein offenes Forum
Szenarien
Schaffen Sie eine Schar
Bob will einen neuen Schwarm schaffen.
Bob creates a local Git repository.
Dann erstellt er eine erste unterzeichnete Verpflichtung mit folgenden Worten:
Sein öffentlicher Schlüssel in
/admins
Sein Gerätesertifikaat in ̀ /geräte `
Seine CRL in ̀ /crls`
Das Hash des ersten Kommits wird zum ID des Gesprächs.
Bob kündigt seinen anderen Geräten an, dass er eine neue Konversation erstellt.
Ein Zusatz
Alice fügt Bob hinzu.
Alice fügt Bob zum Repo hinzu:
Fügt den eingeladenen URI in
/invited
hinzuZugabe der CRL in
/crls
Alice schickt eine Anfrage zum DHT.
Einladung zu empfangen
Alice wird eingeladen, sich dem vorher geschaffenen Schwarm anzuschließen.
Sie nimmt die Einladung an (wenn sie ablehnt, tut nichts, bleibt sie in der Einladung und Alice wird nie eine Nachricht erhalten)
Eine Peer-to-Peer-Verbindung zwischen Alice und Bob ist geschehen.
Alice pull the Git repo of Bob. WARNING this means that messages need a connection, not from the DHT like today.
Alice bestätigt die Verpflichtungen von Bob
Um zu bestätigen, dass Alice Mitglied ist, entfernt sie die Einladung aus dem Verzeichnis
/invited
und fügt ihr Zertifikat dann in das Verzeichnis/members
hinzu.Sobald alle Kommitte validiert und auf ihrem Gerät, werden andere Mitglieder der Gruppe von Alice entdeckt. Mit diesen Peers, sie wird die DRT (unterhalb erklärt) mit Bob als Bootstrap zu konstruieren.
Eine Nachricht senden
Alice schickt eine Nachricht
Eine Nachricht zu senden ist ziemlich einfach. Alice schreibt eine Kommit-Message in folgendem Format:
{
"type": "text/plain",
"body": "coucou"
}
and adds her device and CRL to the repository if missing (others must be able to verify the commit). Merge conflicts are avoided because we are mostly based on commit messages, not files (unless CRLS + certificates but they are located). Then she announces the new commit via the DRT with a service message (explained later) and pings the DHT for mobile devices (they must receive a push notification).
Für das Pinging anderer Geräte sendet der Absender einem anderen Mitglied eine SIP-Nachricht mit einem Mimetype = „Application/im-gitmessage-id“ mit einem JSON mit der „deviceId“, die die Nachricht sendet, dem „id“ des Gesprächs und der „commit“
Eine Nachricht empfangen
Bob erhält die Nachricht von Alice
Bob do a Git pull on Alice
Die Verpflichtungen müssen über einen Haken überprüft werden
Wenn alle Commits gültig sind, werden die Commits gespeichert und angezeigt.
If all commits are not valid, pull is canceled. Alice must reestablish her state to a correct state.
Validierung eines Verpflichtungsbestimmungsbereichs
Um zu vermeiden, dass Benutzer einige unerwünschte Kommitte (mit Konflikten, falschen Nachrichten usw.) durchführen, muss jedes Kommitte (von dem ältesten bis zum neuesten) vor der Verschmelzung einer Remote-Fläche validiert werden:
Bemerkung
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.
Überprüfen Sie für jede Verpflichtung, ob das Gerät, das die Verpflichtung senden will, zur Zeit zugelassen ist und die Zertifikate vorhanden sind (in Geräten für das Gerät und in Mitgliedern oder Administratoren für den Emittenten).
Das Kommit hat 2 Eltern, also ist es eine Fusion, nichts mehr zu bestätigen hier
Das Commit hat 0 Eltern, es ist das Anfangscommit:
Überprüfen Sie, ob admin-Certifikat hinzugefügt wurde
Überprüfen Sie, ob das Gerät-Cert hinzugefügt ist
Kontroll-CRLs hinzugefügt
Überprüfen Sie, ob keine andere Datei hinzugefügt wird
Das commit hat 1 Mutter, das commit-Message ist ein JSON mit einem Typ:
Wenn Text (oder ein anderer Mime-Typ, der keine Dateien ändert)
Überprüfungsunterzeichnung aus dem Zertifikat im Repo
Überprüfen Sie, ob keine seltsame Datei außerhalb des Gerätes Cert hinzugefügt oder entfernt wird
Wenn sie stimmen
Überprüfen Sie, ob voteType unterstützt wird (Verbot, Unban)
Überprüfen Sie, ob die Stimme für den Benutzer bestimmt ist, der das Kommit unterschreibt.
Check that vote is from an admin and device present and not banned
Überprüfen Sie, ob keine seltsamen Dateien hinzugefügt oder entfernt werden
Wenn Mitglied
Wenn hinzugefügt
Überprüfen Sie, ob die Verpflichtung korrekt unterzeichnet ist
Überprüfen Sie, ob das Zertifikat in /invited hinzugefügt ist
Überprüfen Sie, ob keine seltsamen Dateien hinzugefügt oder entfernt werden
Wenn ONE_TO_ONE, überprüfen Sie, dass wir nur einen Administrator, ein Mitglied haben
Wenn ADMIN_INVITES_ONLY, überprüfen Sie, dass die Einladung von einem Admin
Wenn sich
Überprüfen Sie, ob die Verpflichtung korrekt unterzeichnet ist
Überprüfen Sie, ob das Gerät hinzugefügt wurde
Überprüfen Sie, ob die Einladung an Mitglieder weitergeleitet wird
Überprüfen Sie, ob keine seltsamen Dateien hinzugefügt oder entfernt werden
Wenn verboten
Überprüfen Sie, ob die Abstimmung gültig ist.
Überprüfen Sie, ob der Benutzer über einen Admin verboten ist
Überprüfen Sie, ob das Mitglied- oder Gerätesertifika auf Verbot/
Überprüfen Sie, ob nur die mit der Abstimmung verbundenen Dateien entfernt werden
Überprüfen Sie, ob keine seltsamen Dateien hinzugefügt oder entfernt werden
Benutzerin kann mit einer alten Version oder dem Peer versucht werden, unerwünschte Kommits zu senden
Verbot eines Geräts
Alice, Bob, Carla, Denys sind in einem Schwarm.
Das ist eines der schwierigsten Szenarien in unserem Kontext.
Zeitstempel der erzeugten Verpflichtungen
Wenn mehrere Admin-Geräte vorhanden sind und wenn Alice mit Bob sprechen kann, aber nicht mit Denys und Carla; Carla mit Denys sprechen kann; Denys verbietet Alice, Alice verbietet Denys, wie wird es aussehen, wenn die 4 Mitglieder die Gespräche fusionieren.
Ein Gerät kann kompromittiert, gestohlen oder sein Zertifikat verfallen. Wir sollten ein Gerät verbieten und vermeiden, dass es über sein Verlauf lügt oder in der Vergangenheit Nachrichten sendet (durch Änderung seines Zertifikats oder des Zeitstauchers seines Kommitments).
Ähnliche Systeme (mit verteilten Gruppensystemen) sind nicht so viel, aber hier sind einige Beispiele:
[mpOTR definiert nicht, wie man jemanden verbietet]
Signal, ohne einen zentralen Server für Gruppenchat (EDIT: Sie ändern diesen Punkt kürzlich), gibt nicht die Möglichkeit, jemanden aus einer Gruppe zu verbieten.
Dieses Stimmsystem benötigt eine menschliche Aktion, um jemanden zu verbieten oder muss sich auf die CRL-Informationen aus dem Repository stützen (weil wir externen CRLs nicht vertrauen können).
Entfernen Sie ein Gerät aus einem Gespräch
Das ist der einzige Teil, an dem ein Konsens besteht, um eine Spaltung zu vermeiden. Wenn sich zwei Mitglieder aus dem Gespräch treten, was wird dann das dritte sehen?
Dies ist notwendig, um widerrufene Geräte zu erkennen oder einfach zu vermeiden, dass unerwünschte Personen in einem öffentlichen Raum vorhanden sind.
Alice entfernt Bob.
Wichtig
Alice MUST be an admin to vote.
Erstens stimmt sie für das Verbot von Bob. Dazu erstellt sie die Datei in /votes/ban/members/uri_bob/uri_alice (Mitglieder können durch Geräte für ein Gerät ersetzt werden, oder für Einladungen oder Admin für Admin eingeladen werden) und verpflichtet sich,
Dann überprüft sie, ob die Abstimmung gelöst ist. Das bedeutet, dass >50% der Admin bereit sind, Bob zu verbieten (wenn sie allein ist, ist es sicher mehr als 50%).
Wenn die Abstimmung gelöst ist, können Dateien in /votes/ban entfernt werden, alle Dateien für Bob in /members, /admins, /invited, /CRLs, /devices entfernt werden (oder nur in /devices, wenn es sich um ein Gerät handelt, das verboten ist) und Bobs Zertifikat kann in /banned/members/bob_uri.crt (oder /banned/devices/uri.crt, wenn ein Gerät verboten ist) platziert und dem repo übertragen werden
Dann informiert Alice andere Benutzer (außer Bob)
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
Dann überprüft sie, ob die Abstimmung gelöst ist. Das bedeutet, dass >50% der Admin bereit sind, Bob zu verbieten (wenn sie allein ist, ist es sicher mehr als 50%).
Wenn die Abstimmung gelöst ist, können Dateien in /votes/unban entfernt werden, alle Dateien für Bob in /members, /admins, /invited, /CRLs, können neu hinzugefügt werden (oder nur in /devices, wenn es sich um ein Gerät handelt, das nicht verboten ist) und dem Repo verpflichtet werden
Entfernen Sie ein Gespräch
Speichern Sie in convInfos removed=time::now() (wie removeKontakt speichert in Kontakten) dass die Konversation entfernt und mit den Geräten anderer Benutzer synchronisiert wird
Wenn ein neuer Kompromiss für dieses Gespräch eingegangen ist, wird er ignoriert.
Wenn Jami noch in Betrieb ist, wird das Gespräch nicht bekannt gegeben.
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.
Wenn wir sicher sind, dass jemand synchronisiert ist, entfernen wir erledigt=zeit::now() und synchronisieren wir mit den Geräten anderer Benutzer
Alle Geräte des Benutzers können das Repository und die damit verbundenen Dateien löschen
Wie ein Modus angegeben wird
Die Modus können nicht im Laufe der Zeit geändert werden. Oder es ist ein anderes Gespräch. Also werden diese Daten in der ersten Kommit-Nachricht gespeichert.
{
"type": "initial",
"mode": 0,
}
Derzeit akzeptiert „Mode“ Werte 0 (ONE_TO_ONE), 1 (ADMIN_INVITES_ONLY), 2 (INVITES_ONLY), 3 (PUBLIC)
Processes for 1:1 swarms
Das Ziel ist es, die alte API (addContact/removeContact, sendTrustRequest/acceptTrustRequest/discardTrustRequest) zu erhalten, um einen Schwarm mit einem Peer und seinem Kontakt zu generieren. Dies bedeutet immer noch einige Änderungen, die wir nicht ignorieren können:
Der Prozess ist immer noch derselbe, ein Konto kann einen Kontakt über addContact hinzufügen und dann eine TrustRequest über die DHT senden.
Die TrustRequest enthält eine „ConversationId“, um dem Peer zu mitteilen, welche Konversation er klonen soll, wenn er die Anfrage akzeptiert
TrustRequest wird erneut versucht, wenn der Kontakt online zurückkehrt. Das ist heute nicht der Fall (da wir keinen neuen TrustRequest erstellen wollen, wenn der Peer den ersten entfernt). Wenn also ein Konto eine Vertrauensanfrage erhält, wird es automatisch ignoriert, wenn die Anfrage mit einem verwandten Gespräch abgelehnt wird (da convRequests synchronisiert werden)
Wenn ein Kontakt die Anfrage akzeptiert, ist eine Synchronisierungsperiode notwendig, denn der Kontakt muss jetzt das Gespräch klonen.
removeContact() wird den Kontakt und die damit verbundenen 1:1-Gespräche entfernen (mit dem gleichen Prozess wie „Entfernen Sie eine Konversation“).
Schwierige Szenarien
Es gibt einige Fälle, in denen zwei Gespräche erfolgen können.
Alice adds Bob.
Bob accepts.
Alice removes Bob.
Alice adds Bob.
oder
Alice adds Bob and Bob adds Alice at the same time, but both are not connected together.
In diesem Fall werden zwei Gespräche erzeugt. Wir wollen keine Nachrichten von Benutzern entfernen oder hier eine Konversation auswählen. So wird manchmal zwei 1:1-Schwarm zwischen den gleichen Mitgliedern angezeigt. Es wird einige Fehler während der Übergangszeit erzeugen (da wir nicht API brechen wollen, wird die abgeleitete Konversation eine der beiden gezeigten Gespräche sein, aber für jetzt ist es „ok-ish“, wird behoben, wenn die Kunden KonversationId für alle APIs (Anrufe, Dateitransfer, etc.) vollständig verarbeiten).
Wichtig
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() wird {{„Synchronisierung“: „Wahr“}} zurückgeben, wenn sie synchronisiert wird.
ConfigurationManager::getConversationMembers() will return a map of two URIs (the current account and the peer who sent the request).
Gespräche verlangen eine Spezifikation
Die Gesprächsanfragen werden durch eine Map<String, String> mit folgenden Tasten dargestellt:
id: the conversation ID
from: URI of the sender
Empfang: Zeitstempel
Titel: (optional) Name für das Gespräch
Beschreibung: (optional)
Avatar: (optional)
Synchronisierung des Gesprächsprofilen
Um zu identifizieren, benötigt ein Gespräch im Allgemeinen einige Metadaten, wie einen Titel (z.B. Jami), eine Beschreibung (z.B. einige Links, was das Projekt ist, etc.) und ein Bild (das Logo des Projekts). Diese Metadaten sind optional, werden jedoch an alle Mitglieder geteilt, daher müssen sie synchronisiert und in die Anfragen aufgenommen werden.
Speicherung im Repository
Das Konversationsprofil wird in einer klassischen vCard-Datei an der Basis (/profile.vcf
) gespeichert, wie:
BEGIN:VCARD
VERSION:2.1
FN:TITLE
DESCRIPTION:DESC
END:VCARD
Synchronisierung
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).
Zuletzt angezeigt
In den synchronisierten Daten sendet jedes Gerät den Status der Gespräche an andere Geräte. In diesem Zustand wird der letzte angezeigte gesendet. Da jedoch jedes Gerät seinen eigenen Zustand für jedes Gespräch haben kann und wahrscheinlich ohne dasselbe letzte Kommit zu einem bestimmten Zeitpunkt, gibt es mehrere Szenarien zu berücksichtigen:
Es werden fünf Szenarien unterstützt:
Wenn die letzte von anderen Geräten gesendete Anzeige die gleiche ist wie die aktuelle, ist nichts zu tun.
wenn für das aktuelle Gerät keine letzte Anzeige vorhanden ist, wird die Fernanzeigungsnachricht verwendet.
Wenn die letzte Remote nicht im Repo vorhanden ist, bedeutet dies, dass das Commit später abgerufen wird, also wird das Ergebnis in Cache gebracht
Wenn die Fernbedienung bereits abgerufen ist, überprüfen wir, ob die letzte angezeigte Lokalvorrichtung in der Geschichte ist, um sie zu ersetzen
Wenn schließlich eine Nachricht vom gleichen Autor angekündigt wird, bedeutet dies, dass wir die letzte angezeigte Nachricht aktualisieren müssen.
Einstellungen
Jedes Gespräch hat die von dem Benutzer festgelegten Präferenzen angeschlossen. Diese Präferenzen werden über die Geräte des Benutzers synchronisiert. Dies kann die Farbe des Gesprächs sein, wenn der Benutzer Benachrichtigungen ignorieren möchte, Dateigrößenbeschränkung usw.
„color“ - the color of the conversation (#RRGGBB format)
„ignoreNotifications“ - die Benachrichtigungen für neue Nachrichten in diesem Gespräch zu ignorieren
„Symbol“ - um ein Standard-Emoji zu definieren.
Diese Präferenzen werden in einem MapStringString-Paket gespeichert, in accountDir/conversation_data/conversationId/preferences
gespeichert und nur über SyncMsg über Geräte des gleichen Benutzers gesendet.
Die API zur Interaktion mit den Präferenzen sind:
// 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*/);
};
Konfliktmanagement durch Fusion
Da zwei Admin die Beschreibung gleichzeitig ändern können, kann auf profile.vcf
ein Fusionkonflikt auftreten. In diesem Fall wird das Commit mit dem höheren Hash (z.B. ffffff > 000000) gewählt.
API
Der Benutzer hat 2 Methoden zur Erfassung und Einstellung der Metadaten der Konversation:
<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>
wo infos
eine map<str, str>
mit folgenden Tasten ist:
Modus: Lese-Nur
Titel
Beschreibung
Avatar
Wiederum ein Konto importieren (Link/Export)
Das Archiv muss conversationId enthalten, um Gespräche auf neuen Commits nach einem Re-Import abrufen zu können (weil es zu diesem Zeitpunkt keine Einladung gibt).
Das Gespräch ist da, in diesem Fall kann der Dämon dieses Gespräch wieder klonen.
Die conversationId fehlt, so dass der Daemon (über eine Nachricht
{{"Anwendung/Einladung", conversationId}}
) eine neue Einladung bittet, die der Benutzer (wieder) akzeptieren muss
Wichtig
A conversation can only be retrieved if a contact or another device is there, else it will be lost. There is no magic.
Gebrauchsprotokolle
Git
Warum diese Wahl
Each conversation will be a Git repository. This choice is motivated by:
Wir müssen Nachrichten synchronisieren und bestellen. Der Merkle Tree ist die perfekte Struktur dafür und kann durch das Zusammenspielen von Zweigen linearisiert werden. Außerdem, weil es von Git massiv verwendet wird, ist es einfach, zwischen Geräten zu synchronisieren.
Wird in der Natur verteilt, massiv verwendet, viele Backends und Plug-ins.
Kann über Haken und massiv genutzte Krypto-Verbindungen überprüfen
Kann bei Bedarf in einer Datenbank gespeichert werden
Konflikte werden vermieden, indem man mit Kommit-Nachrichten, nicht mit Dateien, arbeitet.
Was wir bestätigen müssen
Leistung?
git.lock
kann niedrig seinAnschläge in Libgit2
Mehrfach gleichzeitig?
Grenzen
Um eine Konversation zu löschen, muss das Gerät die Konversation verlassen und eine andere erstellen.
Nicht dauerhafte Nachrichten (z. B. Nachrichten, die nur für einige Minuten gelesen werden können) können jedoch über eine spezielle Nachricht über die DRT (z. B. Notifikationen zum Tippen oder Lesen) gesendet werden.
Struktur
/
- 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
Dateifügelübertragung
Swarm ändert den Dateitransfer massiv. Jetzt synchronisiert sich die gesamte Geschichte, so dass alle Geräte im Gespräch alte Dateien leicht abrufen können. Diese Änderungen ermöglichen es uns, von einer Logik zu wechseln, in der der Absender die Datei auf andere Geräte verschoben hat, über das Versuchen, sich mit ihren Geräten zu verbinden (das war schlecht, weil es nicht wirklich gegen Verbindungsänderungen / Fehler bestand und benötigte einen manuellen erneuten Versuch), zu einer Logik, in der der Absender anderen Geräten erlauben, herunterzuladen.
Protokoll
Der Absender fügt in die Unterhaltung ein neues Commit hinzu:
value["tid"] = "RANDOMID";
value["displayName"] = "DISPLAYNAME";
value["totalSize"] = "SIZE OF THE FILE";
value["sha3sum"] = "SHA3SUM OF THE FILE";
value["type"] = "application/data-transfer+json";
und erstellt einen Link in ${data_path}/conversation_data/${conversation_id}/${file_id}
wo file_id=${commitid}_${value["Tid"]}.${extension}
Dann kann der Empfänger nun die Dateien herunterladen, indem er die Geräte kontaktiert, die die Datei beherbergen, indem er einen Kanal mit name="data-transfer://" + conversationId + "/" + currentDeviceId() + "/" + fileId
öffnet und die Informationen speichert, dass die Datei in ${data_path}/conversation_data/${conversation_id}/waiting
Das Anschlussgerät akzeptiert den Kanal, indem es überprüft, ob die Datei gesendet werden kann (wenn sha3sum korrekt ist und wenn Datei existiert). Der Empfänger hält den ersten geöffneten Kanal, schließt die anderen und schreibt in eine Datei (mit dem gleichen Weg wie der Absender: ${data_path}/conversation_data/${conversation_id}/${file_id}
) alle eingehenden Daten.
Wenn die Übertragung abgeschlossen ist oder der Kanal geschlossen ist, wird die sha3sum überprüft, um zu bestätigen, dass die Datei korrekt ist (andernfalls wird sie gelöscht).
Im Falle eines Ausfalls, wenn ein Gerät des Gesprächs wieder online ist, bitten wir alle Wartedateien auf die gleiche Weise.
Ruf in Schwarm
Idee
A swarm conversation can have multiple rendez-vous. A rendez-vous is defined by the following URI:
„accountUri/deviceId/conversationId/confId“ wo accountUri/deviceId den Host beschreibt.
Der Gastgeber kann auf zwei Arten bestimmt werden:
In der Metadatenmasse, wo sie wie der Titel/Desk/Avatar des Raumes gespeichert sind.
Oder der erste Anrufer.
Bei der Anleitung eines Anrufs wird der Gastgeber dem Schwarm ein neues Commit hinzufügen, wobei der URI (AccountUri/DeviceId/ConversationId/confId) angeschlossen werden soll.
Jeder Teil wird die Information erhalten, dass ein Anruf gestartet wurde und kann sich daran beteiligen, indem er es anruft.
Angriffe?
Avoid Git bombs
Anmerkungen
Der Zeitstempel eines Commits ist zuverlässig, weil er bearbeitet werden kann. Nur dem Zeitstempel des Nutzers kann man vertrauen.
TLS
Git-Operationen, Steuerungsnachrichten, Dateien und andere Dinge verwenden einen P2p TLS v1.3-Link mit nur Verschlüsselungen, die PFS garantieren.
DHT (UDP)
Verwendet zur Absendung von Nachrichten für Mobiltelefone (um Push-Benachrichtigungen auszulösen) und zur Einleitung von TCP-Verbindungen.
Netzwerkaktivität
Ein Einladungsprozess
Alice will Bob einladen:
Alice fügt Bob zu einem Gespräch hinzu.
Alice generates an invite: { „application/invite+json“ : { „conversationId“: „$id“, „members“: [{…}] }}
Zwei Möglichkeiten zum Versenden der Nachricht a. Wenn nicht verbunden, über die DHT b. Anders, Alice sendet auf dem SIP-Kanal
Zwei Möglichkeiten für Bob a. Erhält die Einladung, ein Signal wird für den Client b. Nicht verbunden, so wird nie die Anfrage erhalten, weil Alice nicht wissen muss, ob Bob einfach ignoriert oder blockiert Alice.
Prozess, um jemandem eine Nachricht zu senden
Alice will Bob eine Nachricht senden:
Alice fügt eine Nachricht in die Repo hinzu, gibt eine ID
Alice erhält eine Nachricht (von sich selbst) wenn sie erfolgreich ist
In beiden Fällen wird eine Nachricht erstellt: { „Application/im-gitmessage-id“ : „{„id“:“\(convId", "commit":"\)commitId“, „deviceId“: „$alice_device_hash“}“}. a. Wenn nicht verbunden ist, über den DHT b. Anders sendet Alice auf dem SIP-Kanal
Vier Möglichkeiten für Bob: a. Bob ist nicht mit Alice verbunden, also wenn er Alice vertraut, bitten Sie um eine neue Verbindung und gehen Sie zu b. b. Wenn verbunden, holen Sie von Alice und kündigen Sie neue Nachrichten an c. Bob kennt dieses Gespräch nicht. Bitten Sie über die DHT, um zuerst eine Einladung zu erhalten, um dieses Gespräch zu akzeptieren ({„Anwendung/Einladung“, GesprächId}) d. Bob ist getrennt (kein Netzwerk, oder einfach geschlossen). Er wird die neue Nachricht nicht erhalten, sondern versuchen, zu synchronisieren, wenn die nächste Verbindung auftritt
Durchführung
! [Diagramm: Schwarm-Chat-Klassen]
Supported messages
Initial message
{
"type": "initial",
"mode": 0,
"invited": "URI"
}
Represents the first commit of a repository and contains the mode:
enum class ConversationMode : int { ONE_TO_ONE = 0, ADMIN_INVITES_ONLY, INVITES_ONLY, PUBLIC }
and invited
if mode = 0.
Text message
{
"type": "text/plain",
"body": "content",
"react-to": "id (optional)"
}
Or for an edition:
{
"type": "application/edited-message",
"body": "content",
"edit": "id of the edited commit"
}
Anrufe
Show the end of a call (duration in milliseconds):
{
"type": "application/call-history+json",
"to": "URI",
"duration": "3000"
}
Or for hosting a call in a group (when it starts)
{
"type": "application/call-history+json",
"uri": "host URI",
"device": "device of the host",
"confId": "hosted confId"
}
A second commit with the same JSON + duration
is added at the end of the call when hosted.
Add a file
{
"type": "application/data-transfer+json",
"tid": "unique identifier of the file",
"displayName": "File name",
"totalSize": "3000",
"sha3sum": "a sha3 sum"
}
totalSize
is in bits,
Updating profile
{
"type": "application/update-profile",
}
Member event
{
"type": "member",
"uri": "member URI",
"action": "add/join/remove/ban"
}
When a member is invited, join or leave or is kicked from a conversation
Vote event
Generated by administrators to add a vote for kicking or un-kicking someone.
{
"type": "vote",
"uri": "member URI",
"action": "ban/unban"
}
!! Altes Entwurf!!
Bemerkung
Following notes are not organized yet. Just some line of thoughts.
Krypto-Verbesserungen.
Für eine ernsthafte Gruppen-Chat-Funktion brauchen wir auch ernsthafte Krypto. Wenn ein Zertifikat als die vorherigen DHT-Werte einer Konversation gestohlen wird, kann die Konversation entschlüsselt werden. Vielleicht müssen wir zu etwas wie Double Ratchet gehen.
Bemerkung
A lib might exist to implement group conversations.
ECC-Unterstützung in OpenDHT benötigt
Verwendung
Add Roles?
Es gibt zwei wichtige Anwendungsfälle für Gruppenchats:
Etwas wie ein Mattermost in einem Unternehmen, mit privaten Kanälen und einigen Rollen (Admin/Spectator/Bot/etc) oder für Bildung (wo nur wenige aktiv sind).
Horizontale Gespräche wie ein Gespräch zwischen Freunden.
Jami will be for which one?
Umsetzungsinterpretation
Ein Zertifikat für eine Gruppe, die Benutzer mit einer Flagge für eine Rolle unterschreiben.
Komm mit in ein Gespräch.
Nur über eine direkte Einladung
Über einen Link/QR-Code/was auch immer
Über einen Zimmernamen?
Was wir brauchen
Vertraulichkeit: Mitglieder außerhalb des Gruppenchats dürfen keine Nachrichten in der Gruppe lesen
Weiterhin geheim gehalten: Wenn ein Schlüssel der Gruppe gefährdet ist, sollten frühere Nachrichten vertraulich bleiben (soweit möglich)
Nachrichtenordnung: Nachrichten müssen in der richtigen Reihenfolge angeordnet werden
Synchronisierung: Es ist auch notwendig, sicherzustellen, dass alle Nachrichten so schnell wie möglich vorhanden sind.
Persistenz: Eigentlich ist eine Nachricht auf der DHT nur 10 Minuten lang. Weil es die beste Zeit ist, die für diese Art von DHT berechnet wird. Um Daten zu erhalten, muss der Knoten den Wert auf der DHT alle 10 Minuten neu setzen. Eine andere Möglichkeit, wenn der Knoten offline ist, ist es, Knoten die Daten neu zu setzen. Aber wenn nach 10 Minuten, 8 Knoten sind noch hier, werden sie 64 Anfragen machen (und es ist exponentiell). Der aktuelle Weg, Spamming zu vermeiden, ist abfragt. Dies wird immer noch 64 Anfragen tun, aber die maximale Redundanz auf 8 Knoten begrenzen.
Andere verteilte Wege
IPFS: Ich brauche eine Untersuchung.
Ich brauche eine Untersuchung.
Ich brauche eine Untersuchung.
Auf der Grundlage der aktuellen Arbeit, die wir haben
Gruppen-Chat kann auf der gleichen Arbeit basieren, die wir bereits für mehrere Geräte haben (aber hier mit einem Gruppenzertifikat).
Hier muss die Datenbank vom Client in den Daemon verschoben werden.
Wenn niemand mit dem Netzwerk verbunden ist, kann die Synchronisierung nicht durchgeführt werden, und die Person wird das Gespräch nie sehen
Ein weiterer spezieller DHT
Wie ein DHT mit einem Superbenutzer.
Dateifügelübertragung
Derzeit basiert der Dateitransferalgorithmus auf einer TURN-Verbindung (siehe Dateifügelübertragung). Bei einer großen Gruppe wird dies schlecht sein.
Ein anderes Problem: derzeit gibt es keine Implementierung von TCP-Unterstützung für ICE in PJSIP.
Ressourcen
Die Kommission hat die Kommission mit der Erteilung der Angabe der Kommission über die Durchführung der Verordnung (EG) Nr. 1271/2006 über die Verarbeitung von Informationen über die Verarbeitung von Daten zur Verfügung gestellt.
Robuste verteilte Synchronisierung vernetzter linearer Systeme mit intermittierender Information (Sean Phillips und Ricardo G. Sanfelice)