Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,8 @@ class MethodHandler : FlutterPlugin,
val url = Mobile.paymentRedirect(
map["provider"] as String,
map["planId"] as String,
map["email"] as String
map["email"] as String,
map["idempotencyKey"] as? String ?: ""
Comment thread
atavism marked this conversation as resolved.
Outdated
)
withContext(Dispatchers.Main) {
success(url)
Expand Down
28 changes: 15 additions & 13 deletions lantern-core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,10 @@
StripeBillingPortalUrl() (string, error)
AcknowledgeGooglePurchase(purchaseToken, planId string) (string, error)
AcknowledgeApplePurchase(receipt, planII string) (string, error)
PaymentRedirect(provider, planID, email string) (string, error)
PaymentRedirect(provider, planID, email, idempotencyKey string) (string, error)
ActivationCode(email, resellerCode string) error
SubscriptionPaymentRedirectURL(redirectBody account.PaymentRedirectData) (string, error)
StripeSubscriptionPaymentRedirect(subscriptionType, planID, email string) (string, error)
StripeSubscriptionPaymentRedirect(subscriptionType, planID, email, idempotencyKey string) (string, error)
}

type SplitTunnel interface {
Expand Down Expand Up @@ -866,25 +866,27 @@
return lc.client.SubscriptionPaymentRedirectURL(lc.ctx, redirectBody)
}

func (lc *LanternCore) StripeSubscriptionPaymentRedirect(subscriptionType, planID, email string) (string, error) {
func (lc *LanternCore) StripeSubscriptionPaymentRedirect(subscriptionType, planID, email, idempotencyKey string) (string, error) {
deviceID := lc.MyDeviceId()
redirectBody := account.PaymentRedirectData{
Provider: "stripe",
Plan: planID,
DeviceName: deviceID,
Email: email,
BillingType: account.SubscriptionType(subscriptionType),
Provider: "stripe",
Plan: planID,
DeviceName: deviceID,
Email: email,
BillingType: account.SubscriptionType(subscriptionType),
IdempotencyKey: idempotencyKey,

Check failure on line 877 in lantern-core/core.go

View workflow job for this annotation

GitHub Actions / build

unknown field IdempotencyKey in struct literal of type account.PaymentRedirectData
}
Comment thread
atavism marked this conversation as resolved.
return lc.SubscriptionPaymentRedirectURL(redirectBody)
}

func (lc *LanternCore) PaymentRedirect(provider, planId, email string) (string, error) {
func (lc *LanternCore) PaymentRedirect(provider, planId, email, idempotencyKey string) (string, error) {
deviceName := lc.MyDeviceId()
body := account.PaymentRedirectData{
Provider: provider,
Plan: planId,
DeviceName: deviceName,
Email: email,
Provider: provider,
Plan: planId,
DeviceName: deviceName,
Email: email,
IdempotencyKey: idempotencyKey,

Check failure on line 889 in lantern-core/core.go

View workflow job for this annotation

GitHub Actions / build

unknown field IdempotencyKey in struct literal of type account.PaymentRedirectData
}
Comment thread
atavism marked this conversation as resolved.
return lc.client.PaymentRedirect(lc.ctx, body)
}
Expand Down
10 changes: 6 additions & 4 deletions lantern-core/ffi/ffi.go
Original file line number Diff line number Diff line change
Expand Up @@ -633,16 +633,17 @@ func fetchUserData() *C.char {
// Fetch stipe subscription payment redirect link
//
//export stripeSubscriptionPaymentRedirect
func stripeSubscriptionPaymentRedirect(subType, _planId, _email *C.char) *C.char {
func stripeSubscriptionPaymentRedirect(subType, _planId, _email, _idempotencyKey *C.char) *C.char {
subscriptionType := C.GoString(subType)
planID := C.GoString(_planId)
email := C.GoString(_email)
idempotencyKey := C.GoString(_idempotencyKey)
return runOnGoStack(func() *C.char {
c, errStr := requireCore()
if errStr != nil {
return errStr
}
redirect, err := c.StripeSubscriptionPaymentRedirect(subscriptionType, planID, email)
redirect, err := c.StripeSubscriptionPaymentRedirect(subscriptionType, planID, email, idempotencyKey)
if err != nil {
return SendError(err)
}
Expand All @@ -653,16 +654,17 @@ func stripeSubscriptionPaymentRedirect(subType, _planId, _email *C.char) *C.char
// Fetch payment redirect link for providers like alipay
//
//export paymentRedirect
func paymentRedirect(_plan, _provider, _email *C.char) *C.char {
func paymentRedirect(_plan, _provider, _email, _idempotencyKey *C.char) *C.char {
plan := C.GoString(_plan)
provider := C.GoString(_provider)
email := C.GoString(_email)
idempotencyKey := C.GoString(_idempotencyKey)
return runOnGoStack(func() *C.char {
c, errStr := requireCore()
if errStr != nil {
return errStr
}
redirect, err := c.PaymentRedirect(provider, plan, email)
redirect, err := c.PaymentRedirect(provider, plan, email, idempotencyKey)
if err != nil {
return SendError(err)
}
Expand Down
11 changes: 6 additions & 5 deletions lantern-core/mobile/mobile.go
Original file line number Diff line number Diff line change
Expand Up @@ -555,17 +555,18 @@ func AcknowledgeApplePurchase(receipt, planII string) (string, error) {
})
}

func PaymentRedirect(provider, planId, email string) (string, error) {
return withCoreR(func(c lanterncore.Core) (string, error) { return c.PaymentRedirect(provider, planId, email) })

func PaymentRedirect(provider, planId, email, idempotencyKey string) (string, error) {
return withCoreR(func(c lanterncore.Core) (string, error) {
return c.PaymentRedirect(provider, planId, email, idempotencyKey)
})
}

// /This is specifically for stripe subscriptions that require a redirect to complete the payment
// This is only used for macos
func StripeSubscriptionPaymentRedirect(subType, planId, email string) (string, error) {
func StripeSubscriptionPaymentRedirect(subType, planId, email, idempotencyKey string) (string, error) {
slog.Debug("stripeSubscriptionPaymentRedirect called")
return withCoreR(func(c lanterncore.Core) (string, error) {
return c.StripeSubscriptionPaymentRedirect(subType, planId, email)
return c.StripeSubscriptionPaymentRedirect(subType, planId, email, idempotencyKey)
})
}

Expand Down
8 changes: 8 additions & 0 deletions lib/core/common/common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ String generatePassword() {
).join();
}

String generatePaymentRedirectIdempotencyKey() {
final random = Random.secure();
return List.generate(
16,
(_) => random.nextInt(256).toRadixString(16).padLeft(2, '0'),
).join();
}

bool isStoreVersion() {
if (!PlatformUtils.isMobile) {
return false;
Expand Down
10 changes: 9 additions & 1 deletion lib/features/plans/provider/payment_notifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,14 @@ class PaymentNotifier extends _$PaymentNotifier {
String planId,
String email,
) async {
final idempotencyKey = generatePaymentRedirectIdempotencyKey();
return ref
.read(lanternServiceProvider)
.stipeSubscriptionPaymentRedirect(
type: type,
planId: planId,
email: email,
idempotencyKey: idempotencyKey,
);
}

Expand All @@ -77,9 +79,15 @@ class PaymentNotifier extends _$PaymentNotifier {
required String planId,
required String email,
}) async {
final idempotencyKey = generatePaymentRedirectIdempotencyKey();
return ref
.read(lanternServiceProvider)
.paymentRedirect(provider: provider, planId: planId, email: email);
.paymentRedirect(
provider: provider,
planId: planId,
email: email,
idempotencyKey: idempotencyKey,
);
}

Future<Either<Failure, String?>> startUpgradeFlow({
Expand Down
12 changes: 7 additions & 5 deletions lib/lantern/lantern_core_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,19 @@ abstract class LanternCoreService {

Future<Either<Failure, String>> getOAuthProvider();


///Payments methods
Future<Either<Failure, String>> stipeSubscriptionPaymentRedirect(
{required BillingType type,
required String planId,
required String email});
Future<Either<Failure, String>> stipeSubscriptionPaymentRedirect({
required BillingType type,
required String planId,
required String email,
required String idempotencyKey,
});

Future<Either<Failure, String>> paymentRedirect({
required String provider,
required String planId,
required String email,
required String idempotencyKey,
});

// this is used for stripe subscription
Expand Down
4 changes: 4 additions & 0 deletions lib/lantern/lantern_ffi_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,7 @@ class LanternFFIService implements LanternCoreService {
required BillingType type,
required String planId,
required String email,
required String idempotencyKey,
}) async {
try {
appLogger.debug('Starting Stripe Subscription Payment Redirect');
Expand All @@ -747,6 +748,7 @@ class LanternFFIService implements LanternCoreService {
type.name.toCharPtr,
planId.toCharPtr,
email.toCharPtr,
idempotencyKey.toCharPtr,
)
.toDartString();
});
Expand Down Expand Up @@ -889,6 +891,7 @@ class LanternFFIService implements LanternCoreService {
required String provider,
required String planId,
required String email,
required String idempotencyKey,
}) async {
try {
final result = await runInBackground<String>(() async {
Expand All @@ -897,6 +900,7 @@ class LanternFFIService implements LanternCoreService {
planId.toCharPtr,
provider.toCharPtr,
email.toCharPtr,
idempotencyKey.toCharPtr,
)
.toDartString();
});
Expand Down
15 changes: 13 additions & 2 deletions lib/lantern/lantern_generated_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5669,8 +5669,14 @@ class LanternBindings {
ffi.Pointer<ffi.Char> subType,
ffi.Pointer<ffi.Char> _planId,
ffi.Pointer<ffi.Char> _email,
ffi.Pointer<ffi.Char> _idempotencyKey,
) {
return _stripeSubscriptionPaymentRedirect(subType, _planId, _email);
return _stripeSubscriptionPaymentRedirect(
subType,
_planId,
_email,
_idempotencyKey,
);
}

late final _stripeSubscriptionPaymentRedirectPtr =
Expand All @@ -5680,6 +5686,7 @@ class LanternBindings {
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
)
>
>('stripeSubscriptionPaymentRedirect');
Expand All @@ -5690,15 +5697,17 @@ class LanternBindings {
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
)
>();

ffi.Pointer<ffi.Char> paymentRedirect(
ffi.Pointer<ffi.Char> _plan,
ffi.Pointer<ffi.Char> _provider,
ffi.Pointer<ffi.Char> _email,
ffi.Pointer<ffi.Char> _idempotencyKey,
) {
return _paymentRedirect(_plan, _provider, _email);
return _paymentRedirect(_plan, _provider, _email, _idempotencyKey);
}

late final _paymentRedirectPtr =
Expand All @@ -5708,6 +5717,7 @@ class LanternBindings {
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
)
>
>('paymentRedirect');
Expand All @@ -5717,6 +5727,7 @@ class LanternBindings {
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>,
)
>();

Expand Down
16 changes: 14 additions & 2 deletions lib/lantern/lantern_platform_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ class LanternPlatformService implements LanternCoreService {
required BillingType type,
required String planId,
required String email,
required String idempotencyKey,
}) async {
if (!PlatformUtils.isMacOS) {
return left(
Expand All @@ -663,7 +664,12 @@ class LanternPlatformService implements LanternCoreService {
try {
final redirectUrl = await _methodChannel.invokeMethod<String>(
'stripeSubscriptionPaymentRedirect',
{"type": type.name, "planId": planId, "email": email},
{
"type": type.name,
"planId": planId,
"email": email,
"idempotencyKey": idempotencyKey,
},
);
return Right(redirectUrl!);
} catch (e) {
Expand Down Expand Up @@ -758,14 +764,20 @@ class LanternPlatformService implements LanternCoreService {
required String provider,
required String planId,
required String email,
required String idempotencyKey,
}) async {
if (PlatformUtils.isIOS) {
throw UnimplementedError("This not supported on IOS");
}
try {
final redirectUrl = await _methodChannel.invokeMethod<String>(
'paymentRedirect',
{'provider': provider, 'planId': planId, 'email': email},
{
'provider': provider,
'planId': planId,
'email': email,
'idempotencyKey': idempotencyKey,
},
);
return Right(redirectUrl!);
} catch (e, stackTrace) {
Expand Down
6 changes: 6 additions & 0 deletions lib/lantern/lantern_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -175,18 +175,21 @@ class LanternService implements LanternCoreService {
required BillingType type,
required String planId,
required String email,
required String idempotencyKey,
}) {
if (PlatformUtils.isFFISupported) {
return _ffiService.stipeSubscriptionPaymentRedirect(
type: type,
planId: planId,
email: email,
idempotencyKey: idempotencyKey,
);
}
return _platformService.stipeSubscriptionPaymentRedirect(
type: type,
planId: planId,
email: email,
idempotencyKey: idempotencyKey,
);
}

Expand Down Expand Up @@ -354,18 +357,21 @@ class LanternService implements LanternCoreService {
required String provider,
required String planId,
required String email,
required String idempotencyKey,
}) {
if (PlatformUtils.isFFISupported) {
return _ffiService.paymentRedirect(
provider: provider,
planId: planId,
email: email,
idempotencyKey: idempotencyKey,
);
}
return _platformService.paymentRedirect(
provider: provider,
planId: planId,
email: email,
idempotencyKey: idempotencyKey,
);
}

Expand Down
Loading
Loading