1
0
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:
Kyle Spearrin 2019-09-16 09:22:22 -04:00
parent d009aa57c0
commit 9e51eaea28
4 changed files with 138 additions and 0 deletions

View File

@ -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();

View 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; }
}
}
}

View File

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Bit.Core.Services
{
public interface IAppleIapService
{
Task<bool> VerifyReceiptAsync(string receiptData);
}
}

View 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;
}
}
}