diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 7490ae39..9ba2f497 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -99,7 +99,7 @@ jobs: - name: Install Dependencies run: | sudo apt-get update -y - sudo apt-get install -y tar clang cmake ninja-build pkg-config libgtk-3-dev make python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libunwind-dev locate patchelf gir1.2-appindicator3-0.1 libappindicator3-1 libappindicator3-dev + sudo apt-get install -y tar clang cmake ninja-build pkg-config libgtk-3-dev make python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libunwind-dev locate patchelf gir1.2-appindicator3-0.1 libappindicator3-1 libappindicator3-dev libsecret-1-0 libjsoncpp1 libsecret-1-dev libjsoncpp-dev - name: Install AppImage Tool run: | diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md index 125d1cae..a32d58af 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTION.md @@ -120,9 +120,9 @@ Do the following: - Download the latest Flutter SDK (>=2.15.1) & enable desktop support - Install Development dependencies in linux - - `libgstreamer1.0-dev` & `libgstreamer-plugins-base1.0-dev` (for Debian/Ubuntu) - - `gstreamer`, `gst-libav`, `gst-plugins-base` & `gst-plugins-good` (for Arch/Manjaro) - - `gstreamer1-devel gstreamer1-plugins-base-tools gstreamer1-doc gstreamer1-plugins-base-devel gstreamer1-plugins-good gstreamer1-plugins-good-extras` (for Fedora) + - `libappindicator3-1 gir1.2-appindicator3-0.1 libappindicator3-dev libsecret-1-0 libjsoncpp1 libsecret-1-dev libjsoncpp-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev` (for Debian/Ubuntu) + - `libappindicator-gtk3 libsecret jsoncpp gstreamer gst-libav gst-plugins-base gst-plugins-good` (for Arch/Manjaro) + - `libappindicator libsecret libsecret-devel jsoncpp gstreamer1-devel gstreamer1-plugins-base-tools gstreamer1-doc gstreamer1-plugins-base-devel gstreamer1-plugins-good gstreamer1-plugins-good-extras` (for Fedora) - Clone the Repo & Run `flutter pub get` in the Terminal - Create a `secrets.json` in root of the project. The structure should be similar to the following example: diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index dbb1709e..523f66b9 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -14,13 +14,34 @@ - - - - + + + + diff --git a/lib/main.dart b/lib/main.dart index 70d37027..71688d49 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -25,9 +25,9 @@ import 'package:spotube/services/audio_player.dart'; import 'package:spotube/services/pocketbase.dart'; import 'package:spotube/services/youtube.dart'; import 'package:spotube/themes/theme.dart'; +import 'package:spotube/utils/persisted_state_notifier.dart'; import 'package:system_theme/system_theme.dart'; import 'package:path_provider/path_provider.dart'; - import 'package:spotube/hooks/use_init_sys_tray.dart'; Future main(List rawArgs) async { @@ -83,6 +83,7 @@ Future main(List rawArgs) async { cachePrefix: "oss.krtirtho.spotube", cacheDir: (await getApplicationSupportDirectory()).path, ); + await PersistedStateNotifier.initializeBoxes(); Hive.registerAdapter(CacheTrackAdapter()); Hive.registerAdapter(CacheTrackEngagementAdapter()); Hive.registerAdapter(CacheTrackSkipSegmentAdapter()); diff --git a/lib/provider/authentication_provider.dart b/lib/provider/authentication_provider.dart index 057ddda2..c09cb199 100644 --- a/lib/provider/authentication_provider.dart +++ b/lib/provider/authentication_provider.dart @@ -79,7 +79,7 @@ class AuthenticationNotifier bool get isLoggedIn => state != null; - AuthenticationNotifier() : super(null, "authentication"); + AuthenticationNotifier() : super(null, "authentication", encrypted: true); Timer? _refreshTimer; diff --git a/lib/utils/persisted_state_notifier.dart b/lib/utils/persisted_state_notifier.dart index 78219051..60b8d2fd 100644 --- a/lib/utils/persisted_state_notifier.dart +++ b/lib/utils/persisted_state_notifier.dart @@ -1,22 +1,66 @@ import 'dart:async'; +import 'dart:convert'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:hive/hive.dart'; +import 'package:spotube/utils/primitive_utils.dart'; + +const secureStorage = FlutterSecureStorage( + aOptions: AndroidOptions( + encryptedSharedPreferences: true, + ), +); + +const kKeyBoxName = "spotube_box_name"; +String getBoxKey(String boxName) => "spotube_box_$boxName"; abstract class PersistedStateNotifier extends StateNotifier { final String cacheKey; + final bool encrypted; FutureOr onInit() {} PersistedStateNotifier( super.state, - this.cacheKey, - ) { + this.cacheKey, { + this.encrypted = false, + }) { _load().then((_) => onInit()); } + static late LazyBox _box; + static late LazyBox _encryptedBox; + + static Future initializeBoxes() async { + String? boxName = await secureStorage.read(key: kKeyBoxName); + + if (boxName == null) { + boxName = "spotube-${PrimitiveUtils.uuid.v4()}"; + await secureStorage.write(key: kKeyBoxName, value: boxName); + } + + String? encryptionKey = await secureStorage.read(key: getBoxKey(boxName)); + + if (encryptionKey == null) { + encryptionKey = base64Url.encode(Hive.generateSecureKey()); + await secureStorage.write( + key: getBoxKey(boxName), + value: encryptionKey, + ); + } + + _encryptedBox = await Hive.openLazyBox( + boxName, + encryptionCipher: HiveAesCipher(base64Url.decode(encryptionKey)), + ); + + _box = await Hive.openLazyBox("spotube_cache"); + } + + LazyBox get box => encrypted ? _encryptedBox : _box; + Future _load() async { - final box = await Hive.openLazyBox("spotube_cache"); final json = await box.get(cacheKey); if (json != null) { @@ -47,7 +91,6 @@ abstract class PersistedStateNotifier extends StateNotifier { } void save() async { - final box = await Hive.openLazyBox("spotube_cache"); box.put(cacheKey, toJson()); } diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index ed93fee3..2cfba36e 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) desktop_multi_window_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopMultiWindowPlugin"); desktop_multi_window_plugin_register_with_registrar(desktop_multi_window_registrar); + g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); + flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); g_autoptr(FlPluginRegistrar) native_context_menu_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "NativeContextMenuPlugin"); native_context_menu_plugin_register_with_registrar(native_context_menu_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 10ec1986..7fba8190 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_linux catcher desktop_multi_window + flutter_secure_storage_linux native_context_menu screen_retriever system_theme diff --git a/linux/packaging/deb/make_config.yaml b/linux/packaging/deb/make_config.yaml index 2d2acfea..e6ad8c61 100644 --- a/linux/packaging/deb/make_config.yaml +++ b/linux/packaging/deb/make_config.yaml @@ -14,6 +14,8 @@ dependencies: - libgstreamer-plugins-base1.0-dev - libappindicator3-1 - gir1.2-appindicator3-0.1 + - libsecret-1-0 + - libjsoncpp1 essential: false icon: assets/spotube-logo.png diff --git a/linux/packaging/rpm/make_config.yaml b/linux/packaging/rpm/make_config.yaml index a3996b92..7b39b750 100644 --- a/linux/packaging/rpm/make_config.yaml +++ b/linux/packaging/rpm/make_config.yaml @@ -12,6 +12,8 @@ requires: - gstreamer1-plugins-base-devel - gstreamer1-plugins-good - libappindicator + - jsoncpp + - libsecret display_name: Spotube diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 08679c1c..61fdf59c 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,6 +11,7 @@ import audioplayers_darwin import catcher import desktop_multi_window import device_info_plus +import flutter_secure_storage_macos import native_context_menu import package_info_plus import path_provider_foundation @@ -30,6 +31,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { CatcherPlugin.register(with: registry.registrar(forPlugin: "CatcherPlugin")) FlutterMultiWindowPlugin.register(with: registry.registrar(forPlugin: "FlutterMultiWindowPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) NativeContextMenuPlugin.register(with: registry.registrar(forPlugin: "NativeContextMenuPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) diff --git a/macos/Runner/DebugProfile.entitlements b/macos/Runner/DebugProfile.entitlements index 3ba6c126..e016b40d 100644 --- a/macos/Runner/DebugProfile.entitlements +++ b/macos/Runner/DebugProfile.entitlements @@ -1,14 +1,16 @@ - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.client - - com.apple.security.network.server - - - + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.client + + com.apple.security.network.server + + keychain-access-groups + + + \ No newline at end of file diff --git a/macos/Runner/Release.entitlements b/macos/Runner/Release.entitlements index 7a2230dc..cdf193e5 100644 --- a/macos/Runner/Release.entitlements +++ b/macos/Runner/Release.entitlements @@ -1,12 +1,14 @@ - - com.apple.security.app-sandbox - - com.apple.security.network.client - - com.apple.security.network.server - - - + + com.apple.security.app-sandbox + + com.apple.security.network.client + + com.apple.security.network.server + + keychain-access-groups + + + \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index e99abacc..7cb82a3d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -725,6 +725,54 @@ packages: url: "https://pub.dev" source: hosted version: "1.72.1" + flutter_secure_storage: + dependency: "direct main" + description: + name: flutter_secure_storage + sha256: "98352186ee7ad3639ccc77ad7924b773ff6883076ab952437d20f18a61f0a7c5" + url: "https://pub.dev" + source: hosted + version: "8.0.0" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + sha256: "0912ae29a572230ad52d8a4697e5518d7f0f429052fd51df7e5a7952c7efe2a3" + url: "https://pub.dev" + source: hosted + version: "1.1.3" + flutter_secure_storage_macos: + dependency: transitive + description: + name: flutter_secure_storage_macos + sha256: "083add01847fc1c80a07a08e1ed6927e9acd9618a35e330239d4422cd2a58c50" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + sha256: b3773190e385a3c8a382007893d678ae95462b3c2279e987b55d140d3b0cb81b + url: "https://pub.dev" + source: hosted + version: "1.0.1" + flutter_secure_storage_web: + dependency: transitive + description: + name: flutter_secure_storage_web + sha256: "42938e70d4b872e856e678c423cc0e9065d7d294f45bc41fc1981a4eb4beaffe" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + sha256: fc2910ec9b28d60598216c29ea763b3a96c401f0ce1d13cdf69ccb0e5c93c3ee + url: "https://pub.dev" + source: hosted + version: "2.0.0" flutter_svg: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index e32b70a8..621ca32d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,6 +37,7 @@ dependencies: flutter_hooks: ^0.18.2+1 flutter_inappwebview: ^5.7.2+3 flutter_riverpod: ^2.1.1 + flutter_secure_storage: ^8.0.0 flutter_svg: ^1.1.6 fuzzywuzzy: ^0.2.0 go_router: ^6.0.2 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index a8be95c8..b234d9f0 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("CatcherPlugin")); DesktopMultiWindowPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("DesktopMultiWindowPlugin")); + FlutterSecureStorageWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); NativeContextMenuPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("NativeContextMenuPlugin")); PermissionHandlerWindowsPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index bc353537..7f082953 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_windows catcher desktop_multi_window + flutter_secure_storage_windows native_context_menu permission_handler_windows screen_retriever