mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
Delete CakePay Auth-token if the API returns 401 (#3538)
* delete cakepay auth token on 401 * fix cakepay auth refresh * fix Cake Pay error handling
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
class CakePayUnauthorizedException implements Exception {
|
||||
const CakePayUnauthorizedException();
|
||||
|
||||
@override
|
||||
String toString() => 'Cake Pay session is no longer valid, please log in again.';
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/cake_pay/src/cake_pay_exceptions.dart';
|
||||
import 'package:cake_wallet/cake_pay/src/models/cake_pay_card.dart';
|
||||
import 'package:cake_wallet/cake_pay/src/models/cake_pay_order.dart';
|
||||
import 'package:cake_wallet/cake_pay/src/widgets/cake_pay_alert_modal.dart';
|
||||
@@ -497,19 +498,37 @@ class CakePayBuyCardPage extends BasePage {
|
||||
}
|
||||
|
||||
Future<void> purchaseCard(BuildContext context) async {
|
||||
bool isLogged = await cakePayBuyCardViewModel.isUserLogged;
|
||||
if (!isLogged) {
|
||||
cakePayBuyCardViewModel.isSimulatingFlow = false;
|
||||
Navigator.of(context).pushNamed(Routes.cakePayWelcomePage);
|
||||
} else {
|
||||
try {
|
||||
await cakePayBuyCardViewModel.createOrder();
|
||||
} catch (_) {
|
||||
try {
|
||||
final isLogged = await cakePayBuyCardViewModel.isUserLogged;
|
||||
|
||||
if (!isLogged) {
|
||||
cakePayBuyCardViewModel.isSimulatingFlow = false;
|
||||
await cakePayBuyCardViewModel.logout();
|
||||
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pushNamed(Routes.cakePayWelcomePage);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await cakePayBuyCardViewModel.createOrder();
|
||||
} on CakePayUnauthorizedException {
|
||||
cakePayBuyCardViewModel.isSimulatingFlow = false;
|
||||
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pushNamed(Routes.cakePayWelcomePage);
|
||||
}
|
||||
} catch (error) {
|
||||
cakePayBuyCardViewModel.isSimulatingFlow = false;
|
||||
_sendViewModel.state = FailureState(
|
||||
_sendViewModel.translateErrorMessage(
|
||||
error,
|
||||
cakePayBuyCardViewModel.walletType,
|
||||
_sendViewModel.wallet.currency,
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
cakePayBuyCardViewModel.isPurchasing = false;
|
||||
}
|
||||
cakePayBuyCardViewModel.isPurchasing = false;
|
||||
}
|
||||
|
||||
BuildContext? dialogContext;
|
||||
|
||||
@@ -477,11 +477,18 @@ class _ShopTabState extends State<_ShopTab> {
|
||||
if (i >= vendors.length) return const _Loading();
|
||||
final vendor = vendors[i];
|
||||
return CardItem(
|
||||
logoUrl: vendor.card?.cardImageUrl,
|
||||
title: vendor.name,
|
||||
subTitle: vendor.card?.description ?? '',
|
||||
onTap: () => Navigator.pushNamed(context, Routes.cakePayBuyCardPage,
|
||||
arguments: [vendor]));
|
||||
logoUrl: vendor.card?.cardImageUrl,
|
||||
title: vendor.name,
|
||||
subTitle: vendor.card?.description ?? '',
|
||||
onTap: () async {
|
||||
await Navigator.pushNamed(
|
||||
context,
|
||||
Routes.cakePayBuyCardPage,
|
||||
arguments: [vendor],
|
||||
);
|
||||
await viewModel.checkAuth();
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:cake_wallet/cake_pay/src/cake_pay_exceptions.dart';
|
||||
import 'package:cake_wallet/cake_pay/src/models/cake_pay_order.dart';
|
||||
import 'package:cake_wallet/cake_pay/src/models/cake_pay_user_credentials.dart';
|
||||
import 'package:cake_wallet/cake_pay/src/models/cake_pay_vendor.dart';
|
||||
@@ -129,6 +130,10 @@ class CakePayApi {
|
||||
body: body,
|
||||
);
|
||||
|
||||
if (response.statusCode == 401) {
|
||||
throw const CakePayUnauthorizedException();
|
||||
}
|
||||
|
||||
if (response.statusCode == 201) {
|
||||
final data = json.decode(response.body) as Map<String, dynamic>;
|
||||
return CakePayOrder.fromMap(data);
|
||||
@@ -168,6 +173,10 @@ class CakePayApi {
|
||||
headers: headers,
|
||||
);
|
||||
|
||||
if (response.statusCode == 401) {
|
||||
throw const CakePayUnauthorizedException();
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
@@ -203,6 +212,10 @@ class CakePayApi {
|
||||
|
||||
printV('Response: ${response.statusCode}');
|
||||
|
||||
if (response.statusCode == 401) {
|
||||
throw const CakePayUnauthorizedException();
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/cake_pay/src/cake_pay_exceptions.dart';
|
||||
import 'package:cake_wallet/cake_pay/src/services/cake_pay_api.dart';
|
||||
import 'package:cake_wallet/cake_pay/src/models/cake_pay_order.dart';
|
||||
import 'package:cake_wallet/cake_pay/src/models/cake_pay_vendor.dart';
|
||||
@@ -95,29 +96,51 @@ class CakePayService {
|
||||
required bool confirmsTermsAgreed,
|
||||
}) async {
|
||||
final userEmail = (await secureStorage.read(key: cakePayEmailStorageKey))!;
|
||||
final token = (await secureStorage.read(key: cakePayUserTokenKey))!;
|
||||
return await cakePayApi.createOrder(
|
||||
apiKey: cakePayApiKey,
|
||||
cardId: cardId,
|
||||
price: price,
|
||||
quantity: quantity,
|
||||
token: token,
|
||||
userEmail: userEmail,
|
||||
confirmsNoVpn: confirmsNoVpn,
|
||||
confirmsVoidedRefund: confirmsVoidedRefund,
|
||||
confirmsTermsAgreed: confirmsTermsAgreed,
|
||||
return _withUserToken(
|
||||
(token) => cakePayApi.createOrder(
|
||||
apiKey: cakePayApiKey,
|
||||
cardId: cardId,
|
||||
price: price,
|
||||
quantity: quantity,
|
||||
token: token,
|
||||
userEmail: userEmail,
|
||||
confirmsNoVpn: confirmsNoVpn,
|
||||
confirmsVoidedRefund: confirmsVoidedRefund,
|
||||
confirmsTermsAgreed: confirmsTermsAgreed,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<CakePayOrder> findOrderById({required String orderId}) async {
|
||||
final token = (await secureStorage.read(key: cakePayUserTokenKey))!;
|
||||
return await cakePayApi.getOrderById(orderId: orderId, token: token);
|
||||
}
|
||||
Future<CakePayOrder> findOrderById({required String orderId}) => _withUserToken(
|
||||
(token) => cakePayApi.getOrderById(
|
||||
orderId: orderId,
|
||||
token: token,
|
||||
),
|
||||
);
|
||||
|
||||
///Simulate Purchase Gift Card
|
||||
Future<String> simulatePayment({required String orderId}) async {
|
||||
final token = (await secureStorage.read(key: cakePayUserTokenKey))!;
|
||||
return await cakePayApi.simulatePayment(
|
||||
CSRFToken: CSRFToken, authorization: authorization, token: token, orderId: orderId);
|
||||
Future<String> simulatePayment({required String orderId}) => _withUserToken(
|
||||
(token) => cakePayApi.simulatePayment(
|
||||
CSRFToken: CSRFToken,
|
||||
authorization: authorization,
|
||||
token: token,
|
||||
orderId: orderId,
|
||||
),
|
||||
);
|
||||
|
||||
/// Wrapper for requests with user token
|
||||
Future<T> _withUserToken<T>(Future<T> Function(String token) request) async {
|
||||
try {
|
||||
final token = await secureStorage.read(key: cakePayUserTokenKey) ?? '';
|
||||
|
||||
if (token.isEmpty) {
|
||||
throw const CakePayUnauthorizedException();
|
||||
}
|
||||
|
||||
return await request(token);
|
||||
} on CakePayUnauthorizedException {
|
||||
await logout();
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import 'package:cake_wallet/src/screens/order_details/cake_pay_detail_list_card_item.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_pay_order_list_card.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list_status_row.dart';
|
||||
import 'package:cake_wallet/themes/core/material_base_theme.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/order_details_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
@@ -14,6 +16,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/list_row.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
class OrderDetailsPage extends BasePage {
|
||||
OrderDetailsPage(this.orderDetailsViewModel);
|
||||
@@ -43,11 +46,44 @@ class OrderDetailsPageBodyState extends State<OrderDetailsPageBody> {
|
||||
|
||||
final OrderDetailsViewModel orderDetailsViewModel;
|
||||
final MaterialThemeBase currentTheme;
|
||||
ReactionDisposer? _sessionExpiredReaction;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_sessionExpiredReaction = reaction<bool>(
|
||||
(_) => orderDetailsViewModel.isCakePaySessionExpired,
|
||||
(isExpired) {
|
||||
if (!isExpired) {
|
||||
return;
|
||||
}
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (dialogContext) => AlertWithOneAction(
|
||||
alertTitle: S.of(dialogContext).error,
|
||||
alertContent: S.of(dialogContext).cake_pay_session_expired,
|
||||
buttonText: S.of(dialogContext).ok,
|
||||
buttonAction: () => Navigator.of(dialogContext).pop(),
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
fireImmediately: true,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
_sessionExpiredReaction?.call();
|
||||
orderDetailsViewModel.timer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:cake_wallet/cake_pay/src/cake_pay_exceptions.dart';
|
||||
import 'package:cake_wallet/order/order_provider_description.dart';
|
||||
import 'package:cake_wallet/order/order.dart';
|
||||
import 'package:cake_wallet/order/order_source_description.dart';
|
||||
@@ -221,6 +222,8 @@ abstract class CakePayBuyCardViewModelBase with Store {
|
||||
orders.add(orderRecord);
|
||||
updateRemainingTime();
|
||||
_startExpirationTimer();
|
||||
} on CakePayUnauthorizedException {
|
||||
rethrow;
|
||||
} catch (e) {
|
||||
sendViewModel.state = FailureState(
|
||||
sendViewModel.translateErrorMessage(e, walletType, sendViewModel.wallet.currency));
|
||||
@@ -275,8 +278,6 @@ abstract class CakePayBuyCardViewModelBase with Store {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> logout() async => await _cakePayService.logout();
|
||||
|
||||
void _startExpirationTimer() {
|
||||
_timer?.cancel();
|
||||
_timer = Timer.periodic(Duration(seconds: 1), (_) {
|
||||
|
||||
@@ -78,7 +78,6 @@ abstract class CakePayCardsListViewModelBase with Store {
|
||||
};
|
||||
|
||||
String searchString;
|
||||
String? username;
|
||||
int page;
|
||||
|
||||
late Country _initialSelectedCountry;
|
||||
@@ -87,6 +86,9 @@ abstract class CakePayCardsListViewModelBase with Store {
|
||||
late bool _initialDisplayDenominationsCards;
|
||||
late bool _initialDisplayCustomValueCards;
|
||||
|
||||
@observable
|
||||
String? username;
|
||||
|
||||
@observable
|
||||
List<CakePayCard> userCards;
|
||||
|
||||
@@ -189,12 +191,9 @@ abstract class CakePayCardsListViewModelBase with Store {
|
||||
|
||||
@action
|
||||
Future<void> checkAuth() async {
|
||||
authFuture = ObservableFuture(cakePayService.isLogged());
|
||||
|
||||
final logged = await authFuture!;
|
||||
if (logged) {
|
||||
username = await cakePayService.getUserEmail();
|
||||
}
|
||||
final logged = await cakePayService.isLogged();
|
||||
username = logged ? await cakePayService.getUserEmail() : null;
|
||||
authFuture = ObservableFuture.value(logged);
|
||||
}
|
||||
|
||||
@action
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:cake_wallet/buy/buy_provider_description.dart';
|
||||
import 'package:cake_wallet/cake_pay/src/cake_pay_exceptions.dart';
|
||||
import 'package:cake_wallet/cake_pay/src/models/cake_pay_order.dart';
|
||||
import 'package:cake_wallet/cake_pay/src/services/cake_pay_service.dart';
|
||||
import 'package:cake_wallet/core/utilities.dart';
|
||||
@@ -64,6 +65,9 @@ abstract class OrderDetailsViewModelBase with Store {
|
||||
@observable
|
||||
ObservableList<StandartListItem> items;
|
||||
|
||||
@observable
|
||||
bool isCakePaySessionExpired = false;
|
||||
|
||||
final CakePayService cakePayService;
|
||||
final Box<Order> orders;
|
||||
OrderProvider? _provider;
|
||||
@@ -74,7 +78,9 @@ abstract class OrderDetailsViewModelBase with Store {
|
||||
@action
|
||||
Future<void> _updateOrder() async {
|
||||
try {
|
||||
if (_provider == null) return;
|
||||
if (_provider == null || isCakePaySessionExpired) {
|
||||
return;
|
||||
}
|
||||
|
||||
final updatedOrderObj = await _provider!.findOrderById(order.id);
|
||||
final updatedOrder = updatedOrderObj.$1;
|
||||
@@ -95,6 +101,9 @@ abstract class OrderDetailsViewModelBase with Store {
|
||||
}
|
||||
|
||||
_updateItems();
|
||||
} on CakePayUnauthorizedException {
|
||||
timer?.cancel();
|
||||
isCakePaySessionExpired = true;
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user