diff --git a/lib/page/subpage_settings.dart b/lib/page/subpage_settings.dart index 2c06bf1d..f2c2ab6e 100644 --- a/lib/page/subpage_settings.dart +++ b/lib/page/subpage_settings.dart @@ -237,8 +237,7 @@ class SettingsSubpageState extends PlatformSubpageState { "https://github.com/50431040/device_identity"), LicenseItem("tutorial_coach_mark", LICENSE_MIT, "https://github.com/RafaelBarbosatec/tutorial_coach_mark"), - LicenseItem("toml", LICENSE_MIT, - "https://github.com/just95/toml.dart"), + LicenseItem("toml", LICENSE_MIT, "https://github.com/just95/toml.dart"), LicenseItem("pub_semver", LICENSE_BSD_3_0_CLAUSE, "https://github.com/dart-lang/pub_semver"), ]; @@ -252,10 +251,10 @@ class SettingsSubpageState extends PlatformSubpageState { await ForumRepository.getInstance().logout(); } finally { progressDialog.dismiss(showAnim: false); - SettingsProvider.getInstance() - .preferences - ?.clear() - .then((value) => FlutterApp.restartApp(context)); + await SettingsProvider.getInstance().preferences?.clear(); + if (mounted) { + FlutterApp.restartApp(context); + } } } diff --git a/lib/util/shared_preferences.dart b/lib/util/shared_preferences.dart index 9d8ee197..c7915b1c 100644 --- a/lib/util/shared_preferences.dart +++ b/lib/util/shared_preferences.dart @@ -15,6 +15,8 @@ * along with thFlutterSecureStorageis program. If not, see . */ +import 'package:encrypt/encrypt.dart'; +import 'dart:async'; import 'dart:convert'; import 'dart:math'; @@ -35,7 +37,9 @@ class XSharedPreferences { final FlutterSecureStorage _keyStore; late final EncryptedSharedPreferences _preferences; - XSharedPreferences._() : _keyStore = const FlutterSecureStorage(); + XSharedPreferences._() : _keyStore = const FlutterSecureStorage( + wOptions: WindowsOptions(useBackwardCompatibility: true), + ); static XSharedPreferences? _instance; @@ -67,7 +71,7 @@ class XSharedPreferences { } String key = (await _instance!._keyStore.read(key: KEY_CIPHER))!; // initialize the encrypted preferences. - await EncryptedSharedPreferences.initialize(key); + await EncryptedSharedPreferences.initialize(key, encryptor: LegacyAESEncryptor()); _instance!._preferences = EncryptedSharedPreferences.getInstance(); // migrate the data from [SharedPreferences] to [EncryptedSharedPreferences] // if the data has not been flagged as migrated. @@ -97,11 +101,18 @@ class XSharedPreferences { // Proxy methods for [EncryptedSharedPreferences] - Future clear() => _preferences.clear(); + Future clear() async { + bool success = await _preferences.clear(); + if (success) { + // mark the data as migrated after clearing. Or the data written after clearing will be re-migrated. + await _instance!.setBool(KEY_MIGRATED, true); + } + return success; + } Future remove(String key) => _preferences.remove(key); - Future> getKeys() => _preferences.getKeys(); + FutureOr> getKeys() => _preferences.getKeys(); Future setString(String dataKey, String? dataValue) => _preferences.setString(dataKey, dataValue); @@ -141,3 +152,32 @@ class XSharedPreferences { } } } + + +/// @w568w (2024-11-26): +/// encrypt_shared_preferences quietly changed the default AES Encryptor to use SIC mode from CBC mode. +/// This is obviously a breaking change, but it is mentioned nowhere in the changelog. Average noob developer. +/// +/// So this class is an implementation of the legacy AES Encryptor. +class LegacyAESEncryptor extends IEncryptor{ + @override + String encrypt(String key, String plainText) { + assert(key.length == 16); + final cipherKey = Key.fromUtf8(key); + final encryptService = Encrypter(AES(cipherKey, mode: AESMode.cbc)); + final initVector = IV.fromUtf8(key); + + Encrypted encryptedData = encryptService.encrypt(plainText, iv: initVector); + return encryptedData.base64; + } + + @override + String decrypt(String key, String encryptedData) { + assert(key.length == 16); + final cipherKey = Key.fromUtf8(key); + final encryptService = Encrypter(AES(cipherKey, mode: AESMode.cbc)); + final initVector = IV.fromUtf8(key); + + return encryptService.decrypt(Encrypted.fromBase64(encryptedData), iv: initVector); + } +} diff --git a/pubspec.lock b/pubspec.lock index f2d43187..1a3464f6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -431,7 +431,7 @@ packages: source: hosted version: "2.0.0" encrypt: - dependency: transitive + dependency: "direct main" description: name: encrypt sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2" @@ -442,10 +442,10 @@ packages: dependency: "direct main" description: name: encrypt_shared_preferences - sha256: "83324f4350442d4b19994b22e5d87766eed9ee87b8211626b3b0d84bce1e98b9" + sha256: "6d9496f5873ab38d8cbea52dfeafc5e361a61193cc4d9f2da5f0f092b5ddab1a" url: "https://pub.dev" source: hosted - version: "0.3.8" + version: "0.8.1" equatable: dependency: transitive description: @@ -498,10 +498,10 @@ packages: dependency: transitive description: name: file_selector_linux - sha256: b2b91daf8a68ecfa4a01b778a6f52edef9b14ecd506e771488ea0f2e0784198b + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" url: "https://pub.dev" source: hosted - version: "0.9.3+1" + version: "0.9.3+2" file_selector_macos: dependency: transitive description: @@ -789,10 +789,10 @@ packages: dependency: "direct main" description: name: flutter_secure_storage - sha256: "22dbf16f23a4bcf9d35e51be1c84ad5bb6f627750565edd70dab70f3ff5fff8f" + sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0" url: "https://pub.dev" source: hosted - version: "8.1.0" + version: "9.2.2" flutter_secure_storage_linux: dependency: transitive description: @@ -829,10 +829,10 @@ packages: dependency: transitive description: name: flutter_secure_storage_windows - sha256: "38f9501c7cb6f38961ef0e1eacacee2b2d4715c63cc83fe56449c4d3d0b47255" + sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "3.1.2" flutter_svg: dependency: transitive description: @@ -1378,10 +1378,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a + sha256: "8c4967f8b7cb46dc914e178daa29813d83ae502e0529d7b0478330616a691ef7" url: "https://pub.dev" source: hosted - version: "2.2.12" + version: "2.2.14" path_provider_foundation: dependency: transitive description: @@ -2152,10 +2152,10 @@ packages: dependency: transitive description: name: vector_graphics_compiler - sha256: ab9ff38fc771e9ee1139320adbe3d18a60327370c218c60752068ebee4b49ab1 + sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad" url: "https://pub.dev" source: hosted - version: "1.1.15" + version: "1.1.16" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index bae10bad..3e8e6115 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -91,12 +91,9 @@ dependencies: git: url: https://github.com/w568w/receive_intent.git - # These two libraries are used to encrypt shared preferences. - # They introduced breaking changes in their latest versions, - # making them unable to read the old encrypted data. - # Therefore, we have to pin them at the these versions. - flutter_secure_storage: ^8.0.0 - encrypt_shared_preferences: ^0.3.5 + flutter_secure_storage: ^9.0.0 + encrypt_shared_preferences: ^0.8.1 + encrypt: any device_identity: ^1.0.0 tutorial_coach_mark: ^1.2.9 flutter_platform_widgets: ^7.0.0