Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(linux): crash on no secret service #608

Merged
merged 1 commit into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions lib/components/shared/dialogs/prompt_dialog.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import 'package:flutter/material.dart';
import 'package:spotube/extensions/context.dart';

Future<bool> showPromptDialog({
required BuildContext context,
required String title,
required String message,
String okText = "Ok",
String cancelText = "Cancel",
String? cancelText = "Cancel",
}) async {
return showDialog<bool>(
context: context,
Expand All @@ -14,12 +15,15 @@ Future<bool> showPromptDialog({
title: Text(title),
content: Text(message),
actions: [
OutlinedButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text(cancelText),
),
if (cancelText != null)
OutlinedButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text(
cancelText == "Cancel" ? context.l10n.cancel : cancelText,
),
),
FilledButton(
child: Text(okText),
child: Text(okText == "Ok" ? context.l10n.ok : okText),
onPressed: () => Navigator.of(context).pop(true),
),
],
Expand Down
5 changes: 4 additions & 1 deletion lib/l10n/app_bn.arb
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,8 @@
"developers": "ডেভেলপার",
"not_logged_in": "আপনি লগইন করা নেই",
"search_mode": "অনুসন্ধান মোড",
"youtube_api_type": "API প্রকার"
"youtube_api_type": "API প্রকার",
"ok": "ঠিক আছে",
"failed_to_encrypt": "এনক্রিপ্ট করা ব্যর্থ হয়েছে",
"encryption_failed_warning": "Spotube আপনার তথ্যগুলি নিরাপদভাবে স্টোর করতে এনক্রিপশন ব্যবহার করে। কিন্তু এটি ব্যর্থ হয়েছে। তাই এটি অনিরাপদ স্টোরে ফলফল হবে\nযদি আপনি Linux ব্যবহার করেন, তবে দয়া করে নিশ্চিত হউন যে আপনার কোনও সিক্রেট-সার্ভিস gnome-keyring, kde-wallet, keepassxc ইত্যাদি ইনস্টল করা আছে"
}
5 changes: 4 additions & 1 deletion lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,8 @@
"developers": "Entwickler",
"not_logged_in": "Sie sind nicht angemeldet",
"search_mode": "Suchmodus",
"youtube_api_type": "API-Typ"
"youtube_api_type": "API-Typ",
"ok": "OK",
"failed_to_encrypt": "Verschlüsselung fehlgeschlagen",
"encryption_failed_warning": "Spotube verwendet Verschlüsselung, um Ihre Daten sicher zu speichern. Dies ist jedoch fehlgeschlagen. Daher wird es auf unsichere Speicherung zurückgreifen\nWenn Sie Linux verwenden, stellen Sie bitte sicher, dass Sie Secret-Services wie gnome-keyring, kde-wallet und keepassxc installiert haben"
}
7 changes: 5 additions & 2 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,8 @@
"developers": "Developers",
"not_logged_in": "You're not logged in",
"search_mode": "Search Mode",
"youtube_api_type": "API Type"
}
"youtube_api_type": "API Type",
"ok": "Ok",
"failed_to_encrypt": "Failed to encrypt",
"encryption_failed_warning": "Spotube uses encryption to securely store your data. But failed to do so. So it'll fallback to insecure storage\nIf you're using linux, please make sure you've any secret-service (gnome-keyring, kde-wallet, keepassxc etc) installed"
}
7 changes: 5 additions & 2 deletions lib/l10n/app_es.arb
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,8 @@
"developers": "Desarrolladores",
"not_logged_in": "No has iniciado sesión",
"search_mode": "Modo de búsqueda",
"youtube_api_type": "Tipo de API de YouTube"
}
"youtube_api_type": "Tipo de API de YouTube",
"ok": "OK",
"failed_to_encrypt": "Error al cifrar",
"encryption_failed_warning": "Spotube utiliza el cifrado para almacenar sus datos de forma segura. Pero ha fallado. Por lo tanto, volverá a un almacenamiento no seguro\nSi está utilizando Linux, asegúrese de tener instalados servicios secretos como gnome-keyring, kde-wallet y keepassxc"
}
5 changes: 4 additions & 1 deletion lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,8 @@
"developers": "Développeurs",
"not_logged_in": "Vous n'êtes pas connecté(e)",
"search_mode": "Mode de recherche",
"youtube_api_type": "Type d'API"
"youtube_api_type": "Type d'API",
"ok": "OK",
"failed_to_encrypt": "Échec de la cryptage",
"encryption_failed_warning": "Spotube utilise le cryptage pour stocker vos données en toute sécurité. Mais cela a échoué. Il basculera donc vers un stockage non sécurisé\nSi vous utilisez Linux, assurez-vous d'avoir installé des services secrets tels que gnome-keyring, kde-wallet et keepassxc"
}
5 changes: 4 additions & 1 deletion lib/l10n/app_hi.arb
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,8 @@
"developers": "डेवलपर्स",
"not_logged_in": "आप लॉग इन नहीं हैं",
"search_mode": "खोज मोड",
"youtube_api_type": "API प्रकार"
"youtube_api_type": "API प्रकार",
"ok": "ठीक है",
"failed_to_encrypt": "एन्क्रिप्ट करने में विफल रहा",
"encryption_failed_warning": "Spotube आपके डेटा को सुरक्षित रूप से स्टोर करने के लिए एन्क्रिप्शन का उपयोग करता है। लेकिन इसमें विफल रहा। इसलिए, यह असुरक्षित स्टोरेज पर फॉलबैक करेगा\nयदि आप Linux का उपयोग कर रहे हैं, तो कृपया सुनिश्चित करें कि आपके पास gnome-keyring, kde-wallet, keepassxc आदि जैसी कोई सीक्रेट-सर्विस इंस्टॉल की गई है"
}
5 changes: 4 additions & 1 deletion lib/l10n/app_ja.arb
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,8 @@
"developers": "開発",
"not_logged_in": "ログインしていません",
"search_mode": "検索モード",
"youtube_api_type": "APIの種類"
"youtube_api_type": "APIの種類",
"ok": "分かりました",
"failed_to_encrypt": "暗号化に失敗しました",
"encryption_failed_warning": "Spotubeはデータを安全に保存するために暗号化を使用しています。しかし、失敗しました。したがって、安全でないストレージにフォールバックします\nLinuxを使用している場合は、gnome-keyring、kde-wallet、keepassxcなどのシークレットサービスがインストールされていることを確認してください"
}
7 changes: 5 additions & 2 deletions lib/l10n/app_zh.arb
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,8 @@
"developers": "开发者",
"not_logged_in": "你尚未登录",
"search_mode": "搜索模式",
"youtube_api_type": "API 类型"
}
"youtube_api_type": "API 类型",
"ok": "确定",
"failed_to_encrypt": "加密失败",
"encryption_failed_warning": "Spotube使用加密来安全地存储您的数据。但是失败了。因此,它将回退到不安全的存储\n如果您使用Linux,请确保已安装gnome-keyring、kde-wallet和keepassxc等秘密服务"
}
13 changes: 13 additions & 0 deletions lib/pages/root/root_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:spotube/components/shared/dialogs/replace_downloaded_dialog.dart';
import 'package:spotube/components/root/bottom_player.dart';
import 'package:spotube/components/root/sidebar.dart';
import 'package:spotube/components/root/spotube_navigation_bar.dart';
import 'package:spotube/hooks/use_update_checker.dart';
import 'package:spotube/provider/download_manager_provider.dart';
import 'package:spotube/utils/persisted_state_notifier.dart';

const rootPaths = {
0: "/",
Expand All @@ -33,6 +35,17 @@ class RootApp extends HookConsumerWidget {
final showingDialogCompleter = useRef(Completer()..complete());
final downloader = ref.watch(downloadManagerProvider.notifier);

useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
final sharedPreferences = await SharedPreferences.getInstance();

if (sharedPreferences.getBool(kIsUsingEncryption) == false &&
context.mounted) {
await PersistedStateNotifier.showNoEncryptionDialog(context);
}
});
}, []);

useEffect(() {
downloader.onFileExists = (track) async {
if (!isMounted()) return false;
Expand Down
40 changes: 38 additions & 2 deletions lib/utils/persisted_state_notifier.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import 'dart:async';
import 'dart:convert';

import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hive/hive.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:spotube/collections/routes.dart';
import 'package:spotube/components/shared/dialogs/prompt_dialog.dart';
import 'package:spotube/extensions/context.dart';
import 'package:spotube/utils/platform.dart';
import 'package:spotube/utils/primitive_utils.dart';

Expand All @@ -15,6 +19,8 @@ const secureStorage = FlutterSecureStorage(
);

const kKeyBoxName = "spotube_box_name";
const kNoEncryptionWarningShownKey = "showedNoEncryptionWarning";
const kIsUsingEncryption = "isUsingEncryption";
String getBoxKey(String boxName) => "spotube_box_$boxName";

abstract class PersistedStateNotifier<T> extends StateNotifier<T> {
Expand All @@ -34,12 +40,36 @@ abstract class PersistedStateNotifier<T> extends StateNotifier<T> {
static late LazyBox _box;
static late LazyBox _encryptedBox;

static Future<void> showNoEncryptionDialog(BuildContext context) async {
final localStorage = await SharedPreferences.getInstance();
final wasShownAlready =
localStorage.getBool(kNoEncryptionWarningShownKey) == true;

if (wasShownAlready || !context.mounted) {
return;
}

await showPromptDialog(
context: context,
title: context.l10n.failed_to_encrypt,
message: context.l10n.encryption_failed_warning,
cancelText: null,
);
await localStorage.setBool(kNoEncryptionWarningShownKey, true);
}

static Future<String?> read(String key) async {
final localStorage = await SharedPreferences.getInstance();
if (kIsMacOS || kIsIOS) {
return localStorage.getString(key);
} else {
return secureStorage.read(key: key);
try {
await localStorage.setBool(kIsUsingEncryption, true);
return await secureStorage.read(key: key);
} catch (e) {
await localStorage.setBool(kIsUsingEncryption, false);
return localStorage.getString(key);
}
}
}

Expand All @@ -49,7 +79,13 @@ abstract class PersistedStateNotifier<T> extends StateNotifier<T> {
await localStorage.setString(key, value);
return;
} else {
return secureStorage.write(key: key, value: value);
try {
await localStorage.setBool(kIsUsingEncryption, true);
await secureStorage.write(key: key, value: value);
} catch (e) {
await localStorage.setBool(kIsUsingEncryption, false);
await localStorage.setString(key, value);
}
}
}

Expand Down