diff --git a/Report/appendices/appendix-b.typ b/Report/appendices/appendix-b.typ index 1aafe18..d50c124 100644 --- a/Report/appendices/appendix-b.typ +++ b/Report/appendices/appendix-b.typ @@ -50,17 +50,17 @@ Wallenc — мобильное приложение для Android: `VaultsManag #pz-fig("fig_06_encrypt_dialog.jpg", [Диалог включения шифрования], "fig-06-rp") -=== Открытие и закрытие зашифрованного vault +=== Открытие и закрытие зашифрованного storage -1. Для зашифрованного vault выберите «Открыть». -2. Введите пароль. При успехе содержимое доступно для просмотра. -3. Используйте «Закрыть» для блокировки. +1. Для зашифрованного storage выберите «Открыть». +2. Введите пароль. При успехе содержимое storage доступно для просмотра (`IUnlockManager`). +3. Используйте «Закрыть» для блокировки storage. #pz-fig("fig_07_open_close_dialog.jpg", [Диалог открытия и закрытия], "fig-07-rp") === Переименование и удаление -Долгое нажатие или меню vault → «Переименовать» / «Удалить». Подтвердите действие в диалоге. +Долгое нажатие или меню storage → «Переименовать» / «Удалить». Подтвердите действие в диалоге. #pz-fig("fig_08_rename_delete_dialog.jpg", [Диалог переименования и удаления], "fig-08-rp") diff --git a/Report/images/IMAGES_REGISTRY.md b/Report/images/IMAGES_REGISTRY.md index a09548c..2ac5cd1 100644 --- a/Report/images/IMAGES_REGISTRY.md +++ b/Report/images/IMAGES_REGISTRY.md @@ -23,8 +23,8 @@ | № | Имя файла | Тип | Статус | Где в ПЗ | Примечание (содержание) | label | |---|-----------|-----|--------|----------|-------------------------|-------| | 01 | `fig_01_start_sync.png` | PlantUML | ready | гл. 3.3.3, 4.1.4 | Старт → Room → SyncWorker. **PUML** | fig-01 | -| 02 | `fig_02_vault_lifecycle.png` | PlantUML | ready | гл. 3.3.3, 4.1.4 | Жизненный цикл storage. **PUML** | fig-02 | -| 03 | `fig_03_navigation_hub.png` | PlantUML | ready | гл. 3.3.3, 4.1.4 | Навигация + SyncWorker. **PUML** | fig-03 | +| 02 | `fig_02_vault_lifecycle.png` | PlantUML | ready | гл. 3.3.3, 4.1.4 | Жизненный цикл **IStorage** (не vault). **PUML** | fig-02 | +| 03 | `fig_03_navigation_hub.png` | PlantUML | ready | гл. 3.3.3, 4.1.4 | Main: LocalVault → storage; удалённые vault → VaultBrowser → storage. **PUML** | fig-03 | | 04 | `fig_04_domain_class.png` | PlantUML | ready | гл. 2.3.2, 4.2.1 | Классы `:domain`. **PUML** | fig-04 | | 05 | `fig_05_local_vaults.jpg` | Скриншот UI | ready | гл. 3.4, 5, прил. Б, В | Список storage (локальный vault) | fig-05 | | 06 | `fig_06_encrypt_dialog.jpg` | Скриншот UI | ready | гл. 3.4, 4.1.1, 5, прил. Б, В | Диалог включения шифрования | fig-06 | @@ -36,7 +36,7 @@ | 12 | `fig_12_tasks_screen.jpg` | Скриншот UI | ready | гл. 5.2.3, прил. В | Экран задач | fig-12 | | 13 | `fig_13_tasks_notification.jpg` | Скриншот UI | ready | гл. 5.2.3, прил. В | Уведомление о задаче | fig-13 | | 14 | `fig_14_context_system.png` | PlantUML | ready | гл. 1.2.1, 2.1.4 | Контекстная диаграмма. **PUML** | fig-14 | -| 15 | `fig_15_bpmn_vault.png` | PlantUML | ready | гл. 2.1.3 | BPMN. **PUML** | fig-15 | +| 15 | `fig_15_bpmn_vault.png` | PlantUML | ready | гл. 2.1.3 | BPMN жизненный цикл **storage** (шифрование storage, не vault). **PUML** | fig-15 | | 16 | `fig_16_dfd_level0.png` | PlantUML | ready | гл. 2.2 | DFD-0. **PUML** | fig-16 | | 17 | `fig_17_use_case.png` | PlantUML | ready | гл. 2.3.1 | Прецеденты. **PUML** | fig-17 | | 18 | `fig_18_deployment.png` | PlantUML | ready | гл. 2.3.3 | Развёртывание. **PUML** | fig-18 | @@ -60,6 +60,8 @@ Номер «Рисунок N» — по порядку появления в тексте, не по номеру в имени файла. +Пример: **Рисунок 3** в ПЗ — это `fig_15_bpmn_vault.png` (гл. 2), а не `fig_03_navigation_hub.png` (гл. 3, обычно ~рис. 6). + ## fig_31 Один скрин `./gradlew connectedDebugAndroidTest` из корня репозитория, `BUILD SUCCESSFUL` (см. прежнее описание в истории реестра). diff --git a/Report/images/fig_01_start_sync.png b/Report/images/fig_01_start_sync.png index fb2510b..8379fb5 100644 Binary files a/Report/images/fig_01_start_sync.png and b/Report/images/fig_01_start_sync.png differ diff --git a/Report/images/fig_02_vault_lifecycle.png b/Report/images/fig_02_vault_lifecycle.png index afa548a..4419895 100644 Binary files a/Report/images/fig_02_vault_lifecycle.png and b/Report/images/fig_02_vault_lifecycle.png differ diff --git a/Report/images/fig_03_navigation_hub.png b/Report/images/fig_03_navigation_hub.png index d2fc0e8..6059e0d 100644 Binary files a/Report/images/fig_03_navigation_hub.png and b/Report/images/fig_03_navigation_hub.png differ diff --git a/Report/images/fig_04_domain_class.png b/Report/images/fig_04_domain_class.png index 57717dd..4978b99 100644 Binary files a/Report/images/fig_04_domain_class.png and b/Report/images/fig_04_domain_class.png differ diff --git a/Report/images/fig_11_room_schema.png b/Report/images/fig_11_room_schema.png index ad0d201..0da5a4c 100644 Binary files a/Report/images/fig_11_room_schema.png and b/Report/images/fig_11_room_schema.png differ diff --git a/Report/images/fig_14_context_system.png b/Report/images/fig_14_context_system.png index f514d89..6c6dfd8 100644 Binary files a/Report/images/fig_14_context_system.png and b/Report/images/fig_14_context_system.png differ diff --git a/Report/images/fig_15_bpmn_vault.png b/Report/images/fig_15_bpmn_vault.png index 652dda8..763582f 100644 Binary files a/Report/images/fig_15_bpmn_vault.png and b/Report/images/fig_15_bpmn_vault.png differ diff --git a/Report/images/fig_16_dfd_level0.png b/Report/images/fig_16_dfd_level0.png index b98ce72..d43a4e2 100644 Binary files a/Report/images/fig_16_dfd_level0.png and b/Report/images/fig_16_dfd_level0.png differ diff --git a/Report/images/fig_17_use_case.png b/Report/images/fig_17_use_case.png index 08ef4b6..8511889 100644 Binary files a/Report/images/fig_17_use_case.png and b/Report/images/fig_17_use_case.png differ diff --git a/Report/images/fig_18_deployment.png b/Report/images/fig_18_deployment.png index 3472170..08fae06 100644 Binary files a/Report/images/fig_18_deployment.png and b/Report/images/fig_18_deployment.png differ diff --git a/Report/images/fig_19_clean_architecture.png b/Report/images/fig_19_clean_architecture.png index c67179d..c699f2e 100644 Binary files a/Report/images/fig_19_clean_architecture.png and b/Report/images/fig_19_clean_architecture.png differ diff --git a/Report/images/fig_20_oauth_sequence.png b/Report/images/fig_20_oauth_sequence.png index 3d39bf8..15b6aaf 100644 Binary files a/Report/images/fig_20_oauth_sequence.png and b/Report/images/fig_20_oauth_sequence.png differ diff --git a/Report/images/fig_21_encrypt_flow.png b/Report/images/fig_21_encrypt_flow.png index 90959f7..f9069ae 100644 Binary files a/Report/images/fig_21_encrypt_flow.png and b/Report/images/fig_21_encrypt_flow.png differ diff --git a/Report/images/fig_22_cjm_vault.png b/Report/images/fig_22_cjm_vault.png index 92317e7..600b718 100644 Binary files a/Report/images/fig_22_cjm_vault.png and b/Report/images/fig_22_cjm_vault.png differ diff --git a/Report/images/fig_23_module_deps.png b/Report/images/fig_23_module_deps.png index 5cddbff..491a6b5 100644 Binary files a/Report/images/fig_23_module_deps.png and b/Report/images/fig_23_module_deps.png differ diff --git a/Report/images/fig_32_manual_test_checklist.png b/Report/images/fig_32_manual_test_checklist.png index 77aead8..cb4b2d6 100644 Binary files a/Report/images/fig_32_manual_test_checklist.png and b/Report/images/fig_32_manual_test_checklist.png differ diff --git a/Report/images/fig_35_sync_merge_algorithm.png b/Report/images/fig_35_sync_merge_algorithm.png index 1b0de67..df1fd47 100644 Binary files a/Report/images/fig_35_sync_merge_algorithm.png and b/Report/images/fig_35_sync_merge_algorithm.png differ diff --git a/Report/images/fig_36_ml_on_device.png b/Report/images/fig_36_ml_on_device.png index 49d4c09..1cb32c5 100644 Binary files a/Report/images/fig_36_ml_on_device.png and b/Report/images/fig_36_ml_on_device.png differ diff --git a/Report/includes/abbreviations.typ b/Report/includes/abbreviations.typ index 5523c33..f35647d 100644 --- a/Report/includes/abbreviations.typ +++ b/Report/includes/abbreviations.typ @@ -7,7 +7,7 @@ В настоящем документе применяются следующие обозначения и сокращения: #pz-table( - [], + [Обозначения и сокращения], 2, table.header([Обозначение], [Расшифровка]), [API], [Application Programming Interface — программный интерфейс приложения], diff --git a/Report/includes/abstract-en.typ b/Report/includes/abstract-en.typ index f262eb1..3d1457f 100644 --- a/Report/includes/abstract-en.typ +++ b/Report/includes/abstract-en.typ @@ -12,15 +12,11 @@ #pz-front-heading(page-break: false)[Annotation] #{ - set par(first-line-indent: 0pt, justify: true) + set par(first-line-indent: 1.25cm, justify: true) - [The thesis is devoted to a mobile application for secure storage of user data (the Wallenc software product). Data is encrypted on the device before upload; decryption is performed only when the user enters a valid key. The work includes analysis of analogues, requirements, architecture and UI design, Kotlin implementation for Android, testing, and a brief economic assessment.] + [This explanatory note is devoted to the development of a mobile application for secure storage of user data (the Wallenc software product). It describes analysis of the subject area and analogues, requirements formulation, architecture and user interface design, software implementation in Kotlin (Android, Jetpack Compose, Room, Hilt), testing, and a brief economic assessment.] parbreak() - [The application uses MVVM and Clean Architecture. Main features are local and remote vault management, client-side AES encryption, Room metadata storage, and Yandex OAuth integration.] - - parbreak() - - [Keywords: mobile application, client-side encryption, Android, vault, OAuth, Room.] + [Implemented: the VaultsManager → vault → storage → files hierarchy (one LocalVault on the device, remote vaults via OAuth), client-side AES encryption, service metadata in Room, and a project-level synchronization contour without passing encryption keys to the provider. The source code is hosted in a private GitLab repository at Southern Federal University. Full source listings are in Appendix A; software documentation is in Appendix B.] } diff --git a/Report/includes/ch01.typ b/Report/includes/ch01.typ index deae5df..fc60884 100644 --- a/Report/includes/ch01.typ +++ b/Report/includes/ch01.typ @@ -18,7 +18,7 @@ === Назначение и цели создания системы -*Назначение* системы Wallenc — предоставление пользователю мобильного клиента для работы с иерархией *vault → storage → файлы*: один локальный vault на устройстве, удалённые vault по учётным записям провайдера; внутри каждого vault пользователь управляет отдельными storage с обязательным клиентским шифрованием до выгрузки во внешнее хранилище. +*Назначение* системы Wallenc — предоставление пользователю мобильного клиента для работы с иерархией *VaultsManager → vault → storage → файлы*: один `LocalVault` на устройстве, удалённые vault по OAuth; внутри vault пользователь создаёт и управляет *storage*; шифрование (`StorageEncryptionInfo`, `Encryptor`) применяется к storage, а не к vault. *Цели создания*: обеспечить единую модель vault и storage; минимизировать доверие к провайдеру; поддержать расширение списка провайдеров через адаптеры; сохранить служебные метаданные в локальной БД без хранения пользовательского контента в открытом виде. diff --git a/Report/includes/ch02.typ b/Report/includes/ch02.typ index b1744b4..e7d3339 100644 --- a/Report/includes/ch02.typ +++ b/Report/includes/ch02.typ @@ -10,13 +10,13 @@ === Карта процессов -Основные процессы: создание storage в vault → опциональное шифрование → открытие → работа с файлами → закрытие; для удалённых vault — OAuth → привязка учётной записи → листинг storage провайдера → проектная синхронизация. +Основные процессы: создание storage в vault → опциональное шифрование storage → открытие storage → работа с файлами → закрытие; для удалённых vault — OAuth → привязка учётной записи → листинг storage провайдера → проектная синхронизация. === Диаграмма BPMN -На рисунке @fig-15 представлена диаграмма BPMN основного процесса работы с vault. +На рисунке @fig-15 представлена диаграмма BPMN основного процесса работы со storage внутри vault. -#pz-fig("fig_15_bpmn_vault.png", [BPMN: создание vault, шифрование, открытие, работа с содержимым], "fig-15") +#pz-fig("fig_15_bpmn_vault.png", [BPMN: storage — создание, шифрование, открытие, содержимое], "fig-15") === Карта систем @@ -32,7 +32,7 @@ DFD уровня 0 (рис. @fig-16) отражает потоки между UI === Диаграмма прецедентов -Прецеденты включают управление vault, шифрование, работу с содержимым, OAuth и проектную синхронизацию (рис. @fig-17). +Прецеденты включают управление storage, подключение удалённых vault (OAuth), шифрование и открытие storage, работу с файлами и синхронизацию групп storage (рис. @fig-17). #pz-fig("fig_17_use_case.png", [Диаграмма прецедентов Wallenc], "fig-17") diff --git a/Report/includes/ch03.typ b/Report/includes/ch03.typ index eabdca1..2948f57 100644 --- a/Report/includes/ch03.typ +++ b/Report/includes/ch03.typ @@ -6,7 +6,7 @@ === Анализ конкурентов и определение сильных и слабых сторон -По результатам сравнения аналогов (табл. @tbl-analog) для Wallenc выделены сильные стороны: единый UI для локальных и удалённых vault, явное отображение состояния шифрования, диалоги подтверждения деструктивных операций. Слабые стороны конкурентов (привязка к экосистеме, узкая предметная область) учтены при проектировании навигации. +По результатам сравнения аналогов (табл. @tbl-analog) для Wallenc выделены сильные стороны: единый UI для списков storage (в LocalVault и удалённых vault), явное отображение состояния шифрования storage, диалоги подтверждения деструктивных операций. Слабые стороны конкурентов (привязка к экосистеме, узкая предметная область) учтены при проектировании навигации. === Ограничения и допущения проектирования UI @@ -16,7 +16,7 @@ === Потребности и барьеры пользователя -Потребности: хранить файлы в «сейфе» без доверия к облаку; синхронизировать между устройствами. Барьеры: сложность OAuth, страх потери пароля, неочевидность состояния «vault открыт». +Потребности: хранить файлы в «сейфе» без доверия к облаку; синхронизировать между устройствами. Барьеры: сложность OAuth, страх потери пароля, неочевидность состояния «storage открыт» (разблокирован). === Полезные сценарии из аналогов @@ -31,26 +31,26 @@ 3, table.header([ID], [Формулировка], [Критерий приёмки]), [US-1], [Создаю storage для файлов в локальном vault на устройстве], [Storage в списке (рис. 5)], - [US-2], [Включаю шифрование vault паролем], [Статус encrypted, тест T-8], - [US-3], [Открываю зашифрованный vault ключом], [Доступ к контенту, тест T-9], + [US-2], [Включаю шифрование storage паролем], [Статус encrypted, тест T-8], + [US-3], [Открываю зашифрованный storage ключом], [Доступ к контенту, тест T-9], [US-4], [Подключаю Яндекс и удалённый vault], [OAuth OK, тест T-10], [US-5], [Вижу прогресс фоновых задач], [Экран задач, тест T-11], - [US-6], [Храню TOTP и текстовые секреты в vault], [`TwoFaTotpTest`, UI IT], + [US-6], [Храню TOTP и текстовые секреты в storage], [`TwoFaTotpTest`, UI IT], ) === Customer Journey Map -CJM сценария «защитить и открыть vault» представлен на рисунке @fig-22. +CJM сценария «защитить и открыть storage» представлен на рисунке @fig-22. -#pz-fig("fig_22_cjm_vault.png", [Customer Journey Map: защита и открытие vault], "fig-22") +#pz-fig("fig_22_cjm_vault.png", [Customer Journey Map: защита и открытие storage], "fig-22") === Пользовательский сценарий -Диаграммы потоков: старт приложения и фоновая синхронизация (@fig-01), жизненный цикл vault (@fig-02), навигация с главного экрана (@fig-03). +Диаграммы потоков: старт приложения и фоновая синхронизация (@fig-01), жизненный цикл storage (@fig-02), навигация Main: LocalVault / удалённые vault → storage (@fig-03). -#pz-fig("fig_01_start_sync.png", [Старт приложения и фоновая синхронизация (проект)], "fig-01") -#pz-fig("fig_02_vault_lifecycle.png", [Жизненный цикл vault и очередь синхронизации], "fig-02") -#pz-fig("fig_03_navigation_hub.png", [Навигация с главного экрана и SyncWorker], "fig-03") +#pz-fig("fig_01_start_sync.png", [Старт приложения и фоновая синхронизация], "fig-01") +#pz-fig("fig_02_vault_lifecycle.png", [Жизненный цикл storage и журнал синхронизации], "fig-02") +#pz-fig("fig_03_navigation_hub.png", [Навигация Main: список storage, VaultBrowser, StorageHome], "fig-03") == Проработка прототипа и особенности дизайна @@ -58,7 +58,7 @@ CJM сценария «защитить и открыть vault» предста #pz-fig("fig_05_local_vaults.jpg", [Список storage в локальном vault (экран «локальные vault»)], "fig-05") #pz-fig("fig_06_encrypt_dialog.jpg", [Диалог включения шифрования], "fig-06") -#pz-fig("fig_07_open_close_dialog.jpg", [Диалог открытия и закрытия vault], "fig-07") +#pz-fig("fig_07_open_close_dialog.jpg", [Диалог открытия и закрытия storage], "fig-07") #pz-fig("fig_08_rename_delete_dialog.jpg", [Диалог переименования и удаления], "fig-08") #pz-fig("fig_09_remote_vaults.jpg", [Экран удалённых vault], "fig-09") #pz-fig("fig_10_yandex_oauth.jpg", [Добавление удалённого vault, OAuth Яндекс], "fig-10") @@ -67,7 +67,7 @@ CJM сценария «защитить и открыть vault» предста == Требования к эргономике и доступности -Интерфейс должен отображать состояние vault без перехода в технические экраны: признаки «зашифровано», «открыто», «выполняется операция» (`isBusy`). Диалоги деструктивных действий (удаление, отключение шифрования) требуют явного подтверждения. Тексты сообщений об ошибках OAuth и неверном ключе формулируются нейтрально, без раскрытия внутренних путей и имён файлов. +Интерфейс должен отображать состояние каждого storage без перехода в технические экраны: признаки «зашифровано», «открыто» (`IUnlockManager.openedStorages`), «выполняется операция» (`isBusy`). Диалоги деструктивных действий (удаление storage, отключение шифрования) требуют явного подтверждения. Тексты сообщений об ошибках OAuth и неверном ключе формулируются нейтрально, без раскрытия внутренних путей и имён файлов. == Вывод diff --git a/Report/includes/ch04.typ b/Report/includes/ch04.typ index 0b001d6..8be15c5 100644 --- a/Report/includes/ch04.typ +++ b/Report/includes/ch04.typ @@ -10,7 +10,7 @@ Класс `Encryptor` формирует `StorageEncryptionInfo`, проверяет ключ и выполняет шифрование/дешифрование на клиенте. Unit-тесты подтверждают корректность для верного и неверного ключа (гл. 5). -=== Модуль управления vault и шифрованием +=== Модуль управления storage и шифрованием Use case `ManageStoragesEncryptionUseCase` инкапсулирует проверку `canEncrypt`, включение шифрования и открытие хранилища. ViewModel предотвращает повторный запуск шифрования для занятого storage. @@ -136,12 +136,12 @@ abstract class AppDb : IAppDb, RoomDatabase() Модуль `:ui` и `:app` содержат Compose-экраны, ViewModel и навигацию. OAuth Яндекс запускается из UI удалённых vault: ```kotlin -viewModel.yandexSignIn.launch { outcome -> +remoteVaultAuthenticator.beginLink(CloudBrand.YANDEX) { outcome -> when (outcome) { - is RemoteYandexAuthResult.Success -> - viewModel.onYandexAuthSuccess(outcome.accessToken) - is RemoteYandexAuthResult.Failure -> { /* ошибка */ } - RemoteYandexAuthResult.Cancelled -> { } + is VaultLinkOutcome.Success -> + viewModel.onVaultLinked(outcome.registration) + is VaultLinkOutcome.Failed -> { /* ошибка */ } + VaultLinkOutcome.Cancelled -> { } } } ``` diff --git a/Report/includes/ch05.typ b/Report/includes/ch05.typ index e265a19..711f906 100644 --- a/Report/includes/ch05.typ +++ b/Report/includes/ch05.typ @@ -42,8 +42,8 @@ [T-5], [2FA TOTP генерация], [Unit], [Да], [Совпадение с эталоном Java OTP], [T-6], [Маппинг ошибок сети/диска], [Unit], [Да], [Типизированные `WallencException`], [T-7], [CRUD storage в LocalVault], [Ручной], [Нет], [Список обновлён (рис. @fig-05)], - [T-8], [Включение шифрования vault], [Ручной], [Нет], [Статус «зашифровано» (рис. @fig-06)], - [T-9], [Открытие/закрытие vault], [Ручной], [Нет], [Доступ только с ключом (рис. @fig-07)], + [T-8], [Включение шифрования storage], [Ручной], [Нет], [Статус «зашифровано» (рис. @fig-06)], + [T-9], [Открытие/закрытие storage], [Ручной], [Нет], [Доступ только с ключом (рис. @fig-07)], [T-10], [OAuth Яндекс], [Ручной / IT], [Частично], [Токен в Room (рис. @fig-10)], [T-11], [Экран задач и уведомления], [Ручной], [Частично], [Прогресс и завершение (рис. 12–13)], [T-12], [Compose: секреты и 2FA], [IT], [Да], [Отображение без падений (рис. @fig-33–@fig-34)], @@ -127,7 +127,7 @@ table.header([ID], [Шаг], [Статус], [Фактический результат], [Иллюстрация]), [T-7], [Создать storage в LocalVault], [OK], [Storage в списке], [@fig-05], [T-8], [Включить шифрование], [OK], [Статус encrypted], [@fig-06], - [T-9], [Открыть/закрыть vault], [OK], [Контент только при открытом vault], [@fig-07], + [T-9], [Открыть/закрыть storage], [OK], [Контент только при открытом storage], [@fig-07], [T-10], [OAuth Яндекс], [OK], [Запись в `DbYandexAccount`], [@fig-10], [T-11], [Фоновая задача шифрования], [OK], [Прогресс на экране задач], [рис. 12], [T-12], [Уведомление о завершении], [OK], [Notification отображён], [рис. 13], diff --git a/Report/includes/ch07-vpk.typ b/Report/includes/ch07-vpk.typ index b737d2e..687b5df 100644 --- a/Report/includes/ch07-vpk.typ +++ b/Report/includes/ch07-vpk.typ @@ -6,7 +6,7 @@ #emph[Способен решать прикладные задачи анализа данных и принятия решений с использованием искусственного интеллекта.] -В текущей версии Wallenc модели машинного обучения в runtime не внедрены: продукт строится на zero-knowledge модели, отсутствует доверенный сервер приложения, а выгрузка расшифрованного содержимого vault на облако для обучения противоречила бы заявленным требованиям безопасности. Ниже рассмотрено, какие прикладные задачи анализа данных и автоматизированных решений *могли бы* быть добавлены в перспективе без нарушения клиентской модели угроз. +В текущей версии Wallenc модели машинного обучения в runtime не внедрены: продукт строится на zero-knowledge модели, отсутствует доверенный сервер приложения, а выгрузка расшифрованного содержимого storage на облако для обучения противоречила бы заявленным требованиям безопасности. Ниже рассмотрено, какие прикладные задачи анализа данных и автоматизированных решений *могли бы* быть добавлены в перспективе без нарушения клиентской модели угроз. == Связь компетенции с предметом ВКР diff --git a/Report/includes/common.typ b/Report/includes/common.typ index dbccda7..5917971 100644 --- a/Report/includes/common.typ +++ b/Report/includes/common.typ @@ -1,7 +1,7 @@ // Таблицы — как в «Пример работы с Typst.typ» и gost: figure + table + table.header. // Разрыв длинных таблиц и подпись сверху задаёт шаблон modern-g7-32 (style.typ). -#show table: set text(hyphenate: true) +#show table: set text(hyphenate: true, lang: "ru") #let pz-appendix-title(body) = heading(level: 1)[#body] @@ -160,19 +160,11 @@ let start-page = state("pz-table-start-page", none) figure( kind: table, - { - show table: set text(hyphenate: true, lang: "ru") - show table.cell: it => { - set align(left + top) - set par(justify: false) - it - } - context { - let fig-loc = here() - let tab-num = counter(figure.where(kind: table)).at(fig-loc).first() - start-page.update(none) - pz-table-inner(columns, header-cells, tab-num, start-page, ..arguments(..tail)) - } + context { + let fig-loc = here() + let tab-num = counter(figure.where(kind: table)).at(fig-loc).first() + start-page.update(none) + pz-table-inner(columns, header-cells, tab-num, start-page, ..arguments(..tail)) }, caption: caption, ) diff --git a/Report/puml/fig_01_start_sync.puml b/Report/puml/fig_01_start_sync.puml index a5423af..ac3ace1 100644 --- a/Report/puml/fig_01_start_sync.puml +++ b/Report/puml/fig_01_start_sync.puml @@ -21,9 +21,8 @@ start :Инициализация Room, загрузка метаданных vault; -if (Есть сохранённые vault?) then (нет) - :Экран «первый запуск» / - создание локального vault; +if (Есть LocalVault / storage?) then (нет) + :Первый запуск; else (да) endif @@ -35,10 +34,10 @@ else (нет) endif partition "**Основной поток (UI)**" { - :(A) Главный экран: - список локальных и удалённых vault; - :Действия пользователя - (открыть, зашифровать, содержимое…); + :(A) Main: LocalVault — список storage, + вкладка удалённых — список IVault; + :Действия с **storage** + (шифрование, открытие, файлы…); } fork diff --git a/Report/puml/fig_02_vault_lifecycle.puml b/Report/puml/fig_02_vault_lifecycle.puml index 283a930..16a2252 100644 --- a/Report/puml/fig_02_vault_lifecycle.puml +++ b/Report/puml/fig_02_vault_lifecycle.puml @@ -1,8 +1,8 @@ @startuml fig_02_vault_lifecycle scale 3 title -Wallenc — пользовательский поток: жизненный цикл vault -и точки постановки в очередь синхронизации (проект) +Wallenc — жизненный цикл storage (IStorage) +внутри IVault; журнал синхронизации end title skinparam defaultFontName "DejaVu Sans" @@ -13,45 +13,41 @@ skinparam state { skinparam noteBackgroundColor #E3F2FD skinparam noteBorderColor #1565C0 -state "(Б) Список vault" as List +state "(Б) Список storage\n(LocalVault или VaultBrowser)" as List -List --> Create : Создать vault -Create --> List : Vault создан +List --> Create : Создать storage\n(FAB) +Create --> List : Storage создан -List --> EncryptDlg : Включить шифрование -EncryptDlg --> Encrypting : Подтверждение, мастер-ключ +List --> EncryptDlg : Включить шифрование storage +EncryptDlg --> Encrypting : Подтверждение, ключ state Encrypting { - state "Шифрование данных + запись метаданных" as EncWork + state "Шифрование + метаданные Room" as EncWork } Encrypting --> List : Готово note right of Encrypting - После успешной записи **коммита** - в историю Storage (проект): - UUID storage → **очередь синхронизации** - в Room (для таймера) + Запись в журнал sync (проект): + UUID **storage** → очередь + группы DbStorageSyncGroup end note -List --> OpenDlg : Открыть зашифрованный +List --> OpenDlg : Открыть зашифрованный storage OpenDlg --> Opened : Ключ верный OpenDlg --> List : Отмена / неверный ключ state Opened { - state "Просмотр / работа с содержимым" as Browse + state "Файлы, секреты, 2FA\n(StorageHome)" as Browse } -Opened --> List : Закрыть vault / блокировка +Opened --> List : Закрыть / заблокировать storage -List --> RenameDel : Переименовать / удалить +List --> RenameDel : Переименовать / удалить storage RenameDel --> List : Подтверждение note bottom of List - **Синхронизация (проект):** любое изменение, - порождающее новый **коммит** в Storage, - добавляет storage UUID в таблицу очереди; - **SyncService** по таймеру обрабатывает очередь, - сравнивает истории коммитов с удалённой копией - и приводит зашифрованное содержимое - к одному состоянию (без передачи ключей). + **Синхронизация:** изменения в **storage** + пишутся в журнал; StorageSyncEngine + согласует группы storage по ревизиям + (зашифрованное содержимое, без ключей). end note @enduml diff --git a/Report/puml/fig_03_navigation_hub.puml b/Report/puml/fig_03_navigation_hub.puml index d213d73..b32c597 100644 --- a/Report/puml/fig_03_navigation_hub.puml +++ b/Report/puml/fig_03_navigation_hub.puml @@ -1,8 +1,8 @@ @startuml fig_03_navigation_hub scale 2 title -Wallenc — навигация от главного экрана -и связь с фоновой синхронизацией (проект) +Wallenc — навигация (Main) и доменная иерархия +VaultsManager → IVault → IStorage → файлы end title skinparam defaultFontName "DejaVu Sans" @@ -13,39 +13,42 @@ skinparam noteBorderColor #C2185B start -:(A) Главный экран: -список локальных vault; +partition "**Main: нижняя навигация**" { + :(A) Вкладка LocalVault\n(один LocalVault на устройстве); + note right + На экране — список **IStorage**, + не список vault + end note -repeat - :Ожидание действия пользователя; - backward:Назад с подэкрана; - switch (Действие?) - case (FAB / новый vault) - :Создание локального vault; - case (Выбор vault) - :Карточка / детали vault; - case (Удалённые vault) - :Экран удалённых vault; - if (Нужен OAuth Яндекс?) then (да) - :Авторизация Яндекс; - endif - case (Настройки) - :Экран настроек; - endswitch -repeat while (Пользователь в приложении?) is (да) --> нет; + repeat + :Ожидание действия; + backward:Назад с вложенного экрана; + switch (Действие?) + case (FAB) + :createStorage()\nновый **storage** в LocalVault; + case (Выбор storage) + :StorageHome:\nфайлы, 2FA, текстовые секреты; + case (Вкладка «Удалённые vault») + :Список **IVault** (Yandex по OAuth); + if (Нужен OAuth?) then (да) + :Авторизация Яндекс; + endif + :Выбор vault → VaultBrowser; + :Список **storage** в выбранном vault; + :StorageHome; + endswitch + repeat while (Пользователь в Main?) is (да) + -> нет; +} stop floating note right - **Фон: SyncWorker (по таймеру Android) — проект** - • Room: таблица очереди с **UUID storage** - • Периодический запуск метода синхронизации - • Для каждого Storage — история **коммитов** (как git) - • Сравнение локальной и удалённой истории, - приведение зашифрованного содержимого - к одному состоянию (ключи на сервер не уходят) - • Работает **независимо** от текущего экрана UI + **Фон: StorageSyncEngine** + • DbStorageSyncGroup: UUID **storage** в группе + • Журнал изменений по путям, merge ревизий + • Независимо от текущего экрана UI + • Ключи шифрования провайдеру не передаются end note @enduml diff --git a/Report/puml/fig_04_domain_class.puml b/Report/puml/fig_04_domain_class.puml index 30485cb..37541f4 100644 --- a/Report/puml/fig_04_domain_class.puml +++ b/Report/puml/fig_04_domain_class.puml @@ -1,4 +1,5 @@ @startuml fig_04_domain_class +title Модуль :domain — IVaultsManager / IVault / IStorage scale 1.15 skinparam shadowing false skinparam classFontSize 10 @@ -23,9 +24,13 @@ package usecases { class GetOpenedStoragesUseCase { + getOpenedStorages(): StateFlow> } - class ManageLocalVaultUseCase { - + getLocalStorages(): StateFlow> - + createStorage(): Unit + class ManageVaultUseCase { + + find(UUID): IVault? + + storagesOf(UUID): Flow> + + createStorage(UUID): IStorage + } + class FindStorageUseCase { + + find(UUID): IStorage? } class StorageFileManagementUseCase { + getAllDirs(): Unit @@ -101,9 +106,6 @@ package interfaces { class ILogger { + debug(String, String): void } - class IYandexVault { - + getAccountEmail(): String - } class IMetaInfo { + getSize(): long + isDeleted(): boolean @@ -125,13 +127,9 @@ package interfaces { + isVirtualStorage(): boolean } class IVaultsManager { - + getLocalVault(): IVault - + removeRemoteVault(UUID): Unit - + addYandexVault(String): Unit - + getRemoteVaults(): StateFlow> - + getAllStorages(): StateFlow> - + getAllVaults(): StateFlow> - + getUnlockManager(): IUnlockManager + + vaults: StateFlow> + + allStorages: StateFlow> + + unlockManager: IUnlockManager } class IStorageMetaInfo { + getEncInfo(): StorageEncryptionInfo @@ -150,22 +148,16 @@ package interfaces { + getMetaInfo(): StateFlow + isVirtualStorage(): boolean } - class IStorageExplorer { - + getCurrentPath(): StateFlow - } class IVaultInfo { - + getAvailableSpace(): StateFlow - + getType(): VaultType - + getTotalSpace(): StateFlow - + getUuid(): UUID - + isAvailable(): StateFlow - + getStorages(): StateFlow> + + uuid: UUID } class IUnlockManager { + + openedStorages: StateFlow> + + getOpenedStorageKey(UUID): EncryptKey + + open(IStorage, EncryptKey, boolean): IStorage + + rememberKey(IStorage, EncryptKey): Unit + close(IStorage): Unit + close(UUID): Unit - + open(IStorage, EncryptKey, boolean): Unit - + getOpenedStorages(): StateFlow> } class IDirectory { + getMetaInfo(): IMetaInfo @@ -194,15 +186,16 @@ package interfaces { + getFileInfo(String): Unit } class IVault { - + getAvailableSpace(): StateFlow - + getType(): VaultType - + getTotalSpace(): StateFlow + + uuid: UUID + + storages: StateFlow> + + storagesScanInProgress: StateFlow + + isAvailable: StateFlow + + totalSpace: StateFlow + + availableSpace: StateFlow + + createStorage(): IStorage + + createStorage(StorageEncryptionInfo): IStorage + remove(IStorage): Unit - + createStorage(StorageEncryptionInfo): Unit - + getUuid(): UUID - + isAvailable(): StateFlow - + getStorages(): StateFlow> - + createStorage(): Unit + + rescanStorages(): Unit } } @@ -277,25 +270,6 @@ package common.impl { } } -package auth { - class RemoteYandexAuthResult { - } - class RemoteYandexSignInLauncher { - + launch(): void - } -} - -package enums { - class VaultType { - + DECRYPTED: VaultType - + LOCAL: VaultType - + YANDEX: VaultType - + valueOf(String): VaultType - + values(): VaultType[] - + getEntries(): EnumEntries - } -} - usecases.ManageStoragesEncryptionUseCase ..> interfaces.IStorageMetaInfo usecases.ManageStoragesEncryptionUseCase ..> interfaces.IStorageInfo usecases.ManageStoragesEncryptionUseCase ..> tasks.TaskProgress @@ -312,20 +286,16 @@ usecases.RemoveStorageUseCase ..> interfaces.IUnlockManager usecases.RemoveStorageUseCase ..> interfaces.IVault tasks.TaskLogLine ..> tasks.TaskLogLevel tasks.PipelineWork ..> tasks.TaskContext -interfaces.IVault <|.. interfaces.IYandexVault -interfaces.IVaultInfo <|.. interfaces.IYandexVault -interfaces.IYandexVault ..> interfaces.IStorage -interfaces.IYandexVault ..> interfaces.IVault -interfaces.IYandexVault ..> enums.VaultType -interfaces.IYandexVault ..> datatypes.StorageEncryptionInfo usecases.GetOpenedStoragesUseCase ..> interfaces.IStorageInfo usecases.GetOpenedStoragesUseCase ..> interfaces.IUnlockManager tasks.TaskContext ..> tasks.TaskLogLevel tasks.TaskContext ..> tasks.TaskProgress tasks.TaskContext ..> tasks.TaskId -usecases.ManageLocalVaultUseCase ..> interfaces.IStorageInfo -usecases.ManageLocalVaultUseCase ..> interfaces.IVaultsManager -usecases.ManageLocalVaultUseCase ..> interfaces.IVault +usecases.ManageVaultUseCase ..> interfaces.IStorage +usecases.ManageVaultUseCase ..> interfaces.IVaultsManager +usecases.ManageVaultUseCase ..> interfaces.IVault +usecases.FindStorageUseCase ..> interfaces.IStorage +usecases.FindStorageUseCase ..> interfaces.IVaultsManager usecases.StorageFileManagementUseCase ..> interfaces.IFile usecases.StorageFileManagementUseCase ..> interfaces.IStorage usecases.StorageFileManagementUseCase ..> interfaces.IStorageInfo @@ -362,9 +332,7 @@ interfaces.IStorageInfo ..> interfaces.IStorageMetaInfo interfaces.IStorageInfo ..> interfaces.IStorage usecases.RenameStorageUseCase ..> interfaces.IStorage usecases.RenameStorageUseCase ..> interfaces.IStorageInfo -interfaces.IVaultInfo ..> interfaces.IStorageInfo interfaces.IVaultInfo ..> interfaces.IVault -interfaces.IVaultInfo ..> enums.VaultType tasks.TaskForegroundItem ..> tasks.TaskProgress tasks.TaskForegroundItem ..> tasks.TaskId interfaces.IUnlockManager ..> interfaces.IStorage @@ -376,9 +344,7 @@ interfaces.IStorageAccessor ..> datatypes.DataPackage interfaces.IVaultInfo <|.. interfaces.IVault interfaces.IVault ..> interfaces.IStorage interfaces.IVault ..> interfaces.IVaultInfo -interfaces.IVault ..> enums.VaultType interfaces.IVault ..> datatypes.StorageEncryptionInfo -auth.RemoteYandexSignInLauncher ..> auth.RemoteYandexAuthResult datatypes.DataPackage <|-- datatypes.DataPage datatypes.DataPage ..> datatypes.DataPackage interfaces.IFile <|.. common.impl.CommonFile diff --git a/Report/puml/fig_14_context_system.puml b/Report/puml/fig_14_context_system.puml index 9d130fc..aa6b56d 100644 --- a/Report/puml/fig_14_context_system.puml +++ b/Report/puml/fig_14_context_system.puml @@ -12,7 +12,7 @@ rectangle "Wallenc\n(Android)" as App { cloud "Внешний провайдер\n(Яндекс Диск API)" as Cloud -User --> UI : управление vault,\nфайлы, OAuth +User --> UI : storage, vault,\nOAuth, файлы UI --> Domain Domain --> Room Domain --> Cloud : ciphertext,\nOAuth, метаданные API diff --git a/Report/puml/fig_15_bpmn_vault.puml b/Report/puml/fig_15_bpmn_vault.puml index fda1ae1..76e0c59 100644 --- a/Report/puml/fig_15_bpmn_vault.puml +++ b/Report/puml/fig_15_bpmn_vault.puml @@ -1,6 +1,6 @@ @startuml fig_15_bpmn_vault scale 2 -title BPMN: жизненный цикл vault +title BPMN: жизненный цикл storage (IStorage) skinparam defaultFontName "DejaVu Sans" skinparam activity { BackgroundColor #F8F8F8 @@ -8,20 +8,23 @@ skinparam activity { } start -:Создать vault; -if (Нужно шифрование?) then (да) +:Создать **storage** в vault\n(createStorage); +note right + Vault (IVault) не шифруется. + Шифрование только у **storage** +end note +if (Включить шифрование storage?) then (да) :Ввести пароль; - :Шифрование данных; + :enableEncryption(storage); else (нет) endif -:Открыть vault; -:Работа с содержимым; -if (Удалённое хранилище?) then (да) - :OAuth / привязка; - :Синхронизация; +:openStorage(storage)\nпри необходимости; +:Работа с содержимым storage:\nфайлы, 2FA, секреты; +if (Storage в группе синхронизации?) then (да) + :StorageSyncEngine\n(журнал ревизий); else (нет) endif -:Закрыть vault; +:closeStorage / блокировка; stop @enduml diff --git a/Report/puml/fig_21_encrypt_flow.puml b/Report/puml/fig_21_encrypt_flow.puml index c6f9086..df67291 100644 --- a/Report/puml/fig_21_encrypt_flow.puml +++ b/Report/puml/fig_21_encrypt_flow.puml @@ -10,14 +10,14 @@ skinparam activity { start :Пользователь включает шифрование; :Сформировать EncryptKey; -:Encryptor.encrypt данные vault; -:Записать StorageEncryptionInfo\nв Room; +:Encryptor: шифрование файлов\n**storage** (IStorageAccessor); +:storage.setEncInfo → Room\n(DbStorageMetaInfo); :checkKey(ключ); if (Ключ верный?) then (да) - :openStorage(зашифрованное представление); - :Доступ к содержимому; + :IUnlockManager.open(storage)\nвиртуальное представление; + :Доступ к файлам storage; else (нет) - :Ошибка, vault закрыт; + :Ошибка, storage не открыт; endif stop diff --git a/Report/puml/fig_22_cjm_vault.puml b/Report/puml/fig_22_cjm_vault.puml index e46cf27..ec9255e 100644 --- a/Report/puml/fig_22_cjm_vault.puml +++ b/Report/puml/fig_22_cjm_vault.puml @@ -1,6 +1,6 @@ @startuml fig_22_cjm_vault scale 3 -title Customer Journey Map: защита vault +title Customer Journey Map: защита storage skinparam defaultFontName "DejaVu Sans" |Этап| @@ -11,9 +11,9 @@ skinparam defaultFontName "DejaVu Sans" |Действия| |Понимает риск\nоблака| -|Создаёт vault,\nвключает шифрование| -|Открывает vault,\nработает с файлами| -|Синхронизирует\nбез передачи ключей| +|Создаёт storage,\nвключает шифрование storage| +|Открывает storage,\nработает с файлами| +|Синхронизирует storage\nбез передачи ключей| |Ожидания| |Данные не читаются\nпровайдером| diff --git a/Report/puml/fig_36_ml_on_device.puml b/Report/puml/fig_36_ml_on_device.puml index 3b43674..6395855 100644 --- a/Report/puml/fig_36_ml_on_device.puml +++ b/Report/puml/fig_36_ml_on_device.puml @@ -24,7 +24,7 @@ Enc ..> ML : опционально\nлокальные эмбеддинги\nп note bottom of ML Обучение: офлайн на размеченных\nсинтетических/агрегированных данных; - выгрузка содержимого vault\nна облако для train — не используется + выгрузка содержимого storage\nна облако для train — не используется end note @enduml diff --git a/Report/Пояснительная_записка_ПытковРЕ.typ b/Report/Пояснительная_записка_ПытковРЕ.typ index d930622..e9630fb 100644 --- a/Report/Пояснительная_записка_ПытковРЕ.typ +++ b/Report/Пояснительная_записка_ПытковРЕ.typ @@ -66,7 +66,7 @@ #pz-fig("fig_05_local_vaults.jpg", [Локальные vault], "fig-05-app") #pz-fig("fig_06_encrypt_dialog.jpg", [Диалог шифрования], "fig-06-app") -#pz-fig("fig_07_open_close_dialog.jpg", [Открытие и закрытие vault], "fig-07-app") +#pz-fig("fig_07_open_close_dialog.jpg", [Открытие и закрытие storage], "fig-07-app") #pz-fig("fig_08_rename_delete_dialog.jpg", [Переименование и удаление], "fig-08-app") #pz-fig("fig_09_remote_vaults.jpg", [Удалённые vault], "fig-09-app") #pz-fig("fig_10_yandex_oauth.jpg", [OAuth Яндекс], "fig-10-app")