Caccia

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. Nessuna autorità centrale, non si può affidarsi a nessun server.

  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.

L’idea principale è di ottenere un albero di Merkle sincronizzato con i partecipanti.

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

Sceni

Crea un gruppo

Bob wants to create a new swarm

  1. Bob creates a local Git repository.

  2. Poi, crea un primo impegno firmato con quanto segue:

    • La sua chiave pubblica in /admins

    • Il certificato di dispositivo in ̀ /dispositivi `

    • Il suo RLC in ̀ /crls`

  3. Il hash del primo commento diventa l’ID della conversazione.

  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.

Aggiungendo qualcuno

Bob adds Alice

  1. Bob adds Alice to the repo:

    • Aggiunge l’URI invitato in /invited

    • Aggiunge la RLC a /crls

  2. Bob sends a request on the DHT.

Ricevere un invito

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.

Invio di un messaggio

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

Nota

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.

Ricevere un messaggio

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.

Convalida di un impegno

Per evitare che gli utenti spingano alcuni commit indesiderati (con conflitti, messaggi falsi, ecc.), è così che ogni commit (dal più antico al più recente) DEVE essere convalidato prima di unire una branca remota:

Nota

  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.

Interdire un dispositivo

Importante

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.

I sistemi simili (con sistemi di gruppo distribuiti) non sono così tanti, ma questi sono alcuni esempi:

  • [mpOTR non definisce come vietare qualcuno]

  • Signal, senza alcun server centrale per la chat di gruppo (EDIT: hanno recentemente cambiato questo punto), non dà la possibilità di vietare qualcuno da un gruppo.

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

Togliere un dispositivo da una conversazione

Questa è l’unica parte che deve avere un consenso per evitare la divisione della conversazione, come se due membri si calciano l’uno dall’altro dalla conversazione, cosa vedrà la terza?

Questo è necessario per rilevare dispositivi revocati, o semplicemente evitare di ottenere persone indesiderate presenti in una sala pubblica.

Alice removes Bob

Importante

Alice MUST be an admin to vote.

  • Per farlo, crea il file in /votes/ban/members/uri_bob/uri_alice (i membri possono essere sostituiti da dispositivi per un dispositivo, o invitati per inviti o amministratori per amministratori) e impegna

  • Quindi controlla se il voto è risolto. Ciò significa che >50% degli amministratori accetta di vietare Bob (se è sola, è certo che è più del 50%).

  • Se il voto è risolto, i file in /votes/ban possono essere rimossi, tutti i file per Bob in /members, /admins, /invited, /CRL, /devices possono essere rimossi (o solo in /devices se si tratta di un dispositivo che è vietato) e il certificato di Bob può essere inserito in /banned/members/bob_uri.crt (o /banned/devices/uri.crt se un dispositivo è vietato) e impegnato al repo

  • Poi, Alice informa gli altri utenti (fuori di 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

  • Quindi controlla se il voto è risolto. Ciò significa che >50% degli amministratori accetta di vietare Bob (se è sola, è certo che è più del 50%).

  • Se il voto è risolto, i file in /votes/unban possono essere rimossi, tutti i file per Bob in /members, /admins, /invited, /CRL, possono essere riaggiunti (o solo in /devices se si tratta di un dispositivo che non è vietato) e impegnati al repo

Elimina una conversazione

  1. Salvare in convInfos removed=time::now() (come removeContact salva nei contatti) che la conversazione viene rimossa e sincronizzata con i dispositivi di altri utenti

  2. Ora, se viene ricevuto un nuovo impegno per questa conversazione viene ignorato

  3. Se Jami e il repo sono ancora presenti, la conversazione non viene annunciata ai clienti.

  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. Quando siamo sicuri che qualcuno sia sincronizzato, rimuovi erased=time::now() e sincronizza con i dispositivi di altri utenti

  6. Tutti i dispositivi di proprietà dell’utente possono ora cancellare il repository e i file correlati

Come specificare una modalità

I modi non possono essere cambiati nel tempo. O è un’altra conversazione. Quindi, questi dati vengono memorizzati nel messaggio iniziale di commit.

{
    "type": "initial",
    "mode": 0,
}

Per ora, «mode» accetta 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:

Il processo è ancora lo stesso, un account può aggiungere un contatto tramite addContact, quindi inviare una richiesta di fiducia tramite il DHT. Ma due modifiche sono necessarie:

  1. La TrustRequest inserisce un «conversationId» per informare il partner quale conversazione clonare quando accetta la richiesta

  2. TrustRequest viene riprovato quando il contatto torna online. Non è il caso oggi (come non vogliamo generare una nuova TrustRequest se il pari scarica il primo). Quindi, se un account riceve una richiesta di fiducia, verrà ignorato automaticamente se la richiesta con una conversazione correlata viene rifiutata (come convRequests sono sincronizzati)

Poi, quando un contatto accetta la richiesta, è necessario un periodo di sincronizzazione, perché il contatto ora deve clonare la conversazione.

removeContact() rimuoverà il contatto e le conversazioni 1:1 correlate (con lo stesso processo di «Remove a conversation»).

Scenari complicati

Ci sono alcuni casi in cui si possono creare due conversazioni.

  1. Alice adds Bob.

  2. Bob accepts.

  3. Alice removes Bob.

  4. Alice adds Bob.

o

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

Importante

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() restituirà {{«sincronizzazione»: «verità»}} se si sincronizza.

  • ConfigurationManager::getConversationMembers() will return a map of two URIs (the current account and the peer who sent the request).

Conversazioni richiede specifica

Le richieste di conversazione sono rappresentate da una Map<String, String> con le seguenti tasti:

  • id: the conversation ID

  • from: URI of the sender

  • ricevuta: timestamp

  • titolo: nome (opzionale) della conversazione

  • descrizione: (opzionale)

  • avatar: (optional) the profile picture

Sincronizzazione del profilo della conversazione

Per essere identificabili, una conversazione ha generalmente bisogno di alcuni metadati, come un titolo (ad esempio: Jami), una descrizione (ad esempio: alcuni link, quale è il progetto, ecc.), e un’immagine (il logo del progetto).

Storage nel deposito

Il profilo della conversazione è memorizzato in un classico file vCard alla radice (/profile.vcf) come:

BEGIN:VCARD
VERSION:2.1
FN:TITLE
DESCRIPTION:DESC
END:VCARD

Sincronizzazione

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

Ultimo visualizzazione

Nei dati sincronizzati, ogni dispositivo invia agli altri dispositivi lo stato delle conversazioni. In questo stato, viene inviato l’ultimo visualizzato. Tuttavia, poiché ogni dispositivo può avere il suo stato per ogni conversazione, e probabilmente senza lo stesso ultimo impegno in qualche momento, ci sono diversi scenari da tenere conto:

Sono supportati 5 scenari:

  • se l’ultimo display inviato da altri dispositivi è lo stesso di quello attuale, non c’è nulla da fare.

  • se non è stato visualizzato l’ultimo per il dispositivo corrente, viene utilizzato il messaggio visualizzato a distanza.

  • se l’ultimo telecomando visualizzato non è presente nella repo, significa che il commit verrà recuperato in seguito, quindi cache il risultato

  • se il telecomando è già stato recuperato, controlliamo che l’ultimo locale visualizzato sia prima nella storia per sostituirlo

  • Infine, se viene annunciato un messaggio dello stesso autore, significa che dobbiamo aggiornare l’ultimo visualizzato.

Preferenze

Ogni conversazione ha allegato le preferenze impostate dall’utente. Queste preferenze sono sincronizzate tra i dispositivi dell’utente. Questo può essere il colore della conversazione, se l’utente vuole ignorare le notifiche, il limite di dimensione del trasferimento di file, ecc. Per ora, le chiavi riconosciute sono:

  • «color» - the color of the conversation (#RRGGBB format)

  • «ignoreNotifications» - ignorare le notifiche per i nuovi messaggi in questa conversazione

  • «simbolo» - per definire un emoji predefinito.

Queste preferenze sono memorizzate in un pacchetto MapStringString, memorizzato in accountDir/conversation_data/conversationId/preferences e inviate solo tra i dispositivi dello stesso utente tramite SyncMsg.

L’API per interagire con le preferenze è:

// 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*/);
};

Gestione dei conflitti di fusione

Poiché due amministratori possono modificare la descrizione allo stesso tempo, può verificarsi un conflitto di fusione su profile.vcf. In questo caso, verrà scelto il commit con il hash più alto (ad es. ffffff > 000000).

API

L’utente ha ottenuto 2 metodi per ottenere e impostare i metadati della conversazione:

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

dove infos è una map<str, str> con le seguenti chiavi:

  • modalità: solo lettura

  • titolo

  • descrizione

  • avatar: the profile picture

Protocolli utilizzati

Git

Perché questa scelta

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

  1. Merkel Tree è la struttura perfetta per farlo e può essere linearizzata dalla fusione di rami. Inoltre, poiché è ampiamente utilizzato da Git, è facile sincronizzare tra dispositivi.

  2. Distribuito dalla natura, ampiamente utilizzato, un sacco di backend e pluggable.

  3. Può verificare i compromessi tramite ganci e criptovalute utilizzate in massa

  4. Può essere memorizzato in un database se necessario

  5. I conflitti vengono evitati utilizzando messaggi commit, non file.

Cosa dobbiamo confermare

  • Performance? git.lock può essere basso

  • Anciame in libgit2

  • Multiple pulls at the same time?

Limiti

Per eliminare una conversazione, il dispositivo deve lasciare la conversazione e crearne un’altra.

Tuttavia, i messaggi non permanenti (come i messaggi leggibili solo per alcuni minuti) possono essere inviati tramite un messaggio speciale tramite il DRT (come le notifiche di digitazione o lettura).

Struttura

/
 - 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

Trasferimento di file

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.

Protocollo

Il mittente aggiunge un nuovo commit alla conversazione con il seguente formato:

value["tid"] = "RANDOMID";
value["displayName"] = "DISPLAYNAME";
value["totalSize"] = "SIZE OF THE FILE";
value["sha3sum"] = "SHA3SUM OF THE FILE";
value["type"] = "application/data-transfer+json";

e crea un link in ${data_path}/conversation_data/${conversation_id}/${file_id} dove file_id=${commitid}_${value["tide"]}.${extension}

Quindi, il ricevitore può ora scaricare i file contattando i dispositivi che ospitano il file aprendo un canale con name="data-transfer://" + conversationId + "/" + currentDeviceId() + "/" + fileId e memorizzare le informazioni che il file sta aspettando in ${data_path}/conversation_data/${conversation_id}/waiting

Il dispositivo che riceve la connessione accetta il canale verificando se il file può essere inviato (se sha3sum è corretto e se il file esiste). Il ricevitore manterrà il primo canale aperto, chiuderà gli altri e scriverà in un file (con lo stesso percorso del mittente: ${data_path}/conversation_data/${conversation_id}/${file_id}) tutti i dati in arrivo.

Quando il trasferimento è finito o il canale chiuso, la sha3sum viene verificata per verificare che il file è corretto (o è stato eliminato).

In caso di fallimento, quando un dispositivo della conversazione sarà di nuovo online, chiederemo tutti i file in attesa nello stesso modo.

Call in Swarm

L’idea

A swarm conversation can have multiple rendez-vous. A rendez-vous is defined by the following URI:

«accountUri/deviceId/conversationId/confId» dove accountUri/deviceId descrive l’host.

L’ospite può essere determinato in due modi:

  • In the swarm metadatas. Where it’s stored like the title/desc/avatar (profile picture) of the room

  • O l’appaltatore iniziale.

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)

Quindi ogni parte riceverà l’informazione che una chiamata è iniziata e sarà in grado di unirsi a essa chiamando.

Attacks?

  • Avoid Git bombs

Nota

Il timestamp di un commit può essere affidabile perché è modificabile. Solo il timestamp dell’utente può essere affidabile.

TLS

Le operazioni Git, i messaggi di controllo, i file e altre cose utilizzeranno un collegamento TLS v1.3 p2p con solo le cifre che garantiscono PFS. Quindi ogni chiave viene rinegoziata per ogni nuova connessione.

DHT (UDP)

Utilizzato per inviare messaggi per cellulari (per attivare notifiche push) e per avviare connessioni TCP.

Attività di rete

Processo di invito a qualcuno

Alice vuole invitare Bob:

  1. Alice aggiunge Bob a una conversazione

  2. Alice generates an invite: { «application/invite+json» : { «conversationId»: «$id», «members»: [{…}] }}

  3. Due possibilità per l’invio del messaggio a. Se non collegato, tramite il DHT b. Altrimenti, Alice invia sul canale SIP

  4. Due possibilità per Bob a. Riceve l’invito, viene emesso un segnale per il cliente b. Non è connesso, quindi non riceverà mai la richiesta perché Alice non deve sapere se Bob ha semplicemente ignorato o bloccato Alice.

Processo per inviare un messaggio a qualcuno

Alice vuole mandare un messaggio a Bob:

  1. Alice aggiunge un messaggio nel repo, dando un documento

  2. Alice riceve un messaggio (da lei stessa) se riesce

  3. In entrambi i casi viene creato un messaggio: { «applicazione/im-gitmessage-id» : «{«id»:»\(convId", "commit":"\)commitId», «deviceId»: «$alice_device_hash»}»}. a. Se non è collegato, tramite il DHT b. Altrimenti, Alice invia sul canale SIP

  4. Bob non è connesso ad Alice, quindi se si fida di lui, chieda una nuova connessione e vai a b. b. Se è connesso, prendi da Alice e annuncia nuovi messaggi c. Bob non conosce quella conversazione. Chiedi attraverso il DHT di ottenere un invito prima di poter accettare quella conversazione ({«applicazione/invito», conversazioneId}) d. Bob è disconnesso (nessuna rete, o semplicemente chiuso). Non riceverà il nuovo messaggio ma cercherà di sincronizzare quando si verificherà la prossima connessione

Attuazione

! [Diagramma: lezioni di chat di sciame]

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"
}

Chiamate

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"
}

!! OLD DRAFT!!

Nota

Following notes are not organized yet. Just some line of thoughts.

Miglioramenti delle criptovalute.

Per una funzione di chat di gruppo seria, abbiamo anche bisogno di criptovalute serie. Con il design attuale, se un certificato viene rubato come i valori DHT precedenti di una conversazione, la conversazione può essere decrittografata. Forse dobbiamo andare a qualcosa come Double ratchet.

Nota

A lib might exist to implement group conversations.

Necessità di sostegno ECC in OpenDHT

Utilizzamento

Aggiungere ruoli?

Ci sono due principali casi di utilizzo per le chiacchiere di gruppo:

  1. Qualcosa come un Mattermost in un’azienda, con canali privati, e alcuni ruoli (admin/spectator/bot/etc) o per l’istruzione (dove solo pochi sono attivi).

  2. Conversazioni orizzontali come una conversazione tra amici.

Jami will be for which one?

Idea di attuazione

Certificato per un gruppo che firma un utente con una bandiera per un ruolo.

Partecipa a una conversazione

  • Solo con un invito diretto

  • Per via di un link/QR Code/qualunque

  • Via a room name? (a hash on the DHT)

Cosa ci serve

  • Confidenzialità: i membri al di fuori della chat di gruppo non dovrebbero poter leggere i messaggi nel gruppo

  • Segretezza: se una chiave del gruppo è compromessa, i messaggi precedenti dovrebbero rimanere confidenziali (qualora possibile)

  • Ordinazione dei messaggi: è necessario avere i messaggi nell’ordine giusto

  • Sincronizzazione: occorre anche assicurarsi di avere tutti i messaggi il prima possibile.

  • Persistenza: in realtà, un messaggio sul DHT dura solo 10 minuti. Perché è il momento migliore calcolato per questo tipo di DHT. Per persistere i dati, il nodo deve riimpostare il valore sul DHT ogni 10 minuti. Un altro modo per farlo quando il nodo è offline è lasciare che i nodi riimpostino i dati. Ma, se dopo 10 minuti, 8 nodi sono ancora qui, faranno 64 richieste (e è esponenziale).

Altri modi distribuiti

  • IPFS: Need some investigation

  • Ho bisogno di un’indagine.

  • Ho bisogno di un’indagine.

In base al lavoro attuale che abbiamo

Il chat di gruppo può basarsi sullo stesso lavoro che abbiamo già per i dispositivi multi-dispositivi (ma qui, con un certificato di gruppo).

  1. Questo deve spostare il database dal client al demone.

  2. Se nessuno è connesso, la sincronizzazione non può essere fatta, e la persona non vedrà mai la conversazione

Un altro DHT dedicato

Come un DHT con un superutente.

What’s next for file transfers

Currently, the file transfer algorithm is based on a TURN connection (See Trasferimento di file). 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)

Risorse