mirror of
https://github.com/bitwarden/server.git
synced 2025-05-27 14:24:56 -05:00
Apple Iap service
This commit is contained in:
parent
d009aa57c0
commit
9e51eaea28
@ -18,6 +18,7 @@ namespace Bit.Core
|
||||
public virtual bool DisableUserRegistration { get; set; }
|
||||
public virtual bool DisableEmailNewDevice { get; set; }
|
||||
public virtual int OrganizationInviteExpirationHours { get; set; } = 120; // 5 days
|
||||
public virtual string AppleIapPassword { get; set; }
|
||||
public virtual InstallationSettings Installation { get; set; } = new InstallationSettings();
|
||||
public virtual BaseServiceUriSettings BaseServiceUri { get; set; } = new BaseServiceUriSettings();
|
||||
public virtual SqlSettings SqlServer { get; set; } = new SqlSettings();
|
||||
|
57
src/Core/Models/Business/AppleReceiptStatus.cs
Normal file
57
src/Core/Models/Business/AppleReceiptStatus.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Billing.Models
|
||||
{
|
||||
public class AppleReceiptStatus
|
||||
{
|
||||
[JsonProperty("status")]
|
||||
public int? Status { get; set; }
|
||||
[JsonProperty("latest_receipt")]
|
||||
public string LatestReceipt { get; set; }
|
||||
[JsonProperty("receipt")]
|
||||
public AppleReceipt Receipt { get; set; }
|
||||
[JsonProperty("latest_receipt_info")]
|
||||
public AppleReceipt LatestReceiptInfo { get; set; }
|
||||
[JsonProperty("latest_expired_receipt_info")]
|
||||
public AppleReceipt LatestExpiredReceiptInfo { get; set; }
|
||||
[JsonProperty("environment")]
|
||||
public string Environment { get; set; }
|
||||
[JsonProperty("auto_renew_status")]
|
||||
public string AutoRenewStatus { get; set; }
|
||||
[JsonProperty("auto_renew_product_id")]
|
||||
public string AutoRenewProductId { get; set; }
|
||||
[JsonProperty("notification_type")]
|
||||
public string NotificationType { get; set; }
|
||||
[JsonProperty("expiration_intent")]
|
||||
public string ExpirationIntent { get; set; }
|
||||
[JsonProperty("is_in_billing_retry_period")]
|
||||
public string IsInBillingRetryPeriod { get; set; }
|
||||
|
||||
public class AppleReceipt
|
||||
{
|
||||
[JsonProperty("purchase_date")]
|
||||
public DateTime PurchaseDate { get; set; }
|
||||
[JsonProperty("original_purchase_date")]
|
||||
public DateTime OriginalPurchaseDate { get; set; }
|
||||
[JsonProperty("expires_date_formatted")]
|
||||
public DateTime ExpiresDate { get; set; }
|
||||
[JsonProperty("bid")]
|
||||
public string Bid { get; set; }
|
||||
[JsonProperty("bvrs")]
|
||||
public string Bvrs { get; set; }
|
||||
[JsonProperty("product_id")]
|
||||
public string ProductId { get; set; }
|
||||
[JsonProperty("item_id")]
|
||||
public string ItemId { get; set; }
|
||||
[JsonProperty("web_order_line_item_id")]
|
||||
public string WebOrderLineItemId { get; set; }
|
||||
[JsonProperty("quantity")]
|
||||
public string Quantity { get; set; }
|
||||
[JsonProperty("transaction_id")]
|
||||
public string TransactionId { get; set; }
|
||||
[JsonProperty("unique_identifier")]
|
||||
public string UniqueIdentifier { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
9
src/Core/Services/IAppleIapService.cs
Normal file
9
src/Core/Services/IAppleIapService.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
public interface IAppleIapService
|
||||
{
|
||||
Task<bool> VerifyReceiptAsync(string receiptData);
|
||||
}
|
||||
}
|
71
src/Core/Services/Implementations/AppleIapService.cs
Normal file
71
src/Core/Services/Implementations/AppleIapService.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Billing.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Bit.Core.Services.Implementations
|
||||
{
|
||||
public class AppleIapService : IAppleIapService
|
||||
{
|
||||
private readonly HttpClient _httpClient = new HttpClient();
|
||||
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ILogger<AppleIapService> _logger;
|
||||
|
||||
public AppleIapService(
|
||||
GlobalSettings globalSettings,
|
||||
ILogger<AppleIapService> logger)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<bool> VerifyReceiptAsync(string receiptData)
|
||||
{
|
||||
var receiptStatus = await GetReceiptStatusAsync(receiptData);
|
||||
return receiptStatus?.Status == 0;
|
||||
}
|
||||
|
||||
private async Task<AppleReceiptStatus> GetReceiptStatusAsync(string receiptData, bool prod = true,
|
||||
int attempt = 0, AppleReceiptStatus lastReceiptStatus = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(attempt > 4)
|
||||
{
|
||||
throw new Exception("Failed verifying Apple IAP after too many attempts. Last attempt status: " +
|
||||
lastReceiptStatus?.Status ?? "null");
|
||||
}
|
||||
|
||||
var url = string.Format("https://{0}.itunes.apple.com/verifyReceipt", prod ? "buy" : "sandbox");
|
||||
var json = new JObject(new JProperty("receipt-data", receiptData),
|
||||
new JProperty("password", _globalSettings.AppleIapPassword)).ToString();
|
||||
|
||||
var response = await _httpClient.PostAsync(url, new StringContent(json));
|
||||
if(response.IsSuccessStatusCode)
|
||||
{
|
||||
var responseJson = await response.Content.ReadAsStringAsync();
|
||||
var receiptStatus = JsonConvert.DeserializeObject<AppleReceiptStatus>(responseJson);
|
||||
if(receiptStatus.Status == 21007)
|
||||
{
|
||||
return await GetReceiptStatusAsync(receiptData, false, attempt + 1, receiptStatus);
|
||||
}
|
||||
else if(receiptStatus.Status == 21005)
|
||||
{
|
||||
await Task.Delay(2000);
|
||||
return await GetReceiptStatusAsync(receiptData, prod, attempt + 1, receiptStatus);
|
||||
}
|
||||
return receiptStatus;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
_logger.LogWarning(e, "Error verifying Apple IAP receipt.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user