diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c96648..44dad8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Формат: `ГГГГ-ММ-ДД | версия | изменение | контракты | риск` +- 2026-07-07 | v0.5.114 (122) | Требование владельца: звонки/push ДОЛЖНЫ работать при заблокированном телефоне. (1) Биометрическая привязка app password ОТКЛОНЕНА (вариант А) — она неустранимо блокировала приём звонка без разблокировки; откачена из main, сохранена на ветке wip/biometric-binding. App password остаётся защищён шифрованием в покое (Keystore AES-256-GCM из п.3, работает в фоне → звонки/push/приём при блокировке ОК). (2) Приватность локскрина: уведомления сообщений и звонков → VISIBILITY_PRIVATE + generic public-версия («Новое сообщение»/«Входящий звонок»), канал lockscreenVisibility=PRIVATE. Полный контент (отправитель/текст/имя звонящего) — только после разблокировки. Push у приложения plaintext, пароль для показа/звонка НЕ нужен. Проверено сборкой: assembleRelease 53 МБ | контракты не менялись | низкий: только UX уведомлений; звонки/push в фоне работают как раньше - 2026-07-07 | v0.5.114 (122) | Этап 0 п.4b (GPL): восстановлены затёртые копирайты Nextcloud в vendor/talk-android — точной сверкой с апстримом v23.0.0 (скачан с GitHub). 102 файла: искажённые email реальных разработчиков NC (@f7cloud.com → настоящие), холдер «F7cloud»/«F7cloud and F7cloud contributors» → «Nextcloud GmbH and Nextcloud contributors». Название продукта в заголовках оставлено «F7cloud Talk» (ребренд форка, требование trademark-политики NC). Менялись ТОЛЬКО строки копирайта в комментах, код не тронут (103+/103−). Проверено сборкой: assembleRelease 53 МБ OK | лицензирование/атрибуция (не код) | нет: функционально нейтрально, снимает нарушение GPLv3 §4 (атрибуция) - 2026-07-07 | v0.5.114 (122) | Этап 0 п.4a (GPL): добавлен LICENSE (GPL-3.0-or-later) в корень репо — приложение производно от vendored Nextcloud Talk (GPL), значит весь APK под GPL; раздел «Лицензия» в README (обязательство corresponding source по тегу релиза). Восстановление затёртых копирайтов Nextcloud в vendor (п.4b) — отдельно, сверкой с апстримом v23.0.0 | лицензирование (не код) | нет - 2026-07-07 | v0.5.114 (122) | Этап 0 п.3 (безопасность-минимум): (1) trust-all TLS отключён в release — гейт `if(!BuildConfig.DEBUG)` в UnsafeSsl + обе WebView-точки (OfficeWebViewClient, TalkCallActivity), чекбокс «доверять сертификату» скрыт в release (buildConfig включён в core:network и feature:talk); (2) allowBackup=false (переопределяет vendor true, подтверждено в собранном манифесте); (3) app password шифруется в покое ключом AndroidKeystore AES-256-GCM (KeystoreCrypto) + одноразовая миграция legacy-plaintext при load; (4) ревокация app password при logout (AppPasswordRevoker: DELETE /ocs/v2.php/core/apppassword, best-effort). Биометрическая привязка ключа — отдельная задача (конфликтует с фоновыми push/звонками, нужен кэш в памяти). Проверено сборкой: assembleRelease 53 МБ, подпись v2+v3, allowBackup=false OK | НОВЫЙ вызов OCS: DELETE core/apppassword при logout (стандартный NC endpoint) | средний: миграция хранилища и logout затрагивают все сессии — проверить на устройстве вход/выход/перезапуск diff --git a/core/push/src/main/java/ru/forbion/f7cloud/core/push/F7IncomingCallQueue.kt b/core/push/src/main/java/ru/forbion/f7cloud/core/push/F7IncomingCallQueue.kt index 9779983..df1b34a 100644 --- a/core/push/src/main/java/ru/forbion/f7cloud/core/push/F7IncomingCallQueue.kt +++ b/core/push/src/main/java/ru/forbion/f7cloud/core/push/F7IncomingCallQueue.kt @@ -241,7 +241,8 @@ object F7IncomingCallQueue { .setStyle(callStyle) .setCategory(NotificationCompat.CATEGORY_CALL) .setPriority(NotificationCompat.PRIORITY_MAX) - .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setVisibility(NotificationCompat.VISIBILITY_PRIVATE) + .setPublicVersion(genericCallPublic(context, intents.preview)) .setOngoing(true) .setAutoCancel(false) .setOnlyAlertOnce(true) @@ -282,7 +283,8 @@ object F7IncomingCallQueue { .setStyle(NotificationCompat.BigTextStyle().bigText(body)) .setCategory(NotificationCompat.CATEGORY_CALL) .setPriority(NotificationCompat.PRIORITY_MAX) - .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setVisibility(NotificationCompat.VISIBILITY_PRIVATE) + .setPublicVersion(genericCallPublic(context, intents.preview)) .setOngoing(true) .setAutoCancel(false) .setOnlyAlertOnce(true) @@ -304,6 +306,21 @@ object F7IncomingCallQueue { ?: throw IllegalStateException("NotificationManager unavailable") } + /** + * Обезличенная (public) версия уведомления звонка для локскрина: показывает лишь «Входящий + * звонок» без имени звонящего/комнаты (минимум информации, решение владельца). Полное имя — + * в полноэкранном UI звонка/после разблокировки. Full-screen intent работает независимо от visibility. + */ + private fun genericCallPublic(context: Context, preview: PendingIntent): android.app.Notification = + NotificationCompat.Builder(context, F7NotificationChannels.CALLS) + .setSmallIcon(android.R.drawable.stat_sys_phone_call) + .setContentTitle("F7cloud") + .setContentText("Входящий звонок") + .setCategory(NotificationCompat.CATEGORY_CALL) + .setPriority(NotificationCompat.PRIORITY_MAX) + .setContentIntent(preview) + .build() + private fun resolveJoinUrl(context: Context, call: PendingCall): String? { val raw = call.acceptUrl?.takeIf { it.isNotBlank() } ?: AuthStore(context).load()?.let { session -> diff --git a/core/push/src/main/java/ru/forbion/f7cloud/core/push/F7NotificationChannels.kt b/core/push/src/main/java/ru/forbion/f7cloud/core/push/F7NotificationChannels.kt index ec4f94d..699c574 100644 --- a/core/push/src/main/java/ru/forbion/f7cloud/core/push/F7NotificationChannels.kt +++ b/core/push/src/main/java/ru/forbion/f7cloud/core/push/F7NotificationChannels.kt @@ -48,7 +48,10 @@ object F7NotificationChannels { setSound(sound, soundAttrs) } setShowBadge(true) - lockscreenVisibility = android.app.Notification.VISIBILITY_PUBLIC + // Приватно на локскрине: система покажет public-версию (generic), а не полный + // контент (минимум информации, решение владельца). Public-версия задаётся + // per-notification в F7PushNotificationHelper / F7IncomingCallQueue. + lockscreenVisibility = android.app.Notification.VISIBILITY_PRIVATE }, ) } diff --git a/core/push/src/main/java/ru/forbion/f7cloud/core/push/F7PushNotificationHelper.kt b/core/push/src/main/java/ru/forbion/f7cloud/core/push/F7PushNotificationHelper.kt index b5235f7..08e837c 100644 --- a/core/push/src/main/java/ru/forbion/f7cloud/core/push/F7PushNotificationHelper.kt +++ b/core/push/src/main/java/ru/forbion/f7cloud/core/push/F7PushNotificationHelper.kt @@ -49,6 +49,21 @@ object F7PushNotificationHelper { } val iconRes = context.applicationInfo.icon.takeIf { it != 0 } ?: android.R.drawable.stat_notify_chat + // На локскрине — ОБЕЗЛИЧЕННАЯ версия (минимум информации, решение владельца): отправитель + // и текст не утекают на заблокированном экране. Полный контент — после разблокировки. + val genericText = when (type) { + "chat", "room", "message" -> "Новое сообщение" + "call" -> "Входящий звонок" + else -> "Новое уведомление" + } + val publicVersion = NotificationCompat.Builder(context, channel) + .setSmallIcon(iconRes) + .setContentTitle("F7cloud") + .setContentText(genericText) + .setAutoCancel(true) + .setPriority(priority) + .setContentIntent(pending) + .build() val notification = NotificationCompat.Builder(context, channel) .setSmallIcon(iconRes) .setContentTitle(title) @@ -56,6 +71,8 @@ object F7PushNotificationHelper { .setStyle(NotificationCompat.BigTextStyle().bigText(body)) .setAutoCancel(true) .setPriority(priority) + .setVisibility(NotificationCompat.VISIBILITY_PRIVATE) + .setPublicVersion(publicVersion) .setContentIntent(pending) .build() manager.notify((System.currentTimeMillis() % Int.MAX_VALUE).toInt(), notification)