Caccia

Importante

Jami source code tends to use the terms (un)ban, while the user interface uses the terms (un)block.

Sospide

L’obiettivo di questo documento è quello di descrivere come le chat di gruppo (a.k.a. swarm chat) saranno implementate a Jami.

Un swarm è un gruppo in grado di discutere senza alcuna autorità centrale in modo resiliente. Infatti, se due persone non hanno alcuna connettività con il resto del gruppo (cioè interruzione di Internet), ma possono contattarsi (in una LAN per esempio o in una subnetwork), saranno in grado di inviare messaggi tra loro e poi, saranno in grado di sincronizzare con il resto del gruppo quando è possibile.

Quindi, la «swarm» è definita da:

  1. Capacità di divisione e fusione in seguito alla connettività.

  2. Qualsiasi persona deve essere in grado di inviare un messaggio a tutto il gruppo.

  3. Nessuna autorità centrale, non si può affidarsi a nessun server.

  4. I dispositivi devono essere in grado di verificare la validità dei vecchi messaggi e riprodurre l’intera storia.

  5. PFS sul trasporto.

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

Abbiamo identificato quattro modalità per lo chat swarm che vogliamo implementare:

  • ONE_TO_ONE, in pratica il caso che abbiamo oggi quando parli con un amico

  • ADMIN_INVITES_ONLY generalmente una classe in cui l’insegnante può invitare persone, ma non gli studenti

  • INVITES_ONLY un gruppo privato di amici

  • PUBLIC in sostanza un forum aperto

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 annuncia agli altri dispositivi che crea una nuova conversazione, che viene fatta tramite un invito a unirsi allo sciame inviato attraverso il DHT ad altri dispositivi collegati a quell’account.

Aggiungendo qualcuno

Alice adds Bob

  1. Alice aggiunge Bob al repo:

    • Aggiunge l’URI invitato in /invited

    • Aggiunge la RLC a /crls

  2. Alice manda una richiesta sul DHT

Ricevere un invito

Alice gets the invite to join the previously create swarm

  1. Lei accetta l’invito (se rifiuta, non fa nulla, rimarrà solo invitato e Alice non riceverà mai alcun messaggio)

  2. Una connessione tra Alice e Bob è finita.

  3. Alice pull the Git repo of Bob. WARNING this means that messages need a connection, not from the DHT like today.

  4. Alice convalida i commenti di Bob

  5. Per confermare che Alice è membro, rimuove l’invito dal directory /invited, quindi aggiunge il suo certificato nel directory /members

  6. Una volta che tutti i commenti sono stati validati e sul suo dispositivo, gli altri membri del gruppo sono scoperti da Alice. Con questi pari, costruirà il DRT (spiegato di seguito) con Bob come bootstrap.

Invio di un messaggio

Alice sends a message

Inviare un messaggio è abbastanza semplice. Alice scrive un messaggio di commit nel seguente formato:

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

Per pingare altri dispositivi, l’inviatore invia agli altri membri un messaggio SIP con mimetype = «applicazione/im-gitmessage-id» contenente un JSON con il «deviceId» che invia il messaggio, l“«id» della conversazione correlata e il «commit»

Ricevere un messaggio

Bob riceve il messaggio di Alice

  1. Bob do a Git pull on Alice

  2. Gli impegni devono essere verificati con un gancio

  3. Se tutti i commit sono validi, i commit vengono memorizzati e visualizzati.

  4. If all commits are not valid, pull is canceled. Alice must reestablish her state to a correct state.

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.

  • Per ogni commit, verificare che il dispositivo che tenta di inviare il commit sia autorizzato in questo momento e che i certificati siano presenti (nei/nei dispositivi del dispositivo e nei/i membri o/i amministratori dell’emittente).

  • Il commit ha due genitori, quindi è una fusione, non c’è altro da confermare qui

  • Il commit ha 0 genitori, è il commit iniziale:

    • Controllare che il certificato di amministrazione è aggiunto

    • Controllare che il certificato di dispositivo sia aggiunto

    • Controllo delle RRL aggiunte

    • Controllare che nessun altro file è stato aggiunto

  • Il commit ha 1 genitore, il messaggio commit è un JSON con un tipo:

    • Se testo (o altro tipo di mime che non cambia file)

      • Controllo della firma del certificato nel repo

      • Controllare che nessun file strano è aggiunto fuori certificato di dispositivo né rimosso

    • Se si vota

      • Controllare che voteType sia supportato (ban, unban)

      • Controlla che il voto sia per l’utente che firma il commit

      • Check that vote is from an admin and device present and not banned

      • Controllare che nessun file strano è stato aggiunto o rimosso

    • Se il membro

      • Se si aggiunge

        • Controllare che il commit sia corretto

        • Controllare che il certificato sia aggiunto in / invitato

        • Controllare che nessun file strano è stato aggiunto o rimosso

        • Se ONE_TO_ONE, controlla che abbiamo solo un amministratore, un membro

        • Se ADMIN_INVITES_ONLY, controllare che l’invito è da un amministratore

      • Se si unisce

        • Controllare che il commit sia corretto

        • Controllare che il dispositivo è aggiunto

        • Controllare che l” invito sia stato trasferito ai membri

        • Controllare che nessun file strano è stato aggiunto o rimosso

      • Se è vietato

        • Controlla che il voto sia valido

        • Controllare che l’utente è vietato tramite un amministratore

        • Controllare che il certificato di membro o dispositivo sia spostato al proibito/

        • Controllare che siano rimossi solo i file relativi al voto

        • Controllare che nessun file strano è stato aggiunto o rimosso

    • Avvisare l’utente che potrebbe essere con una versione vecchia o che il suo pari ha tentato di inviare commenti indesiderati

Interdire un dispositivo

Alice, Bob, Carla, Denys sono in uno sciame.

Questo è uno dei scenari più difficili del nostro contesto.

  1. Stampi temporali degli impegni generati

  2. Se ci sono più dispositivi di amministrazione e se Alice può parlare con Bob ma non con Denys e Carla; Carla può parlare con Denys; Denys vieta Alice, Alice vieta Denys, qual sarà lo stato quando i 4 membri si uniranno le conversazioni.

  3. Un dispositivo può essere compromesso, rubato o il suo certificato può scadere. Dovremmo essere in grado di vietare un dispositivo e evitare che mentisca sulla sua scadenza o inviare messaggi nel passato (modificando il certificato o il timestamp del suo impegno).

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.

Questo sistema di voto ha bisogno di un’azione umana per vietare qualcuno o deve basarsi sulle informazioni sulle RLC dal repository (perché non possiamo fidarci delle RLC esterne)

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 swarms

L’obiettivo è quello di mantenere l’antica API (addContact/removeContact, sendTrustRequest/acceptTrustRequest/discardTrustRequest) per generare uno sciame con un pari e il suo contatto.

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 questo caso, vengono generate due conversazioni. Non vogliamo rimuovere i messaggi dagli utenti o scegliere una conversazione qui. Quindi, a volte verranno mostrati due sciami 1:1 tra gli stessi membri. Genererà alcuni bug durante il tempo di transizione (come non vogliamo rompere API, la conversazione inferita sarà una delle due conversazioni mostrate, ma per ora è «ok-ish», sarà risolto quando i clienti gestiranno completamente la conversazione ID per tutte le API (chiamata, trasferimento di file, ecc.).

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: (opzionale)

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

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

Swarm modifica massicciamente il trasferimento di file. Ora, tutta la storia è sincronizzata, consentendo a tutti i dispositivi della conversazione di recuperare facilmente i file vecchi. Questi cambiamenti ci permettono di passare da una logica in cui il mittente ha spinto il file su altri dispositivi, attraverso il tentativo di connettersi ai loro dispositivi (Questo era male perché non era davvero resistente ai cambiamenti / errori di connessione e aveva bisogno di un nuovo tentativo manuale) a una logica in cui il mittente consente ad altri dispositivi di scaricare. Inoltre, qualsiasi dispositivo che abbia il file può essere l’host per altri dispositivi, consentendo di recuperare i file anche se il mittente non è lì.

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.

Chiama lo sciame

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:

  • Nel sciame di metadati, dove sono archiviati come il titolo/disc/avatar della stanza.

  • O l’appaltatore iniziale.

Quando si inizia una chiamata, l’host aggiunge un nuovo impegno allo sciame, con l’URI da unire (accountUri/deviceId/conversationId/confId). Questo sarà valido fino alla fine della chiamata (annunciato da un impegno con la durata da mostrare)

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.

Trasferimento di file

Attualmente, l’algoritmo di trasferimento di file si basa su una connessione TURN (vedi Trasferimento di file). Nel caso di un gruppo grande, questo sarà cattivo. Prima di tutto abbiamo bisogno di un implementato p2p per il trasferimento di file. Implementare l’RFC per il trasferimento p2p.

Altro problema: attualmente non esiste un supporto TCP per ICE in PJSIP. Questo è obbligatorio per questo punto (in pjsip o fatto in casa)

Risorse

  • Il sito web è stato pubblicato su www.eprint.iacr.org/2017/666.pdf

  • Robusta sincronizzazione distribuita di sistemi lineari in rete con informazioni intermittenti (Sean Phillips e Ricardo G.Sanfelice)