Confidant представляет собой клиент-серверную систему, позволяющую пользователю надёжно и безопасно хранить логины, пароли, данные банковских карт, файлы и прочую конфиденциальную информацию.
Система предназначена для отлаживания и проверки различных решений и не может использоваться для постоянного хранения конфиденциальной информации.
Предусмотрено создание двух исполняемых файлов:
- для клиента - confidant_client;
- для сервера - confidant_server.
Покрытие юнит-тестами составляет 3,6 %.
Команда для определения покрытия:
go test -coverprofile=coverage.out.tmp ./... && cat coverage.out.tmp | grep -v "_mock.go" > coverage.out && go tool cover -func=coverage.out && go tool cover -html=coverage.outconfidant_client для работы использует БД SQLite и при первом запуске создаёт файл confidant_client.db.
Для удобства использования реализован терминальный интерфейс (TUI) на базе библиотеки tview.
Навигация по интерфейсу:
- между элементами - с помощью
⇥ Tab; - по спискам - с помощью
↑,↓; - активировать элемент или элемент списка -
↵ Enter.
Если в какой-то момент не ясно, на каком элементе стоит фокус, то вероятнее всего он находится на поле с многострочным текстом для возможности его прокрутки при необходимости с помощью ↑, ↓.
Если пользователь авторизован на клиенте, то в таком случае клиент может работать автономно от сервера. Сервер будет необходим только для синхронизации данных.
Перед сохранением конфиденциальных данных в БД происходит их шифрование.
Используется симметричное блочное шифрование AES-GCM с 256-битным ключом.
Обмен данными между клиентом и сервером выполняется через REST API, соответствующее спецификации HTTP/1.1 с использованием методов GET/POST/PUT/PATCH.
При запуске необходимо использовать следующие флаги:
- адрес сервера: флаг
a, переменная окруженияADDRESS, примерlocalhost:7541.
confidant_server для работы использует БД PostreSQL (название БД должно быть confidant).
Логгирование реализовано через middleware.
При запуске необходимо использовать следующие флаги:
- адрес сервера: флаг
a, переменная окруженияADDRESS, пример:7541; - DSN БД: флаг
d, переменная окруженияDATABASE_DSN, примерhost=localhost port=5432 user=postgres password=password dbname=confidant sslmode=disable.
Перед запуском сервера необходимо провести миграции из файла ./resources/migration/000001_tables.up.sql
Регистрация нового пользователя возможна только при запущенном сервере.
При регистрации происходит запись нового пользователя в БД на клиенте и сервере.
После регистрации пользователь считается авторизованым.
Если в БД клиента не найден e-mail или пара e-mail-пароль пользователя, то клиент обращается на сервер.
Если на сервере данная запись найдена, то клиенту в заголовке Authorization с первым словом Bearer поступает access-токен, а в заголовке Refresh-Token - refresh токен. Токены содержат в себе ID пользователя.
Клиент сохраняет поступившую информацию:
- данные пользователя - в БД;
- refresh-токен - в БД;
- access-токен - в оперативной памяти.
При запуске клиента загружаются данные последнего используемого профиля.
Все сохраняемые конфиденциальные данные должны относиться к определённой группе, например "Семья", "Работа", "Личное".
В настройках группы возможно добавить e-mail пользователей, которым будет доступна вся конфиденциальная информация из данной группы.
Конфиденциальные данные делятся на четыре типа:
- заметка;
- пароль;
- банковская карта;
- файл.
Для каждого типа свои форма записи и форма отображения информации.
Все поля сохраняют данные в строковый тип и не имеют валидации введённых данных.
Поля для типа "заметка":
- заметка;
- описание;
- название.
Поля для типа "пароль":
- логин;
- пароль;
- описание;
- название.
Поля для типа "банковская карта":
- номер;
- дата;
- имя;
- CVC2;
- PIN;
- банк;
- описание;
- название.
Предназначен для:
- выбора файла, его шифрования и сохранения в БД;
- декодирования данных из БД и сохранения их в файл на диск.
Поля для типа "файл":
- имя файла;
- размер файла;
- дата изменения файла;
- описание;
- название.
Процессом синхронизации управляет клиент.
Чтобы начать синхронизацию необходимо нажать на кнопку "Синхронизировать".
Эндпоинты синхронизации на сервере доступны только авторизованному клиенту.
Если на сервер поступает невалидный access-токен, клиент обращается на эндпоинт обновления access-токена с помощью refresh-токена. Если refresh-токен также невалидный, на клиенте происходит выход из текущего аккаунта и переход на страницу входа.
Синхронизация происходит в два этапа:
- Синхронизация групп.
- Синхронизация данных.
В БД клиента есть поля:
id- ID группы в БД клиента;id_on_server- ID группы в БД сервера;
Если на сервере такой группы ещё нет, то в поле id_on_server записывается -1.
Синхронизация групп происходит по следующему алгоритму:
- Получение от сервера списка ID всех групп пользователя.
- Формирование списка с
id_on_serverгрупп пользователя БД клиента (т.е. групп, которые уже есть на сервере). - Формирование списка с
idгрупп пользователя БД клиента, гдеid_on_serverравны-1(т.е. групп, которых на сервере нет). - Проверка, есть ли ID группы, полученный с сервера (список п.1) в списке групп с
id_on_serverклиента (список п.2). Если нет, то ID такой группы добавляется в список ID для копирования с сервера на клиент. - Клиент отсылает на сервер список ID, сформированный в п.4. Сервер по данным ID возвращает данные групп. Клиент сохраняет их в БД.
- Синхронизация e-mail.
- Клиент формирует данные групп из списка по п.3 (которых нет на сервере). Отсылает их на сервер. Сервер сохраняет их в БД и присылает полученные ID групп. Клиент обновляет ID этих групп у себя в БД (поле
id_on_server).
В БД клиента есть поля:
id- ID записи данных в БД клиента;id_on_server- ID записи данных в БД сервера;
Если на сервере такой записи ещё нет, то в поле id_on_server записывается -1.
Синхронизация записей данных происходит по следующему алгоритму:
- Получение от сервера списка ID всех записей данных пользователя.
- Формирование списка с
id_on_serverзаписей данных пользователя БД клиента (т.. записей, которые уже есть на сервере). - Формирование списка с
idзаписей данных пользователя БД клиента, гдеid_on_serverравны-1(т.е. записей, которых на сервере нет). - Проверка, есть ли ID записи, полученной с сервера (список п.1) в списке записей с
id_on_serverклиента (список п.2). Если нет, то ID такой записи добавляется в список ID для копирования с сервера на клиент. - Клиент отсылает на сервер список ID, сформированный в п.4. Сервер по данным ID возвращает данные записей. Клиент сохраняет их в БД. Данные записей типа "file" передаются по дополнительному запросу клиента с content-type
application/octet-stream. - Клиент формирует данные записей из списка по п.3 (которых нет на сервере). Отсылает их на сервер. Сервер сохраняет их в БД и присылает полученные ID записей. Клиент обновляет ID этих записей у себя в БД (поле
id_on_server). Данные записей типа "file" передаются по дополнительному запросу клиента с content-typeapplication/octet-stream.
После добавления возможности редактирования и удаления записей данных в алгоритм синхронизации данных будет добавлена проверка записей по датам создания для сохранения наиболее свежей записи.
Все конфиденциальные данные передаются от клиента серверу в сыром (зашифрованном) виде. Сервер не имеет возможности их расшифровать.
Проект оснащён полным циклом CI/CD процесса:
- автоматизированное тестирование: каждый commit вызывает запуск юнит-тестов;
- сборка и публикация образов: прошедший тесты код автоматически упаковывается в Docker-образы, которые публикуются в Docker Hub;
- Deploy посредством Docker Compose: передача проекта в эксплуатацию осуществляется через Docker Compose, где проект интегрируется с СУБД с автоматической миграцией схемы БД с помощью migrate.
- Внедрить поддержку протокола gRPC.
- Расширить основную функциональность системы.
- Продолжать оснащать код юнит-тестами.
- Оснастить систему дополнительными видами тестирования: интеграционными и e2e-тестами.
- Освоить применение Kubernetes для оркестрации контейнеров и повысить опыт управления производственными системами.








