mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 11:39:22 +00:00
Cw-263-TOTP-2FA-In-Security-Settings (#892)
* CW-263-TOTP-2FA-in-security-settings WIP * Implement TOTP 2FA WIP * Implement TOTP 2FA Authentication * chore: Remove unneeded formatting * revert formatting * fixes * CW-263-TOTP-2FA-in-security-settings WIP * Setup TOTP Complete, left with Modify TOTF * CW-263-TOTP-2FA-in-security-settings * CW-263-TOTP-2FA-in-security-settings * CW-263-TOTP-2FA-in-security-settings * fix: Add copy-to-clipboard for qr secret key * fix: Translation * chore: Move strings into translation files * feat: End to end flow for TOTP * hotfix: Switch totp to use sha512 * Update strings; 8 digits and error explanation * fix: Totp 2fa implementation feedback * hotfix: same action for button and alert close * feat: App should show both normal and totp auths when totp is enabled * hotfix: prevent barrier from dismissing * fix: Changes requested during PR review * - Minor Enhancements - Minor UI fixes --------- Co-authored-by: Justin Ehrenhofer <justin.ehrenhofer@gmail.com> Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
This commit is contained in:
parent
40f3ccbe42
commit
43e062d1ac
43 changed files with 1951 additions and 494 deletions
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/core/totp_request_details.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -9,6 +10,8 @@ import 'package:cake_wallet/entities/secret_store_key.dart';
|
|||
import 'package:cake_wallet/entities/encrypt.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
|
||||
import '../src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
|
||||
|
||||
class AuthService with Store {
|
||||
AuthService({
|
||||
required this.secureStorage,
|
||||
|
@ -20,6 +23,8 @@ class AuthService with Store {
|
|||
Routes.showKeys,
|
||||
Routes.backup,
|
||||
Routes.setupPin,
|
||||
Routes.setup_2faPage,
|
||||
Routes.modify2FAPage,
|
||||
];
|
||||
|
||||
final FlutterSecureStorage secureStorage;
|
||||
|
@ -79,6 +84,7 @@ class AuthService with Store {
|
|||
{Function(bool)? onAuthSuccess, String? route, Object? arguments}) async {
|
||||
assert(route != null || onAuthSuccess != null,
|
||||
'Either route or onAuthSuccess param must be passed.');
|
||||
|
||||
if (!requireAuth() && !_alwaysAuthenticateRoutes.contains(route)) {
|
||||
if (onAuthSuccess != null) {
|
||||
onAuthSuccess(true);
|
||||
|
@ -90,17 +96,43 @@ class AuthService with Store {
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Navigator.of(context).pushNamed(Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
onAuthSuccess?.call(false);
|
||||
return;
|
||||
}
|
||||
if (onAuthSuccess != null) {
|
||||
auth.close().then((value) => onAuthSuccess.call(true));
|
||||
} else {
|
||||
auth.close(route: route, arguments: arguments);
|
||||
if (settingsStore.useTOTP2FA) {
|
||||
auth.close(
|
||||
route: Routes.totpAuthCodePage,
|
||||
arguments: TotpAuthArgumentsModel(
|
||||
isForSetup: !settingsStore.useTOTP2FA,
|
||||
onTotpAuthenticationFinished:
|
||||
(bool isAuthenticatedSuccessfully, TotpAuthCodePageState totpAuth) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
onAuthSuccess?.call(false);
|
||||
return;
|
||||
}
|
||||
if (onAuthSuccess != null) {
|
||||
totpAuth.close().then((value) => onAuthSuccess.call(true));
|
||||
} else {
|
||||
totpAuth.close(route: route, arguments: arguments);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
if (onAuthSuccess != null) {
|
||||
auth.close().then((value) => onAuthSuccess.call(true));
|
||||
} else {
|
||||
auth.close(route: route, arguments: arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
|
13
lib/core/totp_request_details.dart
Normal file
13
lib/core/totp_request_details.dart
Normal file
|
@ -0,0 +1,13 @@
|
|||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
|
||||
|
||||
class TotpAuthArgumentsModel {
|
||||
final bool? isForSetup;
|
||||
final bool? isClosable;
|
||||
final OnTotpAuthenticationFinished? onTotpAuthenticationFinished;
|
||||
|
||||
TotpAuthArgumentsModel({
|
||||
this.isForSetup,
|
||||
this.isClosable,
|
||||
this.onTotpAuthenticationFinished,
|
||||
});
|
||||
}
|
613
lib/di.dart
613
lib/di.dart
|
@ -10,6 +10,7 @@ import 'package:cake_wallet/entities/receive_page_option.dart';
|
|||
import 'package:cake_wallet/ionia/ionia_anypay.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_tip.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/onramper_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/payfura_page.dart';
|
||||
|
@ -27,6 +28,10 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dar
|
|||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
|
||||
import 'package:cake_wallet/themes/theme_list.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
|
||||
|
@ -53,8 +58,8 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
|
|||
import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
|
||||
|
@ -187,6 +192,8 @@ import 'package:cake_wallet/core/wallet_loading_service.dart';
|
|||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/entities/qr_view_data.dart';
|
||||
|
||||
import 'core/totp_request_details.dart';
|
||||
|
||||
final getIt = GetIt.instance;
|
||||
|
||||
var _isSetupFinished = false;
|
||||
|
@ -201,18 +208,18 @@ late Box<Order> _ordersSource;
|
|||
late Box<UnspentCoinsInfo>? _unspentCoinsInfoSource;
|
||||
late Box<AnonpayInvoiceInfo> _anonpayInvoiceInfoSource;
|
||||
|
||||
Future setup(
|
||||
{required Box<WalletInfo> walletInfoSource,
|
||||
required Box<Node> nodeSource,
|
||||
required Box<Contact> contactSource,
|
||||
required Box<Trade> tradesSource,
|
||||
required Box<Template> templates,
|
||||
required Box<ExchangeTemplate> exchangeTemplates,
|
||||
required Box<TransactionDescription> transactionDescriptionBox,
|
||||
required Box<Order> ordersSource,
|
||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource,
|
||||
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource,
|
||||
}) async {
|
||||
Future setup({
|
||||
required Box<WalletInfo> walletInfoSource,
|
||||
required Box<Node> nodeSource,
|
||||
required Box<Contact> contactSource,
|
||||
required Box<Trade> tradesSource,
|
||||
required Box<Template> templates,
|
||||
required Box<ExchangeTemplate> exchangeTemplates,
|
||||
required Box<TransactionDescription> transactionDescriptionBox,
|
||||
required Box<Order> ordersSource,
|
||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource,
|
||||
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource,
|
||||
}) async {
|
||||
_walletInfoSource = walletInfoSource;
|
||||
_nodeSource = nodeSource;
|
||||
_contactSource = contactSource;
|
||||
|
@ -225,8 +232,7 @@ Future setup(
|
|||
_anonpayInvoiceInfoSource = anonpayInvoiceInfoSource;
|
||||
|
||||
if (!_isSetupFinished) {
|
||||
getIt.registerSingletonAsync<SharedPreferences>(
|
||||
() => SharedPreferences.getInstance());
|
||||
getIt.registerSingletonAsync<SharedPreferences>(() => SharedPreferences.getInstance());
|
||||
}
|
||||
|
||||
final isBitcoinBuyEnabled = (secrets.wyreSecretKey.isNotEmpty ?? false) &&
|
||||
|
@ -256,84 +262,73 @@ Future setup(
|
|||
walletList: getIt.get<WalletListStore>(),
|
||||
settingsStore: getIt.get<SettingsStore>(),
|
||||
nodeListStore: getIt.get<NodeListStore>()));
|
||||
getIt.registerSingleton<TradesStore>(TradesStore(
|
||||
tradesSource: _tradesSource, settingsStore: getIt.get<SettingsStore>()));
|
||||
getIt.registerSingleton<OrdersStore>(OrdersStore(
|
||||
ordersSource: _ordersSource, settingsStore: getIt.get<SettingsStore>()));
|
||||
getIt.registerSingleton<TradesStore>(
|
||||
TradesStore(tradesSource: _tradesSource, settingsStore: getIt.get<SettingsStore>()));
|
||||
getIt.registerSingleton<OrdersStore>(
|
||||
OrdersStore(ordersSource: _ordersSource, settingsStore: getIt.get<SettingsStore>()));
|
||||
getIt.registerSingleton<TradeFilterStore>(TradeFilterStore());
|
||||
getIt.registerSingleton<TransactionFilterStore>(TransactionFilterStore());
|
||||
getIt.registerSingleton<FiatConversionStore>(FiatConversionStore());
|
||||
getIt.registerSingleton<SendTemplateStore>(
|
||||
SendTemplateStore(templateSource: _templates));
|
||||
getIt.registerSingleton<SendTemplateStore>(SendTemplateStore(templateSource: _templates));
|
||||
getIt.registerSingleton<ExchangeTemplateStore>(
|
||||
ExchangeTemplateStore(templateSource: _exchangeTemplates));
|
||||
getIt.registerSingleton<YatStore>(YatStore(
|
||||
appStore: getIt.get<AppStore>(),
|
||||
secureStorage: getIt.get<FlutterSecureStorage>())
|
||||
..init());
|
||||
getIt.registerSingleton<AnonpayTransactionsStore>(AnonpayTransactionsStore(
|
||||
anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource));
|
||||
getIt.registerSingleton<YatStore>(
|
||||
YatStore(appStore: getIt.get<AppStore>(), secureStorage: getIt.get<FlutterSecureStorage>())
|
||||
..init());
|
||||
getIt.registerSingleton<AnonpayTransactionsStore>(
|
||||
AnonpayTransactionsStore(anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource));
|
||||
|
||||
final secretStore =
|
||||
await SecretStoreBase.load(getIt.get<FlutterSecureStorage>());
|
||||
final secretStore = await SecretStoreBase.load(getIt.get<FlutterSecureStorage>());
|
||||
|
||||
getIt.registerSingleton<SecretStore>(secretStore);
|
||||
|
||||
getIt.registerFactory<KeyService>(
|
||||
() => KeyService(getIt.get<FlutterSecureStorage>()));
|
||||
getIt.registerFactory<KeyService>(() => KeyService(getIt.get<FlutterSecureStorage>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletCreationService, WalletType, void>(
|
||||
(type, _) => WalletCreationService(
|
||||
getIt.registerFactoryParam<WalletCreationService, WalletType, void>((type, _) =>
|
||||
WalletCreationService(
|
||||
initialType: type,
|
||||
keyService: getIt.get<KeyService>(),
|
||||
secureStorage: getIt.get<FlutterSecureStorage>(),
|
||||
sharedPreferences: getIt.get<SharedPreferences>(),
|
||||
walletInfoSource: _walletInfoSource));
|
||||
|
||||
getIt.registerFactory<WalletLoadingService>(
|
||||
() => WalletLoadingService(
|
||||
getIt.registerFactory<WalletLoadingService>(() => WalletLoadingService(
|
||||
getIt.get<SharedPreferences>(),
|
||||
getIt.get<KeyService>(),
|
||||
(WalletType type) => getIt.get<WalletService>(param1: type)));
|
||||
|
||||
getIt.registerFactoryParam<WalletNewVM, WalletType, void>((type, _) =>
|
||||
WalletNewVM(getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
type: type));
|
||||
getIt.registerFactoryParam<WalletNewVM, WalletType, void>((type, _) => WalletNewVM(
|
||||
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
type: type));
|
||||
|
||||
getIt
|
||||
.registerFactoryParam<WalletRestorationFromSeedVM, List, void>((args, _) {
|
||||
getIt.registerFactoryParam<WalletRestorationFromSeedVM, List, void>((args, _) {
|
||||
final type = args.first as WalletType;
|
||||
final language = args[1] as String;
|
||||
final mnemonic = args[2] as String;
|
||||
|
||||
return WalletRestorationFromSeedVM(getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
return WalletRestorationFromSeedVM(
|
||||
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
type: type, language: language, seed: mnemonic);
|
||||
});
|
||||
|
||||
getIt
|
||||
.registerFactoryParam<WalletRestorationFromKeysVM, List, void>((args, _) {
|
||||
getIt.registerFactoryParam<WalletRestorationFromKeysVM, List, void>((args, _) {
|
||||
final type = args.first as WalletType;
|
||||
final language = args[1] as String;
|
||||
|
||||
return WalletRestorationFromKeysVM(getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
return WalletRestorationFromKeysVM(
|
||||
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
type: type, language: language);
|
||||
});
|
||||
|
||||
getIt
|
||||
.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) {
|
||||
getIt.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) {
|
||||
return WalletRestorationFromQRVM(getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type),
|
||||
_walletInfoSource, type);
|
||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource, type);
|
||||
});
|
||||
|
||||
getIt.registerFactory<WalletAddressListViewModel>(() =>
|
||||
WalletAddressListViewModel(
|
||||
appStore: getIt.get<AppStore>(), yatStore: getIt.get<YatStore>(),
|
||||
fiatConversionStore: getIt.get<FiatConversionStore>()
|
||||
));
|
||||
getIt.registerFactory<WalletAddressListViewModel>(() => WalletAddressListViewModel(
|
||||
appStore: getIt.get<AppStore>(),
|
||||
yatStore: getIt.get<YatStore>(),
|
||||
fiatConversionStore: getIt.get<FiatConversionStore>()));
|
||||
|
||||
getIt.registerFactory(() => BalanceViewModel(
|
||||
appStore: getIt.get<AppStore>(),
|
||||
|
@ -349,65 +344,108 @@ Future setup(
|
|||
settingsStore: settingsStore,
|
||||
yatStore: getIt.get<YatStore>(),
|
||||
ordersStore: getIt.get<OrdersStore>(),
|
||||
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>())
|
||||
);
|
||||
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>()));
|
||||
|
||||
getIt.registerFactory<AuthService>(() => AuthService(
|
||||
getIt.registerFactory<AuthService>(
|
||||
() => AuthService(
|
||||
secureStorage: getIt.get<FlutterSecureStorage>(),
|
||||
sharedPreferences: getIt.get<SharedPreferences>(),
|
||||
settingsStore: getIt.get<SettingsStore>(),
|
||||
),
|
||||
);
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactory<AuthViewModel>(() => AuthViewModel(
|
||||
getIt.get<AuthService>(),
|
||||
getIt.get<SharedPreferences>(),
|
||||
getIt.registerFactory<AuthViewModel>(() => AuthViewModel(getIt.get<AuthService>(),
|
||||
getIt.get<SharedPreferences>(), getIt.get<SettingsStore>(), BiometricAuth()));
|
||||
|
||||
getIt.registerFactoryParam<AuthPage, void Function(bool, AuthPageState), bool>(
|
||||
(onAuthFinished, closable) => AuthPage(getIt.get<AuthViewModel>(),
|
||||
onAuthenticationFinished: onAuthFinished, closable: closable));
|
||||
|
||||
getIt.registerFactory<Setup2FAViewModel>(
|
||||
() => Setup2FAViewModel(
|
||||
getIt.get<SettingsStore>(),
|
||||
BiometricAuth()));
|
||||
getIt.get<SharedPreferences>(),
|
||||
getIt.get<AuthService>(),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactory<AuthPage>(
|
||||
() => AuthPage(getIt.get<AuthViewModel>(), onAuthenticationFinished:
|
||||
(isAuthenticated, AuthPageState authPageState) {
|
||||
if (!isAuthenticated) {
|
||||
return;
|
||||
}
|
||||
final authStore = getIt.get<AuthenticationStore>();
|
||||
final appStore = getIt.get<AppStore>();
|
||||
getIt.registerFactoryParam<TotpAuthCodePage, TotpAuthArgumentsModel, void>(
|
||||
(totpAuthPageArguments, _) => TotpAuthCodePage(
|
||||
getIt.get<Setup2FAViewModel>(),
|
||||
totpArguments: totpAuthPageArguments,
|
||||
),
|
||||
);
|
||||
|
||||
if (appStore.wallet != null) {
|
||||
authStore.allowed();
|
||||
return;
|
||||
}
|
||||
getIt.registerFactory<AuthPage>(() {
|
||||
return AuthPage(getIt.get<AuthViewModel>(),
|
||||
onAuthenticationFinished: (isAuthenticated, AuthPageState authPageState) {
|
||||
if (!isAuthenticated) {
|
||||
return;
|
||||
} else {
|
||||
final authStore = getIt.get<AuthenticationStore>();
|
||||
final appStore = getIt.get<AppStore>();
|
||||
final useTotp = appStore.settingsStore.useTOTP2FA;
|
||||
if (useTotp) {
|
||||
authPageState.close(
|
||||
route: Routes.totpAuthCodePage,
|
||||
arguments: TotpAuthArgumentsModel(
|
||||
isForSetup: false,
|
||||
isClosable: false,
|
||||
onTotpAuthenticationFinished: (bool isAuthenticatedSuccessfully,
|
||||
TotpAuthCodePageState totpAuthPageState) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
if (appStore.wallet != null) {
|
||||
authStore.allowed();
|
||||
return;
|
||||
}
|
||||
|
||||
authPageState.changeProcessText('Loading the wallet');
|
||||
totpAuthPageState.changeProcessText('Loading the wallet');
|
||||
|
||||
if (loginError != null) {
|
||||
authPageState
|
||||
.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
}
|
||||
if (loginError != null) {
|
||||
totpAuthPageState.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
}
|
||||
|
||||
ReactionDisposer? _reaction;
|
||||
_reaction = reaction((_) => appStore.wallet, (Object? _) {
|
||||
_reaction?.reaction.dispose();
|
||||
authStore.allowed();
|
||||
});
|
||||
}, closable: false),
|
||||
instanceName: 'login');
|
||||
ReactionDisposer? _reaction;
|
||||
_reaction = reaction((_) => appStore.wallet, (Object? _) {
|
||||
_reaction?.reaction.dispose();
|
||||
authStore.allowed();
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
if (appStore.wallet != null) {
|
||||
authStore.allowed();
|
||||
return;
|
||||
}
|
||||
|
||||
getIt
|
||||
.registerFactoryParam<AuthPage, void Function(bool, AuthPageState), bool>(
|
||||
(onAuthFinished, closable) => AuthPage(getIt.get<AuthViewModel>(),
|
||||
onAuthenticationFinished: onAuthFinished,
|
||||
closable: closable));
|
||||
authPageState.changeProcessText('Loading the wallet');
|
||||
|
||||
getIt.registerFactory(() =>
|
||||
BalancePage(dashboardViewModel: getIt.get<DashboardViewModel>(), settingsStore: getIt.get<SettingsStore>()));
|
||||
if (loginError != null) {
|
||||
authPageState.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
}
|
||||
|
||||
ReactionDisposer? _reaction;
|
||||
_reaction = reaction((_) => appStore.wallet, (Object? _) {
|
||||
_reaction?.reaction.dispose();
|
||||
authStore.allowed();
|
||||
});
|
||||
}
|
||||
}
|
||||
}, closable: false);
|
||||
}, instanceName: 'login');
|
||||
|
||||
getIt.registerFactory(() => BalancePage(
|
||||
dashboardViewModel: getIt.get<DashboardViewModel>(),
|
||||
settingsStore: getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactory<DashboardPage>(() => DashboardPage(
|
||||
balancePage: getIt.get<BalancePage>(),
|
||||
dashboardViewModel: getIt.get<DashboardViewModel>(),
|
||||
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
||||
));
|
||||
balancePage: getIt.get<BalancePage>(),
|
||||
dashboardViewModel: getIt.get<DashboardViewModel>(),
|
||||
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
||||
));
|
||||
|
||||
getIt.registerFactory<DesktopSidebarWrapper>(() {
|
||||
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
@ -420,16 +458,26 @@ Future setup(
|
|||
});
|
||||
getIt.registerFactoryParam<DesktopDashboardPage, GlobalKey<NavigatorState>, void>(
|
||||
(desktopKey, _) => DesktopDashboardPage(
|
||||
balancePage: getIt.get<BalancePage>(),
|
||||
dashboardViewModel: getIt.get<DashboardViewModel>(),
|
||||
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
||||
desktopKey: desktopKey,
|
||||
));
|
||||
balancePage: getIt.get<BalancePage>(),
|
||||
dashboardViewModel: getIt.get<DashboardViewModel>(),
|
||||
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
||||
desktopKey: desktopKey,
|
||||
));
|
||||
|
||||
getIt.registerFactory<TransactionsPage>(() => TransactionsPage(dashboardViewModel: getIt.get<DashboardViewModel>()));
|
||||
getIt.registerFactory<TransactionsPage>(
|
||||
() => TransactionsPage(dashboardViewModel: getIt.get<DashboardViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<ReceiveOptionViewModel, ReceivePageOption?, void>((pageOption, _) => ReceiveOptionViewModel(
|
||||
getIt.get<AppStore>().wallet!, pageOption));
|
||||
getIt.registerFactory<Setup2FAPage>(
|
||||
() => Setup2FAPage(setup2FAViewModel: getIt.get<Setup2FAViewModel>()));
|
||||
|
||||
getIt.registerFactory<Setup2FAQRPage>(
|
||||
() => Setup2FAQRPage(setup2FAViewModel: getIt.get<Setup2FAViewModel>()));
|
||||
|
||||
getIt.registerFactory<Modify2FAPage>(
|
||||
() => Modify2FAPage(setup2FAViewModel: getIt.get<Setup2FAViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<ReceiveOptionViewModel, ReceivePageOption?, void>(
|
||||
(pageOption, _) => ReceiveOptionViewModel(getIt.get<AppStore>().wallet!, pageOption));
|
||||
|
||||
getIt.registerFactoryParam<AnonInvoicePageViewModel, List<dynamic>, void>((args, _) {
|
||||
final address = args.first as String;
|
||||
|
@ -443,28 +491,27 @@ Future setup(
|
|||
getIt.get<SharedPreferences>(),
|
||||
pageOption,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<AnonPayInvoicePage, List<dynamic>, void>((List<dynamic> args, _) {
|
||||
final pageOption = args.last as ReceivePageOption;
|
||||
return AnonPayInvoicePage(
|
||||
getIt.get<AnonInvoicePageViewModel>(param1: args),
|
||||
getIt.get<ReceiveOptionViewModel>(param1: pageOption));
|
||||
});
|
||||
return AnonPayInvoicePage(getIt.get<AnonInvoicePageViewModel>(param1: args),
|
||||
getIt.get<ReceiveOptionViewModel>(param1: pageOption));
|
||||
});
|
||||
|
||||
getIt.registerFactory<ReceivePage>(() => ReceivePage(
|
||||
addressListViewModel: getIt.get<WalletAddressListViewModel>()));
|
||||
getIt.registerFactory<ReceivePage>(
|
||||
() => ReceivePage(addressListViewModel: getIt.get<WalletAddressListViewModel>()));
|
||||
getIt.registerFactory<AddressPage>(() => AddressPage(
|
||||
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
||||
dashboardViewModel: getIt.get<DashboardViewModel>(),
|
||||
receiveOptionViewModel: getIt.get<ReceiveOptionViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletAddressEditOrCreateViewModel, WalletAddressListItem?, void>(
|
||||
(WalletAddressListItem? item, _) => WalletAddressEditOrCreateViewModel(
|
||||
wallet: getIt.get<AppStore>().wallet!, item: item));
|
||||
(WalletAddressListItem? item, _) =>
|
||||
WalletAddressEditOrCreateViewModel(wallet: getIt.get<AppStore>().wallet!, item: item));
|
||||
|
||||
getIt.registerFactoryParam<AddressEditOrCreatePage, dynamic, void>(
|
||||
(dynamic item, _) => AddressEditOrCreatePage(
|
||||
getIt.registerFactoryParam<AddressEditOrCreatePage, dynamic, void>((dynamic item, _) =>
|
||||
AddressEditOrCreatePage(
|
||||
addressEditOrCreateViewModel:
|
||||
getIt.get<WalletAddressEditOrCreateViewModel>(param1: item)));
|
||||
|
||||
|
@ -484,15 +531,16 @@ Future setup(
|
|||
|
||||
getIt.registerFactoryParam<SendPage, PaymentRequest?, void>(
|
||||
(PaymentRequest? initialPaymentRequest, _) => SendPage(
|
||||
sendViewModel: getIt.get<SendViewModel>(),
|
||||
initialPaymentRequest: initialPaymentRequest,
|
||||
));
|
||||
sendViewModel: getIt.get<SendViewModel>(),
|
||||
initialPaymentRequest: initialPaymentRequest,
|
||||
));
|
||||
|
||||
getIt.registerFactory(() => SendTemplatePage(
|
||||
sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
|
||||
getIt.registerFactory(
|
||||
() => SendTemplatePage(sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
|
||||
|
||||
if (DeviceInfo.instance.isMobile) {
|
||||
getIt.registerFactory(() => WalletListViewModel(
|
||||
getIt.registerFactory(
|
||||
() => WalletListViewModel(
|
||||
_walletInfoSource,
|
||||
getIt.get<AppStore>(),
|
||||
getIt.get<WalletLoadingService>(),
|
||||
|
@ -502,7 +550,8 @@ Future setup(
|
|||
} else {
|
||||
// register wallet list view model as singleton on desktop since it can be accessed
|
||||
// from multiple places at the same time (Wallets DropDown, Wallets List in settings)
|
||||
getIt.registerLazySingleton(() => WalletListViewModel(
|
||||
getIt.registerLazySingleton(
|
||||
() => WalletListViewModel(
|
||||
_walletInfoSource,
|
||||
getIt.get<AppStore>(),
|
||||
getIt.get<WalletLoadingService>(),
|
||||
|
@ -511,8 +560,10 @@ Future setup(
|
|||
);
|
||||
}
|
||||
|
||||
getIt.registerFactory(() =>
|
||||
WalletListPage(walletListViewModel: getIt.get<WalletListViewModel>(), authService: getIt.get<AuthService>(),));
|
||||
getIt.registerFactory(() => WalletListPage(
|
||||
walletListViewModel: getIt.get<WalletListViewModel>(),
|
||||
authService: getIt.get<AuthService>(),
|
||||
));
|
||||
|
||||
getIt.registerFactory(() {
|
||||
final wallet = getIt.get<AppStore>().wallet!;
|
||||
|
@ -521,11 +572,12 @@ Future setup(
|
|||
return MoneroAccountListViewModel(wallet);
|
||||
}
|
||||
|
||||
throw Exception('Unexpected wallet type: ${wallet.type} for generate MoneroAccountListViewModel');
|
||||
throw Exception(
|
||||
'Unexpected wallet type: ${wallet.type} for generate MoneroAccountListViewModel');
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => MoneroAccountListPage(
|
||||
accountListViewModel: getIt.get<MoneroAccountListViewModel>()));
|
||||
getIt.registerFactory(
|
||||
() => MoneroAccountListPage(accountListViewModel: getIt.get<MoneroAccountListViewModel>()));
|
||||
|
||||
/*getIt.registerFactory(() {
|
||||
final wallet = getIt.get<AppStore>().wallet;
|
||||
|
@ -542,16 +594,14 @@ Future setup(
|
|||
moneroAccountCreationViewModel:
|
||||
getIt.get<MoneroAccountEditOrCreateViewModel>()));*/
|
||||
|
||||
getIt.registerFactoryParam<MoneroAccountEditOrCreateViewModel,
|
||||
AccountListItem?, void>(
|
||||
getIt.registerFactoryParam<MoneroAccountEditOrCreateViewModel, AccountListItem?, void>(
|
||||
(AccountListItem? account, _) => MoneroAccountEditOrCreateViewModel(
|
||||
monero!.getAccountList(getIt.get<AppStore>().wallet!),
|
||||
haven?.getAccountList(getIt.get<AppStore>().wallet!),
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
accountListItem: account));
|
||||
|
||||
getIt.registerFactoryParam<MoneroAccountEditOrCreatePage, AccountListItem?,
|
||||
void>(
|
||||
getIt.registerFactoryParam<MoneroAccountEditOrCreatePage, AccountListItem?, void>(
|
||||
(AccountListItem? account, _) => MoneroAccountEditOrCreatePage(
|
||||
moneroAccountCreationViewModel:
|
||||
getIt.get<MoneroAccountEditOrCreateViewModel>(param1: account)));
|
||||
|
@ -572,41 +622,37 @@ Future setup(
|
|||
return SecuritySettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AuthService>());
|
||||
});
|
||||
|
||||
getIt
|
||||
.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!));
|
||||
getIt.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactoryParam<WalletSeedPage, bool, void>(
|
||||
(bool isWalletCreated, _) => WalletSeedPage(
|
||||
getIt.get<WalletSeedViewModel>(),
|
||||
isNewWalletCreated: isWalletCreated));
|
||||
getIt.registerFactoryParam<WalletSeedPage, bool, void>((bool isWalletCreated, _) =>
|
||||
WalletSeedPage(getIt.get<WalletSeedViewModel>(), isNewWalletCreated: isWalletCreated));
|
||||
|
||||
getIt
|
||||
.registerFactory(() => WalletKeysViewModel(getIt.get<AppStore>()));
|
||||
getIt.registerFactory(() => WalletKeysViewModel(getIt.get<AppStore>()));
|
||||
|
||||
getIt.registerFactory(() => WalletKeysPage(getIt.get<WalletKeysViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<ContactViewModel, ContactRecord?, void>(
|
||||
(ContactRecord? contact, _) =>
|
||||
ContactViewModel(_contactSource, contact: contact));
|
||||
(ContactRecord? contact, _) => ContactViewModel(_contactSource, contact: contact));
|
||||
|
||||
getIt.registerFactoryParam<ContactListViewModel, CryptoCurrency?, void>(
|
||||
(CryptoCurrency? cur, _) => ContactListViewModel(_contactSource, _walletInfoSource, cur));
|
||||
|
||||
getIt.registerFactoryParam<ContactListPage, CryptoCurrency?, void>((CryptoCurrency? cur, _)
|
||||
=> ContactListPage(getIt.get<ContactListViewModel>(param1: cur)));
|
||||
getIt.registerFactoryParam<ContactListPage, CryptoCurrency?, void>(
|
||||
(CryptoCurrency? cur, _) => ContactListPage(getIt.get<ContactListViewModel>(param1: cur)));
|
||||
|
||||
getIt.registerFactoryParam<ContactPage, ContactRecord?, void>(
|
||||
(ContactRecord? contact, _) =>
|
||||
ContactPage(getIt.get<ContactViewModel>(param1: contact)));
|
||||
(ContactRecord? contact, _) => ContactPage(getIt.get<ContactViewModel>(param1: contact)));
|
||||
|
||||
getIt.registerFactory(() {
|
||||
final appStore = getIt.get<AppStore>();
|
||||
return NodeListViewModel(_nodeSource, appStore);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => ConnectionSyncPage(getIt.get<NodeListViewModel>(), getIt.get<DashboardViewModel>()));
|
||||
getIt.registerFactory(
|
||||
() => ConnectionSyncPage(getIt.get<NodeListViewModel>(), getIt.get<DashboardViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(), getIt.get<AuthService>()));
|
||||
getIt.registerFactory(
|
||||
() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(), getIt.get<AuthService>()));
|
||||
|
||||
getIt.registerFactory(() => PrivacyPage(getIt.get<PrivacySettingsViewModel>()));
|
||||
|
||||
|
@ -614,41 +660,38 @@ Future setup(
|
|||
|
||||
getIt.registerFactory(() => OtherSettingsPage(getIt.get<OtherSettingsViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<NodeCreateOrEditViewModel, WalletType?, void>(
|
||||
(WalletType? type, _) => NodeCreateOrEditViewModel(
|
||||
_nodeSource,
|
||||
type ?? getIt.get<AppStore>().wallet!.type,
|
||||
getIt.get<SettingsStore>()
|
||||
));
|
||||
getIt.registerFactoryParam<NodeCreateOrEditViewModel, WalletType?, void>((WalletType? type, _) =>
|
||||
NodeCreateOrEditViewModel(
|
||||
_nodeSource, type ?? getIt.get<AppStore>().wallet!.type, getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactoryParam<NodeCreateOrEditPage, Node?, bool?>(
|
||||
(Node? editingNode, bool? isSelected) => NodeCreateOrEditPage(
|
||||
(Node? editingNode, bool? isSelected) => NodeCreateOrEditPage(
|
||||
nodeCreateOrEditViewModel: getIt.get<NodeCreateOrEditViewModel>(),
|
||||
editingNode: editingNode,
|
||||
isSelected: isSelected));
|
||||
|
||||
getIt.registerFactory<OnRamperBuyProvider>(() => OnRamperBuyProvider(
|
||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
));
|
||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
));
|
||||
|
||||
getIt.registerFactory(() => OnRamperPage(getIt.get<OnRamperBuyProvider>()));
|
||||
|
||||
getIt.registerFactory<PayfuraBuyProvider>(() => PayfuraBuyProvider(
|
||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
));
|
||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
));
|
||||
|
||||
getIt.registerFactory(() => PayFuraPage(getIt.get<PayfuraBuyProvider>()));
|
||||
|
||||
getIt.registerFactory(() => ExchangeViewModel(
|
||||
getIt.get<AppStore>().wallet!,
|
||||
_tradesSource,
|
||||
getIt.get<ExchangeTemplateStore>(),
|
||||
getIt.get<TradesStore>(),
|
||||
getIt.get<AppStore>().settingsStore,
|
||||
getIt.get<SharedPreferences>(),
|
||||
));
|
||||
getIt.get<AppStore>().wallet!,
|
||||
_tradesSource,
|
||||
getIt.get<ExchangeTemplateStore>(),
|
||||
getIt.get<TradesStore>(),
|
||||
getIt.get<AppStore>().settingsStore,
|
||||
getIt.get<SharedPreferences>(),
|
||||
));
|
||||
|
||||
getIt.registerFactory(() => ExchangeTradeViewModel(
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
|
@ -658,40 +701,34 @@ Future setup(
|
|||
|
||||
getIt.registerFactory(() => ExchangePage(getIt.get<ExchangeViewModel>()));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => ExchangeConfirmPage(tradesStore: getIt.get<TradesStore>()));
|
||||
|
||||
getIt.registerFactory(() => ExchangeTradePage(
|
||||
exchangeTradeViewModel: getIt.get<ExchangeTradeViewModel>()));
|
||||
getIt.registerFactory(() => ExchangeConfirmPage(tradesStore: getIt.get<TradesStore>()));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => ExchangeTemplatePage(getIt.get<ExchangeViewModel>()));
|
||||
() => ExchangeTradePage(exchangeTradeViewModel: getIt.get<ExchangeTradeViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletService, WalletType, void>(
|
||||
(WalletType param1, __) {
|
||||
getIt.registerFactory(() => ExchangeTemplatePage(getIt.get<ExchangeViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletService, WalletType, void>((WalletType param1, __) {
|
||||
switch (param1) {
|
||||
case WalletType.haven:
|
||||
return haven!.createHavenWalletService(_walletInfoSource);
|
||||
case WalletType.monero:
|
||||
return monero!.createMoneroWalletService(_walletInfoSource);
|
||||
case WalletType.bitcoin:
|
||||
return bitcoin!.createBitcoinWalletService(
|
||||
_walletInfoSource, _unspentCoinsInfoSource!);
|
||||
return bitcoin!.createBitcoinWalletService(_walletInfoSource, _unspentCoinsInfoSource!);
|
||||
case WalletType.litecoin:
|
||||
return bitcoin!.createLitecoinWalletService(
|
||||
_walletInfoSource, _unspentCoinsInfoSource!);
|
||||
return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource!);
|
||||
default:
|
||||
throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService');
|
||||
}
|
||||
});
|
||||
|
||||
getIt.registerFactory<SetupPinCodeViewModel>(() => SetupPinCodeViewModel(
|
||||
getIt.get<AuthService>(), getIt.get<SettingsStore>()));
|
||||
getIt.registerFactory<SetupPinCodeViewModel>(
|
||||
() => SetupPinCodeViewModel(getIt.get<AuthService>(), getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactoryParam<SetupPinCodePage,
|
||||
void Function(PinCodeState<PinCodeWidget>, String), void>(
|
||||
(onSuccessfulPinSetup, _) => SetupPinCodePage(
|
||||
getIt.get<SetupPinCodeViewModel>(),
|
||||
getIt.registerFactoryParam<SetupPinCodePage, void Function(PinCodeState<PinCodeWidget>, String),
|
||||
void>(
|
||||
(onSuccessfulPinSetup, _) => SetupPinCodePage(getIt.get<SetupPinCodeViewModel>(),
|
||||
onSuccessfulPinSetup: onSuccessfulPinSetup));
|
||||
|
||||
getIt.registerFactory(() => RescanViewModel(getIt.get<AppStore>().wallet!));
|
||||
|
@ -700,17 +737,16 @@ Future setup(
|
|||
|
||||
getIt.registerFactory(() => FaqPage(getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>(
|
||||
(type, _) => WalletRestoreViewModel(getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>((type, _) =>
|
||||
WalletRestoreViewModel(
|
||||
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
type: type));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>((type, _) =>
|
||||
WalletRestorePage(getIt.get<WalletRestoreViewModel>(param1: type)));
|
||||
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>(
|
||||
(type, _) => WalletRestorePage(getIt.get<WalletRestoreViewModel>(param1: type)));
|
||||
|
||||
getIt
|
||||
.registerFactoryParam<TransactionDetailsViewModel, TransactionInfo, void>(
|
||||
(TransactionInfo transactionInfo, _) {
|
||||
getIt.registerFactoryParam<TransactionDetailsViewModel, TransactionInfo, void>(
|
||||
(TransactionInfo transactionInfo, _) {
|
||||
final wallet = getIt.get<AppStore>().wallet!;
|
||||
return TransactionDetailsViewModel(
|
||||
transactionInfo: transactionInfo,
|
||||
|
@ -724,54 +760,48 @@ Future setup(
|
|||
transactionDetailsViewModel:
|
||||
getIt.get<TransactionDetailsViewModel>(param1: transactionInfo)));
|
||||
|
||||
getIt.registerFactoryParam<NewWalletTypePage,
|
||||
void Function(BuildContext, WalletType), void>(
|
||||
getIt.registerFactoryParam<NewWalletTypePage, void Function(BuildContext, WalletType), void>(
|
||||
(param1, _) => NewWalletTypePage(onTypeSelected: param1));
|
||||
|
||||
getIt.registerFactoryParam<PreSeedPage, WalletType, void>(
|
||||
(WalletType type, _) => PreSeedPage(type));
|
||||
|
||||
getIt.registerFactoryParam<TradeDetailsViewModel, Trade, void>((trade, _) =>
|
||||
TradeDetailsViewModel(tradeForDetails: trade, trades: _tradesSource,
|
||||
TradeDetailsViewModel(
|
||||
tradeForDetails: trade,
|
||||
trades: _tradesSource,
|
||||
settingsStore: getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactory(() => BackupService(
|
||||
getIt.get<FlutterSecureStorage>(),
|
||||
_walletInfoSource,
|
||||
getIt.get<KeyService>(),
|
||||
getIt.get<SharedPreferences>()));
|
||||
getIt.registerFactory(() => BackupService(getIt.get<FlutterSecureStorage>(), _walletInfoSource,
|
||||
getIt.get<KeyService>(), getIt.get<SharedPreferences>()));
|
||||
|
||||
getIt.registerFactory(() => BackupViewModel(getIt.get<FlutterSecureStorage>(),
|
||||
getIt.get<SecretStore>(), getIt.get<BackupService>()));
|
||||
getIt.registerFactory(() => BackupViewModel(
|
||||
getIt.get<FlutterSecureStorage>(), getIt.get<SecretStore>(), getIt.get<BackupService>()));
|
||||
|
||||
getIt.registerFactory(() => BackupPage(getIt.get<BackupViewModel>()));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => EditBackupPasswordViewModel(getIt.get<FlutterSecureStorage>(), getIt.get<SecretStore>()));
|
||||
getIt.registerFactory(() =>
|
||||
EditBackupPasswordViewModel(getIt.get<FlutterSecureStorage>(), getIt.get<SecretStore>()));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>()));
|
||||
getIt.registerFactory(() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<RestoreOptionsPage, bool, void>((bool isNewInstall, _) =>
|
||||
RestoreOptionsPage(isNewInstall: isNewInstall));
|
||||
getIt.registerFactoryParam<RestoreOptionsPage, bool, void>(
|
||||
(bool isNewInstall, _) => RestoreOptionsPage(isNewInstall: isNewInstall));
|
||||
|
||||
getIt.registerFactory(() => RestoreFromBackupViewModel(getIt.get<BackupService>()));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => RestoreFromBackupViewModel(getIt.get<BackupService>()));
|
||||
getIt.registerFactory(() => RestoreFromBackupPage(getIt.get<RestoreFromBackupViewModel>()));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => RestoreFromBackupPage(getIt.get<RestoreFromBackupViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<TradeDetailsPage, Trade, void>((Trade trade, _) =>
|
||||
TradeDetailsPage(getIt.get<TradeDetailsViewModel>(param1: trade)));
|
||||
getIt.registerFactoryParam<TradeDetailsPage, Trade, void>(
|
||||
(Trade trade, _) => TradeDetailsPage(getIt.get<TradeDetailsViewModel>(param1: trade)));
|
||||
|
||||
getIt.registerFactory(() => BuyAmountViewModel());
|
||||
|
||||
getIt.registerFactory(() {
|
||||
final wallet = getIt.get<AppStore>().wallet;
|
||||
|
||||
return BuyViewModel(_ordersSource, getIt.get<OrdersStore>(),
|
||||
getIt.get<SettingsStore>(), getIt.get<BuyAmountViewModel>(),
|
||||
return BuyViewModel(_ordersSource, getIt.get<OrdersStore>(), getIt.get<SettingsStore>(),
|
||||
getIt.get<BuyAmountViewModel>(),
|
||||
wallet: wallet!);
|
||||
});
|
||||
|
||||
|
@ -783,7 +813,8 @@ Future setup(
|
|||
final url = args.first as String;
|
||||
final buyViewModel = args[1] as BuyViewModel;
|
||||
|
||||
return BuyWebViewPage(buyViewModel: buyViewModel, ordersStore: getIt.get<OrdersStore>(), url: url);
|
||||
return BuyWebViewPage(
|
||||
buyViewModel: buyViewModel, ordersStore: getIt.get<OrdersStore>(), url: url);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<OrderDetailsViewModel, Order, void>((order, _) {
|
||||
|
@ -792,8 +823,8 @@ Future setup(
|
|||
return OrderDetailsViewModel(wallet: wallet!, orderForDetails: order);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<OrderDetailsPage, Order, void>((Order order, _) =>
|
||||
OrderDetailsPage(getIt.get<OrderDetailsViewModel>(param1: order)));
|
||||
getIt.registerFactoryParam<OrderDetailsPage, Order, void>(
|
||||
(Order order, _) => OrderDetailsPage(getIt.get<OrderDetailsViewModel>(param1: order)));
|
||||
|
||||
getIt.registerFactory(() => SupportViewModel());
|
||||
|
||||
|
@ -802,20 +833,18 @@ Future setup(
|
|||
getIt.registerFactory(() {
|
||||
final wallet = getIt.get<AppStore>().wallet;
|
||||
|
||||
return UnspentCoinsListViewModel(
|
||||
wallet: wallet!, unspentCoinsInfo: _unspentCoinsInfoSource!);
|
||||
return UnspentCoinsListViewModel(wallet: wallet!, unspentCoinsInfo: _unspentCoinsInfoSource!);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => UnspentCoinsListPage(
|
||||
unspentCoinsListViewModel: getIt.get<UnspentCoinsListViewModel>()));
|
||||
getIt.registerFactory(() =>
|
||||
UnspentCoinsListPage(unspentCoinsListViewModel: getIt.get<UnspentCoinsListViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<UnspentCoinsDetailsViewModel, UnspentCoinsItem,
|
||||
UnspentCoinsListViewModel>(
|
||||
(item, model) => UnspentCoinsDetailsViewModel(
|
||||
unspentCoinsItem: item, unspentCoinsListViewModel: model));
|
||||
(item, model) =>
|
||||
UnspentCoinsDetailsViewModel(unspentCoinsItem: item, unspentCoinsListViewModel: model));
|
||||
|
||||
getIt.registerFactoryParam<UnspentCoinsDetailsPage, List, void>(
|
||||
(List args, _) {
|
||||
getIt.registerFactoryParam<UnspentCoinsDetailsPage, List, void>((List args, _) {
|
||||
final item = args.first as UnspentCoinsItem;
|
||||
final unspentCoinsListViewModel = args[1] as UnspentCoinsListViewModel;
|
||||
|
||||
|
@ -826,11 +855,11 @@ Future setup(
|
|||
|
||||
getIt.registerFactory(() => YatService());
|
||||
|
||||
getIt.registerFactory(() => AddressResolver(yatService: getIt.get<YatService>(),
|
||||
walletType: getIt.get<AppStore>().wallet!.type));
|
||||
getIt.registerFactory(() => AddressResolver(
|
||||
yatService: getIt.get<YatService>(), walletType: getIt.get<AppStore>().wallet!.type));
|
||||
|
||||
getIt.registerFactoryParam<FullscreenQRPage, QrViewData, void>(
|
||||
(QrViewData viewData, _) => FullscreenQRPage(qrViewData: viewData));
|
||||
(QrViewData viewData, _) => FullscreenQRPage(qrViewData: viewData));
|
||||
|
||||
getIt.registerFactory(() => IoniaApi());
|
||||
|
||||
|
@ -839,26 +868,24 @@ Future setup(
|
|||
getIt.registerFactory<IoniaService>(
|
||||
() => IoniaService(getIt.get<FlutterSecureStorage>(), getIt.get<IoniaApi>()));
|
||||
|
||||
getIt.registerFactory<IoniaAnyPay>(
|
||||
() => IoniaAnyPay(
|
||||
getIt.get<IoniaService>(),
|
||||
getIt.get<AnyPayApi>(),
|
||||
getIt.get<AppStore>().wallet!));
|
||||
getIt.registerFactory<IoniaAnyPay>(() => IoniaAnyPay(
|
||||
getIt.get<IoniaService>(), getIt.get<AnyPayApi>(), getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory(() => IoniaGiftCardsListViewModel(ioniaService: getIt.get<IoniaService>()));
|
||||
|
||||
getIt.registerFactory(() => IoniaAuthViewModel(ioniaService: getIt.get<IoniaService>()));
|
||||
|
||||
getIt.registerFactoryParam<IoniaMerchPurchaseViewModel, double, IoniaMerchant>((double amount, merchant) {
|
||||
getIt.registerFactoryParam<IoniaMerchPurchaseViewModel, double, IoniaMerchant>(
|
||||
(double amount, merchant) {
|
||||
return IoniaMerchPurchaseViewModel(
|
||||
ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
|
||||
amount: amount,
|
||||
ioniaMerchant: merchant,
|
||||
sendViewModel: getIt.get<SendViewModel>()
|
||||
);
|
||||
ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
|
||||
amount: amount,
|
||||
ioniaMerchant: merchant,
|
||||
sendViewModel: getIt.get<SendViewModel>());
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaBuyCardViewModel, IoniaMerchant, void>((IoniaMerchant merchant, _) {
|
||||
getIt.registerFactoryParam<IoniaBuyCardViewModel, IoniaMerchant, void>(
|
||||
(IoniaMerchant merchant, _) {
|
||||
return IoniaBuyCardViewModel(ioniaMerchant: merchant);
|
||||
});
|
||||
|
||||
|
@ -886,43 +913,45 @@ Future setup(
|
|||
getIt.registerFactoryParam<IoniaBuyGiftCardDetailPage, List, void>((List args, _) {
|
||||
final amount = args.first as double;
|
||||
final merchant = args.last as IoniaMerchant;
|
||||
return IoniaBuyGiftCardDetailPage(getIt.get<IoniaMerchPurchaseViewModel>(param1: amount, param2: merchant));
|
||||
return IoniaBuyGiftCardDetailPage(
|
||||
getIt.get<IoniaMerchPurchaseViewModel>(param1: amount, param2: merchant));
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaGiftCardDetailsViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) {
|
||||
return IoniaGiftCardDetailsViewModel(
|
||||
ioniaService: getIt.get<IoniaService>(),
|
||||
giftCard: giftCard);
|
||||
getIt.registerFactoryParam<IoniaGiftCardDetailsViewModel, IoniaGiftCard, void>(
|
||||
(IoniaGiftCard giftCard, _) {
|
||||
return IoniaGiftCardDetailsViewModel(
|
||||
ioniaService: getIt.get<IoniaService>(), giftCard: giftCard);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomTipViewModel, List, void>((List args, _) {
|
||||
final amount = args[0] as double;
|
||||
final merchant = args[1] as IoniaMerchant;
|
||||
final tip = args[2] as IoniaTip;
|
||||
getIt.registerFactoryParam<IoniaCustomTipViewModel, List, void>((List args, _) {
|
||||
final amount = args[0] as double;
|
||||
final merchant = args[1] as IoniaMerchant;
|
||||
final tip = args[2] as IoniaTip;
|
||||
|
||||
return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant);
|
||||
return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaGiftCardDetailPage, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) {
|
||||
return IoniaGiftCardDetailPage(getIt.get<IoniaGiftCardDetailsViewModel>(param1: giftCard));
|
||||
getIt.registerFactoryParam<IoniaGiftCardDetailPage, IoniaGiftCard, void>(
|
||||
(IoniaGiftCard giftCard, _) {
|
||||
return IoniaGiftCardDetailPage(getIt.get<IoniaGiftCardDetailsViewModel>(param1: giftCard));
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaMoreOptionsPage, List, void>((List args, _){
|
||||
getIt.registerFactoryParam<IoniaMoreOptionsPage, List, void>((List args, _) {
|
||||
final giftCard = args.first as IoniaGiftCard;
|
||||
|
||||
return IoniaMoreOptionsPage(giftCard);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _)
|
||||
=> IoniaCustomRedeemViewModel(giftCard: giftCard, ioniaService: getIt.get<IoniaService>()));
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>(
|
||||
(IoniaGiftCard giftCard, _) =>
|
||||
IoniaCustomRedeemViewModel(giftCard: giftCard, ioniaService: getIt.get<IoniaService>()));
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _){
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _) {
|
||||
final giftCard = args.first as IoniaGiftCard;
|
||||
|
||||
return IoniaCustomRedeemPage(getIt.get<IoniaCustomRedeemViewModel>(param1: giftCard) );
|
||||
return IoniaCustomRedeemPage(getIt.get<IoniaCustomRedeemViewModel>(param1: giftCard));
|
||||
});
|
||||
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomTipPage, List, void>((List args, _) {
|
||||
return IoniaCustomTipPage(getIt.get<IoniaCustomTipViewModel>(param1: args));
|
||||
});
|
||||
|
@ -937,42 +966,44 @@ Future setup(
|
|||
|
||||
getIt.registerFactory(() => IoniaAccountCardsPage(getIt.get<IoniaAccountViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => AnonPayApi(useTorOnly: getIt.get<SettingsStore>().exchangeStatus == ExchangeApiMode.torOnly,
|
||||
wallet: getIt.get<AppStore>().wallet!)
|
||||
);
|
||||
getIt.registerFactory(() => AnonPayApi(
|
||||
useTorOnly: getIt.get<SettingsStore>().exchangeStatus == ExchangeApiMode.torOnly,
|
||||
wallet: getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory(() => DesktopWalletSelectionDropDown(getIt.get<WalletListViewModel>(), getIt.get<AuthService>()));
|
||||
getIt.registerFactory(() =>
|
||||
DesktopWalletSelectionDropDown(getIt.get<WalletListViewModel>(), getIt.get<AuthService>()));
|
||||
|
||||
getIt.registerFactory(() => DesktopSidebarViewModel());
|
||||
|
||||
getIt.registerFactoryParam<AnonpayDetailsViewModel, AnonpayInvoiceInfo, void>(
|
||||
(AnonpayInvoiceInfo anonpayInvoiceInfo, _)
|
||||
=> AnonpayDetailsViewModel(
|
||||
anonPayApi: getIt.get<AnonPayApi>(),
|
||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||
settingsStore: getIt.get<SettingsStore>(),
|
||||
));
|
||||
(AnonpayInvoiceInfo anonpayInvoiceInfo, _) => AnonpayDetailsViewModel(
|
||||
anonPayApi: getIt.get<AnonPayApi>(),
|
||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||
settingsStore: getIt.get<SettingsStore>(),
|
||||
));
|
||||
|
||||
getIt.registerFactoryParam<AnonPayReceivePage, AnonpayInfoBase, void>(
|
||||
(AnonpayInfoBase anonpayInvoiceInfo, _) => AnonPayReceivePage(invoiceInfo: anonpayInvoiceInfo));
|
||||
(AnonpayInfoBase anonpayInvoiceInfo, _) =>
|
||||
AnonPayReceivePage(invoiceInfo: anonpayInvoiceInfo));
|
||||
|
||||
getIt.registerFactoryParam<AnonpayDetailsPage, AnonpayInvoiceInfo, void>(
|
||||
(AnonpayInvoiceInfo anonpayInvoiceInfo, _)
|
||||
=> AnonpayDetailsPage(anonpayDetailsViewModel: getIt.get<AnonpayDetailsViewModel>(param1: anonpayInvoiceInfo)));
|
||||
(AnonpayInvoiceInfo anonpayInvoiceInfo, _) => AnonpayDetailsPage(
|
||||
anonpayDetailsViewModel: getIt.get<AnonpayDetailsViewModel>(param1: anonpayInvoiceInfo)));
|
||||
|
||||
getIt.registerFactoryParam<IoniaPaymentStatusViewModel, IoniaAnyPayPaymentInfo, AnyPayPaymentCommittedInfo>(
|
||||
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo)
|
||||
=> IoniaPaymentStatusViewModel(
|
||||
getIt.get<IoniaService>(),
|
||||
paymentInfo: paymentInfo,
|
||||
committedInfo: committedInfo));
|
||||
getIt.registerFactoryParam<IoniaPaymentStatusViewModel, IoniaAnyPayPaymentInfo,
|
||||
AnyPayPaymentCommittedInfo>(
|
||||
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) =>
|
||||
IoniaPaymentStatusViewModel(getIt.get<IoniaService>(),
|
||||
paymentInfo: paymentInfo, committedInfo: committedInfo));
|
||||
|
||||
getIt.registerFactoryParam<IoniaPaymentStatusPage, IoniaAnyPayPaymentInfo, AnyPayPaymentCommittedInfo>(
|
||||
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo)
|
||||
=> IoniaPaymentStatusPage(getIt.get<IoniaPaymentStatusViewModel>(param1: paymentInfo, param2: committedInfo)));
|
||||
getIt.registerFactoryParam<IoniaPaymentStatusPage, IoniaAnyPayPaymentInfo,
|
||||
AnyPayPaymentCommittedInfo>(
|
||||
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) =>
|
||||
IoniaPaymentStatusPage(
|
||||
getIt.get<IoniaPaymentStatusViewModel>(param1: paymentInfo, param2: committedInfo)));
|
||||
|
||||
getIt.registerFactoryParam<AdvancedPrivacySettingsViewModel, WalletType, void>((type, _) =>
|
||||
AdvancedPrivacySettingsViewModel(type, getIt.get<SettingsStore>()));
|
||||
getIt.registerFactoryParam<AdvancedPrivacySettingsViewModel, WalletType, void>(
|
||||
(type, _) => AdvancedPrivacySettingsViewModel(type, getIt.get<SettingsStore>()));
|
||||
|
||||
_isSetupFinished = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@ class PreferencesKey {
|
|||
static const currentFiatApiModeKey = 'current_fiat_api_mode';
|
||||
static const allowBiometricalAuthenticationKey =
|
||||
'allow_biometrical_authentication';
|
||||
static const useTOTP2FA = 'use_totp_2fa';
|
||||
static const failedTotpTokenTrials = 'failed_token_trials';
|
||||
static const totpSecretKey = 'totp_qr_secret_key';
|
||||
static const disableExchangeKey = 'disable_exchange';
|
||||
static const exchangeStatusKey = 'exchange_status';
|
||||
static const currentTheme = 'current_theme';
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/core/totp_request_details.dart';
|
||||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/buy/order.dart';
|
||||
import 'package:cake_wallet/entities/qr_view_data.dart';
|
||||
|
@ -33,6 +34,10 @@ import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart';
|
|||
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
|
||||
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
|
||||
import 'package:cake_wallet/src/screens/support/support_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
|
||||
|
@ -149,6 +154,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
case Routes.restoreOptions:
|
||||
final isNewInstall = settings.arguments as bool;
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) => getIt.get<RestoreOptionsPage>(param1: isNewInstall));
|
||||
|
||||
case Routes.restoreWalletFromSeedKeys:
|
||||
|
@ -262,6 +268,26 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
param1: settings.arguments as OnAuthenticationFinished,
|
||||
param2: true));
|
||||
|
||||
case Routes.totpAuthCodePage:
|
||||
final args = settings.arguments as TotpAuthArgumentsModel;
|
||||
return MaterialPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) => getIt.get<TotpAuthCodePage>(
|
||||
param1: args,
|
||||
),
|
||||
);
|
||||
|
||||
case Routes.login:
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (context) => WillPopScope(
|
||||
child: getIt.get<AuthPage>(instanceName: 'login'),
|
||||
onWillPop: () async =>
|
||||
// FIX-ME: Additional check does it works correctly
|
||||
(await SystemChannels.platform.invokeMethod<bool>('SystemNavigator.pop') ??
|
||||
false),
|
||||
),
|
||||
fullscreenDialog: true);
|
||||
|
||||
case Routes.unlock:
|
||||
return MaterialPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
|
@ -303,14 +329,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
param1: args?['editingNode'] as Node?,
|
||||
param2: args?['isSelected'] as bool?));
|
||||
|
||||
case Routes.login:
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (context) => WillPopScope(
|
||||
child: getIt.get<AuthPage>(instanceName: 'login'),
|
||||
onWillPop: () async =>
|
||||
// FIX-ME: Additional check does it works correctly
|
||||
(await SystemChannels.platform.invokeMethod<bool>('SystemNavigator.pop') ?? false)),
|
||||
fullscreenDialog: true);
|
||||
|
||||
|
||||
case Routes.accountCreation:
|
||||
return CupertinoPageRoute<String>(
|
||||
|
@ -346,6 +365,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
|
||||
case Routes.tradeDetails:
|
||||
return MaterialPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) =>
|
||||
getIt.get<TradeDetailsPage>(param1: settings.arguments as Trade));
|
||||
|
||||
|
@ -363,6 +383,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
final args = settings.arguments as List;
|
||||
|
||||
return MaterialPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) =>
|
||||
getIt.get<BuyWebViewPage>(param1: args));
|
||||
|
||||
|
@ -372,6 +393,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
getIt.get<WalletRestorationFromSeedVM>(param1: args);
|
||||
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) => RestoreWalletFromSeedDetailsPage(
|
||||
walletRestorationFromSeedVM: walletRestorationFromSeedVM));
|
||||
|
||||
|
@ -405,6 +427,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
|
||||
case Routes.restoreFromBackup:
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) => getIt.get<RestoreFromBackupPage>());
|
||||
|
||||
case Routes.support:
|
||||
|
@ -543,6 +566,15 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
fullscreenDialog: true,
|
||||
builder: (_) => getIt.get<TransactionsPage>());
|
||||
|
||||
case Routes.setup_2faPage:
|
||||
return MaterialPageRoute<void>(builder: (_) => getIt.get<Setup2FAPage>());
|
||||
|
||||
case Routes.setup_2faQRPage:
|
||||
return MaterialPageRoute<void>(builder: (_) => getIt.get<Setup2FAQRPage>());
|
||||
|
||||
case Routes.modify2FAPage:
|
||||
return MaterialPageRoute<void>(builder: (_) => getIt.get<Modify2FAPage>());
|
||||
|
||||
default:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => Scaffold(
|
||||
|
|
|
@ -84,4 +84,8 @@ class Routes {
|
|||
static const payfuraPage = '/pay_fura_page';
|
||||
static const desktop_actions = '/desktop_actions';
|
||||
static const transactionsPage = '/transactions_page';
|
||||
static const setup_2faPage = '/setup_2fa_page';
|
||||
static const setup_2faQRPage = '/setup_2fa_qr_page';
|
||||
static const totpAuthCodePage = '/totp_auth_code_page';
|
||||
static const modify2FAPage = '/modify_2fa_page';
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/core/totp_request_details.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -10,6 +11,8 @@ import 'package:cake_wallet/store/authentication_store.dart';
|
|||
import 'package:cake_wallet/entities/qr_scanner.dart';
|
||||
import 'package:uni_links/uni_links.dart';
|
||||
|
||||
import '../setup_2fa/setup_2fa_enter_code_page.dart';
|
||||
|
||||
class Root extends StatefulWidget {
|
||||
Root({
|
||||
required Key key,
|
||||
|
@ -114,19 +117,49 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
|||
if (_isInactive && !_postFrameCallback && _requestAuth) {
|
||||
_postFrameCallback = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
widget.navigatorKey.currentState?.pushNamed(Routes.unlock,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
widget.navigatorKey.currentState?.pushNamed(
|
||||
Routes.unlock,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
} else {
|
||||
final useTotp = widget.appStore.settingsStore.useTOTP2FA;
|
||||
if (useTotp) {
|
||||
_reset();
|
||||
auth.close(
|
||||
route: Routes.totpAuthCodePage,
|
||||
arguments: TotpAuthArgumentsModel(
|
||||
onTotpAuthenticationFinished:
|
||||
(bool isAuthenticatedSuccessfully, TotpAuthCodePageState totpAuth) {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
_reset();
|
||||
totpAuth.close(
|
||||
route: launchUri != null ? Routes.send : null,
|
||||
arguments: PaymentRequest.fromUri(launchUri),
|
||||
);
|
||||
launchUri = null;
|
||||
},
|
||||
isForSetup: false,
|
||||
isClosable: false,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
_reset();
|
||||
auth.close(
|
||||
route: launchUri != null ? Routes.send : null,
|
||||
arguments: PaymentRequest.fromUri(launchUri),
|
||||
);
|
||||
launchUri = null;
|
||||
}
|
||||
}
|
||||
|
||||
_reset();
|
||||
auth.close(
|
||||
route: launchUri != null ? Routes.send : null,
|
||||
arguments: PaymentRequest.fromUri(launchUri),
|
||||
|
||||
},
|
||||
);
|
||||
launchUri = null;
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
} else if (launchUri != null) {
|
||||
widget.navigatorKey.currentState?.pushNamed(
|
||||
|
|
|
@ -26,64 +26,81 @@ class SecurityBackupPage extends BasePage {
|
|||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.show_keys,
|
||||
handler: (_) => _authService.authenticateAction(context, route: Routes.showKeys),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.create_backup,
|
||||
handler: (_) => _authService.authenticateAction(context, route: Routes.backup),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.settings_change_pin,
|
||||
handler: (_) => _authService.authenticateAction(
|
||||
context,
|
||||
route: Routes.setupPin,
|
||||
arguments: (PinCodeState<PinCodeWidget> setupPinContext, String _) {
|
||||
setupPinContext.close();
|
||||
},
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.show_keys,
|
||||
handler: (_) => _authService.authenticateAction(context, route: Routes.showKeys),
|
||||
),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
if (DeviceInfo.instance.isMobile)
|
||||
Observer(builder: (_) {
|
||||
return SettingsSwitcherCell(
|
||||
title: S.current.settings_allow_biometrical_authentication,
|
||||
value: _securitySettingsViewModel.allowBiometricalAuthentication,
|
||||
onValueChange: (BuildContext context, bool value) {
|
||||
if (value) {
|
||||
_authService.authenticateAction(context,
|
||||
onAuthSuccess: (isAuthenticatedSuccessfully) async {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
if (await _securitySettingsViewModel.biometricAuthenticated()) {
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.create_backup,
|
||||
handler: (_) => _authService.authenticateAction(context, route: Routes.backup),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.settings_change_pin,
|
||||
handler: (_) => _authService.authenticateAction(
|
||||
context,
|
||||
route: Routes.setupPin,
|
||||
arguments: (PinCodeState<PinCodeWidget> setupPinContext, String _) {
|
||||
setupPinContext.close();
|
||||
},
|
||||
),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
if (DeviceInfo.instance.isMobile)
|
||||
Observer(builder: (_) {
|
||||
return SettingsSwitcherCell(
|
||||
title: S.current.settings_allow_biometrical_authentication,
|
||||
value: _securitySettingsViewModel.allowBiometricalAuthentication,
|
||||
onValueChange: (BuildContext context, bool value) {
|
||||
if (value) {
|
||||
_authService.authenticateAction(context,
|
||||
onAuthSuccess: (isAuthenticatedSuccessfully) async {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
if (await _securitySettingsViewModel.biometricAuthenticated()) {
|
||||
_securitySettingsViewModel
|
||||
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
|
||||
}
|
||||
} else {
|
||||
_securitySettingsViewModel
|
||||
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
|
||||
}
|
||||
} else {
|
||||
_securitySettingsViewModel
|
||||
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
_securitySettingsViewModel.setAllowBiometricalAuthentication(value);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
_securitySettingsViewModel.setAllowBiometricalAuthentication(value);
|
||||
}
|
||||
});
|
||||
}),
|
||||
Observer(builder: (_) {
|
||||
return SettingsPickerCell<PinCodeRequiredDuration>(
|
||||
title: S.current.require_pin_after,
|
||||
items: PinCodeRequiredDuration.values,
|
||||
selectedItem: _securitySettingsViewModel.pinCodeRequiredDuration,
|
||||
onItemSelected: (PinCodeRequiredDuration code) {
|
||||
_securitySettingsViewModel.setPinCodeRequiredDuration(code);
|
||||
},
|
||||
);
|
||||
}),
|
||||
Observer(builder: (_) {
|
||||
return SettingsPickerCell<PinCodeRequiredDuration>(
|
||||
title: S.current.require_pin_after,
|
||||
items: PinCodeRequiredDuration.values,
|
||||
selectedItem: _securitySettingsViewModel.pinCodeRequiredDuration,
|
||||
onItemSelected: (PinCodeRequiredDuration code) {
|
||||
_securitySettingsViewModel.setPinCodeRequiredDuration(code);
|
||||
Observer(
|
||||
builder: (context) {
|
||||
return SettingsCellWithArrow(
|
||||
title: _securitySettingsViewModel.useTotp2FA
|
||||
? S.current.modify_2fa
|
||||
: S.current.setup_2fa,
|
||||
handler: (_) => _authService.authenticateAction(
|
||||
context,
|
||||
route: _securitySettingsViewModel.useTotp2FA
|
||||
? Routes.modify2FAPage
|
||||
: Routes.setup_2faPage,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
]),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
55
lib/src/screens/setup_2fa/modify_2fa_page.dart
Normal file
55
lib/src/screens/setup_2fa/modify_2fa_page.dart
Normal file
|
@ -0,0 +1,55 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
|
||||
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
|
||||
import '../../../routes.dart';
|
||||
|
||||
class Modify2FAPage extends BasePage {
|
||||
Modify2FAPage({required this.setup2FAViewModel});
|
||||
|
||||
final Setup2FAViewModel setup2FAViewModel;
|
||||
|
||||
@override
|
||||
String get title => S.current.modify_2fa;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.disable_cake_2fa,
|
||||
handler: (_) async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.current.disable_cake_2fa,
|
||||
alertContent: S.current.question_to_disable_2fa,
|
||||
leftButtonText: S.current.cancel,
|
||||
rightButtonText: S.current.disable,
|
||||
actionLeftButton: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
actionRightButton: () {
|
||||
setup2FAViewModel.setUseTOTP2FA(false);
|
||||
Navigator.pushNamedAndRemoveUntil(
|
||||
context, Routes.dashboard, (route) => false);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
62
lib/src/screens/setup_2fa/setup_2fa.dart
Normal file
62
lib/src/screens/setup_2fa/setup_2fa.dart
Normal file
|
@ -0,0 +1,62 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
|
||||
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
|
||||
|
||||
import '../../widgets/standard_list.dart';
|
||||
|
||||
class Setup2FAPage extends BasePage {
|
||||
Setup2FAPage({required this.setup2FAViewModel});
|
||||
|
||||
final Setup2FAViewModel setup2FAViewModel;
|
||||
|
||||
@override
|
||||
String get title => S.current.setup_2fa;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
S.current.important_note,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 14,
|
||||
height: 1.571,
|
||||
color: Theme.of(context).primaryTextTheme.headline6!.color!,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
S.current.setup_2fa_text,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14,
|
||||
height: 1.571,
|
||||
color: Theme.of(context).primaryTextTheme.headline6!.color!,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 86),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.setup_totp_recommended,
|
||||
handler: (_) => Navigator.of(context).pushNamed(Routes.setup_2faQRPage),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
221
lib/src/screens/setup_2fa/setup_2fa_enter_code_page.dart
Normal file
221
lib/src/screens/setup_2fa/setup_2fa_enter_code_page.dart
Normal file
|
@ -0,0 +1,221 @@
|
|||
import 'package:another_flushbar/flushbar.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/core/totp_request_details.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/view_model/auth_state.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/widgets/popup_cancellable_alert.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
import '../../../palette.dart';
|
||||
import '../../../routes.dart';
|
||||
|
||||
typedef OnTotpAuthenticationFinished = void Function(bool, TotpAuthCodePageState);
|
||||
|
||||
class TotpAuthCodePage extends StatefulWidget {
|
||||
TotpAuthCodePage(
|
||||
this.setup2FAViewModel, {
|
||||
required this.totpArguments,
|
||||
});
|
||||
|
||||
final Setup2FAViewModel setup2FAViewModel;
|
||||
|
||||
final TotpAuthArgumentsModel totpArguments;
|
||||
|
||||
@override
|
||||
TotpAuthCodePageState createState() => TotpAuthCodePageState();
|
||||
}
|
||||
|
||||
class TotpAuthCodePageState extends State<TotpAuthCodePage> {
|
||||
final _key = GlobalKey<ScaffoldState>();
|
||||
|
||||
ReactionDisposer? _reaction;
|
||||
Flushbar<void>? _authBar;
|
||||
Flushbar<void>? _progressBar;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_reaction ??= reaction((_) => widget.setup2FAViewModel.state, (ExecutionState state) {
|
||||
if (state is ExecutedSuccessfullyState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
widget.totpArguments.onTotpAuthenticationFinished!(true, this);
|
||||
});
|
||||
}
|
||||
|
||||
if (state is FailureState) {
|
||||
print(state.error);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
widget.totpArguments.onTotpAuthenticationFinished!(false, this);
|
||||
});
|
||||
}
|
||||
|
||||
if (state is AuthenticationBanned) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
widget.totpArguments.onTotpAuthenticationFinished!(false, this);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_reaction?.reaction.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void changeProcessText(String text) {
|
||||
dismissFlushBar(_authBar);
|
||||
_progressBar = createBar<void>(text, duration: null)..show(_key.currentContext!);
|
||||
}
|
||||
|
||||
Future<void> close({String? route, dynamic arguments}) async {
|
||||
if (_key.currentContext == null) {
|
||||
throw Exception('Key context is null. Should be not happened');
|
||||
}
|
||||
await Future<void>.delayed(Duration(milliseconds: 50));
|
||||
if (route != null) {
|
||||
Navigator.of(_key.currentContext!).pushReplacementNamed(route, arguments: arguments);
|
||||
} else {
|
||||
Navigator.of(_key.currentContext!).pop();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
key: _key,
|
||||
resizeToAvoidBottomInset: false,
|
||||
body: TOTPEnterCode(
|
||||
setup2FAViewModel: widget.setup2FAViewModel,
|
||||
isForSetup: widget.totpArguments.isForSetup ?? false,
|
||||
isClosable: widget.totpArguments.isClosable ?? true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void dismissFlushBar(Flushbar<dynamic>? bar) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await bar?.dismiss();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class TOTPEnterCode extends BasePage {
|
||||
TOTPEnterCode({
|
||||
required this.setup2FAViewModel,
|
||||
required this.isForSetup,
|
||||
required this.isClosable,
|
||||
}) : totpController = TextEditingController() {
|
||||
totpController.addListener(() {
|
||||
setup2FAViewModel.enteredOTPCode = totpController.text;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
String get title => isForSetup ? S.current.setup_2fa : S.current.verify_with_2fa;
|
||||
|
||||
Widget? leading(BuildContext context) {
|
||||
return isClosable ? super.leading(context) : null;
|
||||
}
|
||||
|
||||
final TextEditingController totpController;
|
||||
final Setup2FAViewModel setup2FAViewModel;
|
||||
final bool isForSetup;
|
||||
final bool isClosable;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
BaseTextFormField(
|
||||
textAlign: TextAlign.left,
|
||||
hintText: S.current.totp_code,
|
||||
controller: totpController,
|
||||
keyboardType: TextInputType.number,
|
||||
placeholderTextStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
S.current.please_fill_totp,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.2,
|
||||
color: Palette.darkGray,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Spacer(),
|
||||
Observer(
|
||||
builder: (context) {
|
||||
return PrimaryButton(
|
||||
isDisabled: setup2FAViewModel.enteredOTPCode.length != 8,
|
||||
onPressed: () async {
|
||||
final result =
|
||||
await setup2FAViewModel.totp2FAAuth(totpController.text, isForSetup);
|
||||
final bannedState = setup2FAViewModel.state is AuthenticationBanned;
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return PopUpCancellableAlertDialog(
|
||||
contentText: _textDisplayedInPopupOnResult(result, bannedState, context),
|
||||
actionButtonText: S.of(context).ok,
|
||||
buttonAction: () {
|
||||
result ? setup2FAViewModel.success() : null;
|
||||
if (isForSetup && result) {
|
||||
Navigator.pushNamedAndRemoveUntil(
|
||||
context, Routes.dashboard, (route) => false);
|
||||
} else {
|
||||
Navigator.of(context).pop(result);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
text: S.of(context).continue_text,
|
||||
color: Theme.of(context).accentTextTheme.bodyLarge!.color!,
|
||||
textColor: Colors.white,
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _textDisplayedInPopupOnResult(bool result, bool bannedState, BuildContext context) {
|
||||
switch (result) {
|
||||
case true:
|
||||
return isForSetup ? S.current.totp_2fa_success : S.current.totp_verification_success;
|
||||
case false:
|
||||
if (bannedState) {
|
||||
final state = setup2FAViewModel.state as AuthenticationBanned;
|
||||
return S.of(context).failed_authentication(state.error);
|
||||
} else {
|
||||
return S.current.totp_2fa_failure;
|
||||
}
|
||||
default:
|
||||
return S.current.enter_totp_code;
|
||||
}
|
||||
}
|
||||
}
|
145
lib/src/screens/setup_2fa/setup_2fa_qr_page.dart
Normal file
145
lib/src/screens/setup_2fa/setup_2fa_qr_page.dart
Normal file
|
@ -0,0 +1,145 @@
|
|||
import 'package:cake_wallet/core/totp_request_details.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart' as qr;
|
||||
import '../../../palette.dart';
|
||||
import '../../widgets/primary_button.dart';
|
||||
import '../../widgets/standard_list.dart';
|
||||
|
||||
class Setup2FAQRPage extends BasePage {
|
||||
Setup2FAQRPage({required this.setup2FAViewModel});
|
||||
|
||||
final Setup2FAViewModel setup2FAViewModel;
|
||||
|
||||
@override
|
||||
String get title => S.current.setup_2fa;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
|
||||
final copyImage = Image.asset(
|
||||
'assets/images/copy_content.png',
|
||||
height: 12,
|
||||
width: 12,
|
||||
color: Color(0xFF355688),
|
||||
);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: 58),
|
||||
Text(
|
||||
S.current.add_secret_code,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
height: 1.5714,
|
||||
color: Palette.darkBlueCraiola,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 3,
|
||||
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 3,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
child: QrImage(
|
||||
data: setup2FAViewModel.totpVersionOneLink,
|
||||
version: qr.QrVersions.auto,
|
||||
)),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 13),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
S.current.totp_secret_code,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Palette.darkGray,
|
||||
height: 1.8333,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
'${setup2FAViewModel.secretKey}',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
height: 1.375,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: '${setup2FAViewModel.secretKey}'));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
color: Color(0xFFF2F0FA),
|
||||
),
|
||||
child: copyImage,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
StandardListSeparator(),
|
||||
Spacer(),
|
||||
PrimaryButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushReplacementNamed(
|
||||
Routes.totpAuthCodePage,
|
||||
arguments: TotpAuthArgumentsModel(
|
||||
isForSetup: true,
|
||||
)
|
||||
|
||||
);
|
||||
},
|
||||
text: S.current.continue_text,
|
||||
color: Theme.of(context).accentTextTheme.bodyLarge!.color!,
|
||||
textColor: Colors.white,
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
|
||||
import 'package:cake_wallet/src/widgets/alert_background.dart';
|
||||
|
||||
class PopUpCancellableAlertDialog extends StatelessWidget {
|
||||
final String contentText;
|
||||
final String actionButtonText;
|
||||
final VoidCallback? buttonAction;
|
||||
final bool sameActionForButtonAndClose;
|
||||
|
||||
const PopUpCancellableAlertDialog({
|
||||
super.key,
|
||||
this.contentText = '',
|
||||
this.actionButtonText = '',
|
||||
this.buttonAction,
|
||||
this.sameActionForButtonAndClose = true,
|
||||
});
|
||||
bool get barrierDismissible => false;
|
||||
Color? get actionButtonTextColor => null;
|
||||
Color? get actionButtonColor => null;
|
||||
|
||||
Widget content(BuildContext context) {
|
||||
return Text(
|
||||
contentText,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).primaryTextTheme.titleLarge!.color!,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => barrierDismissible ? Navigator.of(context).pop() : null,
|
||||
child: AlertBackground(
|
||||
child: Stack(
|
||||
alignment: AlignmentDirectional.center,
|
||||
children: [
|
||||
Positioned(
|
||||
top: 280,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||
child: Container(
|
||||
width: 340,
|
||||
padding: EdgeInsets.all(10),
|
||||
color: Theme.of(context).accentTextTheme.titleLarge!.decorationColor!,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 8, 24, 32),
|
||||
child: content(context),
|
||||
),
|
||||
PrimaryButton(
|
||||
onPressed: buttonAction,
|
||||
text: actionButtonText,
|
||||
color: Color(0xffE9F2FC),
|
||||
textColor: Palette.darkBlueCraiola,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
AlertCloseButton(
|
||||
onTap: sameActionForButtonAndClose ? buttonAction : null,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,8 @@ import 'package:cake_wallet/palette.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class AlertCloseButton extends StatelessWidget {
|
||||
AlertCloseButton({this.image, this.bottom});
|
||||
AlertCloseButton({this.image, this.bottom, this.onTap});
|
||||
final VoidCallback? onTap;
|
||||
|
||||
final Image? image;
|
||||
final double? bottom;
|
||||
|
@ -17,7 +18,7 @@ class AlertCloseButton extends StatelessWidget {
|
|||
return Positioned(
|
||||
bottom: bottom ?? 60,
|
||||
child: GestureDetector(
|
||||
onTap: () => Navigator.of(context).pop(),
|
||||
onTap: onTap ?? () => Navigator.of(context).pop(),
|
||||
child: Container(
|
||||
height: 42,
|
||||
width: 42,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/pin_code_required_duration.dart';
|
||||
|
@ -5,6 +7,7 @@ import 'package:cake_wallet/entities/preferences_key.dart';
|
|||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/themes/theme_list.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
@ -38,12 +41,16 @@ abstract class SettingsStoreBase with Store {
|
|||
required bool initialDisableSell,
|
||||
required FiatApiMode initialFiatMode,
|
||||
required bool initialAllowBiometricalAuthentication,
|
||||
required String initialTotpSecretKey,
|
||||
required bool initialUseTOTP2FA,
|
||||
required int initialFailedTokenTrial,
|
||||
required ExchangeApiMode initialExchangeStatus,
|
||||
required ThemeBase initialTheme,
|
||||
required int initialPinLength,
|
||||
required String initialLanguageCode,
|
||||
// required String initialCurrentLocale,
|
||||
required this.appVersion,
|
||||
required this.deviceName,
|
||||
required Map<WalletType, Node> nodes,
|
||||
required this.shouldShowYatPopup,
|
||||
required this.isBitcoinBuyEnabled,
|
||||
|
@ -53,38 +60,41 @@ abstract class SettingsStoreBase with Store {
|
|||
TransactionPriority? initialMoneroTransactionPriority,
|
||||
TransactionPriority? initialHavenTransactionPriority,
|
||||
TransactionPriority? initialLitecoinTransactionPriority})
|
||||
: nodes = ObservableMap<WalletType, Node>.of(nodes),
|
||||
_sharedPreferences = sharedPreferences,
|
||||
fiatCurrency = initialFiatCurrency,
|
||||
balanceDisplayMode = initialBalanceDisplayMode,
|
||||
shouldSaveRecipientAddress = initialSaveRecipientAddress,
|
||||
: nodes = ObservableMap<WalletType, Node>.of(nodes),
|
||||
_sharedPreferences = sharedPreferences,
|
||||
fiatCurrency = initialFiatCurrency,
|
||||
balanceDisplayMode = initialBalanceDisplayMode,
|
||||
shouldSaveRecipientAddress = initialSaveRecipientAddress,
|
||||
fiatApiMode = initialFiatMode,
|
||||
allowBiometricalAuthentication = initialAllowBiometricalAuthentication,
|
||||
totpSecretKey = initialTotpSecretKey,
|
||||
useTOTP2FA = initialUseTOTP2FA,
|
||||
numberOfFailedTokenTrials = initialFailedTokenTrial,
|
||||
isAppSecure = initialAppSecure,
|
||||
disableBuy = initialDisableBuy,
|
||||
disableSell = initialDisableSell,
|
||||
fiatApiMode = initialFiatMode,
|
||||
allowBiometricalAuthentication = initialAllowBiometricalAuthentication,
|
||||
disableBuy = initialDisableBuy,
|
||||
disableSell = initialDisableSell,
|
||||
shouldShowMarketPlaceInDashboard = initialShouldShowMarketPlaceInDashboard,
|
||||
exchangeStatus = initialExchangeStatus,
|
||||
currentTheme = initialTheme,
|
||||
pinCodeLength = initialPinLength,
|
||||
languageCode = initialLanguageCode,
|
||||
priority = ObservableMap<WalletType, TransactionPriority>() {
|
||||
exchangeStatus = initialExchangeStatus,
|
||||
currentTheme = initialTheme,
|
||||
pinCodeLength = initialPinLength,
|
||||
languageCode = initialLanguageCode,
|
||||
priority = ObservableMap<WalletType, TransactionPriority>() {
|
||||
//this.nodes = ObservableMap<WalletType, Node>.of(nodes);
|
||||
|
||||
if (initialMoneroTransactionPriority != null) {
|
||||
priority[WalletType.monero] = initialMoneroTransactionPriority;
|
||||
priority[WalletType.monero] = initialMoneroTransactionPriority;
|
||||
}
|
||||
|
||||
if (initialBitcoinTransactionPriority != null) {
|
||||
priority[WalletType.bitcoin] = initialBitcoinTransactionPriority;
|
||||
priority[WalletType.bitcoin] = initialBitcoinTransactionPriority;
|
||||
}
|
||||
|
||||
if (initialHavenTransactionPriority != null) {
|
||||
priority[WalletType.haven] = initialHavenTransactionPriority;
|
||||
priority[WalletType.haven] = initialHavenTransactionPriority;
|
||||
}
|
||||
|
||||
if (initialLitecoinTransactionPriority != null) {
|
||||
priority[WalletType.litecoin] = initialLitecoinTransactionPriority;
|
||||
priority[WalletType.litecoin] = initialLitecoinTransactionPriority;
|
||||
}
|
||||
|
||||
reaction(
|
||||
|
@ -94,8 +104,8 @@ abstract class SettingsStoreBase with Store {
|
|||
|
||||
reaction(
|
||||
(_) => shouldShowYatPopup,
|
||||
(bool shouldShowYatPopup) => sharedPreferences
|
||||
.setBool(PreferencesKey.shouldShowYatPopup, shouldShowYatPopup));
|
||||
(bool shouldShowYatPopup) =>
|
||||
sharedPreferences.setBool(PreferencesKey.shouldShowYatPopup, shouldShowYatPopup));
|
||||
|
||||
priority.observe((change) {
|
||||
final String? key;
|
||||
|
@ -124,8 +134,7 @@ abstract class SettingsStoreBase with Store {
|
|||
reaction(
|
||||
(_) => shouldSaveRecipientAddress,
|
||||
(bool shouldSaveRecipientAddress) => sharedPreferences.setBool(
|
||||
PreferencesKey.shouldSaveRecipientAddressKey,
|
||||
shouldSaveRecipientAddress));
|
||||
PreferencesKey.shouldSaveRecipientAddressKey, shouldSaveRecipientAddress));
|
||||
|
||||
reaction((_) => isAppSecure, (bool isAppSecure) {
|
||||
sharedPreferences.setBool(PreferencesKey.isAppSecureKey, isAppSecure);
|
||||
|
@ -149,40 +158,46 @@ abstract class SettingsStoreBase with Store {
|
|||
}
|
||||
|
||||
reaction(
|
||||
(_) => fiatApiMode,
|
||||
(FiatApiMode mode) => sharedPreferences.setInt(
|
||||
PreferencesKey.currentFiatApiModeKey, mode.serialize()));
|
||||
(_) => fiatApiMode,
|
||||
(FiatApiMode mode) =>
|
||||
sharedPreferences.setInt(PreferencesKey.currentFiatApiModeKey, mode.serialize()));
|
||||
|
||||
reaction(
|
||||
(_) => currentTheme,
|
||||
(ThemeBase theme) =>
|
||||
sharedPreferences.setInt(PreferencesKey.currentTheme, theme.raw));
|
||||
reaction((_) => currentTheme,
|
||||
(ThemeBase theme) => sharedPreferences.setInt(PreferencesKey.currentTheme, theme.raw));
|
||||
|
||||
reaction(
|
||||
(_) => allowBiometricalAuthentication,
|
||||
(bool biometricalAuthentication) => sharedPreferences.setBool(
|
||||
PreferencesKey.allowBiometricalAuthenticationKey,
|
||||
biometricalAuthentication));
|
||||
PreferencesKey.allowBiometricalAuthenticationKey, biometricalAuthentication));
|
||||
|
||||
reaction(
|
||||
(_) => useTOTP2FA, (bool use) => sharedPreferences.setBool(PreferencesKey.useTOTP2FA, use));
|
||||
|
||||
reaction(
|
||||
(_) => numberOfFailedTokenTrials,
|
||||
(int failedTokenTrail) =>
|
||||
sharedPreferences.setInt(PreferencesKey.failedTotpTokenTrials, failedTokenTrail));
|
||||
|
||||
reaction((_) => totpSecretKey,
|
||||
(String totpKey) => sharedPreferences.setString(PreferencesKey.totpSecretKey, totpKey));
|
||||
|
||||
reaction(
|
||||
(_) => shouldShowMarketPlaceInDashboard,
|
||||
(bool value) =>
|
||||
sharedPreferences.setBool(PreferencesKey.shouldShowMarketPlaceInDashboard, value));
|
||||
|
||||
reaction(
|
||||
(_) => pinCodeLength,
|
||||
(int pinLength) => sharedPreferences.setInt(
|
||||
PreferencesKey.currentPinLength, pinLength));
|
||||
reaction((_) => pinCodeLength,
|
||||
(int pinLength) => sharedPreferences.setInt(PreferencesKey.currentPinLength, pinLength));
|
||||
|
||||
reaction(
|
||||
(_) => languageCode,
|
||||
(String languageCode) => sharedPreferences.setString(
|
||||
PreferencesKey.currentLanguageCode, languageCode));
|
||||
(String languageCode) =>
|
||||
sharedPreferences.setString(PreferencesKey.currentLanguageCode, languageCode));
|
||||
|
||||
reaction(
|
||||
(_) => pinTimeOutDuration,
|
||||
(PinCodeRequiredDuration pinCodeInterval) => sharedPreferences.setInt(
|
||||
PreferencesKey.pinTimeOutDuration, pinCodeInterval.value));
|
||||
(PinCodeRequiredDuration pinCodeInterval) =>
|
||||
sharedPreferences.setInt(PreferencesKey.pinTimeOutDuration, pinCodeInterval.value));
|
||||
|
||||
reaction(
|
||||
(_) => balanceDisplayMode,
|
||||
|
@ -190,17 +205,15 @@ abstract class SettingsStoreBase with Store {
|
|||
PreferencesKey.currentBalanceDisplayModeKey, mode.serialize()));
|
||||
|
||||
reaction(
|
||||
(_) => exchangeStatus,
|
||||
(ExchangeApiMode mode) => sharedPreferences.setInt(
|
||||
PreferencesKey.exchangeStatusKey, mode.serialize()));
|
||||
(_) => exchangeStatus,
|
||||
(ExchangeApiMode mode) =>
|
||||
sharedPreferences.setInt(PreferencesKey.exchangeStatusKey, mode.serialize()));
|
||||
|
||||
this
|
||||
.nodes
|
||||
.observe((change) {
|
||||
if (change.newValue != null && change.key != null) {
|
||||
_saveCurrentNode(change.newValue!, change.key!);
|
||||
}
|
||||
});
|
||||
this.nodes.observe((change) {
|
||||
if (change.newValue != null && change.key != null) {
|
||||
_saveCurrentNode(change.newValue!, change.key!);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static const defaultPinLength = 4;
|
||||
|
@ -240,6 +253,20 @@ abstract class SettingsStoreBase with Store {
|
|||
@observable
|
||||
bool allowBiometricalAuthentication;
|
||||
|
||||
@observable
|
||||
String totpSecretKey;
|
||||
|
||||
@computed
|
||||
String get totpVersionOneLink {
|
||||
return 'otpauth://totp/Cake%20Wallet:$deviceName?secret=$totpSecretKey&issuer=Cake%20Wallet&algorithm=SHA512&digits=8&period=30';
|
||||
}
|
||||
|
||||
@observable
|
||||
bool useTOTP2FA;
|
||||
|
||||
@observable
|
||||
int numberOfFailedTokenTrials;
|
||||
|
||||
@observable
|
||||
ExchangeApiMode exchangeStatus;
|
||||
|
||||
|
@ -263,6 +290,8 @@ abstract class SettingsStoreBase with Store {
|
|||
|
||||
String appVersion;
|
||||
|
||||
String deviceName;
|
||||
|
||||
SharedPreferences _sharedPreferences;
|
||||
|
||||
ObservableMap<WalletType, Node> nodes;
|
||||
|
@ -271,7 +300,7 @@ abstract class SettingsStoreBase with Store {
|
|||
final node = nodes[walletType];
|
||||
|
||||
if (node == null) {
|
||||
throw Exception('No node found for wallet type: ${walletType.toString()}');
|
||||
throw Exception('No node found for wallet type: ${walletType.toString()}');
|
||||
}
|
||||
|
||||
return node;
|
||||
|
@ -280,10 +309,10 @@ abstract class SettingsStoreBase with Store {
|
|||
bool isBitcoinBuyEnabled;
|
||||
|
||||
bool get shouldShowReceiveWarning =>
|
||||
_sharedPreferences.getBool(PreferencesKey.shouldShowReceiveWarning) ?? true;
|
||||
_sharedPreferences.getBool(PreferencesKey.shouldShowReceiveWarning) ?? true;
|
||||
|
||||
Future<void> setShouldShowReceiveWarning(bool value) async =>
|
||||
_sharedPreferences.setBool(PreferencesKey.shouldShowReceiveWarning, value);
|
||||
_sharedPreferences.setBool(PreferencesKey.shouldShowReceiveWarning, value);
|
||||
|
||||
static Future<SettingsStore> load(
|
||||
{required Box<Node> nodeSource,
|
||||
|
@ -291,18 +320,15 @@ abstract class SettingsStoreBase with Store {
|
|||
FiatCurrency initialFiatCurrency = FiatCurrency.usd,
|
||||
BalanceDisplayMode initialBalanceDisplayMode = BalanceDisplayMode.availableBalance,
|
||||
ThemeBase? initialTheme}) async {
|
||||
|
||||
final sharedPreferences = await getIt.getAsync<SharedPreferences>();
|
||||
final currentFiatCurrency = FiatCurrency.deserialize(raw:
|
||||
sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!);
|
||||
final currentFiatCurrency = FiatCurrency.deserialize(
|
||||
raw: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!);
|
||||
|
||||
TransactionPriority? moneroTransactionPriority =
|
||||
monero?.deserializeMoneroTransactionPriority(
|
||||
raw: sharedPreferences
|
||||
.getInt(PreferencesKey.moneroTransactionPriority)!);
|
||||
TransactionPriority? moneroTransactionPriority = monero?.deserializeMoneroTransactionPriority(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!);
|
||||
TransactionPriority? bitcoinTransactionPriority =
|
||||
bitcoin?.deserializeBitcoinTransactionPriority(sharedPreferences
|
||||
.getInt(PreferencesKey.bitcoinTransactionPriority)!);
|
||||
bitcoin?.deserializeBitcoinTransactionPriority(
|
||||
sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority)!);
|
||||
|
||||
TransactionPriority? havenTransactionPriority;
|
||||
TransactionPriority? litecoinTransactionPriority;
|
||||
|
@ -322,8 +348,7 @@ abstract class SettingsStoreBase with Store {
|
|||
litecoinTransactionPriority ??= bitcoin?.getLitecoinTransactionPriorityMedium();
|
||||
|
||||
final currentBalanceDisplayMode = BalanceDisplayMode.deserialize(
|
||||
raw: sharedPreferences
|
||||
.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
|
||||
raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
|
||||
// FIX-ME: Check for which default value we should have here
|
||||
final shouldSaveRecipientAddress =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey) ?? false;
|
||||
|
@ -334,29 +359,29 @@ abstract class SettingsStoreBase with Store {
|
|||
final disableSell =
|
||||
sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? false;
|
||||
final currentFiatApiMode = FiatApiMode.deserialize(
|
||||
raw: sharedPreferences
|
||||
.getInt(PreferencesKey.currentFiatApiModeKey) ?? FiatApiMode.enabled.raw);
|
||||
final allowBiometricalAuthentication = sharedPreferences
|
||||
.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
|
||||
false;
|
||||
raw: sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey) ??
|
||||
FiatApiMode.enabled.raw);
|
||||
final allowBiometricalAuthentication =
|
||||
sharedPreferences.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? false;
|
||||
final totpSecretKey = sharedPreferences.getString(PreferencesKey.totpSecretKey) ?? '';
|
||||
final useTOTP2FA = sharedPreferences.getBool(PreferencesKey.useTOTP2FA) ?? false;
|
||||
final tokenTrialNumber = sharedPreferences.getInt(PreferencesKey.failedTotpTokenTrials) ?? 0;
|
||||
final shouldShowMarketPlaceInDashboard =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldShowMarketPlaceInDashboard) ?? true;
|
||||
final exchangeStatus = ExchangeApiMode.deserialize(
|
||||
raw: sharedPreferences
|
||||
.getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw);
|
||||
final legacyTheme =
|
||||
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
|
||||
? ThemeType.dark.index
|
||||
: ThemeType.bright.index;
|
||||
final savedTheme = initialTheme ?? ThemeList.deserialize(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ??
|
||||
legacyTheme);
|
||||
raw: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey) ??
|
||||
ExchangeApiMode.enabled.raw);
|
||||
final legacyTheme = (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
|
||||
? ThemeType.dark.index
|
||||
: ThemeType.bright.index;
|
||||
final savedTheme = initialTheme ??
|
||||
ThemeList.deserialize(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? legacyTheme);
|
||||
final actionListDisplayMode = ObservableList<ActionListDisplayMode>();
|
||||
actionListDisplayMode.addAll(deserializeActionlistDisplayModes(
|
||||
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ??
|
||||
defaultActionsMode));
|
||||
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ?? defaultActionsMode));
|
||||
var pinLength = sharedPreferences.getInt(PreferencesKey.currentPinLength);
|
||||
final timeOutDuration = sharedPreferences.getInt(PreferencesKey.pinTimeOutDuration);
|
||||
final timeOutDuration = sharedPreferences.getInt(PreferencesKey.pinTimeOutDuration);
|
||||
final pinCodeTimeOutDuration = timeOutDuration != null
|
||||
? PinCodeRequiredDuration.deserialize(raw: timeOutDuration)
|
||||
: defaultPinCodeTimeOutDuration;
|
||||
|
@ -366,40 +391,38 @@ abstract class SettingsStoreBase with Store {
|
|||
pinLength = defaultPinLength;
|
||||
}
|
||||
|
||||
final savedLanguageCode =
|
||||
sharedPreferences.getString(PreferencesKey.currentLanguageCode) ??
|
||||
await LanguageService.localeDetection();
|
||||
final savedLanguageCode = sharedPreferences.getString(PreferencesKey.currentLanguageCode) ??
|
||||
await LanguageService.localeDetection();
|
||||
final nodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
|
||||
final bitcoinElectrumServerId = sharedPreferences
|
||||
.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
|
||||
final litecoinElectrumServerId = sharedPreferences
|
||||
.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
|
||||
final havenNodeId = sharedPreferences
|
||||
.getInt(PreferencesKey.currentHavenNodeIdKey);
|
||||
final bitcoinElectrumServerId =
|
||||
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
|
||||
final litecoinElectrumServerId =
|
||||
sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
|
||||
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
|
||||
final moneroNode = nodeSource.get(nodeId);
|
||||
final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
|
||||
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
|
||||
final havenNode = nodeSource.get(havenNodeId);
|
||||
final packageInfo = await PackageInfo.fromPlatform();
|
||||
final shouldShowYatPopup =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true;
|
||||
final deviceName = await _getDeviceName() ?? '';
|
||||
final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true;
|
||||
|
||||
final nodes = <WalletType, Node>{};
|
||||
|
||||
if (moneroNode != null) {
|
||||
nodes[WalletType.monero] = moneroNode;
|
||||
nodes[WalletType.monero] = moneroNode;
|
||||
}
|
||||
|
||||
if (bitcoinElectrumServer != null) {
|
||||
nodes[WalletType.bitcoin] = bitcoinElectrumServer;
|
||||
nodes[WalletType.bitcoin] = bitcoinElectrumServer;
|
||||
}
|
||||
|
||||
if (litecoinElectrumServer != null) {
|
||||
nodes[WalletType.litecoin] = litecoinElectrumServer;
|
||||
nodes[WalletType.litecoin] = litecoinElectrumServer;
|
||||
}
|
||||
|
||||
if (havenNode != null) {
|
||||
nodes[WalletType.haven] = havenNode;
|
||||
nodes[WalletType.haven] = havenNode;
|
||||
}
|
||||
|
||||
return SettingsStore(
|
||||
|
@ -407,6 +430,7 @@ abstract class SettingsStoreBase with Store {
|
|||
initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard,
|
||||
nodes: nodes,
|
||||
appVersion: packageInfo.version,
|
||||
deviceName: deviceName,
|
||||
isBitcoinBuyEnabled: isBitcoinBuyEnabled,
|
||||
initialFiatCurrency: currentFiatCurrency,
|
||||
initialBalanceDisplayMode: currentBalanceDisplayMode,
|
||||
|
@ -416,6 +440,9 @@ abstract class SettingsStoreBase with Store {
|
|||
initialDisableSell: disableSell,
|
||||
initialFiatMode: currentFiatApiMode,
|
||||
initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
|
||||
initialTotpSecretKey: totpSecretKey,
|
||||
initialUseTOTP2FA: useTOTP2FA,
|
||||
initialFailedTokenTrial: tokenTrialNumber,
|
||||
initialExchangeStatus: exchangeStatus,
|
||||
initialTheme: savedTheme,
|
||||
actionlistDisplayMode: actionListDisplayMode,
|
||||
|
@ -430,34 +457,38 @@ abstract class SettingsStoreBase with Store {
|
|||
}
|
||||
|
||||
Future<void> reload({required Box<Node> nodeSource}) async {
|
||||
|
||||
final sharedPreferences = await getIt.getAsync<SharedPreferences>();
|
||||
|
||||
fiatCurrency = FiatCurrency.deserialize(
|
||||
raw: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!);
|
||||
|
||||
priority[WalletType.monero] = monero?.deserializeMoneroTransactionPriority(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!) ??
|
||||
raw: sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!) ??
|
||||
priority[WalletType.monero]!;
|
||||
priority[WalletType.bitcoin] = bitcoin?.deserializeBitcoinTransactionPriority(
|
||||
sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!) ??
|
||||
sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!) ??
|
||||
priority[WalletType.bitcoin]!;
|
||||
|
||||
if (sharedPreferences.getInt(PreferencesKey.havenTransactionPriority) != null) {
|
||||
priority[WalletType.haven] = monero?.deserializeMoneroTransactionPriority(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.havenTransactionPriority)!) ??
|
||||
raw: sharedPreferences.getInt(PreferencesKey.havenTransactionPriority)!) ??
|
||||
priority[WalletType.haven]!;
|
||||
}
|
||||
if (sharedPreferences.getInt(PreferencesKey.litecoinTransactionPriority) != null) {
|
||||
priority[WalletType.litecoin] = bitcoin?.deserializeLitecoinTransactionPriority(
|
||||
sharedPreferences.getInt(PreferencesKey.litecoinTransactionPriority)!) ??
|
||||
sharedPreferences.getInt(PreferencesKey.litecoinTransactionPriority)!) ??
|
||||
priority[WalletType.litecoin]!;
|
||||
}
|
||||
|
||||
balanceDisplayMode = BalanceDisplayMode.deserialize(
|
||||
raw: sharedPreferences
|
||||
.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
|
||||
raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
|
||||
shouldSaveRecipientAddress =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey) ??
|
||||
shouldSaveRecipientAddress;
|
||||
totpSecretKey = sharedPreferences.getString(PreferencesKey.totpSecretKey) ?? totpSecretKey;
|
||||
useTOTP2FA = sharedPreferences.getBool(PreferencesKey.useTOTP2FA) ?? useTOTP2FA;
|
||||
numberOfFailedTokenTrials =
|
||||
sharedPreferences.getInt(PreferencesKey.failedTotpTokenTrials) ?? numberOfFailedTokenTrials;
|
||||
sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey) ?? shouldSaveRecipientAddress;
|
||||
isAppSecure =
|
||||
sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure;
|
||||
|
@ -472,19 +503,16 @@ abstract class SettingsStoreBase with Store {
|
|||
sharedPreferences.getBool(PreferencesKey.shouldShowMarketPlaceInDashboard) ??
|
||||
shouldShowMarketPlaceInDashboard;
|
||||
exchangeStatus = ExchangeApiMode.deserialize(
|
||||
raw: sharedPreferences
|
||||
.getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw);
|
||||
final legacyTheme =
|
||||
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
|
||||
? ThemeType.dark.index
|
||||
: ThemeType.bright.index;
|
||||
raw: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey) ??
|
||||
ExchangeApiMode.enabled.raw);
|
||||
final legacyTheme = (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
|
||||
? ThemeType.dark.index
|
||||
: ThemeType.bright.index;
|
||||
currentTheme = ThemeList.deserialize(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ??
|
||||
legacyTheme);
|
||||
raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? legacyTheme);
|
||||
actionlistDisplayMode = ObservableList<ActionListDisplayMode>();
|
||||
actionlistDisplayMode.addAll(deserializeActionlistDisplayModes(
|
||||
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ??
|
||||
defaultActionsMode));
|
||||
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ?? defaultActionsMode));
|
||||
var pinLength = sharedPreferences.getInt(PreferencesKey.currentPinLength);
|
||||
// If no value
|
||||
if (pinLength == null || pinLength == 0) {
|
||||
|
@ -493,15 +521,15 @@ abstract class SettingsStoreBase with Store {
|
|||
pinCodeLength = pinLength;
|
||||
|
||||
languageCode = sharedPreferences.getString(PreferencesKey.currentLanguageCode) ?? languageCode;
|
||||
shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? shouldShowYatPopup;
|
||||
shouldShowYatPopup =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? shouldShowYatPopup;
|
||||
|
||||
final nodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
|
||||
final bitcoinElectrumServerId = sharedPreferences
|
||||
.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
|
||||
final litecoinElectrumServerId = sharedPreferences
|
||||
.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
|
||||
final havenNodeId = sharedPreferences
|
||||
.getInt(PreferencesKey.currentHavenNodeIdKey);
|
||||
final bitcoinElectrumServerId =
|
||||
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
|
||||
final litecoinElectrumServerId =
|
||||
sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
|
||||
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
|
||||
final moneroNode = nodeSource.get(nodeId);
|
||||
final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
|
||||
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
|
||||
|
@ -535,12 +563,10 @@ abstract class SettingsStoreBase with Store {
|
|||
PreferencesKey.currentLitecoinElectrumSererIdKey, node.key as int);
|
||||
break;
|
||||
case WalletType.monero:
|
||||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentNodeIdKey, node.key as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, node.key as int);
|
||||
break;
|
||||
case WalletType.haven:
|
||||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentHavenNodeIdKey, node.key as int);
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentHavenNodeIdKey, node.key as int);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -548,4 +574,29 @@ abstract class SettingsStoreBase with Store {
|
|||
|
||||
nodes[walletType] = node;
|
||||
}
|
||||
|
||||
static Future<String?> _getDeviceName() async {
|
||||
String? deviceName = '';
|
||||
final deviceInfoPlugin = DeviceInfoPlugin();
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
final androidInfo = await deviceInfoPlugin.androidInfo;
|
||||
deviceName = '${androidInfo.brand}%20${androidInfo.manufacturer}%20${androidInfo.model}';
|
||||
print(deviceName);
|
||||
} else if (Platform.isIOS) {
|
||||
final iosInfo = await deviceInfoPlugin.iosInfo;
|
||||
deviceName = iosInfo.model;
|
||||
} else if (Platform.isLinux) {
|
||||
final linuxInfo = await deviceInfoPlugin.linuxInfo;
|
||||
deviceName = linuxInfo.prettyName;
|
||||
} else if (Platform.isMacOS) {
|
||||
final macInfo = await deviceInfoPlugin.macOsInfo;
|
||||
deviceName = macInfo.computerName;
|
||||
} else if (Platform.isWindows) {
|
||||
final windowsInfo = await deviceInfoPlugin.windowsInfo;
|
||||
deviceName = windowsInfo.productName;
|
||||
}
|
||||
|
||||
return deviceName;
|
||||
}
|
||||
}
|
||||
|
|
83
lib/utils/totp_utils.dart
Normal file
83
lib/utils/totp_utils.dart
Normal file
|
@ -0,0 +1,83 @@
|
|||
import 'dart:math';
|
||||
import 'package:base32/base32.dart';
|
||||
import 'package:crypto/crypto.dart';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
//*========================== TOTP 2FA Related Utilities ==========================================
|
||||
|
||||
String generateRandomBase32SecretKey(int byteLength) {
|
||||
final Random _secureRandom = Random.secure();
|
||||
// Generate random bytes
|
||||
final randomBytes = Uint8List.fromList(
|
||||
List<int>.generate(byteLength, (i) => _secureRandom.nextInt(256)),
|
||||
);
|
||||
|
||||
// Encode bytes to base32
|
||||
final base32SecretKey = base32.encode(randomBytes);
|
||||
|
||||
return base32SecretKey;
|
||||
}
|
||||
|
||||
String generateOTP({required String secretKey, required int input}) {
|
||||
/// base32 decode the secret
|
||||
var hmacKey = base32.decode(secretKey);
|
||||
|
||||
/// initial the HMAC-SHA1 object
|
||||
var hmacSha = Hmac(sha512, hmacKey);
|
||||
|
||||
/// get hmac answer
|
||||
var hmac = hmacSha.convert(intToBytelist(input: input)).bytes;
|
||||
|
||||
/// calculate the init offset
|
||||
int offset = hmac[hmac.length - 1] & 0xf;
|
||||
|
||||
/// calculate the code
|
||||
int code = ((hmac[offset] & 0x7f) << 24 |
|
||||
(hmac[offset + 1] & 0xff) << 16 |
|
||||
(hmac[offset + 2] & 0xff) << 8 |
|
||||
(hmac[offset + 3] & 0xff));
|
||||
|
||||
/// get the initial string code
|
||||
var strCode = (code % pow(10, 8)).toString();
|
||||
strCode = strCode.padLeft(8, '0');
|
||||
|
||||
return strCode;
|
||||
}
|
||||
|
||||
List<int> intToBytelist({required int input, int padding = 8}) {
|
||||
List<int> _result = [];
|
||||
var _input = input;
|
||||
while (_input != 0) {
|
||||
_result.add(_input & 0xff);
|
||||
_input >>= padding;
|
||||
}
|
||||
_result.addAll(List<int>.generate(padding, (_) => 0));
|
||||
_result = _result.sublist(0, padding);
|
||||
_result = _result.reversed.toList();
|
||||
return _result;
|
||||
}
|
||||
|
||||
String totpNow(String secretKey) {
|
||||
int _formatTime = timeFormat(time: DateTime.now());
|
||||
return generateOTP(input: _formatTime, secretKey: secretKey);
|
||||
}
|
||||
|
||||
int timeFormat({required DateTime time}) {
|
||||
final _timeStr = time.millisecondsSinceEpoch.toString();
|
||||
final _formatTime = _timeStr.substring(0, _timeStr.length - 3);
|
||||
|
||||
return int.parse(_formatTime) ~/ 30;
|
||||
}
|
||||
|
||||
bool verify({String? otp, DateTime? time, required String secretKey}) {
|
||||
if (otp == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var _time = time ?? DateTime.now();
|
||||
var _input = timeFormat(time: _time);
|
||||
|
||||
String otpTime = generateOTP(input: _input, secretKey: secretKey);
|
||||
return otp == otpTime;
|
||||
}
|
159
lib/view_model/set_up_2fa_viewmodel.dart
Normal file
159
lib/view_model/set_up_2fa_viewmodel.dart
Normal file
|
@ -0,0 +1,159 @@
|
|||
// ignore_for_file: prefer_final_fields
|
||||
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/utils/totp_utils.dart' as Utils;
|
||||
import 'package:cake_wallet/view_model/auth_state.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../core/auth_service.dart';
|
||||
import '../core/execution_state.dart';
|
||||
import '../generated/i18n.dart';
|
||||
|
||||
part 'set_up_2fa_viewmodel.g.dart';
|
||||
|
||||
class Setup2FAViewModel = Setup2FAViewModelBase with _$Setup2FAViewModel;
|
||||
|
||||
abstract class Setup2FAViewModelBase with Store {
|
||||
final SettingsStore _settingsStore;
|
||||
final AuthService _authService;
|
||||
final SharedPreferences _sharedPreferences;
|
||||
|
||||
Setup2FAViewModelBase(this._settingsStore, this._sharedPreferences, this._authService)
|
||||
: _failureCounter = 0,
|
||||
enteredOTPCode = '',
|
||||
state = InitialExecutionState() {
|
||||
_getRandomBase32SecretKey();
|
||||
reaction((_) => state, _saveLastAuthTime);
|
||||
}
|
||||
|
||||
static const maxFailedTrials = 3;
|
||||
static const banTimeout = 180; // 3 minutes
|
||||
final banTimeoutKey = S.current.auth_store_ban_timeout;
|
||||
|
||||
String get secretKey => _settingsStore.totpSecretKey;
|
||||
String get deviceName => _settingsStore.deviceName;
|
||||
String get totpVersionOneLink => _settingsStore.totpVersionOneLink;
|
||||
|
||||
@observable
|
||||
ExecutionState state;
|
||||
|
||||
@observable
|
||||
int _failureCounter;
|
||||
|
||||
@observable
|
||||
String enteredOTPCode;
|
||||
|
||||
@computed
|
||||
bool get useTOTP2FA => _settingsStore.useTOTP2FA;
|
||||
|
||||
void _getRandomBase32SecretKey() {
|
||||
final randomBase32Key = Utils.generateRandomBase32SecretKey(16);
|
||||
_setBase32SecretKey(randomBase32Key);
|
||||
}
|
||||
|
||||
@action
|
||||
void setUseTOTP2FA(bool value) {
|
||||
_settingsStore.useTOTP2FA = value;
|
||||
}
|
||||
|
||||
@action
|
||||
void _setBase32SecretKey(String value) {
|
||||
if (_settingsStore.totpSecretKey == '') {
|
||||
_settingsStore.totpSecretKey = value;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
void clearBase32SecretKey() {
|
||||
_settingsStore.totpSecretKey = '';
|
||||
}
|
||||
|
||||
Duration? banDuration() {
|
||||
final unbanTimestamp = _sharedPreferences.getInt(banTimeoutKey);
|
||||
|
||||
if (unbanTimestamp == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final unbanTime = DateTime.fromMillisecondsSinceEpoch(unbanTimestamp);
|
||||
final now = DateTime.now();
|
||||
|
||||
if (now.isAfter(unbanTime)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Duration(milliseconds: unbanTimestamp - now.millisecondsSinceEpoch);
|
||||
}
|
||||
|
||||
Future<Duration> ban() async {
|
||||
final multiplier = _failureCounter - maxFailedTrials;
|
||||
final timeout = (multiplier * banTimeout) * 1000;
|
||||
final unbanTimestamp = DateTime.now().millisecondsSinceEpoch + timeout;
|
||||
await _sharedPreferences.setInt(banTimeoutKey, unbanTimestamp);
|
||||
|
||||
return Duration(milliseconds: timeout);
|
||||
}
|
||||
|
||||
@action
|
||||
Future<bool> totp2FAAuth(String otpText, bool isForSetup) async {
|
||||
state = InitialExecutionState();
|
||||
_failureCounter = _settingsStore.numberOfFailedTokenTrials;
|
||||
final _banDuration = banDuration();
|
||||
|
||||
if (_banDuration != null) {
|
||||
state = AuthenticationBanned(
|
||||
error: S.current.auth_store_banned_for +
|
||||
'${_banDuration.inMinutes}' +
|
||||
S.current.auth_store_banned_minutes);
|
||||
return false;
|
||||
}
|
||||
|
||||
final result = Utils.verify(
|
||||
secretKey: secretKey,
|
||||
otp: otpText,
|
||||
);
|
||||
|
||||
isForSetup ? setUseTOTP2FA(result) : null;
|
||||
|
||||
if (result) {
|
||||
return true;
|
||||
} else {
|
||||
final value = _settingsStore.numberOfFailedTokenTrials + 1;
|
||||
adjustTokenTrialNumber(value);
|
||||
print(value);
|
||||
if (_failureCounter >= maxFailedTrials) {
|
||||
final banDuration = await ban();
|
||||
state = AuthenticationBanned(
|
||||
error: S.current.auth_store_banned_for +
|
||||
'${banDuration.inMinutes}' +
|
||||
S.current.auth_store_banned_minutes);
|
||||
return false;
|
||||
}
|
||||
|
||||
state = FailureState('Incorrect code');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
void success() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
state = ExecutedSuccessfullyState();
|
||||
adjustTokenTrialNumber(0);
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
void adjustTokenTrialNumber(int value) {
|
||||
_failureCounter = value;
|
||||
_settingsStore.numberOfFailedTokenTrials = value;
|
||||
}
|
||||
|
||||
void _saveLastAuthTime(ExecutionState state) {
|
||||
if (state is ExecutedSuccessfullyState) {
|
||||
_authService.saveLastAuthTime();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,6 +21,9 @@ abstract class SecuritySettingsViewModelBase with Store {
|
|||
@computed
|
||||
bool get allowBiometricalAuthentication => _settingsStore.allowBiometricalAuthentication;
|
||||
|
||||
@computed
|
||||
bool get useTotp2FA => _settingsStore.useTOTP2FA;
|
||||
|
||||
@computed
|
||||
PinCodeRequiredDuration get pinCodeRequiredDuration => _settingsStore.pinTimeOutDuration;
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||
CwMoneroPlugin.register(with: registry.registrar(forPlugin: "CwMoneroPlugin"))
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin"))
|
||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||
FlutterSecureStorageMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageMacosPlugin"))
|
||||
InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin"))
|
||||
FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
|
|
|
@ -71,6 +71,7 @@ dependencies:
|
|||
wakelock: ^0.6.2
|
||||
flutter_mailer: ^2.0.2
|
||||
device_info_plus: 8.1.0
|
||||
base32: 2.1.3
|
||||
in_app_review: ^2.0.6
|
||||
cake_backup:
|
||||
git:
|
||||
|
|
|
@ -707,6 +707,23 @@
|
|||
"error_text_input_above_maximum_limit":"المبلغ أكبر من الحد الأقصى",
|
||||
"show_market_place": "إظهار السوق",
|
||||
"prevent_screenshots": "منع لقطات الشاشة وتسجيل الشاشة",
|
||||
"modify_2fa": "تعديل 2 عامل المصادقة",
|
||||
"disable_cake_2fa": "تعطيل 2 عامل المصادقة",
|
||||
"question_to_disable_2fa":"هل أنت متأكد أنك تريد تعطيل Cake 2FA؟ لن تكون هناك حاجة إلى رمز 2FA للوصول إلى المحفظة ووظائف معينة.",
|
||||
"disable": "إبطال",
|
||||
"setup_2fa": "تعيين 2 عامل المصادقة",
|
||||
"verify_with_2fa": "تحقق مع Cake 2FA",
|
||||
"totp_code": "كود TOTP",
|
||||
"please_fill_totp": "يرجى ملء الرمز المكون من 8 أرقام الموجود على جهازك الآخر",
|
||||
"totp_2fa_success": "نجاح! تم تمكين Cake 2FA لهذه المحفظة. تذكر حفظ بذرة ذاكري في حالة فقد الوصول إلى المحفظة.",
|
||||
"totp_verification_success" :"تم التحقق بنجاح!",
|
||||
"totp_2fa_failure": "شفرة خاطئة. يرجى تجربة رمز مختلف أو إنشاء مفتاح سري جديد. استخدم تطبيق 2FA متوافقًا يدعم الرموز المكونة من 8 أرقام و SHA512.",
|
||||
"enter_totp_code": "الرجاء إدخال رمز TOTP.",
|
||||
"add_secret_code":"أضف هذا الرمز السري إلى جهاز آخر",
|
||||
"totp_secret_code":"كود TOTP السري",
|
||||
"important_note": "ملاحظة مهمة",
|
||||
"setup_2fa_text": "كعكة 2FA ليست آمنة مثل التخزين البارد. تحمي 2FA من الأنواع الأساسية للهجمات ، مثل قيام صديقك بتقديم بصمة إصبعك أثناء نومك. لا تحمي Cake 2FA من جهاز مخترق من قِبل مهاجم متطور. إذا فقدت الوصول إلى رموز 2FA الخاصة بك ، ستفقد إمكانية الوصول إلى هذه المحفظة. سوف تحتاج إلى استعادة محفظتك من بذرة ذاكري. يجب عليك بالتالي الاحتفاظ بنسخة احتياطية من بذور الذاكرة الخاصة بك! علاوة على ذلك ، سيتمكن أي شخص لديه حق الوصول إلى بذرة (بذور) ذاكري من سرقة أموالك ، متجاوزًا Cake 2FA. لن يتمكن فريق دعم الكيك من مساعدتك إذا فقدت الوصول إلى بذرتك ، نظرًا لأن Cake هي المحفظة غير الحافظة.",
|
||||
"setup_totp_recommended": "إعداد TOTP (موصى به)",
|
||||
"disable_buy": "تعطيل إجراء الشراء",
|
||||
"disable_sell": "قم بتعطيل إجراء البيع"
|
||||
}
|
||||
|
|
|
@ -703,6 +703,23 @@
|
|||
"error_text_input_above_maximum_limit" : "Сумата надвишава максималната",
|
||||
"show_market_place":"Покажи пазар",
|
||||
"prevent_screenshots": "Предотвратете екранни снимки и запис на екрана",
|
||||
"modify_2fa": "Модифициране на тортата 2FA",
|
||||
"disable_cake_2fa": "Деактивирайте Cake 2FA",
|
||||
"question_to_disable_2fa":"Сигурни ли сте, че искате да деактивирате Cake 2FA? Вече няма да е необходим 2FA код за достъп до портфейла и определени функции.",
|
||||
"disable": "Деактивиране",
|
||||
"setup_2fa": "Настройка на Cake 2FA",
|
||||
"verify_with_2fa": "Проверете с Cake 2FA",
|
||||
"totp_code": "TOTP код",
|
||||
"please_fill_totp": "Моля, попълнете 8-цифрения код на другото ви устройство",
|
||||
"totp_2fa_success": "Успех! Cake 2FA е активиран за този портфейл. Не забравяйте да запазите мнемоничното начало, в случай че загубите достъп до портфейла.",
|
||||
"totp_verification_success" :"Проверката е успешна!",
|
||||
"totp_2fa_failure": "Грешен код. Моля, опитайте с различен код или генерирайте нов таен ключ. Използвайте съвместимо 2FA приложение, което поддържа 8-цифрени кодове и SHA512.",
|
||||
"enter_totp_code": "Моля, въведете TOTP кода.",
|
||||
"add_secret_code":"Добавете този таен код към друго устройство",
|
||||
"totp_secret_code":"TOTP таен код",
|
||||
"important_note": "Важна забележка",
|
||||
"setup_2fa_text": "Тортата 2FA НЕ е толкова сигурна, колкото хладилното съхранение. 2FA защитава срещу основни видове атаки, като например вашият приятел да предостави вашия пръстов отпечатък, докато спите.\n\n Cake 2FA НЕ защитава срещу компрометирано устройство от сложен хакер.\n\n Ако загубите достъп до своите 2FA кодове , ЩЕ ЗАГУБИТЕ ДОСТЪП ДО ТОЗИ ПОРТФЕЙЛ. Ще трябва да възстановите портфейла си от мнемонично семе. ЗАТОВА ТРЯБВА ДА НАПРАВИТЕ РЕЗЕРВНО КОПИЕ НА ВАШИТЕ МНЕМОНИЧНИ СЕМЕНА! Освен това, някой с достъп до вашите мнемонични начални точки ще може да открадне вашите средства, заобикаляйки Cake 2FA.\n\n Персоналът по поддръжката на Cake няма да може да ви помогне, ако загубите достъп до вашите мнемонични начални стойности, тъй като Cake е портфейл без попечителство.",
|
||||
"setup_totp_recommended": "Настройка на TOTP (препоръчително)",
|
||||
"disable_buy": "Деактивирайте действието за покупка",
|
||||
"disable_sell": "Деактивирайте действието за продажба"
|
||||
}
|
||||
|
|
|
@ -703,6 +703,23 @@
|
|||
"error_text_input_above_maximum_limit" : "Částka je větší než maximální hodnota",
|
||||
"show_market_place": "Zobrazit trh",
|
||||
"prevent_screenshots": "Zabránit vytváření snímků obrazovky a nahrávání obrazovky",
|
||||
"modify_2fa": "Upravte Cake 2FA",
|
||||
"disable_cake_2fa": "Zakázat Cake 2FA",
|
||||
"question_to_disable_2fa":"Opravdu chcete deaktivovat Cake 2FA? Pro přístup k peněžence a některým funkcím již nebude potřeba kód 2FA.",
|
||||
"disable": "Zakázat",
|
||||
"setup_2fa": "Nastavení Cake 2FA",
|
||||
"verify_with_2fa": "Ověřte pomocí Cake 2FA",
|
||||
"totp_code": "Kód TOTP",
|
||||
"please_fill_totp": "Vyplňte prosím 8místný kód na vašem druhém zařízení",
|
||||
"totp_2fa_success": "Úspěch! Pro tuto peněženku povolen Cake 2FA. Nezapomeňte si uložit mnemotechnický klíč pro případ, že ztratíte přístup k peněžence.",
|
||||
"totp_verification_success" :"Ověření proběhlo úspěšně!",
|
||||
"totp_2fa_failure": "Nesprávný kód. Zkuste prosím jiný kód nebo vygenerujte nový tajný klíč. Použijte kompatibilní aplikaci 2FA, která podporuje 8místné kódy a SHA512.",
|
||||
"enter_totp_code": "Zadejte kód TOTP.",
|
||||
"add_secret_code":"Přidejte tento tajný kód do jiného zařízení",
|
||||
"totp_secret_code":"Tajný kód TOTP",
|
||||
"important_note": "Důležitá poznámka",
|
||||
"setup_2fa_text": "Cake 2FA NENÍ tak bezpečný jako skladování v chladu. 2FA chrání před základními typy útoků, jako je váš přítel, který vám poskytne otisk prstu, když spíte.\n\n Cake 2FA nechrání před napadením zařízení sofistikovaným útočníkem.\n\n Pokud ztratíte přístup ke svým kódům 2FA , ZTRÁTÍTE PŘÍSTUP K TÉTO PENĚŽENCE. Budete muset obnovit svou peněženku z mnemotechnického semínka. MUSÍTE TEDY ZÁLOHOVAT SVÉ MNEMONICKÉ SEMÉNKY! Kromě toho někdo s přístupem k vašemu mnemotechnickému semenu bude moci ukrást vaše finanční prostředky a obejít Cake 2FA.\n\n Pracovníci podpory Cake vám nebudou schopni pomoci, pokud ztratíte přístup k vašemu mnemotechnickému semenu, protože Cake je nevazební peněženka.",
|
||||
"setup_totp_recommended": "Nastavit TOTP (doporučeno)",
|
||||
"disable_buy": "Zakázat akci nákupu",
|
||||
"disable_sell": "Zakázat akci prodeje"
|
||||
}
|
||||
|
|
|
@ -709,6 +709,23 @@
|
|||
"error_text_input_above_maximum_limit" : "Menge ist über dem Maximum",
|
||||
"show_market_place": "Marktplatz anzeigen",
|
||||
"prevent_screenshots": "Verhindern Sie Screenshots und Bildschirmaufzeichnungen",
|
||||
"modify_2fa": "Kuchen 2FA ändern",
|
||||
"disable_cake_2fa": "Kuchen 2FA deaktivieren",
|
||||
"question_to_disable_2fa":"Sind Sie sicher, dass Sie Cake 2FA deaktivieren möchten? Für den Zugriff auf die Brieftasche und bestimmte Funktionen wird kein 2FA-Code mehr benötigt.",
|
||||
"disable": "Deaktivieren",
|
||||
"setup_2fa": "Setup-Kuchen 2FA",
|
||||
"verify_with_2fa": "Verifizieren Sie mit Cake 2FA",
|
||||
"totp_code": "TOTP-Code",
|
||||
"please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist",
|
||||
"totp_2fa_success": "Erfolg! Cake 2FA für dieses Wallet aktiviert. Denken Sie daran, Ihren mnemonischen Seed zu speichern, falls Sie den Zugriff auf die Brieftasche verlieren.",
|
||||
"totp_verification_success" :"Verifizierung erfolgreich!",
|
||||
"totp_2fa_failure": "Falscher Code. Bitte versuchen Sie es mit einem anderen Code oder generieren Sie einen neuen geheimen Schlüssel. Verwenden Sie eine kompatible 2FA-App, die 8-stellige Codes und SHA512 unterstützt.",
|
||||
"enter_totp_code": "Bitte geben Sie den TOTP-Code ein.",
|
||||
"add_secret_code":"Fügen Sie diesen Geheimcode einem anderen Gerät hinzu",
|
||||
"totp_secret_code":"TOTP-Geheimcode",
|
||||
"important_note": "Wichtiger Hinweis",
|
||||
"setup_2fa_text": "Cake 2FA ist NICHT so sicher wie eine Kühllagerung. 2FA schützt vor grundlegenden Arten von Angriffen, z. B. wenn Ihr Freund Ihren Fingerabdruck bereitstellt, während Sie schlafen.\n\n Cake 2FA schützt NICHT vor einem kompromittierten Gerät durch einen raffinierten Angreifer.\n\n Wenn Sie den Zugriff auf Ihre 2FA-Codes verlieren , VERLIEREN SIE DEN ZUGANG ZU DIESEM WALLET. Sie müssen Ihre Brieftasche aus mnemonic Seed wiederherstellen. SIE MÜSSEN DESHALB IHRE MNEMONISCHEN SEEDS SICHERN! Außerdem kann jemand mit Zugriff auf Ihre mnemonischen Seed(s) Ihr Geld stehlen und Cake 2FA umgehen.\n\n Cake-Supportmitarbeiter können Ihnen nicht helfen, wenn Sie den Zugriff auf Ihre mnemonischen Seed(s) verlieren, da Cake ein Brieftasche ohne Verwahrung.",
|
||||
"setup_totp_recommended": "TOTP einrichten (empfohlen)",
|
||||
"disable_buy": "Kaufaktion deaktivieren",
|
||||
"disable_sell": "Verkaufsaktion deaktivieren"
|
||||
}
|
||||
|
|
|
@ -709,6 +709,23 @@
|
|||
"error_text_input_above_maximum_limit" : "Amount is more than the maximum",
|
||||
"show_market_place" :"Show Marketplace",
|
||||
"prevent_screenshots": "Prevent screenshots and screen recording",
|
||||
"modify_2fa": "Modify Cake 2FA",
|
||||
"disable_cake_2fa": "Disable Cake 2FA",
|
||||
"question_to_disable_2fa":"Are you sure that you want to disable Cake 2FA? A 2FA code will no longer be needed to access the wallet and certain functions.",
|
||||
"disable": "Disable",
|
||||
"setup_2fa": "Setup Cake 2FA",
|
||||
"verify_with_2fa": "Verify with Cake 2FA",
|
||||
"totp_code": "TOTP Code",
|
||||
"please_fill_totp": "Please fill in the 8-digit code present on your other device",
|
||||
"totp_2fa_success": "Success! Cake 2FA enabled for this wallet. Remember to save your mnemonic seed in case you lose wallet access.",
|
||||
"totp_verification_success" :"Verification Successful!",
|
||||
"totp_2fa_failure": "Incorrect code. Please try a different code or generate a new secret key. Use a compatible 2FA app that supports 8-digit codes and SHA512.",
|
||||
"enter_totp_code": "Please enter the TOTP Code.",
|
||||
"add_secret_code":"Add this secret code to another device",
|
||||
"totp_secret_code":"TOTP Secret Code",
|
||||
"important_note": "Important note",
|
||||
"setup_2fa_text": "Cake 2FA is NOT as secure as cold storage. 2FA protects against basic types of attacks, such as your friend providing your fingerprint while you are sleeping.\n\n Cake 2FA does NOT protect against a compromised device by a sophisticated attacker.\n\n If you lose access to your 2FA codes, YOU WILL LOSE ACCESS TO THIS WALLET. You will need to restore your wallet from mnemonic seed. YOU MUST THEREFORE BACK UP YOUR MNEMONIC SEEDS! Further, someone with access to your mnemonic seed(s) will be able to steal your funds, bypassing Cake 2FA.\n\n Cake support staff will be unable to assist you if you lose access to your mnemonic seed, since Cake is a noncustodial wallet.",
|
||||
"setup_totp_recommended": "Set up TOTP (Recommended)",
|
||||
"disable_buy": "Disable buy action",
|
||||
"disable_sell": "Disable sell action"
|
||||
}
|
||||
|
|
|
@ -709,6 +709,23 @@
|
|||
"error_text_input_above_maximum_limit" : "La cantidad es más que el máximo",
|
||||
"show_market_place": "Mostrar mercado",
|
||||
"prevent_screenshots": "Evitar capturas de pantalla y grabación de pantalla",
|
||||
"modify_2fa": "Modificar torta 2FA",
|
||||
"disable_cake_2fa": "Desactivar pastel 2FA",
|
||||
"question_to_disable_2fa":"¿Está seguro de que desea deshabilitar Cake 2FA? Ya no se necesitará un código 2FA para acceder a la billetera y a ciertas funciones.",
|
||||
"disable": "Desactivar",
|
||||
"setup_2fa": "Configurar pastel 2FA",
|
||||
"verify_with_2fa": "Verificar con Cake 2FA",
|
||||
"totp_code": "Código TOTP",
|
||||
"please_fill_totp": "Complete el código de 8 dígitos presente en su otro dispositivo",
|
||||
"totp_2fa_success": "¡Éxito! Cake 2FA habilitado para esta billetera. Recuerde guardar su semilla mnemotécnica en caso de que pierda el acceso a la billetera.",
|
||||
"totp_verification_success" :"¡Verificación exitosa!",
|
||||
"totp_2fa_failure": "Código incorrecto. Intente con un código diferente o genere una nueva clave secreta. Use una aplicación 2FA compatible que admita códigos de 8 dígitos y SHA512.",
|
||||
"enter_totp_code": "Ingrese el código TOTP.",
|
||||
"add_secret_code":"Agregue este código secreto a otro dispositivo",
|
||||
"totp_secret_code":"Código secreto TOTP",
|
||||
"important_note": "Nota IMPORTANTE",
|
||||
"setup_2fa_text": "Cake 2FA NO es tan seguro como el almacenamiento en frío. 2FA protege contra tipos básicos de ataques, como cuando un amigo proporciona su huella digital mientras usted duerme.\n\n Cake 2FA NO protege contra un dispositivo comprometido por un atacante sofisticado.\n\n Si pierde el acceso a sus códigos 2FA , PERDERÁS EL ACCESO A ESTA BILLETERA. Deberá restaurar su billetera desde la semilla mnemotécnica. ¡POR LO TANTO, DEBE HACER UNA COPIA DE SEGURIDAD DE SUS SEMILLAS MNEMÓNICAS! Además, alguien con acceso a sus semillas mnemotécnicas podrá robar sus fondos, sin pasar por Cake 2FA.\n\n El personal de soporte de Cake no podrá ayudarlo si pierde el acceso a su semilla mnemotécnica, ya que Cake es un billetera sin custodia.",
|
||||
"setup_totp_recommended": "Configurar TOTP (Recomendado)",
|
||||
"disable_buy": "Desactivar acción de compra",
|
||||
"disable_sell": "Desactivar acción de venta"
|
||||
}
|
||||
|
|
|
@ -709,6 +709,23 @@
|
|||
"error_text_input_above_maximum_limit" : "Le montant est supérieur au maximum",
|
||||
"show_market_place" :"Afficher la place de marché",
|
||||
"prevent_screenshots": "Empêcher les captures d'écran et l'enregistrement d'écran",
|
||||
"modify_2fa": "Modifier le gâteau 2FA",
|
||||
"disable_cake_2fa": "Désactiver le gâteau 2FA",
|
||||
"question_to_disable_2fa":"Êtes-vous sûr de vouloir désactiver Cake 2FA ? Un code 2FA ne sera plus nécessaire pour accéder au portefeuille et à certaines fonctions.",
|
||||
"disable": "Désactiver",
|
||||
"setup_2fa": "Gâteau d'installation 2FA",
|
||||
"verify_with_2fa": "Vérifier avec Cake 2FA",
|
||||
"totp_code": "Code TOTP",
|
||||
"please_fill_totp": "Veuillez renseigner le code à 8 chiffres présent sur votre autre appareil",
|
||||
"totp_2fa_success": "Succès! Cake 2FA activé pour ce portefeuille. N'oubliez pas de sauvegarder votre graine mnémonique au cas où vous perdriez l'accès au portefeuille.",
|
||||
"totp_verification_success" :"Vérification réussie !",
|
||||
"totp_2fa_failure": "Code incorrect. Veuillez essayer un code différent ou générer une nouvelle clé secrète. Utilisez une application 2FA compatible qui prend en charge les codes à 8 chiffres et SHA512.",
|
||||
"enter_totp_code": "Veuillez entrer le code TOTP.",
|
||||
"add_secret_code":"Ajouter ce code secret à un autre appareil",
|
||||
"totp_secret_code":"Code secret TOTP",
|
||||
"important_note": "Note importante",
|
||||
"setup_2fa_text": "Cake 2FA n'est PAS aussi sûr que le stockage à froid. 2FA protège contre les types d'attaques de base, comme votre ami fournissant votre empreinte digitale pendant que vous dormez.\n\n Cake 2FA ne protège PAS contre un appareil compromis par un attaquant sophistiqué.\n\n Si vous perdez l'accès à vos codes 2FA , VOUS PERDREZ L'ACCÈS À CE PORTEFEUILLE. Vous devrez restaurer votre portefeuille à partir de graines mnémotechniques. VOUS DEVEZ DONC SAUVEGARDER VOS SEMENCES MNEMONIQUES ! De plus, quelqu'un ayant accès à vos graines mnémoniques pourra voler vos fonds, en contournant Cake 2FA.\n\n Le personnel d'assistance de Cake ne pourra pas vous aider si vous perdez l'accès à vos graines mnémoniques, puisque Cake est un portefeuille non dépositaire.",
|
||||
"setup_totp_recommended": "Configurer TOTP (recommandé)",
|
||||
"disable_buy": "Désactiver l'action d'achat",
|
||||
"disable_sell": "Désactiver l'action de vente"
|
||||
}
|
||||
|
|
|
@ -709,6 +709,23 @@
|
|||
"error_text_input_above_maximum_limit" : "राशि अधिकतम से अधिक है",
|
||||
"show_market_place":"बाज़ार दिखाएँ",
|
||||
"prevent_screenshots": "स्क्रीनशॉट और स्क्रीन रिकॉर्डिंग रोकें",
|
||||
"modify_2fa": "केक 2FA संशोधित करें",
|
||||
"disable_cake_2fa": "केक 2FA अक्षम करें",
|
||||
"question_to_disable_2fa":"क्या आप सुनिश्चित हैं कि आप Cake 2FA को अक्षम करना चाहते हैं? वॉलेट और कुछ कार्यों तक पहुँचने के लिए अब 2FA कोड की आवश्यकता नहीं होगी।",
|
||||
"disable": "अक्षम करना",
|
||||
"setup_2fa": "सेटअप केक 2FA",
|
||||
"verify_with_2fa": "केक 2FA के साथ सत्यापित करें",
|
||||
"totp_code": "टीओटीपी कोड",
|
||||
"please_fill_totp": "कृपया अपने दूसरे डिवाइस पर मौजूद 8 अंकों का कोड भरें",
|
||||
"totp_2fa_success": "सफलता! इस वॉलेट के लिए Cake 2FA सक्षम है। यदि आप वॉलेट एक्सेस खो देते हैं तो अपने स्मरक बीज को सहेजना याद रखें।",
|
||||
"totp_verification_success" :"सत्यापन सफल!",
|
||||
"totp_2fa_failure": "गलत कोड़। कृपया एक अलग कोड का प्रयास करें या एक नई गुप्त कुंजी उत्पन्न करें। 8-अंकीय कोड और SHA512 का समर्थन करने वाले संगत 2FA ऐप का उपयोग करें।",
|
||||
"enter_totp_code": "कृपया TOTP कोड दर्ज करें।",
|
||||
"add_secret_code":"इस गुप्त कोड को किसी अन्य डिवाइस में जोड़ें",
|
||||
"totp_secret_code":"टीओटीपी गुप्त कोड",
|
||||
"important_note": "महत्वपूर्ण लेख",
|
||||
"setup_2fa_text": "केक 2FA कोल्ड स्टोरेज जितना सुरक्षित नहीं है। 2FA बुनियादी प्रकार के हमलों से बचाता है, जैसे कि आपका मित्र सोते समय आपको अपना फ़िंगरप्रिंट प्रदान करता है।\n\n Cake 2FA परिष्कृत हमलावर द्वारा किसी डिवाइस से छेड़छाड़ से रक्षा नहीं करता है।\n\n यदि आप अपने 2FA कोड तक पहुंच खो देते हैं , आप इस वॉलेट तक पहुंच खो देंगे। आपको अपने बटुए को स्मरणीय बीज से पुनर्स्थापित करने की आवश्यकता होगी। इसलिए आपको अपने स्मरणीय बीजों का बैकअप लेना चाहिए! इसके अलावा, आपके स्मरक बीज (बीजों) तक पहुंच रखने वाला कोई व्यक्ति केक 2FA को दरकिनार कर आपके धन की चोरी करने में सक्षम होगा। अप्रबंधित बटुआ।",
|
||||
"setup_totp_recommended": "टीओटीपी सेट अप करें (अनुशंसित)",
|
||||
"disable_buy": "खरीद कार्रवाई अक्षम करें",
|
||||
"disable_sell": "बेचने की कार्रवाई अक्षम करें"
|
||||
}
|
||||
|
|
|
@ -709,6 +709,28 @@
|
|||
"error_text_input_above_maximum_limit" : "Iznos je veći od maskimalnog",
|
||||
"show_market_place" : "Prikaži tržište",
|
||||
"prevent_screenshots": "Spriječite snimke zaslona i snimanje zaslona",
|
||||
"modify_2fa": "Izmijenite tortu 2FA",
|
||||
"disable_cake_2fa": "Onemogući Cake 2FA",
|
||||
"question_to_disable_2fa":"Jeste li sigurni da želite onemogućiti Cake 2FA? 2FA kod više neće biti potreban za pristup novčaniku i određenim funkcijama.",
|
||||
"disable": "Onemogući",
|
||||
"setup_2fa": "Postavljanje torte 2FA",
|
||||
"verify_with_2fa": "Provjerite s Cake 2FA",
|
||||
"totp_code": "TOTP kod",
|
||||
"please_fill_totp": "Unesite 8-znamenkasti kod koji se nalazi na vašem drugom uređaju",
|
||||
"totp_2fa_success": "Uspjeh! Cake 2FA omogućen za ovaj novčanik. Ne zaboravite spremiti svoje mnemoničko sjeme u slučaju da izgubite pristup novčaniku.",
|
||||
"totp_verification_success" :"Provjera uspješna!",
|
||||
"totp_2fa_failure": "Neispravan kod. Pokušajte s drugim kodom ili generirajte novi tajni ključ. Koristite kompatibilnu 2FA aplikaciju koja podržava 8-znamenkasti kod i SHA512.",
|
||||
"enter_totp_code": "Unesite TOTP kod.",
|
||||
"add_secret_code":"Dodajte ovaj tajni kod na drugi uređaj",
|
||||
"totp_secret_code":"TOTP tajni kod",
|
||||
"important_note": "Važna nota",
|
||||
"setup_2fa_text": "Torta 2FA NIJE sigurna kao hladno skladište. 2FA štiti od osnovnih vrsta napada, kao što je vaš prijatelj koji vam daje otisak prsta dok spavate.\n\n Cake 2FA NE štiti od kompromitiranog uređaja od strane sofisticiranog napadača.\n\n Ako izgubite pristup svojim 2FA kodovima , IZGUBIT ĆETE PRISTUP OVOM NOVČANIKU. Morat ćete obnoviti svoj novčanik iz mnemoničkog sjemena. STOGA MORATE NAPRAVITI SIGURNOSNE KOPIJE SVOJIH MNEMONIČKIH SJEMENA! Nadalje, netko tko ima pristup vašem mnemoničkom seedu(ima) moći će ukrasti vaša sredstva, zaobilazeći Cake 2FA.\n\n Cake osoblje za podršku neće vam moći pomoći ako izgubite pristup svom mnemoničkom seedu, budući da je Cake neskrbnički novčanik.",
|
||||
"setup_totp_recommended": "Postavite TOTP (preporučeno)",
|
||||
"disable_buy": "Onemogući kupnju",
|
||||
"disable_sell": "Onemogući akciju prodaje"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -685,6 +685,34 @@
|
|||
"error_text_input_above_maximum_limit" : "Jumlah lebih dari maksimal",
|
||||
"show_market_place": "Tampilkan Pasar",
|
||||
"prevent_screenshots": "Cegah tangkapan layar dan perekaman layar",
|
||||
"modify_2fa": "Ubah Kue 2FA",
|
||||
"disable_cake_2fa": "Nonaktifkan Kue 2FA",
|
||||
"question_to_disable_2fa":"Apakah Anda yakin ingin menonaktifkan Cake 2FA? Kode 2FA tidak lagi diperlukan untuk mengakses dompet dan fungsi tertentu.",
|
||||
"disable": "Cacat",
|
||||
"setup_2fa": "Siapkan Kue 2FA",
|
||||
"verify_with_2fa": "Verifikasi dengan Cake 2FA",
|
||||
"totp_code": "Kode TOTP",
|
||||
"please_fill_totp": "Harap isi kode 8 digit yang ada di perangkat Anda yang lain",
|
||||
"totp_2fa_success": "Kesuksesan! Cake 2FA diaktifkan untuk dompet ini. Ingatlah untuk menyimpan benih mnemonik Anda jika Anda kehilangan akses dompet.",
|
||||
"totp_verification_success" :"Verifikasi Berhasil!",
|
||||
"totp_2fa_failure": "Kode salah. Silakan coba kode lain atau buat kunci rahasia baru. Gunakan aplikasi 2FA yang kompatibel yang mendukung kode 8 digit dan SHA512.",
|
||||
"enter_totp_code": "Masukkan Kode TOTP.",
|
||||
"add_secret_code":"Tambahkan kode rahasia ini ke perangkat lain",
|
||||
"totp_secret_code":"Kode Rahasia TOTP",
|
||||
"important_note": "Catatan penting",
|
||||
"setup_2fa_text": "Cake 2FA TIDAK seaman cold storage. 2FA melindungi dari jenis serangan dasar, seperti teman Anda memberikan sidik jari saat Anda sedang tidur.\n\n Cake 2FA TIDAK melindungi dari perangkat yang disusupi oleh penyerang canggih.\n\n Jika Anda kehilangan akses ke kode 2FA , ANDA AKAN KEHILANGAN AKSES KE DOMPET INI. Anda perlu memulihkan dompet Anda dari benih mnemonik. OLEH KARENA ITU, ANDA HARUS MENYIMPAN BIJI MNEMONIK ANDA! Selanjutnya, seseorang yang memiliki akses ke benih mnemonik Anda akan dapat mencuri dana Anda, melewati Cake 2FA.\n\n Staf pendukung Cake tidak akan dapat membantu Anda jika Anda kehilangan akses ke benih mnemonik Anda, karena Cake adalah dompet tanpa hak asuh.",
|
||||
"setup_totp_recommended": "Siapkan TOTP (Disarankan)",
|
||||
"disable_buy": "Nonaktifkan tindakan beli",
|
||||
"disable_sell": "Nonaktifkan aksi jual"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -709,6 +709,23 @@
|
|||
"error_text_input_above_maximum_limit" : "L'ammontare è superiore al massimo",
|
||||
"show_market_place":"Mostra mercato",
|
||||
"prevent_screenshots": "Impedisci screenshot e registrazione dello schermo",
|
||||
"modify_2fa": "Modifica Torta 2FA",
|
||||
"disable_cake_2fa": "Disabilita Cake 2FA",
|
||||
"question_to_disable_2fa":"Sei sicuro di voler disabilitare Cake 2FA? Non sarà più necessario un codice 2FA per accedere al portafoglio e ad alcune funzioni.",
|
||||
"disable": "disattivare",
|
||||
"setup_2fa": "Imposta la torta 2FA",
|
||||
"verify_with_2fa": "Verifica con Cake 2FA",
|
||||
"totp_code": "Codice TOTP",
|
||||
"please_fill_totp": "Inserisci il codice di 8 cifre presente sull'altro tuo dispositivo",
|
||||
"totp_2fa_success": "Successo! Cake 2FA abilitato per questo portafoglio. Ricordati di salvare il tuo seme mnemonico nel caso in cui perdi l'accesso al portafoglio.",
|
||||
"totp_verification_success" :"Verifica riuscita!",
|
||||
"totp_2fa_failure": "Codice non corretto. Prova un codice diverso o genera una nuova chiave segreta. Utilizza un'app 2FA compatibile che supporti codici a 8 cifre e SHA512.",
|
||||
"enter_totp_code": "Inserisci il codice TOTP.",
|
||||
"add_secret_code":"Aggiungi questo codice segreto a un altro dispositivo",
|
||||
"totp_secret_code":"TOTP codice segreto",
|
||||
"important_note": "Nota importante",
|
||||
"setup_2fa_text": "Cake 2FA NON è sicuro come la cella frigorifera. 2FA protegge da tipi di attacchi di base, come il tuo amico che fornisce la tua impronta digitale mentre dormi.\n\n Cake 2FA NON protegge da un dispositivo compromesso da un aggressore sofisticato.\n\n Se perdi l'accesso ai tuoi codici 2FA , PERDERAI L'ACCESSO A QUESTO PORTAFOGLIO. Dovrai ripristinare il tuo portafoglio dal seme mnemonico. DOVETE QUINDI SOSTITUIRE I VOSTRI SEMI MNEMONICI! Inoltre, qualcuno con accesso ai tuoi seed mnemonici sarà in grado di rubare i tuoi fondi, aggirando Cake 2FA.\n\n Il personale di supporto di Cake non sarà in grado di aiutarti se perdi l'accesso al tuo seed mnemonico, poiché Cake è un portafoglio non detentivo.",
|
||||
"setup_totp_recommended": "Imposta TOTP (consigliato)",
|
||||
"disable_buy": "Disabilita l'azione di acquisto",
|
||||
"disable_sell": "Disabilita l'azione di vendita"
|
||||
}
|
||||
|
|
|
@ -709,6 +709,23 @@
|
|||
"error_text_input_above_maximum_limit" : "金額は最大値を超えています",
|
||||
"show_market_place":"マーケットプレイスを表示",
|
||||
"prevent_screenshots": "スクリーンショットと画面録画を防止する",
|
||||
"modify_2fa": "ケーキの 2FA を変更する",
|
||||
"disable_cake_2fa": "Cake 2FA を無効にする",
|
||||
"question_to_disable_2fa":"Cake 2FA を無効にしてもよろしいですか?ウォレットと特定の機能にアクセスするために 2FA コードは必要なくなります。",
|
||||
"disable": "無効にする",
|
||||
"setup_2fa": "セットアップ ケーキ 2FA",
|
||||
"verify_with_2fa": "Cake 2FA で検証する",
|
||||
"totp_code": "TOTP コード",
|
||||
"please_fill_totp": "他のデバイスにある 8 桁のコードを入力してください",
|
||||
"totp_2fa_success": "成功!このウォレットでは Cake 2FA が有効になっています。ウォレットへのアクセスを失った場合に備えて、ニーモニック シードを忘れずに保存してください。",
|
||||
"totp_verification_success" :"検証成功!",
|
||||
"totp_2fa_failure": "コードが正しくありません。 別のコードを試すか、新しい秘密鍵を生成してください。 8 桁のコードと SHA512 をサポートする互換性のある 2FA アプリを使用してください。",
|
||||
"enter_totp_code": "TOTPコードを入力してください。",
|
||||
"add_secret_code":"このシークレット コードを別のデバイスに追加する",
|
||||
"totp_secret_code":"TOTPシークレットコード",
|
||||
"important_note": "重要な注意点",
|
||||
"setup_2fa_text": "Cake 2FA は、コールド ストレージほど安全ではありません。 2FA は、あなたが寝ているときに友人が指紋を提供するなどの基本的なタイプの攻撃から保護します。\n\n Cake 2FA は、巧妙な攻撃者による侵害されたデバイスから保護しません。\n\n 2FA コードにアクセスできなくなった場合、このウォレットにアクセスできなくなります。ニーモニック シードからウォレットを復元する必要があります。したがって、ニーモニック シードをバックアップする必要があります。さらに、あなたのニーモニック シードにアクセスできる誰かが、Cake 2FA をバイパスして、あなたの資金を盗むことができます。\n\n Cake は無印の財布。",
|
||||
"setup_totp_recommended": "TOTP を設定する (推奨)",
|
||||
"disable_buy": "購入アクションを無効にする",
|
||||
"disable_sell": "販売アクションを無効にする"
|
||||
}
|
||||
}
|
|
@ -709,6 +709,23 @@
|
|||
"error_text_input_above_maximum_limit" : "금액이 최대 값보다 많습니다.",
|
||||
"show_market_place":"마켓플레이스 표시",
|
||||
"prevent_screenshots": "스크린샷 및 화면 녹화 방지",
|
||||
"modify_2fa": "수정 케이크 2FA",
|
||||
"disable_cake_2fa": "케이크 2FA 비활성화",
|
||||
"question_to_disable_2fa":"Cake 2FA를 비활성화하시겠습니까? 지갑 및 특정 기능에 액세스하는 데 더 이상 2FA 코드가 필요하지 않습니다.",
|
||||
"disable": "장애를 입히다",
|
||||
"setup_2fa": "케이크 2FA 설정",
|
||||
"verify_with_2fa": "케이크 2FA로 확인",
|
||||
"totp_code": "TOTP 코드",
|
||||
"please_fill_totp": "다른 기기에 있는 8자리 코드를 입력하세요.",
|
||||
"totp_2fa_success": "성공! 이 지갑에 케이크 2FA가 활성화되었습니다. 지갑 액세스 권한을 잃을 경우를 대비하여 니모닉 시드를 저장하는 것을 잊지 마십시오.",
|
||||
"totp_verification_success" :"확인 성공!",
|
||||
"totp_2fa_failure": "잘못된 코드입니다. 다른 코드를 시도하거나 새 비밀 키를 생성하십시오. 8자리 코드와 SHA512를 지원하는 호환되는 2FA 앱을 사용하세요.",
|
||||
"enter_totp_code": "TOTP 코드를 입력하세요.",
|
||||
"add_secret_code":"이 비밀 코드를 다른 장치에 추가",
|
||||
"totp_secret_code":"TOTP 비밀 코드",
|
||||
"important_note": "중요 사항",
|
||||
"setup_2fa_text": "케이크 2FA는 냉장 보관만큼 안전하지 않습니다. 2FA는 당신이 잠자는 동안 친구가 지문을 제공하는 것과 같은 기본적인 유형의 공격으로부터 보호합니다.\n\n Cake 2FA는 정교한 공격자에 의해 손상된 장치로부터 보호하지 않습니다.\n\n 2FA 코드에 대한 액세스 권한을 잃으면 , 이 지갑에 대한 액세스 권한을 잃게 됩니다. 니모닉 시드에서 지갑을 복원해야 합니다. 따라서 니모닉 시드를 백업해야 합니다! 또한 니모닉 시드에 액세스할 수 있는 사람이 Cake 2FA를 우회하여 자금을 훔칠 수 있습니다.\n\n 니모닉 시드에 대한 액세스 권한을 잃으면 Cake 지원 직원이 도와줄 수 없습니다. 비수탁 지갑.",
|
||||
"setup_totp_recommended": "TOTP 설정(권장)",
|
||||
"disable_buy": "구매 행동 비활성화",
|
||||
"disable_sell": "판매 조치 비활성화"
|
||||
}
|
||||
|
|
|
@ -709,6 +709,35 @@
|
|||
"error_text_input_above_maximum_limit" : "ပမာဏသည် အများဆုံးထက် ပိုများသည်။",
|
||||
"show_market_place":"စျေးကွက်ကိုပြသပါ။",
|
||||
"prevent_screenshots": "ဖန်သားပြင်ဓာတ်ပုံများနှင့် မျက်နှာပြင်ရိုက်ကူးခြင်းကို တားဆီးပါ။",
|
||||
"modify_2fa": "ကိတ်မုန့် 2FA ကို ပြင်ဆင်ပါ။",
|
||||
"disable_cake_2fa": "ကိတ်မုန့် 2FA ကို ပိတ်ပါ။",
|
||||
"question_to_disable_2fa":"Cake 2FA ကို ပိတ်လိုသည်မှာ သေချာပါသလား။ ပိုက်ဆံအိတ်နှင့် အချို့သောလုပ်ဆောင်ချက်များကို အသုံးပြုရန်အတွက် 2FA ကုဒ်တစ်ခု မလိုအပ်တော့ပါ။",
|
||||
"disable": "ပိတ်ပါ။",
|
||||
"setup_2fa": "ကိတ်မုန့် 2FA စနစ်ထည့်သွင်းပါ။",
|
||||
"verify_with_2fa": "Cake 2FA ဖြင့် စစ်ဆေးပါ။",
|
||||
"totp_code": "TOTP ကုဒ်",
|
||||
"please_fill_totp": "သင့်အခြားစက်တွင်ရှိသော ဂဏန်း ၈ လုံးကုဒ်ကို ကျေးဇူးပြု၍ ဖြည့်ပါ။",
|
||||
"totp_2fa_success": "အောင်မြင် ဤပိုက်ဆံအိတ်အတွက် ကိတ်မုန့် 2FA ကို ဖွင့်ထားသည်။ ပိုက်ဆံအိတ်ဝင်ရောက်ခွင့်ဆုံးရှုံးသွားသောအခါတွင် သင်၏ mnemonic မျိုးစေ့များကို သိမ်းဆည်းရန် မမေ့ပါနှင့်။",
|
||||
"totp_verification_success" :"အတည်ပြုခြင်း အောင်မြင်ပါသည်။",
|
||||
"totp_2fa_failure": "ကုဒ်မမှန်ပါ။ ကျေးဇူးပြု၍ အခြားကုဒ်တစ်ခုကို စမ်းကြည့်ပါ သို့မဟုတ် လျှို့ဝှက်သော့အသစ်တစ်ခု ဖန်တီးပါ။ ဂဏန်း ၈ လုံးကုဒ်များနှင့် SHA512 ကို ပံ့ပိုးပေးသည့် တွဲဖက်အသုံးပြုနိုင်သော 2FA အက်ပ်ကို အသုံးပြုပါ။",
|
||||
"enter_totp_code": "ကျေးဇူးပြု၍ TOTP ကုဒ်ကို ထည့်ပါ။",
|
||||
"add_secret_code":"ဤလျှို့ဝှက်ကုဒ်ကို အခြားစက်ပစ္စည်းသို့ ထည့်ပါ။",
|
||||
"totp_secret_code":"TOTP လျှို့ဝှက်ကုဒ်",
|
||||
"important_note": "အရေးကြီးသောမှတ်ချက်",
|
||||
"setup_2fa_text": "ကိတ်မုန့် 2FA သည် အအေးခန်းကဲ့သို့ မလုံခြုံပါ။ 2FA သည် သင်အိပ်နေစဉ်တွင် သင့်သူငယ်ချင်းသည် သင့်လက်ဗွေရာကို ပေးဆောင်ခြင်းကဲ့သို့သော အခြေခံတိုက်ခိုက်မှုအမျိုးအစားများကို ကာကွယ်ပေးပါသည်။\n\n Cake 2FA သည် ခေတ်မီဆန်းပြားသော တိုက်ခိုက်သူ၏ အန္တရာယ်ပြုသည့်စက်ပစ္စည်းကို မကာကွယ်ပါ။\n\n သင်၏ 2FA ကုဒ်များကို အသုံးပြုခွင့်ဆုံးရှုံးသွားပါက၊ ဤပိုက်ဆံအိတ်ကို သင်ဝင်ရောက်ခွင့်ဆုံးရှုံးလိမ့်မည်။ သင့်ပိုက်ဆံအိတ်ကို mnemonic မျိုးစေ့မှ ပြန်လည်ရယူရန် လိုအပ်မည်ဖြစ်သည်။ ထို့ကြောင့် သင်၏ MNEMONIC မျိုးစေ့များကို အရန်သိမ်းထားရပါမည်။ ထို့အပြင်၊ သင်၏ mnemonic မျိုးစေ့(များ) ကို အသုံးပြုခွင့်ရှိသူတစ်ဦးက Cake 2FA ကိုကျော်ဖြတ်ကာ သင့်ရန်ပုံငွေများကို ခိုးယူနိုင်ပါမည်။\n\n ကိတ်မုန့်သည် သင့် mnemonic မျိုးစေ့သို့ ဝင်ရောက်ခွင့်ဆုံးရှုံးသွားပါက သင့်အား ကူညီပေးနိုင်မည်မဟုတ်ပါ၊ အထိန်းအချုပ်မရှိသော ပိုက်ဆံအိတ်။",
|
||||
"setup_totp_recommended": "TOTP ကို စနစ်ထည့်သွင်းပါ (အကြံပြုထားသည်)",
|
||||
"disable_buy": "ဝယ်ယူမှု လုပ်ဆောင်ချက်ကို ပိတ်ပါ။",
|
||||
"disable_sell": "ရောင်းချခြင်းလုပ်ဆောင်ချက်ကို ပိတ်ပါ။"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -709,6 +709,23 @@
|
|||
"error_text_input_above_maximum_limit" : "Bedrag is meer dan maximaal",
|
||||
"show_market_place":"Toon Marktplaats",
|
||||
"prevent_screenshots": "Voorkom screenshots en schermopname",
|
||||
"modify_2fa": "Wijzig Cake 2FA",
|
||||
"disable_cake_2fa": "Taart 2FA uitschakelen",
|
||||
"question_to_disable_2fa":"Weet je zeker dat je Cake 2FA wilt uitschakelen? Er is geen 2FA-code meer nodig om toegang te krijgen tot de portemonnee en bepaalde functies.",
|
||||
"disable": "Uitzetten",
|
||||
"setup_2fa": "Opstelling Taart 2FA",
|
||||
"verify_with_2fa": "Controleer met Cake 2FA",
|
||||
"totp_code": "TOTP-code",
|
||||
"please_fill_totp": "Vul de 8-cijferige code in die op uw andere apparaat aanwezig is",
|
||||
"totp_2fa_success": "Succes! Cake 2FA ingeschakeld voor deze portemonnee. Vergeet niet om uw geheugensteuntje op te slaan voor het geval u de toegang tot de portemonnee kwijtraakt.",
|
||||
"totp_verification_success" :"Verificatie geslaagd!",
|
||||
"totp_2fa_failure": "Foute code. Probeer een andere code of genereer een nieuwe geheime sleutel. Gebruik een compatibele 2FA-app die 8-cijferige codes en SHA512 ondersteunt.",
|
||||
"enter_totp_code": "Voer de TOTP-code in.",
|
||||
"add_secret_code":"Voeg deze geheime code toe aan een ander apparaat",
|
||||
"totp_secret_code":"TOTP-geheime code",
|
||||
"important_note": "Belangrijke notitie",
|
||||
"setup_2fa_text": "Cake 2FA is NIET zo veilig als koude opslag. 2FA beschermt tegen basistypen aanvallen, zoals uw vriend die uw vingerafdruk geeft terwijl u slaapt.\n\n Cake 2FA biedt GEEN bescherming tegen een gecompromitteerd apparaat door een geavanceerde aanvaller.\n\n Als u de toegang tot uw 2FA-codes kwijtraakt , VERLIEST U DE TOEGANG TOT DEZE PORTEFEUILLE. U moet uw portemonnee herstellen van mnemonic seed. JE MOET DAAROM EEN BACK-UP MAKEN VAN JE MNEMONISCHE ZADEN! Verder kan iemand met toegang tot je geheugensteuntje(s) je geld stelen, waarbij Cake 2FA wordt omzeild.\n\n Het ondersteunend personeel van Cake kan je niet helpen als je de toegang tot je geheugensteuntje kwijtraakt, aangezien Cake een niet-bewaarbare portemonnee.",
|
||||
"setup_totp_recommended": "TOTP instellen (aanbevolen)",
|
||||
"disable_buy": "Koopactie uitschakelen",
|
||||
"disable_sell": "Verkoopactie uitschakelen"
|
||||
}
|
||||
|
|
|
@ -709,6 +709,23 @@
|
|||
"error_text_input_above_maximum_limit" : "Kwota jest większa niż maksymalna",
|
||||
"show_market_place" : "Pokaż rynek",
|
||||
"prevent_screenshots": "Zapobiegaj zrzutom ekranu i nagrywaniu ekranu",
|
||||
"modify_2fa": "Zmodyfikuj ciasto 2FA",
|
||||
"disable_cake_2fa": "Wyłącz Cake 2FA",
|
||||
"question_to_disable_2fa":"Czy na pewno chcesz wyłączyć Cake 2FA? Kod 2FA nie będzie już potrzebny do uzyskania dostępu do portfela i niektórych funkcji.",
|
||||
"disable": "Wyłączyć",
|
||||
"setup_2fa": "Skonfiguruj ciasto 2FA",
|
||||
"verify_with_2fa": "Sprawdź za pomocą Cake 2FA",
|
||||
"totp_code": "Kod TOTP",
|
||||
"please_fill_totp": "Wpisz 8-cyfrowy kod znajdujący się na drugim urządzeniu",
|
||||
"totp_2fa_success": "Powodzenie! Cake 2FA włączony dla tego portfela. Pamiętaj, aby zapisać swoje mnemoniczne ziarno na wypadek utraty dostępu do portfela.",
|
||||
"totp_verification_success" :"Weryfikacja powiodła się!",
|
||||
"totp_2fa_failure": "Błędny kod. Spróbuj użyć innego kodu lub wygeneruj nowy tajny klucz. Użyj kompatybilnej aplikacji 2FA, która obsługuje 8-cyfrowe kody i SHA512.",
|
||||
"enter_totp_code": "Wprowadź kod TOTP.",
|
||||
"add_secret_code":"Dodaj ten tajny kod do innego urządzenia",
|
||||
"totp_secret_code":"Tajny kod TOTP",
|
||||
"important_note": "Ważna uwaga",
|
||||
"setup_2fa_text": "Cake 2FA NIE jest tak bezpieczny jak przechowywanie w chłodni. 2FA chroni przed podstawowymi typami ataków, takimi jak udostępnienie odcisku palca przez znajomego podczas snu.\n\n Cake 2FA NIE chroni przed zhakowanym urządzeniem przez wyrafinowanego atakującego.\n\n Jeśli utracisz dostęp do swoich kodów 2FA , UTRACISZ DOSTĘP DO TEGO PORTFELA. Będziesz musiał przywrócić swój portfel z mnemonicznego materiału siewnego. DLATEGO MUSISZ ZROBIĆ KOPIĘ SWOICH NASION MNEMONICZNYCH! Co więcej, ktoś z dostępem do twoich mnemonicznych nasion będzie mógł ukraść twoje fundusze, omijając Cake 2FA.\n\n Personel pomocniczy Cake nie będzie mógł ci pomóc, jeśli stracisz dostęp do swojego mnemonicznego seeda, ponieważ Cake jest portfel niezabezpieczony.",
|
||||
"setup_totp_recommended": "Skonfiguruj TOTP (zalecane)",
|
||||
"disable_buy": "Wyłącz akcję kupna",
|
||||
"disable_sell": "Wyłącz akcję sprzedaży"
|
||||
}
|
||||
|
|
|
@ -708,6 +708,23 @@
|
|||
"error_text_input_above_maximum_limit" : "O valor é superior ao máximo",
|
||||
"show_market_place":"Mostrar mercado",
|
||||
"prevent_screenshots": "Evite capturas de tela e gravação de tela",
|
||||
"modify_2fa": "Modificar Bolo 2FA",
|
||||
"disable_cake_2fa": "Desabilitar Bolo 2FA",
|
||||
"question_to_disable_2fa":"Tem certeza de que deseja desativar o Cake 2FA? Um código 2FA não será mais necessário para acessar a carteira e certas funções.",
|
||||
"disable": "Desativar",
|
||||
"setup_2fa": "Bolo de Configuração 2FA",
|
||||
"verify_with_2fa": "Verificar com Cake 2FA",
|
||||
"totp_code": "Código TOTP",
|
||||
"please_fill_totp": "Por favor, preencha o código de 8 dígitos presente em seu outro dispositivo",
|
||||
"totp_2fa_success": "Sucesso! Cake 2FA ativado para esta carteira. Lembre-se de salvar sua semente mnemônica caso perca o acesso à carteira.",
|
||||
"totp_verification_success" :"Verificação bem-sucedida!",
|
||||
"totp_2fa_failure": "Código incorreto. Tente um código diferente ou gere uma nova chave secreta. Use um aplicativo 2FA compatível com códigos de 8 dígitos e SHA512.",
|
||||
"enter_totp_code": "Digite o código TOTP.",
|
||||
"add_secret_code":"Adicione este código secreto a outro dispositivo",
|
||||
"totp_secret_code":"Código Secreto TOTP",
|
||||
"important_note": "Nota importante",
|
||||
"setup_2fa_text": "O Cake 2FA NÃO é tão seguro quanto o armazenamento a frio. O 2FA protege contra tipos básicos de ataques, como seu amigo fornecer sua impressão digital enquanto você está dormindo.\n\n O Cake 2FA NÃO protege contra um dispositivo comprometido por um invasor sofisticado.\n\n Se você perder o acesso aos seus códigos 2FA , VOCÊ PERDERÁ O ACESSO A ESTA CARTEIRA. Você precisará restaurar sua carteira da semente mnemônica. VOCÊ DEVE, PORTANTO, FAZER BACKUP DE SUAS SEMENTES MNEMÔNICAS! Além disso, alguém com acesso às suas sementes mnemônicas poderá roubar seus fundos, ignorando o Cake 2FA.\n\n A equipe de suporte do Cake não poderá ajudá-lo se você perder o acesso à sua semente mnemônica, pois o Cake é um carteira não custodial.",
|
||||
"setup_totp_recommended": "Configurar TOTP (recomendado)",
|
||||
"disable_buy": "Desativar ação de compra",
|
||||
"disable_sell": "Desativar ação de venda"
|
||||
}
|
||||
|
|
|
@ -709,6 +709,23 @@
|
|||
"error_text_input_above_maximum_limit" : "Сумма больше максимальной",
|
||||
"show_market_place":"Показать торговую площадку",
|
||||
"prevent_screenshots": "Предотвратить скриншоты и запись экрана",
|
||||
"modify_2fa": "Изменить торт 2FA",
|
||||
"disable_cake_2fa": "Отключить торт 2FA",
|
||||
"question_to_disable_2fa":"Вы уверены, что хотите отключить Cake 2FA? Код 2FA больше не потребуется для доступа к кошельку и некоторым функциям.",
|
||||
"disable": "Запрещать",
|
||||
"setup_2fa": "Настройка торта 2FA",
|
||||
"verify_with_2fa": "Подтвердить с помощью Cake 2FA",
|
||||
"totp_code": "TOTP-код",
|
||||
"please_fill_totp": "Пожалуйста, введите 8-значный код на другом устройстве",
|
||||
"totp_2fa_success": "Успех! Для этого кошелька включена двухфакторная аутентификация Cake. Не забудьте сохранить мнемоническое семя на случай, если вы потеряете доступ к кошельку.",
|
||||
"totp_verification_success" :"Проверка прошла успешно!",
|
||||
"totp_2fa_failure": "Неверный код. Пожалуйста, попробуйте другой код или создайте новый секретный ключ. Используйте совместимое приложение 2FA, которое поддерживает 8-значные коды и SHA512.",
|
||||
"enter_totp_code": "Пожалуйста, введите TOTP-код.",
|
||||
"add_secret_code":"Добавьте этот секретный код на другое устройство",
|
||||
"totp_secret_code":"Секретный код ТОТП",
|
||||
"important_note": "Важная заметка",
|
||||
"setup_2fa_text": "Cake 2FA НЕ так безопасен, как холодное хранилище. Двухфакторная аутентификация защищает от основных типов атак, таких как отпечаток вашего друга, когда вы спите.\n\n Двухфакторная аутентификация Cake НЕ защищает от взлома устройства опытным злоумышленником.\n\n Если вы потеряете доступ к своим кодам двухфакторной аутентификации. , ВЫ ПОТЕРЯЕТЕ ДОСТУП К ЭТОМУ КОШЕЛЬКУ. Вам нужно будет восстановить свой кошелек из мнемонической семени. ПОЭТОМУ ВЫ ДОЛЖНЫ СОЗДАТЬ РЕЗЕРВНУЮ ВЕРСИЮ СВОИХ МНЕМОНИКОВ! Кроме того, кто-то, имеющий доступ к вашему мнемоническому семени, сможет украсть ваши средства, минуя Cake 2FA.\n\n Персонал службы поддержки Cake не сможет помочь вам, если вы потеряете доступ к своему мнемоническому семени, поскольку Cake — это некастодиальный кошелек.",
|
||||
"setup_totp_recommended": "Настроить TOTP (рекомендуется)",
|
||||
"disable_buy": "Отключить действие покупки",
|
||||
"disable_sell": "Отключить действие продажи"
|
||||
}
|
||||
|
|
|
@ -707,6 +707,23 @@
|
|||
"error_text_input_above_maximum_limit" : "จำนวนเงินสูงกว่าค่าสูงสุด",
|
||||
"show_market_place":"แสดงตลาดกลาง",
|
||||
"prevent_screenshots": "ป้องกันภาพหน้าจอและการบันทึกหน้าจอ",
|
||||
"modify_2fa": "แก้ไขเค้ก 2FA",
|
||||
"disable_cake_2fa": "ปิดการใช้งานเค้ก 2FA",
|
||||
"question_to_disable_2fa":"คุณแน่ใจหรือไม่ว่าต้องการปิดการใช้งาน Cake 2FA ไม่จำเป็นต้องใช้รหัส 2FA ในการเข้าถึงกระเป๋าเงินและฟังก์ชั่นบางอย่างอีกต่อไป",
|
||||
"disable": "ปิดการใช้งาน",
|
||||
"setup_2fa": "ตั้งค่าเค้ก 2FA",
|
||||
"verify_with_2fa": "ตรวจสอบกับ Cake 2FA",
|
||||
"totp_code": "รหัสทีโอพี",
|
||||
"please_fill_totp": "กรุณากรอกรหัส 8 หลักที่อยู่ในอุปกรณ์อื่นของคุณ",
|
||||
"totp_2fa_success": "ความสำเร็จ! Cake 2FA เปิดใช้งานสำหรับกระเป๋าเงินนี้ อย่าลืมบันทึกเมล็ดช่วยจำของคุณในกรณีที่คุณสูญเสียการเข้าถึงกระเป๋าเงิน",
|
||||
"totp_verification_success" :"การยืนยันสำเร็จ!",
|
||||
"totp_2fa_failure": "รหัสไม่ถูกต้อง. โปรดลองใช้รหัสอื่นหรือสร้างรหัสลับใหม่ ใช้แอพ 2FA ที่เข้ากันได้ซึ่งรองรับรหัส 8 หลักและ SHA512",
|
||||
"enter_totp_code": "กรุณาใส่รหัสทีโอที",
|
||||
"add_secret_code":"เพิ่มรหัสลับนี้ไปยังอุปกรณ์อื่น",
|
||||
"totp_secret_code":"รหัสลับ TOTP",
|
||||
"important_note": "โน๊ตสำคัญ",
|
||||
"setup_2fa_text": "Cake 2FA ไม่ปลอดภัยเท่าห้องเย็น 2FA ป้องกันการโจมตีประเภทพื้นฐาน เช่น เพื่อนของคุณให้ลายนิ้วมือขณะที่คุณนอนหลับ\n\n Cake 2FA ไม่ป้องกันอุปกรณ์ที่ถูกบุกรุกโดยผู้โจมตีที่เชี่ยวชาญ\n\n หากคุณสูญเสียการเข้าถึงรหัส 2FA ของคุณ คุณจะสูญเสียการเข้าถึงกระเป๋าเงินนี้ คุณจะต้องกู้คืนกระเป๋าเงินของคุณจากเมล็ดช่วยจำ คุณต้องสำรองเมล็ดความจำของคุณ! นอกจากนี้ ผู้ที่สามารถเข้าถึงเมล็ดช่วยจำของคุณจะสามารถขโมยเงินของคุณ โดยผ่าน Cake 2FA\n\n เจ้าหน้าที่ช่วยเหลือของ Cake จะไม่สามารถช่วยเหลือคุณได้ หากคุณสูญเสียการเข้าถึงเมล็ดช่วยจำ เนื่องจาก Cake เป็น กระเป๋าสตางค์ที่ไม่เป็นผู้ดูแล",
|
||||
"setup_totp_recommended": "ตั้งค่า TOTP (แนะนำ)",
|
||||
"disable_buy": "ปิดการใช้งานการซื้อ",
|
||||
"disable_sell": "ปิดการใช้งานการขาย"
|
||||
}
|
||||
|
|
|
@ -709,6 +709,23 @@
|
|||
"error_text_input_above_maximum_limit" : "Miktar maksimumdan daha fazla",
|
||||
"show_market_place":"Pazar Yerini Göster",
|
||||
"prevent_screenshots": "Ekran görüntülerini ve ekran kaydını önleyin",
|
||||
"modify_2fa": "Cake 2FA'yı Değiştirin",
|
||||
"disable_cake_2fa": "Cake 2FA'yı Devre Dışı Bırak",
|
||||
"question_to_disable_2fa":"Cake 2FA'yı devre dışı bırakmak istediğinizden emin misiniz? M-cüzdana ve belirli işlevlere erişmek için artık 2FA koduna gerek kalmayacak.",
|
||||
"disable": "Devre dışı bırakmak",
|
||||
"setup_2fa": "Kurulum Pastası 2FA",
|
||||
"verify_with_2fa": "Cake 2FA ile Doğrulayın",
|
||||
"totp_code": "TOTP Kodu",
|
||||
"please_fill_totp": "Lütfen diğer cihazınızda bulunan 8 haneli kodu girin",
|
||||
"totp_2fa_success": "Başarı! Bu cüzdan için Cake 2FA etkinleştirildi. Mnemonic seed'inizi cüzdan erişiminizi kaybetme ihtimaline karşı kaydetmeyi unutmayın.",
|
||||
"totp_verification_success" :"Doğrulama Başarılı!",
|
||||
"totp_2fa_failure": "Yanlış kod. Lütfen farklı bir kod deneyin veya yeni bir gizli anahtar oluşturun. 8 basamaklı kodları ve SHA512'yi destekleyen uyumlu bir 2FA uygulaması kullanın.",
|
||||
"enter_totp_code": "Lütfen TOTP Kodunu giriniz.",
|
||||
"add_secret_code":"Bu gizli kodu başka bir cihaza ekleyin",
|
||||
"totp_secret_code":"TOTP Gizli Kodu",
|
||||
"important_note": "Önemli Not",
|
||||
"setup_2fa_text": "Cake 2FA, soğuk hava deposu kadar güvenli DEĞİLDİR. 2FA, siz uyurken arkadaşınızın parmak izinizi sağlaması gibi temel saldırı türlerine karşı koruma sağlar.\n\n Cake 2FA, gelişmiş bir saldırgan tarafından güvenliği ihlal edilmiş bir cihaza karşı koruma SAĞLAMAZ.\n\n 2FA kodlarınıza erişimi kaybederseniz , BU CÜZDANA ERİŞİMİNİZİ KAYBEDECEKSİNİZ. Mnemonic seed'den cüzdanınızı geri yüklemeniz gerekecek. BU NEDENLE HATIRLAYICI TOHUMLARINIZI YEDEKLEMELİSİNİZ! Ayrıca anımsatıcı tohumlarınıza erişimi olan biri, Cake 2FA'yı atlayarak paranızı çalabilir.\n\n Cake, anımsatıcı tohumlarınıza erişimi kaybederseniz size yardımcı olamaz, çünkü Cake bir saklama dışı cüzdan.",
|
||||
"setup_totp_recommended": "TOTP'yi kurun (Önerilir)",
|
||||
"disable_buy": "Satın alma işlemini devre dışı bırak",
|
||||
"disable_sell": "Satış işlemini devre dışı bırak"
|
||||
}
|
||||
|
|
|
@ -708,6 +708,23 @@
|
|||
"error_text_input_above_maximum_limit" : "Сума більше максимальної",
|
||||
"show_market_place":"Відображати маркетплейс",
|
||||
"prevent_screenshots": "Запобігати знімкам екрана та запису екрана",
|
||||
"modify_2fa": "Змінити торт 2FA",
|
||||
"disable_cake_2fa": "Вимкнути Cake 2FA",
|
||||
"question_to_disable_2fa":"Ви впевнені, що хочете вимкнути Cake 2FA? Код 2FA більше не потрібен для доступу до гаманця та певних функцій.",
|
||||
"disable": "Вимкнути",
|
||||
"setup_2fa": "Налаштування Cake 2FA",
|
||||
"verify_with_2fa": "Перевірте за допомогою Cake 2FA",
|
||||
"totp_code": "Код TOTP",
|
||||
"please_fill_totp": "Будь ласка, введіть 8-значний код, наявний на вашому іншому пристрої",
|
||||
"totp_2fa_success": "Успіх! Cake 2FA увімкнено для цього гаманця. Пам’ятайте про збереження мнемоніки на випадок, якщо ви втратите доступ до гаманця.",
|
||||
"totp_verification_success" :"Перевірка успішна!",
|
||||
"totp_2fa_failure": "Невірний код. Спробуйте інший код або створіть новий секретний ключ. Використовуйте сумісний додаток 2FA, який підтримує 8-значні коди та SHA512.",
|
||||
"enter_totp_code": "Будь ласка, введіть код TOTP.",
|
||||
"add_secret_code":"Додайте цей секретний код на інший пристрій",
|
||||
"totp_secret_code":"Секретний код TOTP",
|
||||
"important_note": "Важливе зауваження",
|
||||
"setup_2fa_text": "Торт 2FA НЕ такий безпечний, як холодне зберігання. 2FA захищає від основних типів атак, наприклад ваш друг надає ваш відбиток пальця, поки ви спите.\n\n Cake 2FA НЕ захищає від скомпрометованого пристрою досвідченим зловмисником.\n\n Якщо ви втратите доступ до своїх кодів 2FA , ВИ ВТРАТИТЕ ДОСТУП ДО ЦЬОГО ГАМАНЦЯ. Вам потрібно буде відновити свій гаманець з мнемонічного коду. ТОМУ ВИ ПОВИННІ СТВОРИТИ РЕЗЕРВНУ КОПІЮ СВОЇХ МНЕМОНІЧНИХ НАСІН! Крім того, хтось із доступом до ваших мнемонічних початкових значень зможе викрасти ваші кошти, оминаючи Cake 2FA.\n\n Співробітники служби підтримки Cake не зможуть вам допомогти, якщо ви втратите доступ до своїх мнемонічних вихідних даних, оскільки Cake є гаманець без опіки.",
|
||||
"setup_totp_recommended": "Налаштувати TOTP (рекомендовано)",
|
||||
"disable_buy": "Вимкнути дію покупки",
|
||||
"disable_sell": "Вимкнути дію продажу"
|
||||
}
|
||||
|
|
|
@ -704,6 +704,23 @@
|
|||
"error_text_input_above_maximum_limit" : "رقم زیادہ سے زیادہ سے زیادہ ہے۔",
|
||||
"show_market_place":"بازار دکھائیں۔",
|
||||
"prevent_screenshots": "اسکرین شاٹس اور اسکرین ریکارڈنگ کو روکیں۔",
|
||||
"modify_2fa": "کیک 2FA میں ترمیم کریں۔",
|
||||
"disable_cake_2fa": "کیک 2FA کو غیر فعال کریں۔",
|
||||
"question_to_disable_2fa":"کیا آپ واقعی کیک 2FA کو غیر فعال کرنا چاہتے ہیں؟ بٹوے اور بعض افعال تک رسائی کے لیے اب 2FA کوڈ کی ضرورت نہیں ہوگی۔",
|
||||
"disable": "غیر فعال کریں۔",
|
||||
"setup_2fa": "سیٹ اپ کیک 2FA",
|
||||
"verify_with_2fa": "کیک 2FA سے تصدیق کریں۔",
|
||||
"totp_code": "TOTP کوڈ",
|
||||
"please_fill_totp": "براہ کرم اپنے دوسرے آلے پر موجود 8 ہندسوں کا کوڈ پُر کریں۔",
|
||||
"totp_2fa_success": "کامیابی! کیک 2FA اس بٹوے کے لیے فعال ہے۔ بٹوے تک رسائی سے محروم ہونے کی صورت میں اپنے یادداشت کے بیج کو محفوظ کرنا یاد رکھیں۔",
|
||||
"totp_verification_success" :"توثیق کامیاب!",
|
||||
"totp_2fa_failure": "غلط کوڈ. براہ کرم ایک مختلف کوڈ آزمائیں یا ایک نئی خفیہ کلید بنائیں۔ ایک ہم آہنگ 2FA ایپ استعمال کریں جو 8 ہندسوں کے کوڈز اور SHA512 کو سپورٹ کرتی ہو۔",
|
||||
"enter_totp_code": "براہ کرم TOTP کوڈ درج کریں۔",
|
||||
"add_secret_code":"اس خفیہ کوڈ کو کسی اور ڈیوائس میں شامل کریں۔",
|
||||
"totp_secret_code":"TOTP خفیہ کوڈ",
|
||||
"important_note": "اہم نوٹ",
|
||||
"setup_2fa_text": "کیک 2FA کولڈ اسٹوریج کی طرح محفوظ نہیں ہے۔ 2FA بنیادی قسم کے حملوں سے حفاظت کرتا ہے، جیسے کہ آپ کا دوست آپ کے سوتے وقت آپ کے فنگر پرنٹ فراہم کرتا ہے۔\n\n کیک 2FA کسی جدید حملہ آور کے ذریعے سمجھوتہ کرنے والے آلہ سے حفاظت نہیں کرتا ہے۔\n\n اگر آپ اپنے 2FA کوڈز تک رسائی کھو دیتے ہیں ، آپ اس بٹوے تک رسائی سے محروم ہو جائیں گے۔ آپ کو یادداشت کے بیج سے اپنے بٹوے کو بحال کرنے کی ضرورت ہوگی۔ اس لیے آپ کو اپنے یادداشت کے بیجوں کا بیک اپ لینا چاہیے! اس کے علاوہ، آپ کے یادداشت کے بیج تک رسائی رکھنے والا کوئی شخص کیک 2FA کو نظرانداز کرتے ہوئے آپ کے فنڈز چرا سکے گا۔\n\n اگر آپ اپنے یادداشت کے بیج تک رسائی کھو دیتے ہیں تو کیک کا معاون عملہ آپ کی مدد نہیں کر سکے گا، کیونکہ کیک ایک ہے غیر نگہداشت پرس.",
|
||||
"setup_totp_recommended": "TOTP ترتیب دیں (تجویز کردہ)",
|
||||
"disable_buy": "خرید ایکشن کو غیر فعال کریں۔",
|
||||
"disable_sell": "فروخت کی کارروائی کو غیر فعال کریں۔"
|
||||
}
|
||||
|
|
|
@ -708,6 +708,23 @@
|
|||
"error_text_input_above_maximum_limit" : "金额大于最大值",
|
||||
"show_market_place" :"显示市场",
|
||||
"prevent_screenshots": "防止截屏和录屏",
|
||||
"modify_2fa": "修改蛋糕2FA",
|
||||
"disable_cake_2fa": "禁用蛋糕 2FA",
|
||||
"question_to_disable_2fa":"您确定要禁用 Cake 2FA 吗?访问钱包和某些功能将不再需要 2FA 代码。",
|
||||
"disable": "停用",
|
||||
"setup_2fa": "设置蛋糕 2FA",
|
||||
"verify_with_2fa": "用 Cake 2FA 验证",
|
||||
"totp_code": "TOTP代码",
|
||||
"please_fill_totp": "请填写您其他设备上的 8 位代码",
|
||||
"totp_2fa_success": "成功!为此钱包启用了 Cake 2FA。请记住保存您的助记词种子,以防您无法访问钱包。",
|
||||
"totp_verification_success" :"验证成功!",
|
||||
"totp_2fa_failure": "不正确的代码。 请尝试不同的代码或生成新的密钥。 使用支持 8 位代码和 SHA512 的兼容 2FA 应用程序。",
|
||||
"enter_totp_code": "请输入 TOTP 代码。",
|
||||
"add_secret_code":"将此密码添加到另一台设备",
|
||||
"totp_secret_code":"TOTP密码",
|
||||
"important_note": "重要的提示",
|
||||
"setup_2fa_text": "Cake 2FA 不如冷藏安全。 2FA 可防止基本类型的攻击,例如您的朋友在您睡觉时提供您的指纹。\n\n Cake 2FA 无法防止老练的攻击者破坏设备。\n\n 如果您无法访问您的 2FA 代码, 您将无法访问此钱包。您将需要从助记词种子恢复您的钱包。因此,您必须备份您的助记词种子!此外,有权访问您的助记种子的人将能够绕过 Cake 2FA 窃取您的资金。\n\n 如果您无法访问您的助记种子,Cake 支持人员将无法帮助您,因为 Cake 是一个非托管钱包。",
|
||||
"setup_totp_recommended": "设置 TOTP(推荐)",
|
||||
"disable_buy": "禁用购买操作",
|
||||
"disable_sell": "禁用卖出操作"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue