Erstellen Sie einen verschlüsselten End-to-End-Chat mit Seald und PubNub
Published: 2024-03-18 08:07:59

> **Dieser Artikel wurde von einem Dritten,** [**seald**](https://www.seald.io/)**,** **beigesteuert** **und stellt eine Alternative zu PubNubs eingebauter** [**Verschlüsselung auf Nachrichtenebene**](https://www.pubnub.com/docs/general/setup/data-security#message-encryption) vor**.** **Er wurde ursprünglich auf** [**Hackernoon**](https://hackernoon.com/how-to-build-an-end-to-end-encrypted-chat-with-seald-and-pubnub) **veröffentlicht** **.**

* * *

Heute wollen wir herausfinden, **wie man einen**[**Ende-zu-Ende-verschlüsselten**](https://hackernoon.com/a-cryptographers-guide-to-end-to-end-encryption?ref=hackernoon.com) **Chat** mit **Pubnub** und dem **seald SDK** **erstellen** kann **.**

Ein voll funktionsfähiges Beispiel für die Verwendung von PubNub und Seald finden Sie hier: https: [//github.com/seald/pubnub-example-project](https://github.com/seald/pubnub-example-project?ref=hackernoon.com)

**Was ist Pubnub?**

PubNub ist ein [Echtzeit-Kommunikationsdienst](https://www.pubnub.com/solutions/data-streaming/), der in die meisten Anwendungen integriert werden kann. Er ist zuverlässig und skalierbar und kann leicht in die gängigsten Frameworks integriert werden.

**Was ist Seald?**

Seald.io bietet ein SDK, mit dem Sie **ohne kryptografische Vorkenntnisse** eine **Ende-zu-Ende-Verschlüsselung** mit fortgeschrittenen Verwaltungsfunktionen durchführen können **.** Dieses SDK kann in Web-, Backend-, Mobil- oder Desktop-Anwendungen integriert werden.

Überblick über den Inhalt
-------------------------

-   Warum Ende-zu-Ende-Verschlüsselung?
    
-   Warum Seald.io anstelle des PubNub-Verschlüsselungshakens verwenden?👀
    
-   Ziele 🏆
    
-   Implementierung 🧠
    
-   Hinzufügen von Ende-zu-Ende-Verschlüsselung mit Seald 🔒💬
    
-   Schlussfolgerung ✅
    

**Warum sollte man eine Ende-zu-Ende-Verschlüsselung verwenden? 🔒**
--------------------------------------------------------------------

Die Ende-zu-Ende-Verschlüsselung bietet **das höchste Maß an Datenschutz und Sicherheit.** Sie ermöglicht die Verschlüsselung sensibler Daten, sobald sie erfasst werden. Durch eine frühzeitige Verschlüsselung wird die Angriffsfläche Ihrer Anwendung verringert. Ein weiterer Vorteil ist, dass Sie genau **steuern können, wer auf die Daten zugreifen darf.** Dies schützt auch dann, wenn sie nicht in Ihren Zuständigkeitsbereich fallen, **z. B. bei Diensten Dritter.**

Mit der Ende-zu-Ende-Verschlüsselung behalten Sie jederzeit die **Kontrolle,** wenn Ihre Daten übertragen werden, wenn sie ruhen und sogar, wenn Sie sie nicht in der Hand haben. Damit bietet sie einen weitaus umfassenderen Schutz als andere Verschlüsselungstechnologien (TLS, Festplattenverschlüsselung, ...).

Wann immer Sie mit einem Fall [**konfrontiert**](https://hackernoon.com/60-stories-to-learn-about-compliance?ref=hackernoon.com) sind, in dem die [**Einhaltung von Vorschriften**](https://hackernoon.com/60-stories-to-learn-about-compliance?ref=hackernoon.com) **wichtig ist** (GDPR, HIPAA, SOC-2,...) oder Sie **sensible Daten** haben (Medizin, Verteidigung,...), ist eine Ende-zu-Ende-Verschlüsselung ein Muss. Aber auch für alltäglichere Daten ist sie eine gute Praxis. Eine Datenpanne ist ein verheerendes Ereignis, das immer häufiger vorkommt **.**

**Warum Seald.io anstelle des PubNub-Verschlüsselungshakens verwenden? 👀**
---------------------------------------------------------------------------

PubNub SDK bietet einen einfachen Verschlüsselungshaken, der bei der Instanziierung des SDK das Argument `cipherKey` verwendet. Damit wird sichergestellt, dass alle hochgeladenen Nachrichten verschlüsselt werden **, bevor sie gesendet werden.** Allerdings müssen Sie die Schlüsselverwaltung selbst übernehmen.

Schwachstellen entstehen nur selten durch die Verschlüsselung selbst, sondern meistens **dadurch, dass die Schlüssel** durch Schwachstellen im Sicherheitsmodell nach außen dringen.

**Seald**.io bietet ein robustes, **von der ANSSI zertifiziertes** Sicherheitsmodell mit Echtzeit-Zugriffskontrolle, Benutzerwiderruf und -wiederherstellung, 2FA und mehr.

**Ziele 🏆**
------------

Dieser Artikel erklärt **Schritt für Schritt**, wie man Seald mit PubNub integriert **,** um den Chat mit Ende-zu-Ende-Verschlüsselung zu sichern. Wir werden **eine Beispiel-Messaging-App mit** den folgenden Funktionen erstellen:

-   Einzel- und Gruppen-Chaträume.
    
-   Jedes Mitglied hat einen eigenen Chatraum mit jedem anderen Benutzer.
    
-   Jeder kann einen Gruppen-Chatraum mit mehreren anderen Benutzern erstellen.
    
-   Verwendung von Ende-zu-Ende-Verschlüsselung für jede gesendete Nachricht und Datei.
    
-   Echtzeit-Zugriffsverwaltung für Chats ermöglichen.
    

**Implementierung 🧠**
----------------------

### **Einrichten eines PubNub-Kontos 👤**

Um loszulegen, benötigen Sie **ein PubNub-Konto,** das Sie [hier](https://admin.pubnub.com/?ref=hackernoon.com#/login) einrichten können. Sobald du dich auf deinem Dashboard eingeloggt hast, solltest du sehen, dass **eine Demo-App** mit einem Demo-Keyset erstellt worden ist:

![](https://www.pubnub.com/cdn/3prze68gbwl1/7dlHV6HrK8ycTndYN8kN60/b8c5c4ed358737006494e485ae750867/YIMSJwDGhsOOhi9zHncV7Nc4OJG2-2023-09-20T13_43_30.768Z-sc4346be8h3z6uph34s3t8gi.jpg)

**Wählen Sie das Demo-Keyset aus** und scrollen Sie zur Registerkarte "Konfiguration". Für unsere Demo müssen wir die Berechtigungen " `Dateien"` und " `Objekte"` aktivieren. Für die `Objektberechtigung` werden wir die folgenden Ereignisse verwenden: `Benutzer-Metadaten-Ereignisse`, `Kanal-Metadaten-Ereignisse` und`Mitglieder-Ereignisse`.

Sobald das Keyset erstellt und konfiguriert ist, **müssen wir es in unser Frontend kopieren.**

Dazu erstellen wir eine JSON-Datei im Ordner `src/` mit dem Namen `settings.json`. Wir werden diese Datei für alle API-Schlüssel verwenden, die wir benötigen. Wir beginnen mit dem PubNub-Schlüsselsatz:

```js
{
  "PUBNUB_PUB_KEY": "pub-c-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "PUBNUB_SUB_KEY": "sub-c-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}
```

### **Aufbau eines einfachen Chats mit PubNub 💬**

Wir werden PubNub für fast **alle Backend-Aufgaben** verwenden **.** Unser Backend wird nur die Benutzeranmeldung/-signierung verarbeiten und ein minimalistisches Benutzermodell mit nur einer ID, einem Namen und einer E-Mail verwenden.

Auf der Vorderseite benötigen wir eine kleine Authentifizierungsschnittstelle:

![](https://www.pubnub.com/cdn/3prze68gbwl1/4QeRZBwCwvCKNd643LRd80/51d262b0ec0bc0af901139b02788cc13/YIMSJwDGhsOOhi9zHncV7Nc4OJG2-2023-09-20T13_43_30.784Z-gzbwgy4u8frc04p3yn3tmb87.jpg)

Sobald der Benutzer ein Konto hat, ist das erste, was er braucht, eine Instanz des PubNub SDK.

**Um den Benutzer auf Pubnub zu identifizieren,** müssen wir eine UUID bereitstellen.

Der Einfachheit halber werden wir die gleiche ID wie in unserem Backend verwenden:

```js
/* frontend/src/App.js */
import settings from './settings.json' // our settings file for API keys
/*
...
*/
const pubnub = new PubNub({
    publishKey: settings.PUBNUB_PUB_KEY,
    subscribeKey: settings.PUBNUB_SUB_KEY,
    uuid: currentUser.id
})
```

Um unser Backend so einfach wie möglich zu halten, werden wir die Benutzer-Metadaten von PubNub verwenden, um die Benutzerinformationen auszutauschen.

**Direkt nach der SDK-Instanziierung** rufen wir einfach die PubNub-Funktion `setUUIDMetadata` auf:

```js
/* frontend/src/App.js */
await pubnub.objects.setUUIDMetadata({
  uuid: currentUser.id,
  data: {
    email: currentUser.emailAddress,
    name: currentUser.name
  }
})
```

### **Den Anfangszustand der App erhalten 🌱**

**Das erste, was** wir mit PubNub tun müssen, ist, alle bestehenden Mitglieder abzurufen und sie in unserem lokalen Datenspeicher zu speichern:

```js
/* frontend/src/App.js */
const existingMembers = await pubnub.objects.getAllUUIDMetadata()
dispatch({
  type: SET_USERS,
  payload: {
    users: existingMembers.data.map(u => new User({ id: u.id, name: u.name, emailAddress: u.email }))
  }
})
```

Jeder Chatraum wird einem PubNub-Kanal entsprechen. Wir werden auch einige Metadaten zu jedem Kanal hinzufügen:

-   `ownerId`: Die ID des Benutzers, der den Raum erstellt hat.
    
-   `one2one`: Ein Boolescher Wert zur Unterscheidung von Direktnachrichtenräumen und Gruppenräumen.
    
-   `archiviert`: Ein Boolescher Wert, um einen gelöschten Gruppenraum auszublenden.
    

Die `ownerId` Metadaten werden später beim Hinzufügen des Seald SDK verwendet. PubNub hat kein Eigentumskonzept, aber Seald schon. Es definiert, wer Benutzer zu einem Kanal hinzufügen oder aus ihm entfernen kann. Es definiert im Grunde einen Gruppenadministrator.

Wir beginnen damit, **bestehende Chat-Räume abzurufen.** Wir benötigen auch die Raum-Metadaten, also müssen wir benutzerdefinierte Felder einfügen. Dann müssen wir archivierte Räume herausfiltern und alles an unseren Datenspeicher senden.

Schließlich `abonnieren` wir den mit dem Raum verbundenen PubNub-Kanal, damit wir neue Nachrichten erhalten:

```js
/* frontend/src/App.js */
// Retrieve rooms of which we are members
const memberships = await pubnub.objects.getMemberships({
  include: {
    customChannelFields: true
  }
})
const knownRooms = []
// For each room, retrieve room members
for (const room of memberships.data.filter(r => !r.channel.custom.archived)) {
  const roomMembers = await pubnub.objects.getChannelMembers({ channel: room.channel.id })
  knownRooms.push(new Room({
    id: room.channel.id,
    name: room.channel.name,
    users: roomMembers.data.map(u => u.uuid.id),
    ownerId: room.channel.custom.ownerId,
    one2one: room.channel.custom.one2one
  }))
}
// Store rooms in our data store
dispatch({
  type: SET_ROOMS,
  payload: {
    rooms: knownRooms
  }
})
// Subscribe to channels to get new messages
pubnub.subscribe({ channels: knownRooms.map(r => r.id) })
```

Jetzt haben wir alle Räume abgerufen, in denen wir uns befinden. Wir brauchen noch eine letzte Sache, um die Initialisierung der App zu beenden: Wir müssen sicherstellen, dass wir einen `One2One-Raum` mit jedem anderen Mitglied haben, einschließlich der neu registrierten.

Für jeden neu gefundenen Benutzer werden wir einen neuen Raum **erstellen** und eine Hallo-Nachricht senden.

Dann werden wir die Metadaten des Raums einstellen und ihn abonnieren:

```js
/* frontend/src/App.js */
// Ensure that we have a one2one room with everyone
const one2oneRooms = knownRooms.filter(r => r.one2one)
for (const m of existingMembers.data.filter(u => u.id!== currentUser.id)) {
    if (!one2oneRooms.find(r => r.users.includes(m.id))) {
      // New user found: generating a new one2one room
      const newRoomId = PubNub.generateUUID()
      const newRoom = new Room({
            id: newRoomId,
            users: [currentUser.id, m.id],
            one2one: true,
            name: m.name,
            ownerId: currentUser.id
          })
      // Add the new room to our local list
      dispatch({
        type: EDIT_OR_ADD_ROOM,
        payload: {
          room: new Room({
            id: newRoomId,
            users: [currentUser.id, m.id],
            one2one: true,
            name: m.name, ownerId: currentUser.id
          })
        }
      })
      // Publish a "Hello" message in the room
      await pubnub.publish({
        channel: newRoomId,
        message: {
          type: 'message',
          data: (await sealdSession.encryptMessage('Hello 👋'))
        }
      })
      // Subscribe to the new room
      pubnub.subscribe({ channels: [newRoomId] })
      await pubnub.objects.setChannelMetadata({
        channel: newRoomId,
        data: {
          name: 'one2one',
          custom: {
            one2one: true,
            ownerId: currentUser.id,
          },
        }
      })
      await pubnub.objects.setChannelMembers({
        channel: newRoomId,
        uuids: [currentUser.id, m.id]
      })
    }
}
```

Wenn das alles erledigt ist, **ist** unser anfänglicher App-Status **vollständig definiert.** Wir müssen ihn jedoch auf dem neuesten Stand halten.

Das geht ganz einfach, indem wir einen Event-Listener für `Mitgliedschaftsereignisse` hinzufügen:

```js
/* frontend/src/App.js */
pubnub.addListener({
  objects: async function(objectEvent) {
    if (objectEvent.message.type === 'membership') {
      if (objectEvent.message.event === 'delete') { // User is removed from a room
        /*
        Removing the room from store...
        */
      }
      if (objectEvent.message.event === 'set') { // User is added to a room
        const metadata = await pubnub.objects.getChannelMetadata({ channel: objectEvent.message.data.channel.id })
        const roomMembers = (await pubnub.objects.getChannelMembers({ channel: objectEvent.message.data.channel.id })).data.map(u => u.uuid.id)
        /*
        Adding new room to store + subscribing to new room channel...
        */
      }
    }
  }
})
pubnub.subscribe({ channels: [currentUser.id] }) // channel on which events concerning the current user are published
```

Wir können uns nun einen `one2one-Chatraum` selbst ansehen. Dann werden wir Gruppenräume behandeln.

### **Empfangen und Senden von Nachrichten in einem Chatraum 📩**

In einer `chat.js-Datei` finden wir die gesamte Logik zur Anzeige der Nachrichten eines Chat-Raums.

**Um diesen Raum zu initialisieren,** müssen wir nur alle bereits existierenden Nachrichten abrufen.

Dazu müssen wir nur die Raum-ID kennen:

```js
/* frontend/src/components/Chat.jsx */
const fetchedMessages = (await pubnub.fetchMessages({ channels: [currentRoomId] })).channels[currentRoomId]
```

Wir können den Kanal abonnieren, um neue Nachrichten zu erhalten, und einen Listener hinzufügen, um sie in Echtzeit anzuzeigen:

```js
/* frontend/src/components/Chat.jsx */
pubnub.addListener({ message: handleReceiveMessage })
pubnub.subscribe({ channels: [currentRoomId] })
```

Um eine Nachricht zu senden, müssen wir sie einfach auf dem Kanal veröffentlichen:

```js
/* frontend/src/components/Chat.jsx */
const handleSubmitMessage = async e => {
  /* Some checks that the room is in a correct state... */
  await pubnub.publish({
    channel: state.room.id,
    message: {
      type: 'message',
      data: state.message
    }
  })
}
```

**Um eine Datei zu senden,** laden wir sie zunächst auf PubNub hoch. Dann erhalten wir die URI der hochgeladenen Datei und veröffentlichen sie als Nachricht im Chatraum:

```js
/* frontend/src/components/UploadButton.jsx */
// Upload Encrypted file
const uploadData = await pubnub.sendFile({
  channel: room.id,
  file: myFile,
  storeInHistory: false
})
const fileURL = await pubnub.getFileUrl({ id: uploadData.id, name: uploadData.name, channel: room.id })
await pubnub.publish({
  channel: state.room.id,
  message: {
    type: 'file',
    url: fileURL,
    fileName: await sealdSession.encryptMessage(selectedFiles[0].name)
  }
})
```

#### **Verwaltung von Gruppenchats 👨‍👩‍👦‍👦**

Um Gruppen zu erstellen und zu verwalten, benötigen wir eine Schnittstelle für die Auswahl von Benutzern:

![](https://www.pubnub.com/cdn/3prze68gbwl1/5eUvBiTJXw901zb2ItefN0/2189f12071c272cc34192ca26ce2339f/YIMSJwDGhsOOhi9zHncV7Nc4OJG2-2023-09-20T13_43_30.789Z-qpr0csdfsonvkr3haucsetki.jpg)

**Sobald die Gruppenmitglieder ausgewählt sind,** können wir einen PubNub-Kanal für unseren Raum erstellen und dann Metadaten und Mitgliedschaft für den Kanal festlegen. Der Code ist dem für one2one-Räume sehr ähnlich, daher werden wir ihn hier nicht wiederholen.

Wir haben jetzt eine vollständige Chat-App. **Fügen wir nun eine Ende-zu-Ende-Verschlüsselung für jede Nachricht hinzu!**

**Hinzufügen von Ende-zu-Ende-Verschlüsselung mit Seald 🔒💬**
--------------------------------------------------------------

### **Einrichten eines Seald-Kontos 👤**

Um mit Seald zu beginnen, **erstellen Sie** [hier](https://www.seald.io/create-sdk?ref=hackernoon.com) **ein kostenloses Testkonto**

Wenn Sie auf dem Seald-Dashboard landen, werden einige URLs und API-Tokens angezeigt.

Holen Sie sich die folgenden Elemente:

-   appId
    
-   apiURL
    
-   keyStorageURL
    

Wir werden diese Schlüssel zu unserer `settings.json` hinzufügen:

```js
{
  "PUBNUB_PUB_KEY": "pub-c-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "PUBNUB_SUB_KEY": "sub-c-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "SEALD_APP_ID": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "SEALD_API_URL": "https://api.staging-0.seald.io",
  "SEALD_KEYSTORAGE_URL": "https://ssks.staging-0.seald.io"
}
```

**Um das Seald SDK nutzen zu können,** benötigt jeder Nutzer bei der Anmeldung ein Lizenz-JWT.

Diese JWT muss im Backend unter Verwendung eines Geheimnisses und einer geheimen ID generiert werden.

Kopieren Sie auf der Dashboard-Landingpage das JWT-Geheimnis und die dazugehörige ID in `backend/settings.json`:

```js
{
  "SEALD_JWT_SECRET_ID": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  "SEALD_JWT_SECRET": "XXXXXXXXXXXXXXXXXXXXXXXX"
}
```

Während des Aufrufs der Anmelde-API wird ein JWT für die Seald-Lizenz generiert und zurückgegeben:

```js
/* backend/routes/account.js */
const token = new SignJWT({
  iss: settings.SEALD_JWT_SECRET_ID,
  jti: uuidv4(), /// Random string with enough entropy to never repeat.
  iat: Math.floor(Date.now() / 1000), // JWT valid only for 10 minutes. `Date.now()` returns the  in milliseconds, this needs it in seconds.
  scopes: [3], // PERMISSION_JOIN_TEAM
  join_team: true
})
  .setProtectedHeader({ alg: 'HS256' })
const signupJWT = await token.sign(Buffer.from(settings.SEALD_JWT_SECRET, 'ascii'))
```

Weitere Informationen hierzu finden Sie in [unserem Dokumentationsartikel über JWT](https://docs.seald.io/en/sdk/guides/jwt.html?ref=hackernoon.com#creating-a-json-web-token).

Dann müssen wir **das Seald SDK installieren.**

**Außerdem müssen wir ein Plugin installieren**, um Benutzer auf dem Seald-Server zu identifizieren. Dazu verwenden wir das Paket `sdk-plugin-ssks-password`.

Dieses Plugin ermöglicht eine einfache Passwort-Authentifizierung unserer Benutzer:

```js
npm i -S @seald-io/sdk @seald-io/sdk-plugin-ssks-password
```

### **Instanziierung des Seald SDK 💡**

Anschließend erstellen wir eine Datei `seald.js`. In dieser Datei erstellen wir zunächst eine Funktion zur Instanziierung des Seald SDK:

```js
/* frontend/src/services/seald.js */
import SealdSDK from '@seald-io/sdk-web'
import SealdSDKPluginSSKSPassword from '@seald-io/sdk-plugin-ssks-password'
import settings from './settings.json'
let sealdSDKInstance = null
const instantiateSealdSDK = async () => {
  sealdSDKInstance = SealdSDK({
    appId: settings.SEALD_APP_ID,
    apiURL: settings.SEALD_API_URL,
    plugins: [SealdSDKPluginSSKSPassword(settings.SEALD_KEYSTORAGE_URL)]
  })
}
```

### **Erstellen und Abrufen von Seald-Identitäten 🔑**

In `seald.js` fügen wir außerdem zwei Funktionen hinzu: eine zum Erstellen einer Identität und eine zum Abrufen einer Identität. **Um eine Identität zu erstellen,** benötigen wir auch den Lizenz-JWT, der bei der Kontoerstellung zurückgegeben wird:

```js
/* frontend/src/services/seald.js */
export const createIdentity = async ({ userId, password, signupJWT }) => {
  await instantiateSealdSDK()
  await sealdSDKInstance.initiateIdentity({ signupJWT })
  await sealdSDKInstance.ssksPassword.saveIdentity({ userId, password })
}
export const retrieveIdentity = async ({ userId, password }) => {
  await instantiateSealdSDK()
  await sealdSDKInstance.ssksPassword.retrieveIdentity({ userId, password })
}
```

Während unserer Anmelde- und Anmeldeströme müssen wir diese Funktionen nur aufrufen, nachdem sich der Benutzer angemeldet hat.

Zu diesem Zeitpunkt hat unser Benutzer jedes Mal, wenn er verbunden ist, ein funktionierendes Seald SDK, **bereit zum Ver- und Entschlüsseln!**

**Warnung:** Um die Sicherheit zu gewährleisten, sollte das Passwort vor dem Senden an den Authentifizierungsserver gehasht werden. Weitere Einzelheiten hierzu finden Sie [im Abschnitt über die Passwortauthentifizierung in unserer Dokumentation](https://docs.seald.io/en/sdk/guides/4-identities.html?ref=hackernoon.com#password-also-used-for-authentication).

### **Starten Sie die Ver- und Entschlüsselung von Nachrichten 🔒🔓**

Jeder Chatraum wird mit einer `encryptionSession` auf dem Seald SDK verbunden.

Jedes Mal, wenn wir einen Chatraum erstellen, **müssen wir lediglich eine Zeile hinzufügen, um die Verschlüsselungssitzung zu erstellen und** sie dann zu verwenden:

```js
/* frontend/src/App.js */
// Create a Seald session
const sealdSession = await getSealdSDKInstance().createEncryptionSession(
  { userIds: [currentUser.id, m.id] },
  { metadata: newRoomId }
)
// Publish a "Hello" message in the room
await pubnub.publish({
  channel: newRoomId,
  message: {
    type: 'message',
    data: (await sealdSession.encryptMessage('Hello 👋'))
  }
})
```

Beachten Sie, dass unser Benutzer standardmäßig als Empfänger der `encryptionSession` enthalten ist `.`

Wenn wir auf einen Raum zugreifen, müssen wir die entsprechende `encryptionSession` abrufen. Sie kann aus jeder verschlüsselten Nachricht oder Datei abgerufen werden. Sobald wir sie haben, behalten wir sie in der Komponentenreferenz.

Dann können wir einfach die Funktionen `session.encryptMessage``, session.encryptFile`, `session.decryptMessage` und `session.decryptFile` verwenden.

Lassen Sie uns mit den Nachrichten beginnen. Um eine Nachricht zu senden:

```js
/* frontend/src/components/Chat.js */
const handleSubmitMessage = async m => {
  /* Some validation that we are in a valid room... */
  // if there is no encryption session set in cache yet, create one
  // (should never happen, as a "Hello" is sent on room creation)
  if (!sealdSessionRef.current) {
    sealdSessionRef.current = await getSealdSDKInstance().createEncryptionSession(
      { userIds: state.room.users },
      { metadata: state.room.id }
    )
  }
  // use the session to encrypt the message we are trying to send
  const encryptedMessage = await sealdSessionRef.current.encryptMessage(state.message)
  // publish the encrypted message to pubnub
  await pubnub.publish({
    channel: state.room.id,
    message: {
      type: 'message',
      data: encryptedMessage
    }
  })
  /* Some cleanup... */
}
```

Und wenn wir eine Nachricht erhalten:

```js
/* frontend/src/components/Chat.js */
const decryptMessage = async m => {
  /* Filter out files... */
  let encryptedData = m.message.data
  if (!sealdSessionRef.current) { // no encryption session set in cache yet
    // we try to get it by parsing the current message
    sealdSessionRef.current = await getSealdSDKInstance().retrieveEncryptionSession({ encryptedMessage: encryptedData })
    // now that we have a session loaded, let's decrypt
  }
  const decryptedData = await sealdSessionRef.current.decryptMessage(encryptedData)
  // we have successfully decrypted the message
  return {
    ...m,
    uuid: m.uuid || m.publisher,
    value: decryptedData
  }
  /* Some error handling... */
}
/* Other stuff... */
const handleReceiveMessage = async m => {
  const decryptedMessage = await decryptMessage(m)
  setState(draft => {
    draft.messages = [...draft.messages, decryptedMessage]
  })
}
```

Außerdem verwenden wir diese Funktion `decryptMessage`, um alle Nachrichten zu entschlüsseln, die sich bereits in der Sitzung befinden, wenn wir einen Raum öffnen:

```js
/* frontend/src/components/Chat.js */
const fetchedMessages = (await pubnub.fetchMessages({ channels: [currentRoomId] })).channels[currentRoomId]
const clearMessages = fetchedMessages ? await Promise.all(fetchedMessages.map(decryptMessage)) : []
```

Und nun zu den Dateien. Um eine Datei hochzuladen:

```js
/* frontend/src/components/UploadButton.js */
// Encrypt file
const encryptedBlob = await sealdSession.encryptFile(
  selectedFiles[0],
  selectedFiles[0].name,
  { fileSize: selectedFiles[0].size }
)
const encryptedFile = new File([encryptedBlob], selectedFiles[0].name)
// Upload Encrypted file
const uploadData = await pubnub.sendFile({
  channel: room.id,
  file: encryptedFile,
  storeInHistory: false
})
```

Und um eine Datei zu entschlüsseln:

```js
/* frontend/src/components/Message.js */
const onClick = async () => {
  if (state.data.type === 'file') {
    const response = await fetch(state.data.url)
    const encryptedBlob = await response.blob()
    const { data: clearBlob, filename } = await sealdSession.decryptFile(encryptedBlob)
    const href = window.URL.createObjectURL(clearBlob)
    /* Create an <a> element and simulate a click on it to download the created objectURL */
  }
}
```

### **Gruppenmitglieder verwalten 👨‍👩‍👦**

Gruppenchats haben auch ihre `encryptionSession`. Jedes Mal, wenn eine Gruppe erstellt wird, müssen wir eine erstellen:

```js
/* frontend/src/components/ManageDialogRoom.js.js */
// To create the encryptionSession
const sealdSession = await getSealdSDKInstance().createEncryptionSession(
  { userIds: dialogRoom.selectedUsersId },
  { metadata: newRoomId }
)
```

Dann müssen wir **jedes Mal, wenn wir Gruppenmitglieder ändern,** diese hinzufügen oder aus der Gruppe entfernen:

```js
/* frontend/src/components/ManageDialogRoom.js.js */
// we compare old and new members to figure out which ones were just added or removed
const usersToRemove = dialogRoom.room.users.filter(id => !dialogRoom.selectedUsersId.includes(id))
const usersToAdd = dialogRoom.selectedUsersId.filter(id => !dialogRoom.room.users.includes(id))
if (usersToAdd.length > 0) {
  // for every added user, add them to the Seald session
  await dialogRoom.sealdSession.addRecipients({ userIds: usersToAdd })
  // then add them to the pubnub channel
  await pubnub.objects.setChannelMembers({
    channel: dialogRoom.room.id,
    uuids: usersToAdd
  })
}
if (usersToRemove.length > 0) {
  // for every removed user, revoke them from the Seald session
  await dialogRoom.sealdSession.revokeRecipients({ userIds: usersToRemove })
  // then remove them from the pubnub channel
  for (const u of usersToRemove) {
    await pubnub.objects.removeMemberships({
      channels: [dialogRoom.room.id],
      uuid: u
    })
  }
}
```

**Schlussfolgerung ✅**
----------------------

Wenn das erledigt ist, sind wir fertig!

Wir haben es geschafft, **Seald** mit nur ein paar Zeilen Code **in PubNub** zu integrieren.

Da **der Chat** nun **Ende-zu-Ende-verschlüsselt ist,** können Sie Ihren Nutzern versichern, dass ihre Daten vertraulich bleiben, **selbst im Falle von Datenschutzverletzungen.**

Wie immer, **zögern Sie nicht,** [**Seald zu kontaktieren**](https://www.seald.io/discover?ref=hackernoon.com) **oder** [**PubNub**](https://support.pubnub.com/hc/en-us) zu[**kontaktieren**](https://support.pubnub.com/hc/en-us), wenn Sie zusätzliche Hilfe benötigen.

Wir können es kaum erwarten, zu sehen, was Sie gebaut haben 🥳.

#### Inhalt

[InhaltsübersichtWarum](#h-0) eine[Ende-zu-Ende-Verschlüsselung verwenden? 🔒Warum](#h-1)[Seald.io anstelle des PubNub-Verschlüsselungshakens verwenden? 👀Ziele](#h-2)[🏆Implementierung](#h-3)[🧠Einrichten eines PubNub-Kontos 👤Aufbau](#h-5)[eines grundlegenden Chats mit PubNub 💬Erstellen des](#h-6)[anfänglichen App-Status 🌱Empfangen](#h-7)[und Senden](#h-8)[von](#h-7)[Nachrichten in einem Chatraum 📩Verwaltung eines](#h-8)[Gruppenchats](#h-9)[👨‍👩‍👦‍👦Adding Ende-zu-EndeEnde-zu-Ende-Verschlüsselung mit Seald 🔒💬Einrichten](#h-10)[eines Seald-Kontos 👤Initialisierung](#h-11)[des Seald SDK 💡Erstellen](#h-12)[und Abrufen von Seald-Identitäten 🔑Starten der](#h-13)[Ver- und Entschlüsselung von Nachrichten 🔒🔓Verwaltung von](#h-14)[Gruppenmitgliedern](#h-15)[👨‍👩‍👦Conclusion ✅](#h-16)

Wie kann PubNub Ihnen helfen?
=============================

Dieser Artikel wurde ursprünglich auf [PubNub.com](https://www.pubnub.com/blog/build-an-end-to-end-encrypted-chat-with-seald-and-pubnub/) veröffentlicht.

Unsere Plattform hilft Entwicklern bei der Erstellung, Bereitstellung und Verwaltung von Echtzeit-Interaktivität für Webanwendungen, mobile Anwendungen und IoT-Geräte.

Die Grundlage unserer Plattform ist das größte und am besten skalierbare Echtzeit-Edge-Messaging-Netzwerk der Branche. Mit über 15 Points-of-Presence weltweit, die 800 Millionen monatlich aktive Nutzer unterstützen, und einer Zuverlässigkeit von 99,999 % müssen Sie sich keine Sorgen über Ausfälle, Gleichzeitigkeitsgrenzen oder Latenzprobleme aufgrund von Verkehrsspitzen machen.

PubNub erleben
--------------

Sehen Sie sich die [Live Tour](https://www.pubnub.com/tour/introduction/) an, um in weniger als 5 Minuten die grundlegenden Konzepte hinter jeder PubNub-gestützten App zu verstehen

Einrichten
----------

Melden Sie sich für einen [PubNub-Account](https://admin.pubnub.com/signup/) an und erhalten Sie sofort kostenlosen Zugang zu den PubNub-Schlüsseln

Beginnen Sie
------------

Mit den [PubNub-Dokumenten](https://www.pubnub.com/docs) können Sie sofort loslegen, unabhängig von Ihrem Anwendungsfall oder [SDK](https://www.pubnub.com/docs)