patbef-ServiceOutside/ServiceOutside/Controllers/ResultsController.cs

955 lines
49 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.AspNetCore.Mvc;
using ServiceShared.Database;
using ServiceShared.Models.Request;
using ServiceOutside.Service;
using ServiceShared.Crypto;
using ServiceShared.Models.Response;
using ServiceShared.Models.Response.Exception;
using ServiceShared;
using System.Text.Json;
using ServiceShared.Models.Database;
namespace ServiceOutside.Controllers
{
[ApiController]
[Route("[controller]")]
public class ResultsController : BaseController
{
private readonly ServiceShared.Database.Controllers.Results dbResults;
private readonly ServiceShared.Database.Controllers.Traces dbTraces;
private readonly int MaxOpenedRequest = 10;
private readonly int MaxTryNotFoundResults = 2;
/// <summary>
/// Constructor of ResultsController, that getting instance of configuration, dbcontext and KeyPair
/// </summary>
/// <param name="configuration">Configuration from appsettings.json</param>
/// <param name="dbContext">DbContext</param>
/// <param name="keyPair">Server Curve25519 KeyPair</param>
public ResultsController(IConfiguration configuration, DbContext dbContext, KeyPair keyPair) : base(configuration, dbContext, keyPair)
{
this.dbResults = new ServiceShared.Database.Controllers.Results(dbContext);
this.dbTraces = new ServiceShared.Database.Controllers.Traces(dbContext);
MaxOpenedRequest = configuration.GetValue<int>("MaxOpenedRequest", 10);
MaxTryNotFoundResults = configuration.GetValue<int>("MaxTryNotFoundResults", 2);
Log.Debug("MaxOpenedRequest: " + MaxOpenedRequest + ", MaxTryNotFoundResults: " + MaxTryNotFoundResults);
}
/// <summary>
/// Subscribe request from the mobile clients
/// Subscribe must contain following data: pgs, device_token, udid, public key, device_type, verificator_hash
/// PGS: SHA512 hash from ZIP + BIRTHDAY + SAMPLEID
/// PGS_HASH: AES Encrypted PGS, that can be decrypted by inside service
/// DeviceToken: Token for push notifications
/// UDID: Unique device id
/// Public Key: Public Key of the client
/// Device Type: Type of the client (IOS or ANDROID)
/// Verificator_hash: HMAC Hash, that was created by master password of patient
///
/// RESPONSE: 1. PGS still not exists in the db and will be registred as new one
/// The Subscribe request will be redirected to the InsideService
/// to create a register ack log file
///
/// 2. PGS already exists in the db and sends AlreadySubscribtedException back
///
/// IMPORTANT: One device can have max. 10 opened request at the same time
/// </summary>
/// <param name="encrypted">Encrypted request, that contains Subscribe object</param>
/// <returns>Encrypted response, that contains eather exceptions or success status</returns>
[Route("subscribe")]
[HttpPost]
public JsonResult Subscribe(EncryptedRequest encrypted)
{
EncryptedResponse response = null;
try
{
this.Debug(encrypted, "REQUEST");
if (encrypted.ValidSignature(this.GetClientSharedKey(), this.GetClientSignature(), this.GetClientSignatureKey()))
{
Subscribe subscribe = encrypted.Decrypt<Subscribe>(this.GetClientSharedKey());
if (subscribe != null)
{
ResponseException validationException = ServiceShared.Models.Request.Subscribe.Validate(subscribe);
if (validationException != null)
{
response = new EncryptedResponse("ResponseException", validationException, this.GetClientSharedKey());
}
else if(string.IsNullOrEmpty(subscribe.pgs_hash))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("pgs_hash"), this.GetClientSharedKey());
}
else
{
/** for first subscription pin must exist **/
if(!this.dbResults.DeviceExists(subscribe.udid) && (string.IsNullOrEmpty(subscribe.pin) || subscribe.pin.Length != 5))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("pin"), this.GetClientSharedKey());
}
else
{
ServiceShared.Models.Database.Results dbResults = this.dbResults.GetResults(subscribe.pgs, subscribe.udid);
// Mindmap W-1-1 -- Got a new subscribe
if (dbResults == null)
{
//check if pgs is unique
List<ServiceShared.Models.Database.Results> pgsResults = this.dbResults.GetResults(subscribe.pgs);
// PGS already subscripted
if (pgsResults != null && pgsResults.Count > 0)
{
response = new EncryptedResponse("ResponseException", new AlreadySubscribtedException(), this.GetClientSharedKey());
}
else
{
// first subscription
ServiceShared.Models.Database.Results results = subscribe.ToResults();
// Mindmap W-1-5 - max opened requests(not pickedup) limit by the same device at the same time has been reached
if (this.dbResults.CountOpenedRequest(results) >= MaxOpenedRequest)
{
response = new EncryptedResponse("ResponseException", new MaxOpenedRequestLimitException(), this.GetClientSharedKey());
}
// Mindmap W-1-2 - Create a new results from the subscribe request
else if (this.dbResults.Create(results))
{
// Mindmap W-1-3 - Subscribe successfully send notification to the inside service
response = new EncryptedResponse("success", null, this.GetClientSharedKey());
ServiceInside.Subscribe(subscribe);
Log.Trace("subscribted", results.PGS, results.UDID);
}
else
{
// Mindmap W-1-4 - Some unknown exception occured, results could not be created
Log.Critical(new Exception("could not create results from subscribe(request) in the database (pgs=" + results.PGS + ", udid=" + results.UDID), "ServiceOutside.Controllers.ResultsController", "Subscribe(EncryptedRequest)");
response = new EncryptedResponse("ResponseException", new UnknownException(), this.GetClientSharedKey());
}
}
}
else
{
response = new EncryptedResponse("ResponseException", new AlreadySubscribtedException(), this.GetClientSharedKey());
}
}
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidRequestException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
catch (Exception ex)
{
Log.Critical(ex, "ServiceOutside.Controllers.ResultsController", "Subscribe(EncryptedRequest)");
}
this.Debug(response, "RESPONSE");
return new JsonResult(response);
}
/// <summary>
/// Unsubscribe request from the mobile clients
/// Subscribe must contain following data: pgs, device_token, udid, public key, device_type, verificator_hash
///
/// IMPORTANT: User can unsubscribe the pgs request only by authorized verificator_hash and
/// on the same device, where the request has been registred on
/// </summary>
/// <param name="encrypted">Encrypted request, that contains Subscribe object</param>
/// <returns>Encrypted response, that contains eather exceptions or success status</returns>
[Route("unsubscribe")]
[HttpPost]
public JsonResult Unsubscribe(EncryptedRequest encrypted)
{
EncryptedResponse response = null;
try
{
this.Debug(encrypted, "REQUEST");
if (encrypted.ValidSignature(this.GetClientSharedKey(), this.GetClientSignature(), this.GetClientSignatureKey()))
{
Subscribe subscribe = encrypted.Decrypt<Subscribe>(this.GetClientSharedKey());
if (subscribe != null)
{
ResponseException validationException = ServiceShared.Models.Request.Subscribe.Validate(subscribe);
if (validationException != null)
{
response = new EncryptedResponse("ResponseException", validationException, this.GetClientSharedKey());
}
else
{
ServiceShared.Models.Database.Results dbResults = this.dbResults.GetResults(subscribe.pgs, subscribe.udid);
if (dbResults != null &&
dbResults.PGS == subscribe.pgs &&
dbResults.UDID == subscribe.udid &&
dbResults.DeviceType == subscribe.device_type &&
dbResults.VerificationHash == subscribe.verificator_hash)
{
subscribe.pgs_hash = dbResults.PGS_HASH;
if (this.dbResults.Delete(subscribe.pgs, subscribe.udid))
{
response = new EncryptedResponse("success", null, this.GetClientSharedKey());
ServiceInside.Unsubscribe(subscribe);
Log.Trace("unsubscripted", dbResults.PGS, dbResults.UDID);
}
else
{
Log.Critical(new Exception("Could not delete results from the database, PGS=" + dbResults.PGS + ", UDID=" + dbResults.UDID + ", DeviceType=" + dbResults.DeviceType.ToString() + ", VerificationHash=" + dbResults.VerificationHash), "ServiceOutside.Controllers.ResultsController", "Unsubscribe(EncryptedRequest)");
response = new EncryptedResponse("ResponseException", new UnknownException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new NotAuthorizedException(), this.GetClientSharedKey());
}
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
catch (Exception ex)
{
Log.Critical(ex, "ServiceOutside.Controllers.ResultsController", "Unsubscribe(EncryptedRequest)");
}
this.Debug(response, "RESPONSE");
return new JsonResult(response);
}
/// <summary>
/// Updates verificator_hash for the udid
/// </summary>
/// <param name="encrypted">Encrypted request, that contains ChangeVerificatorHash request</param>
/// <returns>Encrypted response, that contains eather exceptions or success status</returns>
[Route("support")]
[HttpPost]
public JsonResult Support(EncryptedRequest encrypted)
{
EncryptedResponse response = null;
try
{
this.Debug(encrypted, "REQUEST");
if(encrypted.ValidSignature(this.GetClientSharedKey(), this.GetClientSignature(), this.GetClientSignatureKey()))
{
ServiceShared.Models.Request.Support support = encrypted.Decrypt<ServiceShared.Models.Request.Support>(this.GetClientSharedKey());
if (support != null)
{
if (string.IsNullOrEmpty(support.udid))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("udid"), this.GetClientSharedKey());
}
else if (support.udid.Length < 10 || support.udid.Length > 64)
{
response = new EncryptedResponse("ResponseException", new InvalidArgumentException("udid", "wrong length"), this.GetClientSharedKey());
}
else
{
if(support.delete_device)
{
DeleteDevice deleteDevice = new DeleteDevice();
deleteDevice.udid = support.udid;
deleteDevice.verificator_hash = support.verificator_hash;
response = ServiceInside.DeleteDevice(deleteDevice);
if (response != null && response.descriptor.ToLower() == "success")
{
response = new EncryptedResponse("Success", null, this.GetClientSharedKey());
string body = "Thema: " + support.topic + "\r\n" +
"E-Mail des Absenders: " + support.email + "\r\n" +
"Nachricht: " + support.text;
this.dbTraces.DeleteDevice(support.udid);
if (!Mail.SendCustomerRequest(support.topic, body))
{
Log.Critical(new Exception("Could not send customer delete device mail"), "ServiceOutside.Controllers.ResultsController", "DeleteDevice(EncryptedRequest)");
}
}
else
{
Log.Critical(new Exception("Could not delete results for udid in the database, UDID=" + deleteDevice.udid + ", VerificationHash=" + deleteDevice.verificator_hash), "ServiceOutside.Controllers.ResultsController", "DeleteDevice(EncryptedRequest)");
response = new EncryptedResponse("ResponseException", new UnknownException(), this.GetClientSharedKey());
}
}
else
{
string body = "Thema: " + support.topic + "\r\n" +
"E-Mail des Absenders: " + support.email + "\r\n" +
"Nachricht: " + support.text;
if(Mail.SendCustomerRequest(support.topic, body))
{
response = new EncryptedResponse("Success", null, this.GetClientSharedKey());
}
else
{
Log.Critical(new Exception("Could not send customer mail"), "ServiceOutside.Controllers.ResultsController", "SendCustomerRequest(EncryptedRequest)");
response = new EncryptedResponse("ResponseException", new UnknownException(), this.GetClientSharedKey());
}
}
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
catch (Exception ex)
{
Log.Critical(ex, "ServiceOutside.Controllers.ResultsController", "DeleteDevice(EncryptedRequest)");
}
this.Debug(response, "RESPONSE");
return new JsonResult(response);
}
/// <summary>
/// Updates verificator_hash for the udid
/// </summary>
/// <param name="encrypted">Encrypted request, that contains ChangeVerificatorHash request</param>
/// <returns>Encrypted response, that contains eather exceptions or success status</returns>
[Route("update_verificator_hash")]
[HttpPost]
public JsonResult UpdateVerificatorHash(EncryptedRequest encrypted)
{
EncryptedResponse response = null;
try
{
this.Debug(encrypted, "REQUEST");
if (encrypted.ValidSignature(this.GetClientSharedKey(), this.GetClientSignature(), this.GetClientSignatureKey()))
{
ChangeVerificatorHash changeVerificatorHash = encrypted.Decrypt<ChangeVerificatorHash>(this.GetClientSharedKey());
if (changeVerificatorHash != null)
{
if (string.IsNullOrEmpty(changeVerificatorHash.udid))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("udid"), this.GetClientSharedKey());
}
else if (changeVerificatorHash.udid.Length < 10 || changeVerificatorHash.udid.Length > 64)
{
response = new EncryptedResponse("ResponseException", new InvalidArgumentException("udid", "wrong length"), this.GetClientSharedKey());
}
if (string.IsNullOrEmpty(changeVerificatorHash.old_verificator_hash))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("old_verificator_hash"), this.GetClientSharedKey());
}
else if (changeVerificatorHash.old_verificator_hash.Length != 128)
{
response = new EncryptedResponse("ResponseException", new InvalidArgumentException("old_verificator_hash", "wrong length"), this.GetClientSharedKey());
}
if (string.IsNullOrEmpty(changeVerificatorHash.new_verificator_hash))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("new_verificator_hash"), this.GetClientSharedKey());
}
else if (changeVerificatorHash.new_verificator_hash.Length != 128)
{
response = new EncryptedResponse("ResponseException", new InvalidArgumentException("new_verificator_hash", "wrong length"), this.GetClientSharedKey());
}
if (string.IsNullOrEmpty(changeVerificatorHash.pin))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("pin"), this.GetClientSharedKey());
}
else if (changeVerificatorHash.pin.Length != 5)
{
response = new EncryptedResponse("ResponseException", new InvalidArgumentException("pin", "wrong length"), this.GetClientSharedKey());
}
else
{
if (dbResults.UpdateVerificatorHash(changeVerificatorHash.udid, changeVerificatorHash.pin, changeVerificatorHash.old_verificator_hash, changeVerificatorHash.new_verificator_hash))
{
response = new EncryptedResponse("Success", null, this.GetClientSharedKey());
}
else
{
Log.Critical(new Exception("Could not update device verificator_hash in the database, UDID=" + changeVerificatorHash.udid + ", OldVerificationHash=" + changeVerificatorHash.old_verificator_hash + ", NewVerificationHash=" + changeVerificatorHash.new_verificator_hash), "ServiceOutside.Controllers.ResultsController", "UpdateVerificatorHash(EncryptedRequest)");
response = new EncryptedResponse("ResponseException", new NotAuthorizedException(), this.GetClientSharedKey());
}
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
catch (Exception ex)
{
Log.Critical(ex, "ServiceOutside.Controllers.ResultsController", "UpdateVerificatorHash(EncryptedRequest)");
}
this.Debug(response, "RESPONSE");
return new JsonResult(response);
}
/// <summary>
/// Updates DeviceToken for the udid (PUSH-Notification)
/// </summary>
/// <param name="encrypted">Encrypted request, that contains DeviceToken request</param>
/// <returns>Encrypted response, that contains eather exceptions or success status</returns>
[Route("update_token")]
[HttpPost]
public JsonResult DeviceToken(EncryptedRequest encrypted)
{
EncryptedResponse response = null;
try
{
this.Debug(encrypted, "REQUEST");
if (encrypted.ValidSignature(this.GetClientSharedKey(), this.GetClientSignature(), this.GetClientSignatureKey()))
{
DeviceToken deviceToken = encrypted.Decrypt<DeviceToken>(this.GetClientSharedKey());
if (deviceToken != null)
{
if (string.IsNullOrEmpty(deviceToken.udid))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("udid"), this.GetClientSharedKey());
}
else if (string.IsNullOrEmpty(deviceToken.device_token))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("device_token"), this.GetClientSharedKey());
}
if (string.IsNullOrEmpty(deviceToken.verificator_hash))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("verificator_hash"), this.GetClientSharedKey());
}
else if (deviceToken.verificator_hash.Length != 128)
{
response = new EncryptedResponse("ResponseException", new InvalidArgumentException("verificator_hash", "wrong length"), this.GetClientSharedKey());
}
else
{
if (dbResults.UpdateDeviceToken(deviceToken.udid, deviceToken.verificator_hash, deviceToken.device_token))
{
response = new EncryptedResponse("Success", null, this.GetClientSharedKey());
}
else
{
Log.Critical(new Exception("Could not update device token in the database, UDID=" + deviceToken.udid + ", VerificationHash=" + deviceToken.verificator_hash + ", DeviceToken=" + deviceToken.device_token), "ServiceOutside.Controllers.ResultsController", "DeviceToken(EncryptedRequest)");
response = new EncryptedResponse("ResponseException", new NotAuthorizedException(), this.GetClientSharedKey());
}
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
catch (Exception ex)
{
Log.Critical(ex, "ServiceOutside.Controllers.ResultsController", "UpdateVerificatorHash(EncryptedRequest)");
}
this.Debug(response, "RESPONSE");
return new JsonResult(response);
}
/// <summary>
/// Returns Status of results for the mobile clients
/// </summary>
// <param name="encrypted">Encrypted request, that contains Subscribe object</param>
/// <returns>Encrypted response, that contains eather exceptions or status object</returns>
[Route("status")]
[HttpPost]
public JsonResult Status(EncryptedRequest encrypted)
{
EncryptedResponse response = null;
try
{
this.Debug(encrypted, "REQUEST");
if (encrypted.ValidSignature(this.GetClientSharedKey(), this.GetClientSignature(), this.GetClientSignatureKey()))
{
Subscribe subscribe = encrypted.Decrypt<Subscribe>(this.GetClientSharedKey());
if (subscribe != null)
{
ResponseException validationException = ServiceShared.Models.Request.Subscribe.Validate(subscribe);
if (validationException != null)
{
response = new EncryptedResponse("ResponseException", validationException, this.GetClientSharedKey());
}
else
{
ServiceShared.Models.Database.Results dbResults = this.dbResults.GetResults(subscribe.pgs, subscribe.udid);
if (dbResults != null)
{
if(dbResults.PGS == subscribe.pgs &&
dbResults.UDID == subscribe.udid &&
dbResults.DeviceType == subscribe.device_type &&
dbResults.VerificationHash == subscribe.verificator_hash)
{
response = new EncryptedResponse("Status", new ServiceShared.Models.Database.Status(dbResults), this.GetClientSharedKey());
}
else
{
response = new EncryptedResponse("ResponseException", new NotAuthorizedException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new NotAvailableException(), this.GetClientSharedKey());
}
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
catch (Exception ex)
{
Log.Critical(ex, "ServiceOutside.Controllers.ResultsController", "Status(EncryptedRequest)");
}
this.Debug(response, "RESPONSE");
return new JsonResult(response);
}
/// <summary>
/// Returns all of opened(still not pickedup) pgs´s requests for the mobile clients
/// </summary>
// <param name="encrypted">Encrypted request, that contains Subscribe object</param>
/// <returns>Encrypted response, that contains eather exceptions or list of status objects</returns>
[Route("opened")]
[HttpPost]
public JsonResult GetOpened(EncryptedRequest encrypted)
{
EncryptedResponse response = null;
try
{
this.Debug(encrypted, "REQUEST");
if (encrypted.ValidSignature(this.GetClientSharedKey(), this.GetClientSignature(), this.GetClientSignatureKey()))
{
GetOpened openedRequest = encrypted.Decrypt<GetOpened>(this.GetClientSharedKey());
if (openedRequest != null)
{
if (string.IsNullOrEmpty(openedRequest.udid))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("udid"), this.GetClientSharedKey());
}
else if(string.IsNullOrEmpty(openedRequest.verificator_hash))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("verificator_hash"), this.GetClientSharedKey());
}
else
{
List<ServiceShared.Models.Database.Status> dbStatus = this.dbResults.GetOpened(openedRequest.udid, openedRequest.verificator_hash, MaxOpenedRequest, MaxTryNotFoundResults);
if(dbStatus == null)
{
dbStatus = new List<ServiceShared.Models.Database.Status>();
}
response = new EncryptedResponse("List<Status>", dbStatus, this.GetClientSharedKey());
if(dbStatus.Count > 0)
{
/** get not found and rejected status to remove them after response from the database **/
List<ServiceShared.Models.Database.Status> toRemoveStatuses = dbStatus.FindAll(m => !string.IsNullOrEmpty(m.results_status) && (m.results_status.ToLower() == "not_found" || m.results_status.ToLower() == "rejected"));
if(toRemoveStatuses != null)
{
this.dbResults.RemoveStatuses(toRemoveStatuses);
}
}
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
catch (Exception ex)
{
Log.Critical(ex, "ServiceOutside.Controllers.ResultsController", "GetOpened(EncryptedRequest)");
}
this.Debug(response, "RESPONSE");
return new JsonResult(response);
}
/// <summary>
/// Download request from the mobile clients for the encrypted results
/// Subscribe must contain following data: pgs, udid, public key, device_type, verificator_hash
/// PGS: SHA512 hash from ZIP + BIRTHDAY + SAMPLEID
/// UDID: Unique device id
/// Public Key: Public Key of the client
/// Device Type: Type of the client (IOS or ANDROID)
/// Verificator_hash: HMAC Hash, that was created by master password of patient
///
/// RESPONSE: 1. Check if request is authorized
/// a: Valid PGS
/// b: It´s same Device, where the pgs was registred before (UDID & DeviceType)
/// c: Public Key from client is available for encryption
/// d: Valid verficator_hash, that was created by patient
///
/// 2. Check if results is available and is already encrypted by inside service
/// 3. Pickup encrypted file from inside service and send to the client
/// 4. Client has to decrypt first the private key of used public key by his master password
/// 5. After successfully decryption of private key user can decrypt the downloaded encrypted file by private key
/// 6. Each time if user opens the results, he has too confirm it by master password(uo 4. Steps has to be repeated)
/// </summary>
/// <param name="encrypted">Encrypted request, that contains Subscribe object</param>
/// <returns>Encrypted response, that contains eather encrypted content or exception</returns>
[Route("download")]
[HttpPost]
public JsonResult Download(EncryptedRequest encrypted)
{
EncryptedResponse response = null;
try
{
this.Debug(encrypted, "REQUEST");
if (encrypted.ValidSignature(this.GetClientSharedKey(), this.GetClientSignature(), this.GetClientSignatureKey()))
{
Subscribe subscribe = encrypted.Decrypt<Subscribe>(this.GetClientSharedKey());
if (subscribe != null)
{
ResponseException validationException = ServiceShared.Models.Request.Subscribe.Validate(subscribe);
if (validationException != null)
{
response = new EncryptedResponse("ResponseException", validationException, this.GetClientSharedKey());
}
else
{
ServiceShared.Models.Database.Results dbResults = this.dbResults.GetResults(subscribe.pgs, subscribe.udid);
if (dbResults != null &&
dbResults.PGS == subscribe.pgs &&
dbResults.UDID == subscribe.udid &&
dbResults.DeviceType == subscribe.device_type &&
dbResults.VerificationHash == subscribe.verificator_hash)
{
if(dbResults.Available && dbResults.Status == ServiceShared.Models.Database.Results.ResultsStatus.COMPLETED)
{
Download download = ServiceInside.GetDownload(new CheckResults()
{
pgs = dbResults.PGS,
udid = dbResults.UDID
});
if(download != null)
{
response = new EncryptedResponse("Download", download, this.GetClientSharedKey());
Log.Trace("download", dbResults.PGS, dbResults.UDID);
}
else
{
response = new EncryptedResponse("ResponseException", new NotAvailableException(), this.GetClientSharedKey());
this.SendExceptionWithRequestAndHeaders(subscribe);
}
}
else
{
response = new EncryptedResponse("ResponseException", new NotAvailableException(), this.GetClientSharedKey());
this.SendExceptionWithRequestAndHeaders(subscribe);
}
}
else
{
response = new EncryptedResponse("ResponseException", new NotAuthorizedException(), this.GetClientSharedKey());
}
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
catch (Exception ex)
{
Log.Critical(ex, "ServiceOutside.Controllers.ResultsController", "Download(EncryptedRequest)");
}
this.Debug(response, "RESPONSE");
return new JsonResult(response);
}
/// <summary>
/// Updates pickedup flag and timestamp
/// CheckFileChecksum must contain following data: pgs, udid, public key, device_type, verificator_hash, file_checksum
/// PGS: SHA512 hash from ZIP + BIRTHDAY + SAMPLEID
/// UDID: Unique device id
/// Public Key: Public Key of the client
/// Device Type: Type of the client (IOS or ANDROID)
/// Verificator_hash: HMAC Hash, that was created by master password of patient
/// FileChecksum CheckSum of downloaded content after decryption
///
/// RESPONSE: Exception or Success status
/// </summary>
/// <param name="encrypted">Encrypted request, that contains CheckFileChecksum object</param>
/// <returns>Encrypted response, that contains eather encrypted content or exception</returns>
[Route("pickedup")]
[HttpPost]
public JsonResult PickedUp(EncryptedRequest encrypted)
{
EncryptedResponse response = null;
try
{
this.Debug(encrypted, "REQUEST");
if (encrypted.ValidSignature(this.GetClientSharedKey(), this.GetClientSignature(), this.GetClientSignatureKey()))
{
CheckFileChecksum checkSum = encrypted.Decrypt<CheckFileChecksum>(this.GetClientSharedKey());
if (checkSum != null)
{
ResponseException validationException = ServiceShared.Models.Request.Subscribe.Validate(checkSum);
if (validationException != null)
{
response = new EncryptedResponse("ResponseException", validationException, this.GetClientSharedKey());
}
else if(string.IsNullOrEmpty(checkSum.file_checksum))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("file_checksum"), this.GetClientSharedKey());
}
else
{
ServiceShared.Models.Database.Results dbResults = this.dbResults.GetResults(checkSum.pgs, checkSum.udid);
if (dbResults != null &&
dbResults.PGS == checkSum.pgs &&
dbResults.UDID == checkSum.udid &&
dbResults.DeviceType == checkSum.device_type &&
dbResults.VerificationHash == checkSum.verificator_hash)
{
if(!string.IsNullOrEmpty(dbResults.FileChecksum) && dbResults.FileChecksum == checkSum.file_checksum)
{
if(this.dbResults.SetPickedUp(dbResults.PGS, dbResults.UDID))
{
response = new EncryptedResponse("success", null, this.GetClientSharedKey());
ServiceInside.PickedUp(checkSum);
Log.Trace("pickedup", dbResults.PGS, dbResults.UDID);
}
else
{
// Mindmap W-1-4 - Some unknown exception occured, results could not be created
Log.Critical(new Exception("Could not update pickedup flag to the results in the database, PGS=" + dbResults.PGS + ", UDID=" + dbResults.UDID), "ServiceOutside.Controllers.ResultsController", "PickedUp(EncryptedRequest)");
response = new EncryptedResponse("ResponseException", new UnknownException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new WrongFileChecksumException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new NotAuthorizedException(), this.GetClientSharedKey());
}
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
catch (Exception ex)
{
Log.Critical(ex, "ServiceOutside.Controllers.ResultsController", "Download(EncryptedRequest)");
}
this.Debug(response, "RESPONSE");
return new JsonResult(response);
}
/// <summary>
/// Returns PIN of device
/// </summary>
// <param name="encrypted">Encrypted request, that contains GetPIN object</param>
/// <returns>Encrypted response, that contains eather exceptions or PIN object</returns>
[Route("pin")]
[HttpPost]
public JsonResult PIN(EncryptedRequest encrypted)
{
EncryptedResponse response = null;
try
{
this.Debug(encrypted, "REQUEST");
if (encrypted.ValidSignature(this.GetClientSharedKey(), this.GetClientSignature(), this.GetClientSignatureKey()))
{
GetPIN getPINRequest = encrypted.Decrypt<GetPIN>(this.GetClientSharedKey());
if (getPINRequest != null)
{
if (string.IsNullOrEmpty(getPINRequest.udid))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("udid"), this.GetClientSharedKey());
}
else if (string.IsNullOrEmpty(getPINRequest.verificator_hash))
{
response = new EncryptedResponse("ResponseException", new MissingArgumentException("verificator_hash"), this.GetClientSharedKey());
}
else
{
string pin_code = this.dbResults.GetPIN(getPINRequest.udid, getPINRequest.verificator_hash);
if (!string.IsNullOrEmpty(pin_code))
{
PIN pin = new PIN();
pin.udid = getPINRequest.udid;
pin.verificator_hash = getPINRequest.verificator_hash;
pin.code = pin_code;
response = new EncryptedResponse("PIN", pin, this.GetClientSharedKey());
}
else
{
response = new EncryptedResponse("ResponseException", new NotAvailableException(), this.GetClientSharedKey());
}
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
else
{
response = new EncryptedResponse("ResponseException", new InvalidClientException(), this.GetClientSharedKey());
}
}
catch (Exception ex)
{
Log.Critical(ex, "ServiceOutside.Controllers.ResultsController", "GetPIN(EncryptedRequest)");
}
this.Debug(response, "RESPONSE");
return new JsonResult(response);
}
/// <summary>
/// Sends Critical exception with request and headers
/// </summary>
private void SendExceptionWithRequestAndHeaders(object request)
{
try
{
string logs = "";
string body = "";
string headers = "";
if (this.HttpContext != null && this.HttpContext.Request != null && this.HttpContext.Request.Headers != null)
{
foreach (var header in this.HttpContext.Request.Headers)
{
headers += header.Key + "=" + header.Value + "\r\n";
}
}
if(request != null)
{
headers = JsonSerializer.Serialize(request, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
}
logs = "\r\n\r\nHEADERS: " + headers + "\r\nREQUEST: " + body;
Log.Critical(new Exception("Trying to get not available results: " + logs), "ServiceOutside.Controllers.ResultsController", "Download(EncryptedRequest)");
}
catch (Exception ex)
{
Log.Critical(ex, "ServiceOutside.Controllers.ResultsController", "Download(not available results) -> logs");
}
}
}
}