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:
Patrick
2026-09-03 01:58:45 +08:00
committed by GitHub
parent ea4d752914
commit 73a739411f
10 changed files with 160 additions and 46 deletions
@@ -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}');
}
+42 -19
View File
@@ -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;
}
}
}