mirror of
https://github.com/bitwarden/server.git
synced 2025-02-28 03:51:23 +01:00
apple iap service
This commit is contained in:
parent
7a2e86c2ba
commit
8290ddbb94
@ -1,9 +1,15 @@
|
|||||||
using System.Threading.Tasks;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Bit.Core.Services
|
namespace Bit.Core.Services
|
||||||
{
|
{
|
||||||
public interface IAppleIapService
|
public interface IAppleIapService
|
||||||
{
|
{
|
||||||
Task<bool> VerifyReceiptAsync(string receiptData);
|
Task<bool> VerifyReceiptAsync(string receiptData);
|
||||||
|
Task<string> GetVerifiedLastTransactionIdAsync(string receiptData);
|
||||||
|
Task<DateTime?> GetVerifiedLastExpiresDateAsync(string receiptData);
|
||||||
|
string HashReceipt(string receiptData);
|
||||||
|
Task SaveReceiptAsync(string receiptData);
|
||||||
|
Task<string> GetReceiptAsync(string hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Billing.Models;
|
using Bit.Billing.Models;
|
||||||
|
using Bit.Core.Repositories;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
@ -13,20 +18,79 @@ namespace Bit.Core.Services.Implementations
|
|||||||
private readonly HttpClient _httpClient = new HttpClient();
|
private readonly HttpClient _httpClient = new HttpClient();
|
||||||
|
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
private readonly IHostingEnvironment _hostingEnvironment;
|
||||||
|
private readonly IMetaDataRespository _metaDataRespository;
|
||||||
private readonly ILogger<AppleIapService> _logger;
|
private readonly ILogger<AppleIapService> _logger;
|
||||||
|
|
||||||
public AppleIapService(
|
public AppleIapService(
|
||||||
GlobalSettings globalSettings,
|
GlobalSettings globalSettings,
|
||||||
|
IHostingEnvironment hostingEnvironment,
|
||||||
|
IMetaDataRespository metaDataRespository,
|
||||||
ILogger<AppleIapService> logger)
|
ILogger<AppleIapService> logger)
|
||||||
{
|
{
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
|
_hostingEnvironment = hostingEnvironment;
|
||||||
|
_metaDataRespository = metaDataRespository;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> VerifyReceiptAsync(string receiptData)
|
public async Task<bool> VerifyReceiptAsync(string receiptData)
|
||||||
|
{
|
||||||
|
var receiptStatus = await GetVerifiedReceiptStatusAsync(receiptData);
|
||||||
|
return receiptStatus != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetVerifiedLastTransactionIdAsync(string receiptData)
|
||||||
|
{
|
||||||
|
var receiptStatus = await GetVerifiedReceiptStatusAsync(receiptData);
|
||||||
|
return receiptStatus?.LatestReceiptInfo?.LastOrDefault()?.TransactionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<DateTime?> GetVerifiedLastExpiresDateAsync(string receiptData)
|
||||||
|
{
|
||||||
|
var receiptStatus = await GetVerifiedReceiptStatusAsync(receiptData);
|
||||||
|
return receiptStatus?.LatestReceiptInfo?.LastOrDefault()?.ExpiresDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string HashReceipt(string receiptData)
|
||||||
|
{
|
||||||
|
using(var sha256 = SHA256.Create())
|
||||||
|
{
|
||||||
|
var hash = sha256.ComputeHash(Convert.FromBase64String(receiptData));
|
||||||
|
return BitConverter.ToString(hash).Replace("-", string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveReceiptAsync(string receiptData)
|
||||||
|
{
|
||||||
|
var hash = HashReceipt(receiptData);
|
||||||
|
await _metaDataRespository.UpsertAsync("appleReceipt", hash,
|
||||||
|
new KeyValuePair<string, string>("data", receiptData));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetReceiptAsync(string hash)
|
||||||
|
{
|
||||||
|
var receipt = await _metaDataRespository.GetAsync("appleReceipt", hash);
|
||||||
|
return receipt != null && receipt.ContainsKey("data") ? receipt["data"] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<AppleReceiptStatus> GetVerifiedReceiptStatusAsync(string receiptData)
|
||||||
{
|
{
|
||||||
var receiptStatus = await GetReceiptStatusAsync(receiptData);
|
var receiptStatus = await GetReceiptStatusAsync(receiptData);
|
||||||
return receiptStatus?.Status == 0;
|
if(receiptStatus?.Status != 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var validEnvironment = (!_hostingEnvironment.IsProduction() && receiptStatus.Environment == "Sandbox") ||
|
||||||
|
(_hostingEnvironment.IsProduction() && receiptStatus.Environment != "Sandbox");
|
||||||
|
var validProductBundle = receiptStatus.Receipt.BundleId == "com.bitwarden.desktop" ||
|
||||||
|
receiptStatus.Receipt.BundleId == "com.8bit.bitwarden";
|
||||||
|
var validProduct = receiptStatus.LatestReceiptInfo.LastOrDefault()?.ProductId == "premium_annually";
|
||||||
|
if(validEnvironment && validProductBundle && validProduct)
|
||||||
|
{
|
||||||
|
return receiptStatus;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<AppleReceiptStatus> GetReceiptStatusAsync(string receiptData, bool prod = true,
|
private async Task<AppleReceiptStatus> GetReceiptStatusAsync(string receiptData, bool prod = true,
|
||||||
|
Loading…
Reference in New Issue
Block a user