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:
Capacità di divisione e fusione in seguito alla connettività.
Qualsiasi persona deve essere in grado di inviare un messaggio a tutto il gruppo.
Nessuna autorità centrale, non si può affidarsi a nessun server.
I dispositivi devono essere in grado di verificare la validità dei vecchi messaggi e riprodurre l’intera storia.
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
Bob creates a local Git repository.
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`
Il hash del primo commento diventa l’ID della conversazione.
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
Alice aggiunge Bob al repo:
Aggiunge l’URI invitato in
/invited
Aggiunge la RLC a
/crls
Alice manda una richiesta sul DHT
Ricevere un invito
Alice gets the invite to join the previously create swarm
Lei accetta l’invito (se rifiuta, non fa nulla, rimarrà solo invitato e Alice non riceverà mai alcun messaggio)
Una connessione tra Alice e Bob è finita.
Alice pull the Git repo of Bob. WARNING this means that messages need a connection, not from the DHT like today.
Alice convalida i commenti di Bob
Per confermare che Alice è membro, rimuove l’invito dal directory
/invited
, quindi aggiunge il suo certificato nel directory/members
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
Bob do a Git pull on Alice
Gli impegni devono essere verificati con un gancio
Se tutti i commit sono validi, i commit vengono memorizzati e visualizzati.
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
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.
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.
Stampi temporali degli impegni generati
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.
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
Salvare in convInfos removed=time::now() (come removeContact salva nei contatti) che la conversazione viene rimossa e sincronizzata con i dispositivi di altri utenti
Ora, se viene ricevuto un nuovo impegno per questa conversazione viene ignorato
Se Jami e il repo sono ancora presenti, la conversazione non viene annunciata ai clienti.
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.
Quando siamo sicuri che qualcuno sia sincronizzato, rimuovi erased=time::now() e sincronizza con i dispositivi di altri utenti
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:
La TrustRequest inserisce un «conversationId» per informare il partner quale conversazione clonare quando accetta la richiesta
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.
Alice adds Bob.
Bob accepts.
Alice removes Bob.
Alice adds Bob.
o
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
Riimportazione di un conto (link/export)
L’archivio DEVE contenere conversationId per poter recuperare le conversazioni su nuovi commit dopo un re-import (perché non c’è invito a questo punto).
La conversazione è lì, in questo caso, il demone è in grado di riclonare questa conversazione
La conversazioneId è mancante, quindi il demone chiede (attraverso un messaggio
{{"applicazione/invita", conversazioneId}}
) un nuovo invito che l’utente deve (ri) accettare
Importante
A conversation can only be retrieved if a contact or another device is there, else it will be lost. There is no magic.
Protocolli utilizzati
Git
Perché questa scelta
Each conversation will be a Git repository. This choice is motivated by:
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.
Distribuito dalla natura, ampiamente utilizzato, un sacco di backend e pluggable.
Può verificare i compromessi tramite ganci e criptovalute utilizzate in massa
Può essere memorizzato in un database se necessario
I conflitti vengono evitati utilizzando messaggi commit, non file.
Cosa dobbiamo confermare
Performance?
git.lock
può essere bassoAnciame 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:
Alice aggiunge Bob a una conversazione
Alice generates an invite: { «application/invite+json» : { «conversationId»: «$id», «members»: [{…}] }}
Due possibilità per l’invio del messaggio a. Se non collegato, tramite il DHT b. Altrimenti, Alice invia sul canale SIP
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:
Alice aggiunge un messaggio nel repo, dando un documento
Alice riceve un messaggio (da lei stessa) se riesce
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
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:
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).
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).
Questo deve spostare il database dal client al demone.
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)