Cârma
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.
Nu pot avea încredere în niciun server.
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.
Ideea principală este să obţinem un copac Merkle sincronizat cu participanţii.
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).
Scenariile
Creează o mulţime
Bob vrea să creeze un nou ciorp
Bob creates a local Git repository.
Apoi, el creează un angajament inițial semnat cu următoarele:
Cheia sa publică în
/admins
Certificatul de dispozitiv în ̀ /devices `
CRL-ul lui în ̀ /crls`
Hash-ul primului comit devine ID-ul conversației.
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.
Adăugarea cuiva
Bob adds Alice
Bob adds Alice to the repo:
Adăugă URI-ul invitat în
/invited
Adăugă RLC la
/crls
Bob sends a request on the DHT.
Primirea unei invitaţii
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.
Trimite un mesaj
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).
Notă
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.
Primirea unui mesaj
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.
Validarea unui angajament
Pentru a evita utilizatorii împingând unele comituri nedorite (cu conflicte, mesaje false, etc.), acesta este modul în care fiecare comit (de la cel mai vechi la cel mai recent) trebuie validat înainte de a fuziona o ramură de la distanță:
Notă
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.
Interzice un dispozitiv
Important
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.
Sistemele similare (cu sisteme de grup distribuite) nu sunt atât de multe, dar acestea sunt câteva exemple:
[mpOTR nu definește cum să interzici pe cineva]
Signal, fără niciun server central pentru chatul de grup (EDIT: recent au schimbat punctul), nu oferă posibilitatea de a interzice pe cineva dintr-un grup.
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).
Scoate un dispozitiv din conversaţie
Aceasta este singura parte care trebuie să aibă un consens pentru a evita spărgerea conversației, cum ar fi dacă doi membri se lovesc unul pe altul din conversație, ce va vedea al treilea?
Acest lucru este necesar pentru a detecta dispozitivele revocate sau pur și simplu pentru a evita prezența persoanelor nedorite într-o sală publică.
Alice removes Bob
Important
Alice MUST be an admin to vote.
Pentru a face acest lucru, ea creează fișierul în /votes/ban/members/uri_bob/uri_alice (membrii pot fi înlocuiți cu dispozitive pentru un dispozitiv, sau invitați pentru invitații sau admini pentru admini) și se angajează
Apoi verifică dacă votul este rezolvat. Aceasta înseamnă că > 50% dintre administratori sunt de acord să interzică Bob (dacă este singură, este sigur că este mai mult de 50%).
Dacă votul este rezolvat, fișierele în /votes/ban pot fi eliminate, toate fișierele pentru Bob în /membrii, /admins, /invited, /CRLs, /device pot fi eliminate (sau numai în /device dacă este un dispozitiv care este interzis) și certificatul Bob poate fi plasat în /banned/members/bob_uri.crt (sau /banned/devices/uri.crt dacă un dispozitiv este interzis) și angajat la repo
Apoi, Alice informează alți utilizatori (în afară de 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
Apoi verifică dacă votul este rezolvat. Aceasta înseamnă că > 50% dintre administratori sunt de acord să interzică Bob (dacă este singură, este sigur că este mai mult de 50%).
Dacă votul este rezolvat, fișierele în /votes/unban pot fi eliminate, toate fișierele pentru Bob în /membrii, /admins, /invitate, /CRLs, pot fi adăugate din nou (sau numai în /device dacă este un dispozitiv care este neinterzis) și angajate la repo
Îndepărtează o conversaţie
Salvați în convInfos remove=time::now() (cum ar fi removeContact salvează în contacte) că conversația este eliminată și sincronizată cu dispozitivele altor utilizatori
Dacă primim un nou angajament pentru această conversaţie, este ignorat.
Dacă Jami începe şi repo-ul este încă prezent, conversaţia nu este anunţată clienţilor.
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.
Când suntem siguri că cineva este sincronizat, eliminați șters=time::now() și sincronizați cu dispozitivele altor utilizatori
Toate dispozitivele deținute de utilizator pot șterge acum depozitul și fișierele conexe
Cum să specifici o modalitate
Modurile nu pot fi schimbate în timp. Sau este o altă conversație. Deci, aceste date sunt stocate în mesajul inițial de comit. Mesajul de comit va fi următorul:
{
"type": "initial",
"mode": 0,
}
Pentru moment, „modul” acceptă valori 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:
Procesul este tot la fel, un cont poate adăuga un contact prin addContact, apoi trimite o cerere de încredere prin DHT. Dar sunt necesare două schimbări:
TrustRequest include un „conversationId” pentru a informa peer-ul ce conversație să cloneze atunci când acceptă cererea
TrustRequest sunt retestate atunci când contactul revine online. Nu este cazul astăzi (pentru că nu vrem să generăm o nouă TrustRequest dacă colegul respinge prima). Deci, dacă un cont primește o cerere de încredere, va fi ignorat automat dacă cererea cu o conversație aferentă este respinsă (ca convRequests sunt sincronizate)
Apoi, când un contact acceptă cererea, este necesară o perioadă de sincronizare, deoarece contactul trebuie să cloneze conversația.
removeContact() va elimina contactul și conversațiile 1:1 aferente (cu același proces ca „Remove a conversation”). Singura notă aici este că dacă interzicem un contact, nu așteptăm sincronizarea, pur și simplu eliminăm toate fișierele aferente.
Scenarii complicate
Există unele cazuri în care se pot crea două conversații.
Alice adds Bob.
Bob accepts.
Alice removes Bob.
Alice adds Bob.
sau
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)).
Important
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() va întoarce {{„sincronizarea”: „adevărat”}} în cazul sincronizării.
ConfigurationManager::getConversationMembers() will return a map of two URIs (the current account and the peer who sent the request).
Conversaţiile cer specificaţii
Cererile de conversații sunt reprezentate de o Map<String, String> cu următoarele chei:
id: the conversation ID
from: URI of the sender
primită: timestamp
titlu: (opțional) nume pentru conversație
descriere: (opțional)
avatar: (optional) the profile picture
Sincronizarea profilului conversației
Pentru a fi identificabile, o conversație are nevoie de unele metadate, cum ar fi un titlu (de exemplu, Jami), o descriere (de exemplu, unele legături, care este proiectul, etc.), și o imagine (simbolul proiectului). Aceste metadate sînt opționale, dar sînt împărtășite între toți membrii, astfel încît trebuie să fie sincronizate și incorporate în cereri.
Stocare în depozit
Profilul conversației este stocat într-un fișier vCard clasic la rădăcina (/profile.vcf
) cum ar fi:
BEGIN:VCARD
VERSION:2.1
FN:TITLE
DESCRIPTION:DESC
END:VCARD
Sincronizare
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).
Ultima afişare
În datele sincronizate, fiecare dispozitiv trimite altor dispozitive starea conversațiilor. În această stare, ultima afișată este trimisă. Cu toate acestea, deoarece fiecare dispozitiv poate avea propriul stat pentru fiecare conversație, și probabil fără același ultim compromis la un moment dat, există mai multe scenarii de luat în considerare:
Se sprijină 5 scenarii:
Dacă ultima afișare trimisă de alte dispozitive este aceeași cu cea actuală, nu se poate face nimic.
dacă nu există ultima afișare pentru dispozitivul actual, se utilizează mesajul afișat la distanță.
Dacă ultima telecomanda afișată nu este prezentă în repo, înseamnă că commit-ul va fi recuperat mai târziu, astfel încât să cache rezultatul
Dacă telecomanda este deja recuperată, verificăm dacă ultima locală afișată este anterior în istorie pentru a o înlocui
În cele din urmă, dacă un mesaj este anunțat de la același autor, înseamnă că trebuie să actualizăm ultimul afișat.
Preferințe
Fiecare conversație are preferințe atașate stabilite de utilizator. Aceste preferințe sunt sincronizate pe dispozitivele utilizatorului. Aceasta poate fi culoarea conversației, dacă utilizatorul vrea să ignore notificările, limita de dimensiune a transferului de fișiere, etc. Pentru moment, cheile recunoscute sunt:
„color” - the color of the conversation (#RRGGBB format)
„ignore notificări” - să ignori notificările pentru mesaje noi în această conversație
„simbol” - pentru a defini un emoji de parapoartă.
Aceste preferințe sunt stocate într-un pachet MapStringString, stocate în accountDir/conversation_data/conversationId/preferințe
și trimise numai prin intermediul unui singur utilizator prin intermediul SyncMsg.
API-urile pentru a interacționa cu preferințele sunt:
// 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*/);
};
Gestionarea conflictelor de fuziune
Deoarece doi administratori pot modifica descrierea în același timp, un conflict de fuziune poate apărea pe profile.vcf
. În acest caz, va fi ales commit cu hash-ul mai mare (de exemplu ffffff > 000000).
API-uri
Utilizatorul a obținut 2 metode pentru a obține și setarea metadatele conversației:
<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>
unde infos
este o map<str, str>
cu următoarele cheie:
Modul: doar citit
titlu
descriere
avatar: the profile picture
Reimportarea contului (link/export)
Arhiva trebuie să conțină conversația ID pentru a putea recupera conversațiile pe noile comite după un reimport (pentru că nu există invitație la acest moment).
Conversaţia e acolo, în acest caz, demonul este capabil să cloneze din nou această conversaţie
Conversatia ID lipsește, deci daemonul cere (printr-un mesaj
{{"aplicație/invitare", conversatieId}}
) o nouă invitare pe care utilizatorul trebuie să o (re) accepte
Important
A conversation can only be retrieved if a contact or another device is there, else it will be lost. There is no magic.
Protocoluri utilizate
Git
De ce această alegere
Each conversation will be a Git repository. This choice is motivated by:
Merkel Tree este structura perfectă pentru a face acest lucru și poate fi linearizată prin fuziunea ramurilor.
Distribuit de natură, folosit în mod masiv, cu multe backend-uri şi plug-abile.
Pot verifica angajamentele prin croșii și criptomonede utilizate masiv
Poate fi stocat într-o bază de date dacă este necesar
Conflictele sunt evitate folosind mesaje de angajare, nu fișiere.
Ce trebuie să validăm
Performanţa?
git.lock
poate fi scăzutăCârliguri în libgit2
Multiple tragere în același timp?
Limite
Pentru a șterge o conversație, dispozitivul trebuie să părăsească conversația și să creeze alta.
Cu toate acestea, mesajele non-permanente (cum ar fi mesajele care pot fi citite doar pentru câteva minute) pot fi trimise printr-un mesaj special prin intermediul DRT (cum ar fi notificările de tipare sau de citire).
Structura
/
- 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
Transfer de fişiere
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.
Protocolul
Însă, în conversatie, trimiteul adaugă un nou angajament în următorul format:
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 creează un link în ${data_path}/conversation_data/${conversation_id}/${file_id}
unde file_id=${commitid}_${value["tid"]}.${extension}
Apoi, receptorul poate descărca acum fișierele contactând dispozitivele care găzduiesc fișierul prin deschiderea unui canal cu name="data-transfer://" + conversationId + "/" + currentDeviceId() + "/" + fileId
și stochează informațiile despre care fișierul așteaptă în ${data_path}/conversation_data/${conversation_id}/waiting
Dispozitivul care primește conexiunea va accepta canalul verificând dacă fișierul poate fi trimis (dacă sha3sum este corect și dacă există fișier). Receptorul va păstra primul canal deschis, va închide ceilalți și va scrie într-un fișier (cu aceeași cale ca expeditorul: ${data_path}/conversation_data/${conversation_id}/${file_id}
) toate datele de intrare.
Când transferul este finalizat sau canalul este închis, sha3sum este verificat pentru a valida că fișierul este corect (sau este șters).
În cazul eşecului, când un dispozitiv al conversaţiei va fi redat, vom cere toate fişierele de aşteptare în acelaşi mod.
Call in Swarm
Ideea
A swarm conversation can have multiple rendez-vous. A rendez-vous is defined by the following URI:
„accountUri/deviceId/conversationId/confId” unde accountUri/deviceId descrie gazda.
Oaspetele poate fi determinat prin două metode:
In the swarm metadatas. Where it’s stored like the title/desc/avatar (profile picture) of the room
Sau apelantul iniţial.
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)
Fiecare parte va primi informațiile că un apel a început și va putea să se alăture apelului.
Atacuri?
Avoid Git bombs
Notă
Timpul unui commit poate fi de încredere pentru că este editabil.
TLS
Operațiunile Git, mesajele de control, fișierele și alte lucruri vor folosi un link TLS v1.3 p2p cu numai cifre care garantează PFS.
DHT (UDP)
Utilizat pentru a trimite mesaje pentru telefoane mobile (push notificări) și pentru a iniția conexiuni TCP.
Activitate de rețea
Procesul de a invita pe cineva
Alice vrea să-l invite pe Bob:
Alice adaugă Bob la o conversaţie
Alice generates an invite: { „application/invite+json” : { „conversationId”: „$id”, „members”: [{…}] }}
Două posibilități de a trimite mesajul a. Dacă nu este conectat, prin DHT b. Altfel, Alice trimite pe canalul SIP
Bob a. Primeste invitația, un semnal este emis pentru clientul b. Nu este conectat, deci nu va primi niciodată cererea deoarece Alice nu trebuie să știe dacă Bob a ignorat sau a blocat Alice. Singura modalitate este de a regenera o nouă invitație printr-un mesaj nou (cf. următorul scenariu)
Procesul de a trimite un mesaj cuiva
Alice vrea să trimită un mesaj lui Bob:
Alice adaugă un mesaj în repo, oferind o identificare
Alice primeşte un mesaj primit (de la ea) dacă reuşeşte
În ambele cazuri se creează un mesaj: { „application/im-gitmessage-id” : „{„id”:”\(convId", "commit":"\)commitId”, „deviceId”: „$alice_device_hash”}”}. a. Dacă nu este conectat, prin DHT b. Altfel, Alice trimite pe canalul SIP
Bob nu este conectat la Alice, deci dacă are încredere în Alice, cere o nouă conexiune și merge la b. b. Dacă este conectat, ia-l de la Alice și anunță noi mesaje c. Bob nu știe conversația.
Implementare
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.
Mesaj text
{
"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"
}
Apeluri
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"
}
!! JOCĂTĂ BĂRĂ!!
Notă
Following notes are not organized yet. Just some line of thoughts.
Îmbunătăţiri criptografice.
Pentru o funcție de chat de grup serios, avem nevoie de criptografie serioasă. Cu designul actual, dacă un certificat este furat ca valorile DHT anterioare ale unei conversații, conversația poate fi decriptată. Poate că trebuie să mergem la ceva ca ** Double ratchet**.
Notă
A lib might exist to implement group conversations.
Are nevoie de sprijin ECC în OpenDHT
Utilizarea
Să adaugăm roluri?
Există două cazuri de utilizare majore pentru discuțiile de grup:
Ceva de genul Mattermost într-o companie, cu canale private, și unele roluri (admin/spectator/bot/etc) sau pentru educație (unde doar câțiva sunt activi).
Conversaţii orizontale, ca o conversaţie între prieteni.
Jami will be for which one?
Ideea de implementare
Certificat pentru un grup care semnează utilizatorul cu un steag pentru un rol.
Urmăreşte o conversaţie
Doar prin invitaţie directă
Printr-un link/Codul QR/ceea ce
Via a room name? (a hash on the DHT)
Ceea ce avem nevoie
Confidențialitate: membrii din afara grupului de chat nu ar trebui să poată citi mesajele din grup
Secretul de către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către către
Ordonanţa mesajelor: Este necesar să fie mesajele în ordinea corectă
Sincronizare: Este necesar să se asigure că toate mesajele sunt disponibile cât mai curând posibil.
Persistența: De fapt, un mesaj pe DHT trăiește doar 10 minute. Pentru că este cel mai bun timp calculat pentru acest tip de DHT. Pentru a persista datele, nodul trebuie să reinsereze valoarea pe DHT la fiecare 10 minute. Un alt mod de a face când nodul este offline este să lase nodurile să reinsereze datele. Dar, dacă după 10 minute, 8 noduri sunt încă aici, vor face 64 de cereri (și este exponențial). Modul actual de a evita spamming pentru asta este consultat. Acest lucru va face încă 64 de cereri, dar va limita redundanța maximă la 8 noduri.
Alte modalități distribuite
IPFS: Trebuie să se facă nişte investigaţii
Am nevoie de o investigaţie.
Am nevoie de o investigaţie.
Pe baza lucrărilor actuale pe care le avem
Chatul de grup poate fi bazat pe aceeași muncă pe care o avem deja pentru mai multe dispozitive (dar aici, cu un certificat de grup).
Acest lucru trebuie să mute baza de date de la client în daemon.
Dacă nimeni nu este conectat, sincronizarea nu poate fi făcută, iar persoana nu va vedea conversația niciodată
Un alt DHT dedicat
Ca un DHT cu un super utilizator.
What’s next for file transfers
Currently, the file transfer algorithm is based on a TURN connection (See Transfer de fişiere). In the case of a big group, this will be bad. We first need a P2P connection for the file transfer. Implement the RFC for P2P transfer.
Other problem: currently there is no implementation for TCP support for ICE in PJSIP. This is mandatory for this point (in PJSIP or homemade)