public async Task <IActionResult> RunAsync( [HttpTrigger(AuthorizationLevel.Function, "put", Route = "v2/diagnosis")] HttpRequest req) { var requestBody = await new StreamReader(req.Body).ReadToEndAsync(); Logger.LogInformation($"{nameof(RunAsync)}"); // Check Valid Route IValidationServerService.ValidateResult validateResult = ValidationServerService.Validate(req); if (!validateResult.IsValid) { return(validateResult.ErrorActionResult); } var diagnosis = JsonConvert.DeserializeObject <DiagnosisSubmissionParameter>(requestBody); var reqTime = DateTimeOffset.UtcNow; // payload valid if (!diagnosis.IsValid()) { Logger.LogInformation($"Invalid parameter"); return(new BadRequestErrorMessageResult("Invalid parameter")); } // validation support region if (!diagnosis.Regions.Any(_ => SupportRegions.Contains(_))) { Logger.LogInformation($"Regions not supported."); return(new BadRequestErrorMessageResult("Regions not supported.")); } // validation device if (false == await DeviceCheck.Validation(diagnosis, reqTime)) { Logger.LogInformation($"Invalid Device"); return(new BadRequestErrorMessageResult("Invalid Device")); } // validatetion VerificationPayload var verificationResult = await VerificationService.VerificationAsync(diagnosis.VerificationPayload); if (verificationResult != 200) { return(new ObjectResult("Bad VerificationPayload") { StatusCode = verificationResult }); } var timestamp = DateTimeOffset.UtcNow; var keys = diagnosis.Keys.Select(_ => _.ToModel(diagnosis, (ulong)timestamp.ToUnixTimeSeconds())).ToArray(); foreach (var k in keys) { await TekRepository.UpsertAsync(k); } return(new NoContentResult()); }
public async Task RunAsync() { try { Logger.LogInformation($"start {nameof(RunAsync)}"); var batchTimestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); var items = await TekRepository.GetNextAsync(); foreach (var kv in items.GroupBy(_ => new { RollingStartUnixTimeSeconds = _.GetRollingStartUnixTimeSeconds(), RollingPeriodSeconds = _.GetRollingPeriodSeconds() })) { var batchNum = (int)await Sequence.GetNextAsync(SequenceName, 1); batchTimestamp++; foreach (var region in Regions) { // Security considerations: Random Order TemporaryExposureKey var sorted = kv .OrderBy(_ => RandomNumberGenerator.GetInt32(int.MaxValue)); await CreateAsync((ulong)kv.Key.RollingStartUnixTimeSeconds, (ulong)(kv.Key.RollingStartUnixTimeSeconds + kv.Key.RollingPeriodSeconds), region, batchNum, batchTimestamp, sorted.ToArray()); } foreach (var key in kv) { key.Exported = true; await TekRepository.UpsertAsync(key); } } // Write Export Files json var models = await TekExportRepository.GetKeysAsync(0); await BlobService.WriteFilesJsonAsync(models); } catch (Exception ex) { Logger.LogError(ex, $"Error on {nameof(TemporaryExposureKeyExportBatchService)}"); throw; } }
public async Task <IActionResult> RunAsync( [HttpTrigger(AuthorizationLevel.Function, "put", Route = "diagnosis")] HttpRequest req) { var requestBody = await new StreamReader(req.Body).ReadToEndAsync(); var diagnosis = JsonConvert.DeserializeObject <DiagnosisSubmissionParameter>(requestBody); // payload valid if (!diagnosis.IsValid()) { return(new BadRequestErrorMessageResult("Invalid parameter")); } if (!SupportRegions.Contains(diagnosis.Region)) { return(new BadRequestErrorMessageResult("Regions not supported.")); } // validation var validationResult = await Validation.ValidateAsync(req, diagnosis); if (!validationResult.IsValid) { return(validationResult.ErrorActionResult); } // Device validation if (false == await DeviceCheck.Validation(diagnosis)) { return(new BadRequestErrorMessageResult("Invalid Device")); } var timestamp = DateTimeOffset.UtcNow; var keys = diagnosis.Keys.Select(_ => _.ToModel(diagnosis, (ulong)timestamp.ToUnixTimeSeconds())).ToArray(); await DiagnosisRepository.SubmitDiagnosisAsync( diagnosis.SubmissionNumber, timestamp, diagnosis.UserUuid, keys); foreach (var k in keys) { await TekRepository.UpsertAsync(k); } return(new NoContentResult()); }
public async Task <IActionResult> RunApprovedAsync( [HttpTrigger(AuthorizationLevel.Function, "put", Route = "Diagnosis/{submissionNumber}/Approved/{userUuid}")] HttpRequest req, string submissionNumber, string userUuid ) { Logger.LogInformation($"{nameof(DiagnosisApi)} {nameof(RunApprovedAsync)} processed a request."); var result = await Diagnosis.GetAsync(submissionNumber, userUuid); foreach (var key in result.Keys) { await Tek.UpsertAsync(key); } return(new OkResult()); }
public async Task RunAsync() { try { Logger.LogInformation($"start {nameof(RunAsync)}"); var items = await TekRepository.GetNextAsync(); foreach (var kv in items.GroupBy(_ => new { RollingStartUnixTimeSeconds = _.GetRollingStartUnixTimeSeconds(), RollingPeriodSeconds = _.GetRollingPeriodSeconds() })) { foreach (var region in Regions) { // Security considerations: Random Order TemporaryExposureKey var sorted = kv .OrderBy(_ => RandomNumberGenerator.GetInt32(int.MaxValue)); await CreateAsync((ulong)kv.Key.RollingStartUnixTimeSeconds, (ulong)(kv.Key.RollingStartUnixTimeSeconds + kv.Key.RollingPeriodSeconds), region, sorted.ToArray()); } foreach (var key in kv) { key.Exported = true; await TekRepository.UpsertAsync(key); } } } catch (Exception ex) { Logger.LogError(ex, $"Error on {nameof(TemporaryExposureKeyExportBatchService)}"); throw; } }
public async Task <IActionResult> RunAsync( [HttpTrigger(AuthorizationLevel.Function, "put", Route = "v2/diagnosis")] HttpRequest req) { var requestBody = await new StreamReader(req.Body).ReadToEndAsync(); Logger.LogInformation($"{nameof(RunAsync)}"); // Check Valid Route IValidationServerService.ValidateResult validateResult = ValidationServerService.Validate(req); if (!validateResult.IsValid) { return(validateResult.ErrorActionResult); } var diagnosis = JsonConvert.DeserializeObject <V2DiagnosisSubmissionParameter>(requestBody); var reqTime = DateTimeOffset.UtcNow; // payload valid if (!diagnosis.IsValid()) { Logger.LogInformation($"Invalid parameter"); return(new BadRequestErrorMessageResult("Invalid parameter")); } // validation support region if (!diagnosis.Regions.Any(_ => SupportRegions.Contains(_))) { Logger.LogInformation($"Regions not supported."); return(new BadRequestErrorMessageResult("Regions not supported.")); } // validation device Logger.LogInformation("regions: " + (diagnosis?.Regions != null && diagnosis.Regions.Count() != 0 ? string.Join(", ", diagnosis.Regions) : "Empty") + ", " + $"platform: {diagnosis?.Platform}, " + $"deviceVerificationPayload: {diagnosis?.DeviceVerificationPayload}, " + $"appPackageName: {diagnosis?.AppPackageName}, " + $"padding: {diagnosis?.Padding}"); if (false == await DeviceCheck.Validation(diagnosis.Platform, diagnosis, reqTime)) { Logger.LogInformation($"Invalid Device"); return(new BadRequestErrorMessageResult("Invalid Device")); } // Check Chaff request for production // https://google.github.io/exposure-notifications-server/server_functional_requirements.html if (req.Headers?.ContainsKey(CHAFF_HEADER) ?? false) { return(new NoContentResult()); } // validatetion VerificationPayload var verificationResult = await VerificationService.VerificationAsync(diagnosis.VerificationPayload); if (verificationResult != 200) { return(new ObjectResult("Bad VerificationPayload") { StatusCode = verificationResult }); } var timestamp = DateTimeOffset.UtcNow; var keys = diagnosis.Keys.Select(_ => _.ToModel(diagnosis, (ulong)timestamp.ToUnixTimeSeconds())).ToArray(); foreach (var k in keys) { await TekRepository.UpsertAsync(k); } return(new NoContentResult()); }
public async Task <IActionResult> RunAsync( [HttpTrigger(AuthorizationLevel.Function, "put", Route = "diagnosis")] HttpRequest req) { var requestBody = await new StreamReader(req.Body).ReadToEndAsync(); var diagnosis = JsonConvert.DeserializeObject <DiagnosisSubmissionParameter>(requestBody); var reqTime = DateTimeOffset.UtcNow; // payload valid if (!diagnosis.IsValid()) { return(new BadRequestErrorMessageResult("Invalid parameter")); } // validation support region if (!diagnosis.Regions.Any(_ => SupportRegions.Contains(_))) { return(new BadRequestErrorMessageResult("Regions not supported.")); } // validation var validationResult = await Validation.ValidateAsync(req, diagnosis); if (!validationResult.IsValid) { return(validationResult.ErrorActionResult); } // validation device if (false == await DeviceCheck.Validation(diagnosis, reqTime)) { return(new BadRequestErrorMessageResult("Invalid Device")); } // TODO: validatetion VerificationPayload 4xx if (false == true) { return(new ObjectResult("Bad VerificationPayload") { StatusCode = 406 }); } // TODO: validatetion VerificationPayload connnection error 5xx if (false == true) { return(new ObjectResult("Unable to communicate with center") { StatusCode = 503 }); } var timestamp = DateTimeOffset.UtcNow; var keys = diagnosis.Keys.Select(_ => _.ToModel(diagnosis, (ulong)timestamp.ToUnixTimeSeconds())).ToArray(); await DiagnosisRepository.SubmitDiagnosisAsync( diagnosis.VerificationPayload, timestamp, diagnosis.UserUuid, keys); foreach (var k in keys) { await TekRepository.UpsertAsync(k); } return(new NoContentResult()); }
public async Task <IActionResult> RunAsync( [HttpTrigger(AuthorizationLevel.Function, "put", Route = "v3/diagnosis")] HttpRequest req) { var requestBody = await new StreamReader(req.Body).ReadToEndAsync(); _logger.LogInformation($"{nameof(RunAsync)}"); // Check Valid Route IValidationServerService.ValidateResult validateResult = _validationServerService.Validate(req); if (!validateResult.IsValid) { return(validateResult.ErrorActionResult); } var submissionParameter = JsonConvert.DeserializeObject <V3DiagnosisSubmissionParameter>(requestBody); submissionParameter.SetDaysSinceOnsetOfSymptoms(); // Make compatible with Legacy-V1 mode. foreach (var key in submissionParameter.Keys) { var transmissionRiskLevel = TRANSMISSION_RISK_LEVEL_LOWEST; if (key.DaysSinceOnsetOfSymptoms >= Constants.DaysHasInfectiousness) { transmissionRiskLevel = TRANSMISSION_RISK_LEVEL_MEDIUM; } key.TransmissionRisk = transmissionRiskLevel; } // Filter valid keys submissionParameter.Keys = submissionParameter.Keys .Where(key => _temporaryExposureKeyValidationService.Validate(submissionParameter.HasSymptom, key)) .ToArray(); var reqTime = DateTimeOffset.UtcNow; // payload valid if (!submissionParameter.IsValid()) { _logger.LogInformation($"Invalid parameter"); return(new BadRequestErrorMessageResult("Invalid parameter")); } // validation support region if (!submissionParameter.Regions.Any(_ => _supportRegions.Contains(_))) { _logger.LogInformation($"Regions not supported."); return(new BadRequestErrorMessageResult("Regions not supported.")); } // validation device if (!await _deviceValidationService.Validation(submissionParameter.Platform, submissionParameter, reqTime)) { _logger.LogInformation($"Invalid Device"); return(new BadRequestErrorMessageResult("Invalid Device")); } // Check Chaff request for production // https://google.github.io/exposure-notifications-server/server_functional_requirements.html if (req.Headers?.ContainsKey(CHAFF_HEADER) ?? false) { return(new OkObjectResult(JsonConvert.SerializeObject(submissionParameter))); } // validatetion VerificationPayload var verificationResult = await _verificationService.VerificationAsync(submissionParameter.VerificationPayload); if (verificationResult != ((int)HttpStatusCode.OK)) { return(new ObjectResult("Bad VerificationPayload") { StatusCode = verificationResult }); } var newKeys = new List <TemporaryExposureKeyModel>(); var timestamp = (ulong)DateTimeOffset.UtcNow.ToUnixTimeSeconds(); using (SHA256 sha256 = SHA256.Create()) { foreach (var k in submissionParameter.Keys) { var idSeed = $"{submissionParameter.IdempotencyKey},{k.KeyData},{k.RollingStartNumber},{k.RollingPeriod}"; var id = ByteArrayUtils.ToHexString(sha256.ComputeHash(Encoding.ASCII.GetBytes(idSeed))); foreach (var region in submissionParameter.Regions) { var key = k.ToModel(); key.id = id; key.PartitionKey = region; key.Timestamp = timestamp; newKeys.Add(key); } } } foreach (var key in newKeys) { await _tekRepository.UpsertAsync(key); } // Clear Payloads submissionParameter.VerificationPayload = null; submissionParameter.DeviceVerificationPayload = null; return(new OkObjectResult(JsonConvert.SerializeObject(submissionParameter))); }