Как создать приложение для чата со сквозным шифрованием в Next.js: Сообщения и шифрование

Шифрование обеспечивает безопасность данных путем скремблирования, так что только уполномоченные лица могут получить доступ к информации или данным и расшифровать их.

Что мы будем строить

В этой статье рассматривается использование функции базы данных Appwrite для создания приложения для чата. В этой статье мы обеспечим безопасность данных, используя библиотеку cryptr для шифрования и расшифровки строк.

URL GitHub

https://github.com/Iheanacho-ai/chat-app-nextjs

Предварительные условия

Эта статья является второй частью цикла из двух частей, в котором рассказывается о том, как построить сквозной зашифрованный чат с помощью Appwrite в приложении Next.js. Очень важно начать с первой части, чтобы получить максимальную пользу от этой статьи. Ознакомьтесь с первой частью статьи здесь.

Установка cryptr

crypt — это простой модуль aes-256-gcm для шифрования и расшифровки значений строк UTF-8.

Чтобы установить crypt, выполните эту команду терминала в директории нашего проекта.

    npm install cryptr
Войти в полноэкранный режим Выход из полноэкранного режима

Создание коллекции и атрибутов

В левой части приборной панели Appwrite Console перейдите на вкладку Database.

Нажмите на кнопку Добавить базу данных, чтобы создать новую базу данных. Создание новой базы данных приведет нас на страницу Коллекции.

Далее мы создадим коллекцию на вкладке нашей базы данных, нажав кнопку Добавить коллекцию. Это действие перенаправит нас на страницу Разрешения.

На уровне коллекции мы хотим назначить доступ на чтение и доступ на запись со значением role:all. Мы можем настроить эти роли позже, чтобы указать, кто имеет доступ на чтение или запись в нашу базу данных.

В правой части страницы Разрешения скопируйте идентификатор коллекции, который нам понадобится для выполнения операций над документами коллекции.

Далее перейдите на вкладку «Атрибуты», чтобы создать свойства, которыми мы хотим наделить документ.

Давайте создадим строковый атрибут message с размером 256 бит.

Добавление взаимодействия приложения Chat с базой данных

В файле chat.jsx внутри папки pages импортируйте хук useState для обработки состояний, экземпляр Appwrite client и метод Appwrite Databases.

    import {  useState } from 'react';
    import { client} from '../init' 
    import { Databases } from 'appwrite';
Вход в полноэкранный режим Выход из полноэкранного режима

Далее создайте две переменные состояния:

  • Переменную состояния messages для хранения сообщений, которые пользователь собирается отправить.
  • Переменная состояния databaseMessages для хранения сообщений, полученных из базы данных.
    const [message, setMessages] = useState("");
    const [databaseMessages, setDatabaseMessages] = useState(["hey"])
Вход в полноэкранный режим Выход из полноэкранного режима

Затем мы создаем экземпляр databases с помощью метода Appwrite Databases. Этот метод Databases получает в качестве параметров клиента и идентификатор базы данных.

    const databases = new Databases(client, 'DatabaseID');
Вход в полноэкранный режим Выход из полноэкранного режима

Далее мы создадим функцию listMessages и функцию sendMessage.

    const listMessages = async () => {
      const promise = await databases.listDocuments('CollectionID');
      promise.documents.map((document) => setDatabaseMessages(prevArray => [...prevArray, document.message]))
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Функция listMessages в приведенном выше блоке кода делает следующее:

  • Перечисляет все документы в коллекции, используя метод listDocuments в Appwrite. Этот метод listDocuments получает в качестве параметра идентификатор коллекции.
  • Обновляет переменную состояния databaseMessages сообщениями, сохраненными в документах.
    const sendMessage = async () => {
      try {
        await databases.createDocument('CollectionID', 'unique()', {
          "message": message
        });
        alert('message sent')
        setMessages("")
        listMessages()
       }catch (error) {
        console.log(error)
      }
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Приведенная выше функция sendMessage делает следующее:

  • Создает новый документ с помощью функции createDocument() от Appwrite. Эта функция createDocument() получает в качестве параметров ID коллекции, строку unique() и значения атрибутов.
  • Сигнализирует об успешном сохранении сообщения.
  • Очищает переменную message и вызывает функцию listMessages().
  • Записывает все возникшие ошибки в консоль.

Далее мы проверяем, пуст ли массив databaseMessages, затем в цикле просматриваем данные в массиве databaseMessages и отображаем сообщения в нашем приложении чата.

    <div className='messages'>
       {
        databaseMessages ? (
          <div className="message-container">
             {
               databaseMessages.map((databaseMessage)=> (
                <div className="user-message">{databaseMessage}</div>
              ))
            } 
          </div>
        ) : null
      } 
    </div>
Вход в полноэкранный режим Выход из полноэкранного режима

Далее мы передадим переменную message в качестве значения в наше поле ввода и нашу функцию sendMessage в слушатель события onClick на нашей кнопке отправки.

    <div className='input-area'>
      <input type="text" className='message-input' value={message} onChange={(e) => setMessages(e.target.value)}/>
      <button className='send' type='button' onClick={sendMessage}>send</button>
    </div>
Вход в полноэкранный режим Выход из полноэкранного режима

После того как мы закончили с этим разделом, вот как выглядит наш файл chat.jsx.

    import {  useState } from 'react';
    import { client} from '../init' 
    import { Databases } from 'appwrite';

    const Chat = () => {
      const [message, setMessages] = useState("");
      const [databaseMessages, setDatabaseMessages] = useState(["hey"])

      const databases = new Databases(client, 'DatabaseID');

      const listMessages = async () => {
        const promise = await databases.listDocuments('CollectionID');
        promise.documents.map((document) => setDatabaseMessages(prevArray => [...prevArray, document.message]))
      }

      const sendMessage = async () => {
        try {
          await databases.createDocument('CollectionID', 'unique()', {
            "message": message
          });
          alert('message sent')
          setMessages("")
          listMessages()
        } catch (error) {
          console.log(error)
        }
      }

      return (
        <div className='chat'>
          <div className='user-chat'>
            <div className="user-chat-header">USER</div>
            <div className='messages'>
              {
                databaseMessages.map((databaseMessage)=> (
                  <div className="user-message">{databaseMessage}</div>
                ))
              }
            </div>
            <div className='input-area'>
              <input type="text" className='message-input' value={message} onChange={(e) => setMessages(e.target.value)}/>
              <button className='send' type='button' onClick={sendMessage}>send</button>
            </div>
          </div>
        </div>
      ) 
    };
    export default Chat;
Вход в полноэкранный режим Выход из полноэкранного режима

Вот как выглядит наше приложение для чата.

Шифрование

Cryptr требует секретный ключ для шифрования или расшифровки строки. В корне нашего проекта мы создадим файл .env.local, который будет содержать наш секретный ключ.

    ## .env.local

    NEXT_PUBLIC_KEY = "********"
Вход в полноэкранный режим Выход из полноэкранного режима

Использование префикса «NEXT_PUBLIC» при хранении нашего секретного ключа позволяет переменной окружения быть доступной в нашем компоненте.

Далее мы импортируем библиотеку crypt в наш файл chat.jsx.

    import {  useEffect, useState } from 'react';
    import { client} from '../init' 
    import { Databases } from 'appwrite';

    const Cryptr = require('cryptr');
Входим в полноэкранный режим Выход из полноэкранного режима

Затем мы создадим экземпляр cryptr для шифрования и расшифровки нашей строки с помощью секретного ключа.

    import {  useEffect, useState } from 'react';
    import { client} from '../init' 
    import { Databases } from 'appwrite';
    const Cryptr = require('cryptr');

    const Chat = () => {
      ...  
      const cryptr = new Cryptr(process.env.NEXT_PUBLIC_KEY);
      return (
        ...
       ) 
    };
Вход в полноэкранный режим Выход из полноэкранного режима

Функция sendMessages в нашем файле chat.jsx будет отвечать за шифрование данных. Библиотека crypt позволяет нам использовать функцию encrypt для шифрования строк в нашем приложении.

    const sendMessage = async () => {
      // encrypt the string in our message state variable
      const encryptedMessage = cryptr.encrypt(message)
       try {
        await databases.createDocument('62dc54f155f11d4c38cb', 'unique()', {
        // stores the encrypted message instead of the original message
           "message": encryptedMessage
         });
         alert('message sent')
         setMessages("")
         listMessages()
       } catch (error) {
        console.log(error)
      }
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Функция sendMessage шифрует данные в переменной состояния message и затем сохраняет зашифрованные данные в нашей базе данных Appwrite.

Сообщение «hey» шифруется и хранится в нашей базе данных в виде набора цифр.

Далее мы получим зашифрованные данные из нашей базы данных и расшифруем их, чтобы получить оригинальное сообщение.

В функции listMessages мы расшифруем сообщение, полученное из базы данных Appwrite.

    const listMessages = async () => {
      const promise = await databases.listDocuments('62dc54f155f11d4c38cb');
      setDatabaseMessages([])
      promise.documents.map((document) =>{ 
      // map through the documents in the collection and decrypt each message
        const decryptedMessage = cryptr.decrypt(document.message)
        setDatabaseMessages(prevArray => [...prevArray, decryptedMessage])
      }
       )
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Функция listMessages очищает массив databaseMessages перед циклом и расшифровкой сообщений в документе.

Вот как должно выглядеть наше приложение для чата.

Заключение

В этой статье мы рассмотрели создание сквозного зашифрованного чата с помощью cryptr и Appwrite.

Ресурсы

  • Создание локального экземпляра Appwrite в 3 шага
  • API базы данных
  • Установка cryptr

Оцените статью
devanswers.ru
Добавить комментарий