Vulnerable btc seeds (#1238)

* Add flow to notify users with vulnerable seeds

* - Show vulnerable wallets warning on every app launch
- Change text

* increment build number

* add seeds sha text [skip ci]
This commit is contained in:
Omar Hatem 2023-12-19 00:05:27 +02:00 committed by GitHub
parent ec140b813c
commit 01e2a84809
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 8903 additions and 10 deletions

File diff suppressed because it is too large Load diff

View file

@ -374,7 +374,8 @@ Future<void> setup({
settingsStore: settingsStore, settingsStore: settingsStore,
yatStore: getIt.get<YatStore>(), yatStore: getIt.get<YatStore>(),
ordersStore: getIt.get<OrdersStore>(), ordersStore: getIt.get<OrdersStore>(),
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>())); anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>(),
keyService: getIt.get<KeyService>()));
getIt.registerFactory<AuthService>( getIt.registerFactory<AuthService>(
() => AuthService( () => AuthService(
@ -792,8 +793,8 @@ Future<void> setup({
getIt.registerFactory<RobinhoodBuyProvider>( getIt.registerFactory<RobinhoodBuyProvider>(
() => RobinhoodBuyProvider(wallet: getIt.get<AppStore>().wallet!)); () => RobinhoodBuyProvider(wallet: getIt.get<AppStore>().wallet!));
getIt.registerFactory<DFXBuyProvider>( getIt
() => DFXBuyProvider(wallet: getIt.get<AppStore>().wallet!)); .registerFactory<DFXBuyProvider>(() => DFXBuyProvider(wallet: getIt.get<AppStore>().wallet!));
getIt.registerFactory<OnRamperBuyProvider>(() => OnRamperBuyProvider( getIt.registerFactory<OnRamperBuyProvider>(() => OnRamperBuyProvider(
settingsStore: getIt.get<AppStore>().settingsStore, settingsStore: getIt.get<AppStore>().settingsStore,

View file

@ -7,6 +7,7 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sideba
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart'; import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart'; import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
import 'package:cake_wallet/src/widgets/gradient_background.dart'; import 'package:cake_wallet/src/widgets/gradient_background.dart';
import 'package:cake_wallet/src/widgets/vulnerable_seeds_popup.dart';
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart'; import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/version_comparator.dart'; import 'package:cake_wallet/utils/version_comparator.dart';
@ -60,7 +61,8 @@ class DashboardPage extends StatelessWidget {
); );
if (DeviceInfo.instance.isDesktop) { if (DeviceInfo.instance.isDesktop) {
if (responsiveLayoutUtil.screenWidth > ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) { if (responsiveLayoutUtil.screenWidth >
ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
return getIt.get<DesktopSidebarWrapper>(); return getIt.get<DesktopSidebarWrapper>();
} else { } else {
return dashboardPageView; return dashboardPageView;
@ -295,6 +297,8 @@ class _DashboardPageView extends BasePage {
_showReleaseNotesPopup(context); _showReleaseNotesPopup(context);
_showVulnerableSeedsPopup(context);
var needToPresentYat = false; var needToPresentYat = false;
var isInactive = false; var isInactive = false;
@ -354,4 +358,22 @@ class _DashboardPageView extends BasePage {
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion); sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
} }
} }
void _showVulnerableSeedsPopup(BuildContext context) async {
final List<String> affectedWalletNames = await dashboardViewModel.checkAffectedWallets();
if (affectedWalletNames.isNotEmpty) {
Future<void>.delayed(
Duration(seconds: 1),
() {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return VulnerableSeedsPopup(affectedWalletNames);
},
);
},
);
}
}
} }

View file

@ -3,6 +3,7 @@ import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart'; import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart';
import 'package:cake_wallet/src/screens/yat_emoji_id.dart'; import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
import 'package:cake_wallet/src/widgets/vulnerable_seeds_popup.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/utils/version_comparator.dart'; import 'package:cake_wallet/utils/version_comparator.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -110,5 +111,25 @@ class DesktopDashboardPage extends StatelessWidget {
} else if (isNewInstall!) { } else if (isNewInstall!) {
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion); sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
} }
_showVulnerableSeedsPopup(context);
}
void _showVulnerableSeedsPopup(BuildContext context) async {
final List<String> affectedWalletNames = await dashboardViewModel.checkAffectedWallets();
if (affectedWalletNames.isNotEmpty) {
Future<void>.delayed(
Duration(seconds: 1),
() {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return VulnerableSeedsPopup(affectedWalletNames);
},
);
},
);
}
} }
} }

View file

@ -0,0 +1,91 @@
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
import 'package:flutter/material.dart';
class VulnerableSeedsPopup extends StatelessWidget {
final List<String> affectedWalletNames;
const VulnerableSeedsPopup(this.affectedWalletNames, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
AlertBackground(
child: AlertDialog(
insetPadding: EdgeInsets.only(left: 16, right: 16, bottom: 48),
elevation: 0.0,
contentPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(30))),
content: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
gradient: LinearGradient(colors: [
Theme.of(context).extension<DashboardPageTheme>()!.firstGradientBackgroundColor,
Theme.of(context)
.extension<DashboardPageTheme>()!
.secondGradientBackgroundColor,
], begin: Alignment.centerLeft, end: Alignment.centerRight)),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Stack(
children: [
SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Container(
alignment: Alignment.bottomCenter,
child: DefaultTextStyle(
style: TextStyle(
decoration: TextDecoration.none,
fontSize: 24.0,
fontWeight: FontWeight.bold,
fontFamily: 'Lato',
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
),
child: Text("Emergency Notice"),
),
),
),
),
SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(top: 48, bottom: 16),
child: Container(
width: double.maxFinite,
child: Column(
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.7,
),
child: Text(
"Your Bitcoin wallet(s) below use a legacy seed format that is vulnerable, which MAY result in you losing money from these wallet(s) if no action is taken.\nWe recommend that you IMMEDIATELY create wallet(s) in Cake Wallet and immediately transfer the funds to these wallet(s).\nVulnerable wallet name(s):\n\n[${affectedWalletNames.join(", ")}]\n\nFor assistance, please use the in-app support or email support@cakewallet.com",
style: TextStyle(
decoration: TextDecoration.none,
fontSize: 16.0,
fontFamily: 'Lato',
color: Theme.of(context)
.extension<DashboardPageTheme>()!
.textColor,
),
),
)
],
),
),
),
),
],
),
),
),
),
),
AlertCloseButton(bottom: 30)
],
);
}
}

View file

@ -1,3 +1,6 @@
import 'dart:convert';
import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart'; import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart'; import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/buy_provider_types.dart'; import 'package:cake_wallet/entities/buy_provider_types.dart';
@ -24,12 +27,19 @@ import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart'; import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
import 'package:cake_wallet/view_model/settings/sync_mode.dart'; import 'package:cake_wallet/view_model/settings/sync_mode.dart';
import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cryptography/cryptography.dart';
import 'package:cw_core/balance.dart'; import 'package:cw_core/balance.dart';
import 'package:cw_core/cake_hive.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/utils/file.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:eth_sig_util/util/utils.dart';
import 'package:flutter/services.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
part 'dashboard_view_model.g.dart'; part 'dashboard_view_model.g.dart';
@ -46,7 +56,8 @@ abstract class DashboardViewModelBase with Store {
required this.settingsStore, required this.settingsStore,
required this.yatStore, required this.yatStore,
required this.ordersStore, required this.ordersStore,
required this.anonpayTransactionsStore}) required this.anonpayTransactionsStore,
required this.keyService})
: hasSellAction = false, : hasSellAction = false,
hasBuyAction = false, hasBuyAction = false,
hasExchangeAction = false, hasExchangeAction = false,
@ -262,6 +273,8 @@ abstract class DashboardViewModelBase with Store {
bool get hasRescan => wallet.type == WalletType.monero || wallet.type == WalletType.haven; bool get hasRescan => wallet.type == WalletType.monero || wallet.type == WalletType.haven;
final KeyService keyService;
BalanceViewModel balanceViewModel; BalanceViewModel balanceViewModel;
AppStore appStore; AppStore appStore;
@ -283,12 +296,12 @@ abstract class DashboardViewModelBase with Store {
Map<String, List<FilterItem>> filterItems; Map<String, List<FilterItem>> filterItems;
BuyProviderType get defaultBuyProvider => BuyProviderType get defaultBuyProvider =>
settingsStore.defaultBuyProviders[wallet.type] ?? settingsStore.defaultBuyProviders[wallet.type] ?? BuyProviderType.AskEachTime;
BuyProviderType.AskEachTime;
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled; bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
List<BuyProviderType> get availableProviders => BuyProviderType.getAvailableProviders(wallet.type); List<BuyProviderType> get availableProviders =>
BuyProviderType.getAvailableProviders(wallet.type);
bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup; bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup;
@ -433,4 +446,32 @@ abstract class DashboardViewModelBase with Store {
@action @action
void setSyncAll(bool value) => settingsStore.currentSyncAll = value; void setSyncAll(bool value) => settingsStore.currentSyncAll = value;
Future<List<String>> checkAffectedWallets() async {
// await load file
final vulnerableSeedsString = await rootBundle.loadString('assets/text/cakewallet_weak_bitcoin_seeds_hashed_sorted_version1.txt');
final vulnerableSeeds = vulnerableSeedsString.split("\n");
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
List<String> affectedWallets = [];
for (var walletInfo in walletInfoSource.values) {
if (walletInfo.type == WalletType.bitcoin) {
final password = await keyService.getWalletPassword(walletName: walletInfo.name);
final path = await pathForWallet(name: walletInfo.name, type: walletInfo.type);
final jsonSource = await read(path: path, password: password);
final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String;
final hash = await Cryptography.instance.sha256().hash(utf8.encode(mnemonic));
final seedSha = bytesToHex(hash.bytes);
if (vulnerableSeeds.contains(seedSha)) {
affectedWallets.add(walletInfo.name);
}
}
}
return affectedWallets;
}
} }

View file

@ -23,7 +23,7 @@ MONERO_COM_SCHEME="monero.com"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.12.0" CAKEWALLET_VERSION="4.12.0"
CAKEWALLET_BUILD_NUMBER=186 CAKEWALLET_BUILD_NUMBER=187
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
CAKEWALLET_SCHEME="cakewallet" CAKEWALLET_SCHEME="cakewallet"

View file

@ -19,7 +19,7 @@ MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.12.0" CAKEWALLET_VERSION="4.12.0"
CAKEWALLET_BUILD_NUMBER=204 CAKEWALLET_BUILD_NUMBER=205
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
HAVEN_NAME="Haven" HAVEN_NAME="Haven"