Client response QR code size reduced. Cloud provider support.

This commit is contained in:
Andrey Shabarshov 2022-03-26 13:31:17 +00:00
parent 1ab2706a53
commit 5c041da318
10 changed files with 132 additions and 91 deletions

View File

@ -16,7 +16,7 @@
/// Convert ClientToMerchantResponse to string to be used as QR Code source (along with client signature)
/// </summary>
/// <returns> Converted string</returns>
public string AsQRCodeString() => $"{AsDataForSignature()}|{ClientSignature}";
public string AsQRCodeString() => $"{ClientId}|{TimeStampUTC:O}|{ClientSignature}";
public string AsDataForSignature() => $"{ClientId}|{TimeStampUTC:O}|{MerchantRequest.AsQRCodeString()}";
@ -31,15 +31,14 @@
var s = input.Split('|');
if (s.Length < 3)
{
throw new ApplicationException("Expected 3 or more elements");
throw new ApplicationException($"Expected 3 or more elements but got {s.Length}");
}
var res = new ClientToMerchantResponse()
{
MerchantRequest = MerchantToClientRequest.FromString(string.Join("|", s.Skip(2))),
ClientId = s[0],
TimeStampUTC = DateTime.ParseExact(s[1], "O", null),
ClientSignature = s[3]
ClientSignature = s[2]
};
return res;

View File

@ -33,9 +33,9 @@ namespace QRBee.Core.Data
public static MerchantToClientRequest FromString(string input)
{
var s = input.Split('|');
if (s.Length != 6)
if (s.Length < 6)
{
throw new ApplicationException("Expected 6 elements");
throw new ApplicationException($"Expected 6 elements but got {s.Length}");
}
var res = new MerchantToClientRequest

View File

@ -13,18 +13,6 @@
/// Convert PaymentRequest to string
/// </summary>
/// <returns>Converted string</returns>
public string AsString() => ClientResponse.AsQRCodeString();
public static PaymentRequest FromString(string input)
{
if (string.IsNullOrWhiteSpace(input))
{
throw new ApplicationException("The input is wrong!");
}
//doesn't work
var response = ClientToMerchantResponse.FromString(input);
return new PaymentRequest(){ClientResponse = response};
}
public string AsString() => $"{ClientResponse.AsDataForSignature()}|{ClientResponse.ClientSignature}";
}
}

View File

@ -14,7 +14,7 @@ namespace QRBee.Droid
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "12.2.0.155")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "12.1.0.11")]
public partial class Resource
{

View File

@ -9,7 +9,13 @@ namespace QRBee.Droid.Services
{
internal class LocalSettings : ILocalSettings
{
// Use https://10.0.2.2:7000 if you are running in emulator and API server on localhost
#if false
public string QRBeeApiUrl => "https://10.0.2.2:7000";
#else
public string QRBeeApiUrl => "https://qrbee-api.azurewebsites.net/";
#endif
public async Task SaveSettings(Settings settings)
{

View File

@ -17,6 +17,8 @@ namespace QRBee.ViewModels
private decimal _amount;
private string _qrCode;
private MerchantToClientRequest _lastRequest;
public Command GenerateQrCommand { get; }
public Command ScanCommand{ get; }
@ -42,7 +44,13 @@ namespace QRBee.ViewModels
var client = new HttpClient(GetInsecureHandler());
var service = new Core.Client.Client(_settings.QRBeeApiUrl, client);
var paymentRequest = PaymentRequest.FromString(result);
var clientResponse = ClientToMerchantResponse.FromString(result);
clientResponse.MerchantRequest = _lastRequest;
var paymentRequest = new PaymentRequest
{
ClientResponse = clientResponse
};
//QrCode = null;
IsVisible = false;
@ -152,7 +160,7 @@ namespace QRBee.ViewModels
}
else
{
var trans = new MerchantToClientRequest
var request = new MerchantToClientRequest
{
MerchantId = _settings.LoadSettings().ClientId,
MerchantTransactionId = Guid.NewGuid().ToString("D"),
@ -161,10 +169,12 @@ namespace QRBee.ViewModels
TimeStampUTC = DateTime.UtcNow
};
var merchantSignature = _securityService.Sign(Encoding.UTF8.GetBytes(trans.AsDataForSignature()));
trans.MerchantSignature = Convert.ToBase64String(merchantSignature);
var merchantSignature = _securityService.Sign(Encoding.UTF8.GetBytes(request.AsDataForSignature()));
request.MerchantSignature = Convert.ToBase64String(merchantSignature);
QrCode = trans.AsQRCodeString();
_lastRequest = request;
QrCode = request.AsQRCodeString();
IsVisible = true;
}

View File

@ -124,7 +124,7 @@ namespace QRBee.ViewModels
await _settings.SaveSettings(settings);
//if (!_privateKeyHandler.Exists())
if (!_privateKeyHandler.Exists())
{
_privateKeyHandler.GeneratePrivateKey(settings.Name);
}

View File

@ -7,6 +7,7 @@ namespace QRBee.Api.Services.Database
[BsonId] public string? Id { get; set; }
public string? ClientId { get; set; }
public string? Email { get; set; }
public string? Certificate { get; set; }
public DateTime ServerTimeStamp { get; set; }
}

View File

@ -121,7 +121,7 @@ namespace QRBee.Api.Services.Database
throw new ApplicationException("Info Id is null.");
}
var certificate = await TryGetCertificateInfo(info.Id);
var certificate = await TryGetCertificateInfoByEmail(info.Email ?? throw new ApplicationException("Email is not set"));
if (certificate == null)
{
@ -130,7 +130,10 @@ namespace QRBee.Api.Services.Database
return;
}
_logger.LogInformation($"Found certificate with ID: {info.Id}");
await collection.DeleteOneAsync($"{{ _id: \"{certificate.Id}\" }}");
await collection.ReplaceOneAsync($"{{ _id: \"{info.Id}\" }}", info, new ReplaceOptions() { IsUpsert = true });
_logger.LogInformation($"Found certificate with old ID: {certificate.Id} and replaced with new ID: {info.Id}");
}
@ -151,6 +154,23 @@ namespace QRBee.Api.Services.Database
return cursor.Current.FirstOrDefault();
}
/// <summary>
/// Try to find if the Certificate already exists in the database
/// </summary>
/// <param name="email">parameter by which to find CertificateInfo</param>
/// <returns>null if certificate doesn't exist or CertificateInfo</returns>
private async Task<CertificateInfo?> TryGetCertificateInfoByEmail(string email)
{
var collection = _database.GetCollection<CertificateInfo>("Certificates");
using var cursor = await collection.FindAsync($"{{ Email: \"{email}\" }}");
if (!await cursor.MoveNextAsync())
{
return null;
}
return cursor.Current.FirstOrDefault();
}
public async Task<CertificateInfo> GetCertificateInfoByCertificateId(string id)
{
var certificate = await TryGetCertificateInfo(id);

View File

@ -57,7 +57,7 @@ namespace QRBee.Api.Services
var clientCertificate = _securityService.CreateCertificate(clientId,bytes);
var convertedClientCertificate = Convert(clientCertificate, clientId);
var convertedClientCertificate = Convert(clientCertificate, clientId,request.Email);
await _storage.InsertCertificate(convertedClientCertificate);
return new RegistrationResponse
@ -125,6 +125,8 @@ namespace QRBee.Api.Services
}
public async Task<PaymentResponse> Pay(PaymentRequest value)
{
try
{
//1. Check payment request parameters for validity
ValidateTransaction(value);
@ -175,13 +177,27 @@ namespace QRBee.Api.Services
await _storage.UpdateTransaction(info);
//10. Make response for merchant
var response = MakePaymentResponse(value, info.TransactionId ?? "", info.Status==TransactionInfo.TransactionStatus.Succeeded, info.RejectReason);
return response;
}
catch (Exception e)
{
var response = MakePaymentResponse(value, "", false, e.Message);
return response;
}
}
private PaymentResponse MakePaymentResponse(PaymentRequest value, string transactionId, bool result = true, string? errorMessage = null)
{
var response = new PaymentResponse
{
ServerTransactionId = info.TransactionId,
ServerTransactionId = transactionId,
PaymentRequest = value,
ServerTimeStampUTC = DateTime.UtcNow,
Success = res.Success,
RejectReason = res.ErrorMessage,
Success = result,
RejectReason = errorMessage,
};
var signature = _securityService.Sign(Encoding.UTF8.GetBytes(response.AsDataForSignature()));
@ -224,7 +240,7 @@ namespace QRBee.Api.Services
if (!check)
{
throw new ApplicationException($"Signature is incorrect for Id: {id}.");
throw new ApplicationException($"Signature is incorrect for Id: {id}. Data: {data}");
}
}
@ -309,13 +325,14 @@ namespace QRBee.Api.Services
return new TransactionInfo(request, DateTime.UtcNow);
}
private CertificateInfo Convert(X509Certificate2 certificate, string clientId)
private CertificateInfo Convert(X509Certificate2 certificate, string clientId, string email)
{
var convertedCertificate = _securityService.Serialize(certificate);
return new CertificateInfo
{
Id = certificate.SerialNumber,
ClientId = clientId,
Email = email,
Certificate = convertedCertificate,
ServerTimeStamp = DateTime.UtcNow
};