Σκάζες

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. Δεν υπάρχει κεντρική αρχή, δεν μπορεί να βασιστεί σε κανένα διακομιστή.

  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.

Η βασική ιδέα είναι να έχουμε ένα συγχρονισμένο δέντρο Merkle με τους συμμετέχοντες.

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

Σενάρια

Δημιουργήστε ένα Σπάρμ

Ο Μπομπ θέλει να δημιουργήσει ένα νέο σμήνος

  1. Bob creates a local Git repository.

  2. Στη συνέχεια, δημιουργεί μια αρχική υπογεγραμμένη δέσμευση με τα ακόλουθα:

    • Το δημόσιο κλειδί του σε /admins

    • Το πιστοποιητικό του συσκευής του σε ̀ / συσκευές

    • Η ΚΡΑ του είναι στο ̀ /crls`

  3. Το χασάι του πρώτου commit γίνεται το ID της συζήτησης

  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.

Προσθήκη κάποιου

Bob adds Alice

  1. Bob adds Alice to the repo:

    • Προσθέτει το καλεσμένο URI σε /invited

    • Προσθέτει την ΚΑΣ σε /crls

  2. Bob sends a request on the DHT.

Αποκλήση πρόσκλησης

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.

Στείλουμε μήνυμα

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

Σημείωση

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.

Αποκάλυψη μηνύματος

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.

Επαλήθευση της δέσμευσης

Για να αποφευχθεί η επιβολή κάποιων ανεπιθύμητων δεσμεύσεων από τους χρήστες (με συγκρούσεις, ψευδείς μηνύματα κλπ.), έτσι κάθε δεσμεύση (από την παλαιότερη έως την νεότερη) ΑΠΟΥΡΕΙ να επικυρωθεί πριν συγχωνευτεί ένα απομακρυσμένο κλάδο:

Σημείωση

  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.

Απαγορεύστε μια συσκευή

Σημαντικό

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.

Τα παρόμοια συστήματα (με διανεμημένα συστήματα ομάδων) δεν είναι τόσο πολλά, αλλά αυτά είναι μερικά παραδείγματα:

  • [Η MPOTR δεν ορίζει πώς να απαγορεύσεις κάποιον]

  • Το σήμα, χωρίς κεντρικό διακομιστή για ομαδική συνομιλία (EDIT: πρόσφατα άλλαξαν αυτό το σημείο), δεν δίνει τη δυνατότητα να απαγορεύσει κάποιος από μια ομάδα.

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

Αφαιρέστε μια συσκευή από μια συζήτηση

Αυτό είναι το μόνο μέρος που πρέπει να υπάρχει συναίνεση για να αποφευχθεί η διαίρεση της συζήτησης, όπως αν δύο μέλη κλωτσήσουν ο ένας τον άλλο από τη συζήτηση, τι θα δει το τρίτο;

Αυτό είναι απαραίτητο για να εντοπίσουμε ακυρωμένες συσκευές ή απλά να αποφύγουμε την παρουσία ανεπιθύμητων ανθρώπων σε δημόσιο χώρο.

Η “λις βγάζει τον Μπομπ

Σημαντικό

Alice MUST be an admin to vote.

  • Πρώτα, ψηφίζει για την απαγόρευση του Bob. Για να το κάνει αυτό, δημιουργεί το αρχείο σε /votes/ban/members/uri_bob/uri_alice (τα μέλη μπορούν να αντικατασταθούν από συσκευές για μια συσκευή, ή να καλούνται για προσκλήσεις ή διαχειριστές για διαχειριστές) και δεσμεύεται

  • Αυτό σημαίνει ότι >50% των διαχειριστών συμφωνούν να απαγορεύσουν τον Bob (αν είναι μόνη, είναι σίγουρο ότι είναι πάνω από 50%).

  • Εάν η ψηφοφορία επιλυθεί, τα αρχεία που είναι /votes/ban μπορούν να αφαιρεθούν, όλα τα αρχεία για τον Bob στα /members, /admins, /invited, /CRLs, /devices μπορούν να αφαιρεθούν (ή μόνο στα /devices αν είναι συσκευή που απαγορεύεται) και το πιστοποιητικό του Bob μπορεί να τοποθετηθεί στο /banned/members/bob_uri.crt (ή /banned/devices/uri.crt αν μια συσκευή απαγορεύεται) και να ανατεθεί στο repo

  • Στη συνέχεια, η Alice ενημερώνει τους άλλους χρήστες (εκτός από τον 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

  • Αυτό σημαίνει ότι >50% των διαχειριστών συμφωνούν να απαγορεύσουν τον Bob (αν είναι μόνη, είναι σίγουρο ότι είναι πάνω από 50%).

  • Εάν η ψηφοφορία επιλυθεί, τα αρχεία σε /votes/unban μπορούν να αφαιρεθούν, όλα τα αρχεία για τον Bob σε /members, /admins, /invited, /CRLs, μπορούν να προστεθούν ξανά (ή μόνο σε /devices αν είναι μια συσκευή που δεν απαγορεύεται) και να δεσμευτούν στην repo

Αποσύρουμε μια συζήτηση

  1. Αποθηκεύστε στο convInfos removed=time::now() (όπως αποθηκεύστεContact σε επαφές) ότι η συζήτηση αφαιρείται και συγχρονίζεται με τις συσκευές άλλων χρηστών

  2. Αν λάβει κανείς νέα ανακοίνωση για αυτή τη συζήτηση, αγνοείται.

  3. Αν η Τζάμι ξεκινά και η αναθεώρηση είναι ακόμα παρούσα, η συζήτηση δεν ανακοινώνεται στους πελάτες.

  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. Όταν είμαστε σίγουροι ότι κάποιος συγχρονίζεται, αφαιρέστε διαγράφηκε=time::now() και συγχρονίστε με τις συσκευές άλλων χρηστών

  6. Όλες οι συσκευές που ανήκουν στον χρήστη μπορούν τώρα να διαγράψουν το αποθετήριο και τα σχετικά αρχεία

Πώς να καθορίσετε τη λειτουργία

Οι λειτουργίες δεν μπορούν να αλλάξουν με την πάροδο του χρόνου. Ή είναι μια άλλη συζήτηση. Έτσι, αυτά τα δεδομένα αποθηκεύονται στο αρχικό μήνυμα δέσμευσης.

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

Για την ώρα, η «modality» δέχεται τιμές 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:

Η διαδικασία είναι ακόμα η ίδια, ένας λογαριασμός μπορεί να προσθέσει μια επαφή μέσω addContact, στη συνέχεια να στείλει μια αίτηση εμπιστοσύνης μέσω του DHT.

  1. Το TrustRequest ενσωματώνει ένα «conversationId» για να ενημερώσει τον συνάδελφο για ποια συζήτηση να κλωνοποιήσει όταν αποδεχτεί το αίτημα

  2. Το TrustRequest δοκιμάζεται ξανά όταν η επαφή επιστρέφει στο διαδίκτυο. Δεν είναι η περίπτωση σήμερα (όπως δεν θέλουμε να δημιουργήσουμε ένα νέο TrustRequest αν ο συνάδελφος απορρίψει το πρώτο).

Μετά, όταν ένας επαφές δέχεται το αίτημα, είναι απαραίτητη μια περίοδος συγχρονισμού, επειδή ο επαφές τώρα χρειάζεται να κλωνοποιήσει τη συζήτηση.

removeContact() θα αφαιρέσει την επαφή και τις σχετικές συζητήσεις 1:1 (με την ίδια διαδικασία με την «Αφαίρεση μιας συζήτησης»). Το μόνο σημείωμα εδώ είναι ότι αν απαγορεύσουμε μια επαφή, δεν περιμένουμε την συγχρονισμό, απλά αφαιρούμε όλα τα σχετικά αρχεία.

Δυσκολότερα σενάρια

Υπάρχουν ορισμένες περιπτώσεις όπου μπορεί να δημιουργηθούν δύο συζητήσεις.

  1. Alice adds Bob.

  2. Bob accepts.

  3. Alice removes Bob.

  4. Alice adds Bob.

ή

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

Σημαντικό

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() θα επιστρέψει {{«σύγχρονση»: «σωστό»}} εάν συγχρονιστεί.

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

Συζητήσεις ζητούν προδιαγραφή

Οι αιτήσεις συνομιλιών εκπροσωπούνται από ένα Map<String, String> με τα ακόλουθα κλειδιά:

  • id: the conversation ID

  • from: URI of the sender

  • Έκδοση: χρονοσημείο

  • τίτλος: (προαιρετικό) όνομα για τη συζήτηση

  • περιγραφή: (προαιρετική)

  • avatar: (optional) the profile picture

Συγχρονισμός προφίλ συνομιλίας

Για να είναι αναγνωρίσιμη, μια συζήτηση γενικά χρειάζεται κάποια μεταδεδομένα, όπως ένα τίτλο (π.χ. Jami), μια περιγραφή (π.χ. κάποια συνδέσμους, τι είναι το έργο, κλπ.), και μια εικόνα (το λογότυπο του έργου).

Αποθήκευση στο αποθετήριο

Το προφίλ της συζήτησης αποθηκεύεται σε κλασικό αρχείο vCard στη ρίζα (/profile.vcf) όπως:

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

Συγχρονισμός

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

Τελευταία Εμφάνιση

Σε κάθε συσκευή, η ανακοίνωση αυτή είναι η τελευταία που εμφανίζεται. Ωστόσο, επειδή κάθε συσκευή μπορεί να έχει τη δική της κατάσταση για κάθε συζήτηση και πιθανότατα χωρίς την ίδια τελευταία δέσμευση σε κάποιο σημείο, υπάρχουν διάφορα σενάρια που πρέπει να ληφθούν υπόψη:

Υποστηρίζονται πέντε σενάρια:

  • Αν η τελευταία εμφάνιση που αποστέλλεται από άλλες συσκευές είναι η ίδια με την τρέχουσα, δεν υπάρχει τίποτα να γίνει.

  • αν δεν υπάρχει τελευταία προβολή για την τρέχουσα συσκευή, χρησιμοποιείται το τηλεπροβληθέν μήνυμα.

  • Αν η τηλεχειρίνη που εμφανίστηκε τελευταία δεν είναι παρούσα στην αναφορά, σημαίνει ότι το commit θα ληφθεί αργότερα, οπότε cache το αποτέλεσμα

  • Αν το τηλεχειριστήριο έχει ήδη φέρει, ελέγξουμε ότι το τοπικό τελευταίο εμφανίζεται είναι πριν από την ιστορία για να το αντικαταστήσει

  • Τέλος, αν ανακοινωθεί ένα μήνυμα από τον ίδιο συγγραφέα, σημαίνει ότι πρέπει να ενημερώσουμε το τελευταίο που εμφανίστηκε.

Προτιμήσεις

Κάθε συζήτηση έχει προσαρτηθεί προτιμήσεις που ορίζονται από τον χρήστη. Αυτές οι προτιμήσεις συγχρονίζονται σε όλες τις συσκευές του χρήστη. Αυτό μπορεί να είναι το χρώμα της συζήτησης, εάν ο χρήστης θέλει να αγνοήσει ειδοποιήσεις, όριο μεγέθους μεταφοράς αρχείων, κλπ. Για το παρόν, τα αναγνωρισμένα κλειδιά είναι:

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

  • «αποκλείστε τις ειδοποιήσεις» - να αγνοήσετε τις ειδοποιήσεις για νέα μηνύματα σε αυτή τη συζήτηση

  • «σύμβολο» - για να καθορίσετε ένα προεπιλεγμένο emoji.

Οι προτιμήσεις αυτές αποθηκεύονται σε ένα πακέτο MapStringString, αποθηκεύονται στο accountDir/conversation_data/conversationId/preferences και διαβιβάζονται μόνο μεταξύ συσκευών του ίδιου χρήστη μέσω SyncMsg.

Η API για να αλληλεπιδρά με τις προτιμήσεις είναι:

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

Διαχείριση συγκρούσεων συγχώνευσης

Επειδή δύο διαχειριστές μπορούν να αλλάξουν την περιγραφή ταυτόχρονα, μπορεί να συμβεί σύγκρουση συγχώνευσης στο profile.vcf. Σε αυτή την περίπτωση, θα επιλεγεί το commit με το υψηλότερο hash (π.χ. ffffff > 000000).

Επικοινωνιακές μονάδες

Ο χρήστης έχει 2 μεθόδους για να πάρει και να ρυθμίσει τα μεταδεδομένα της συζήτησης:

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

όπου info είναι map<str, str> με τα ακόλουθα κλειδιά:

  • Τρόπος: Μόνο ανάγνωση

  • τίτλος

  • περιγραφή

  • avatar: the profile picture

Χρησιμοποιημένα πρωτόκολλα

Git

Γιατί αυτή η επιλογή

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

  1. Πρέπει να συγχρονίσουμε και να παραγγείλουμε μηνύματα. Το Merkle Tree είναι η τέλεια δομή για να το κάνουμε αυτό και μπορεί να γίνει γραμμισμένη με τη συγχώνευση των κλάδων. Επιπλέον, επειδή χρησιμοποιείται σε μαζική βάση από το Git, είναι εύκολο να συγχρονιστεί μεταξύ των συσκευών.

  2. Διανέμεται από τη φύση, χρησιμοποιείται σε μεγάλο βαθμό, έχει πολλά backend και είναι συνδεδετέα.

  3. Μπορεί να επαληθεύσει τις δεσμεύσεις μέσω χανκς και ευρέως χρησιμοποιούμενων κρυπτονομισμάτων

  4. Μπορεί να αποθηκευτεί σε βάση δεδομένων, εάν είναι απαραίτητο

  5. Οι συγκρούσεις αποφεύγονται χρησιμοποιώντας μηνύματα commit, όχι αρχεία.

Τι πρέπει να επιβεβαιώσουμε

  • Δοκιμασία: git.lock μπορεί να είναι χαμηλή

  • Κάντρα σε libgit2

  • Πολλαπλές τραβήξεις ταυτόχρονα;

Περιορισμοί

Για να διαγράψει μια συζήτηση, η συσκευή πρέπει να φύγει από τη συζήτηση και να δημιουργήσει μια άλλη.

Ωστόσο, μη μόνιμα μηνύματα (όπως μηνύματα που μπορούν να διαβάζονται μόνο για μερικά λεπτά) μπορούν να αποσταλούν μέσω ειδικού μηνύματος μέσω του DRT (όπως ειδοποιήσεις Τάπωσης ή Διαβάσεως).

Διαρθρωση

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

Μεταφορά αρχείων

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.

Πρωτοκόλλιο

Ο αποστολέας προσθέτει μια νέα δέσμευση στη συζήτηση με την ακόλουθη μορφή:

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

και δημιουργεί μια σύνδεση στο ${data_path}/conversation_data/${conversation_id}/${file_id} όπου file_id=${commitid}_${value["tide"]}.${extension}

Στη συνέχεια, ο δέκτης μπορεί τώρα να κατεβάσει τα αρχεία επικοινωνώντας με τις συσκευές που φιλοξενούν το αρχείο ανοίγοντας ένα κανάλι με name="data-transfer://" + conversationId + "/" + currentDeviceId() + "/" + fileId και αποθηκεύοντας τις πληροφορίες που περιμένει το αρχείο σε ${data_path}/conversation_data/${conversation_id}/waiting

Η συσκευή που λαμβάνει την σύνδεση θα αποδεχθεί το κανάλι επιβεβαιώνοντας εάν το αρχείο μπορεί να αποσταλεί (αν sha3sum είναι σωστό και αν υπάρχει αρχείο). Ο δέκτης θα κρατήσει το πρώτο ανοιχτό κανάλι, θα κλείσει τα υπόλοιπα και θα γράψει σε ένα αρχείο (με την ίδια διαδρομή με τον αποστολέα: ${data_path}/conversation_data/${conversation_id}/${file_id}) όλα τα εισερχόμενα δεδομένα.

Όταν η μεταφορά ολοκληρωθεί ή το κανάλι κλείσει, το sha3sum επαληθεύεται για να επικυρώσει ότι το αρχείο είναι σωστό (εάν δεν διαγραφεί).

Σε περίπτωση αποτυχίας, όταν μια συσκευή της συζήτησης θα είναι ξανά online, θα ζητήσουμε όλα τα αρχεία αναμονής με τον ίδιο τρόπο.

Call in Swarm

Ιδέα

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

«accountUri/deviceId/conversationId/confId» όπου ο λογαριασμόςUri/deviceId περιγράφει τον οικοδεσπότη.

Ο οικοδεσπότης μπορεί να προσδιοριστεί με δύο τρόπους:

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

  • Ή ο αρχικός καλεσμένος.

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)

Έτσι κάθε μέρος θα λάβει τις πληροφορίες ότι μια κλήση έχει ξεκινήσει και θα είναι σε θέση να συμμετάσχει σε αυτήν καλώντας την.

Επιθέσεις;

  • Avoid Git bombs

Σημειώσεις

Η χρονοσημίδα ενός commit μπορεί να εμπιστευτείται επειδή είναι επεξεργασόμενη. Μόνο η χρονοσημίδα του χρήστη μπορεί να εμπιστευτείται.

TLS

Οι λειτουργίες Git, τα μηνύματα ελέγχου, τα αρχεία και άλλα πράγματα θα χρησιμοποιούν μια p2p TLS v1.3 σύνδεση με μόνο κρυπτογραφίες που εγγυώνται PFS. Έτσι κάθε κλειδί αναδιαπραγματεύεται για κάθε νέα σύνδεση.

DHT (UDP)

Χρησιμοποιείται για την αποστολή μηνυμάτων για κινητά (για την ενεργοποίηση ειδοποιήσεων push) και για την έναρξη συνδέσεων TCP.

Δικτυακή δραστηριότητα

Η διαδικασία για να καλέσετε κάποιον

Η Άλις θέλει να καλέσει τον Μπομπ:

  1. Η Άλις προσθέτει τον Μπομπ σε μια συζήτηση

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

  3. Δύο δυνατότητες για την αποστολή του μηνύματος α. Αν δεν είναι συνδεδεμένο, μέσω του DHT b. Διαφορετικά, η Alice στέλνει στο κανάλι SIP

  4. Δύο πιθανότητες για τον Bob a. Λαμβάνει την πρόσκληση, ένα σήμα εκπέμπεται για τον πελάτη b. Δεν συνδέεται, έτσι δεν θα λάβει ποτέ την αίτηση, επειδή η Alice δεν πρέπει να ξέρει αν ο Bob απλά αγνοεί ή μπλοκάρει την Alice.

Η διαδικασία για να στείλετε μήνυμα σε κάποιον

Η Άλις θέλει να στείλει ένα μήνυμα στον Μπομπ:

  1. Η Άλις προσθέτει ένα μήνυμα στο repo, δίνοντας ταυτότητα

  2. Η Άλις λαμβάνει ένα μήνυμα (από την ίδια) αν επιτύχει

  3. Δύο πιθανότητες, η Alice και ο Bob είναι συνδεδεμένοι ή όχι. Σε και τις δύο περιπτώσεις δημιουργείται ένα μήνυμα: { «application/im-gitmessage-id» : «{«id»:»\(convId", "commit":"\)commitId», «deviceId»: «$alice_device_hash»}»}.

  4. Τέσσερις πιθανότητες για τον Bob: a. Ο Bob δεν συνδέεται με την Alice, οπότε αν εμπιστεύεται την Alice, ζητήστε μια νέα σύνδεση και πηγαίνετε στο b. b. Αν συνδέεται, πάρτε από την Alice και ανακοινώστε νέα μηνύματα c. Ο Bob δεν γνωρίζει αυτή τη συζήτηση. Ζητήστε μέσω του DHT να πάρετε μια πρόσκληση πρώτα για να μπορέσετε να δεχτείτε αυτή τη συζήτηση ({«εικείμενη αίτηση/προσκληση», συζήτησηId}) d. Ο Bob είναι αποσυνδεδεμένος (δεν υπάρχει δίκτυο, ή απλά κλειστό). Δεν θα λάβει το νέο μήνυμα αλλά θα προσπαθήσει να συγχρονιστεί όταν θα συμβεί η επόμενη σύνδεση

Εφαρμογή

! [Σχέδιο: μαθήματα συνομιλίας σμήνος]

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

Κλήσεις

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

!! Παλιά Σχέδιο!!

Σημείωση

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

Βελτιώσεις στα κρυπτογράφημα.

Για μια σοβαρή ομάδα κουτ λειτουργία, χρειαζόμαστε επίσης σοβαρό κρυπτογράφημα. Με το τρέχον σχεδιασμό, αν ένα πιστοποιητικό κλαπεί ως προηγούμενες τιμές DHT μιας συζήτησης, η συζήτηση μπορεί να αποκρυπτογραφηθεί. Ίσως πρέπει να πάμε σε κάτι σαν Double ratchet.

Σημείωση

A lib might exist to implement group conversations.

Χρειάζεται υποστήριξη ECC στο OpenDHT

Χρήση

Προσθέστε ρόλους;

Υπάρχουν δύο σημαντικές περιπτώσεις χρήσης για ομαδικές συνομιλίες:

  1. Κάτι σαν ένα Mattermost σε μια εταιρεία, με ιδιωτικούς κανάλους, και ορισμένους ρόλους (admin/spectator/bot/etc) ή για εκπαίδευση (όπου μόνο λίγοι είναι ενεργοί).

  2. Οριζόντια συνομιλίες σαν μια συνομιλία μεταξύ φίλων.

Jami will be for which one?

Ινδία υλοποίησης

Ένα πιστοποιητικό για μια ομάδα που υπογράφει χρήστη με σημαία για έναν ρόλο.

Συμπληρώστε μια συζήτηση

  • Μόνο μέσω άμεσης πρόσκλησης

  • Με σύνδεση/Κώδικα QR/ οτιδήποτε

  • Με όνομα δωματίου;

Αυτό που χρειαζόμαστε

  • Εμπιστευτικότητα: τα μέλη εκτός της ομαδικής συνομιλίας δεν πρέπει να μπορούν να διαβάζουν μηνύματα στην ομάδα

  • Προηγούμενη απόρρητη: εάν κάποιο κλειδί από την ομάδα διακυβευτεί, τα προηγούμενα μηνύματα θα πρέπει να παραμείνουν εμπιστευτικά (όσο περισσότερο γίνεται)

  • Τάξη μηνυμάτων: Είναι απαραίτητο να υπάρχουν μηνύματα με τη σωστή σειρά

  • Συγχρονισμός: Υπάρχει επίσης ανάγκη να βεβαιωθείτε ότι έχετε όλα τα μηνύματα το συντομότερο δυνατό.

  • Η επιμονή: Στην πραγματικότητα, ένα μήνυμα στο DHT διαρκεί μόνο 10 λεπτά. Επειδή είναι το καλύτερο χρονοδιάγραμμα που υπολογίζεται για αυτό το είδος DHT. Για να επιμείνουν τα δεδομένα, ο κόμβος πρέπει να επαναθέτει την τιμή στο DHT κάθε 10 λεπτά. Ένας άλλος τρόπος να γίνει όταν ο κόμβος είναι εκτός λειτουργίας είναι να αφήσει τους κόμβους να επαναθέσουν τα δεδομένα.

Άλλες διανεμημένες μεθόδους

  • Χρειάζεται κάποια έρευνα.

  • Χρειάζομαι κάποια έρευνα.

  • Χρειάζομαι κάποια έρευνα.

Με βάση την τρέχουσα εργασία που έχουμε

Το ομαδικό chat μπορεί να βασίζεται στο ίδιο έργο που έχουμε ήδη για πολυ-έργονα (αλλά εδώ, με ένα πιστοποιητικό ομάδας).

  1. Αυτό πρέπει να μεταφέρει την βάση δεδομένων από τον πελάτη στο δαίμονα.

  2. Αν κανείς δεν είναι συνδεδεμένος, η συγχρονισμός δεν μπορεί να γίνει, και το άτομο δεν θα δει ποτέ τη συζήτηση

Άλλο ένα ειδικό DHT

Σαν ένα DHT με έναν υπερωχνητή.

What’s next for file transfers

Currently, the file transfer algorithm is based on a TURN connection (See Μεταφορά αρχείων). 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)

Πηγές