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 <IActionResult> RunWithRegionAsync( [HttpTrigger(AuthorizationLevel.Function, "get", Route = "TemporaryExposureKeys/{region}")] HttpRequest req, string region) { // Check Valid Route IValidationServerService.ValidateResult validateResult = ValidationServerService.Validate(req); if (!validateResult.IsValid) { return(validateResult.ErrorActionResult); } if (!long.TryParse(req.Query?["since"], out var sinceEpochSeconds)) { sinceEpochSeconds = new DateTimeOffset(DateTime.UtcNow.AddDays(-14)).ToUnixTimeSeconds(); } var keysResponse = await TekExport.GetKeysAsync((ulong)sinceEpochSeconds, region); var result = new TemporaryExposureKeysResult(); // TODO: Url util result.Keys = keysResponse .Select(_ => new TemporaryExposureKeysResult.Key() { Url = $"{ExportKeyUrl}/{TekExportBlobStorageContainerPrefix}/{_.Region}/{_.BatchNum}.zip" }); result.Timestamp = keysResponse .OrderByDescending(_ => _.TimestampSecondsSinceEpoch) .FirstOrDefault()?.TimestampSecondsSinceEpoch ?? sinceEpochSeconds; return(new OkObjectResult(result)); }
public async Task <IActionResult> RunAsync( [HttpTrigger(AuthorizationLevel.Function, "post", Route = "register")] HttpRequest req) { Logger.LogInformation("C# HTTP trigger function processed a request."); // Check Valid Route IValidationServerService.ValidateResult validateResult = ValidationServerService.Validate(req); if (!validateResult.IsValid) { return(validateResult.ErrorActionResult); } // UserUuid var userUuid = Guid.NewGuid().ToString("N") + DateTime.UtcNow.Ticks.ToString(); // save to DB return(await Register(userUuid)); }
public async Task <IActionResult> RunAsync( [HttpTrigger(AuthorizationLevel.Function, "delete", Route = "OptOut/{userUuid}")] HttpRequest req, string userUuid) { Logger.LogInformation($"{nameof(OptOutApi)} processed a request."); // Check Valid Route IValidationServerService.ValidateResult validateResult = ValidationServerService.Validate(req); if (!validateResult.IsValid) { return(validateResult.ErrorActionResult); } var user = new UserParameter() { UserUuid = userUuid }; // validation var validationResult = await Validation.ValidateAsync(req, user); if (!validationResult.IsValid) { AddBadRequest(req); return(validationResult.ErrorActionResult); } // delete tek await DiagnosisRepository.DeleteAsync(user); // NOTE:consider privacy: delete published Tek at after 14 days. // delete user await UserRepository.Delete(user); return(new NoContentResult()); }
public async Task <IActionResult> RunAsync( [HttpTrigger(AuthorizationLevel.Function, "put", Route = "v1/event_log")] HttpRequest req ) { _logger.LogInformation($"{nameof(RunAsync)}"); // Check Content-Length. if (!req.Headers.ContainsKey(HEADER_CONTENT_LENGTH)) { return(new StatusCodeResult((int)HttpStatusCode.BadRequest)); } string contentLengthHeader = req.Headers[HEADER_CONTENT_LENGTH].ToString(); bool isNumeric = long.TryParse(contentLengthHeader, out long contentLength); if (!isNumeric) { return(new StatusCodeResult((int)HttpStatusCode.BadRequest)); } else if (contentLength < 0) { return(new StatusCodeResult((int)HttpStatusCode.BadRequest)); } else if (contentLength > Constants.MAX_SIZE_EVENT_LOG_PAYLOAD_BYTES) { return(new StatusCodeResult((int)HttpStatusCode.RequestEntityTooLarge)); } var requestBody = await new StreamReader(req.Body).ReadToEndAsync(); // Check RequestBody size. if (Encoding.ASCII.GetBytes(requestBody).LongLength > Constants.MAX_SIZE_EVENT_LOG_PAYLOAD_BYTES) { return(new StatusCodeResult((int)HttpStatusCode.RequestEntityTooLarge)); } // Check Valid Route IValidationServerService.ValidateResult validateResult = _validationServerService.Validate(req); if (!validateResult.IsValid) { if (validateResult.ErrorActionResult is BadRequestResult) { return(new StatusCodeResult((int)HttpStatusCode.BadRequest)); } else { return(validateResult.ErrorActionResult); } } V1EventLogSubmissionParameter submissionParameter; try { submissionParameter = JsonConvert.DeserializeObject <V1EventLogSubmissionParameter>(requestBody); } catch (JsonSerializationException e) { _logger.LogError("JsonSerializationException occurred."); return(new StatusCodeResult((int)HttpStatusCode.BadRequest)); } var requestTime = DateTimeOffset.UtcNow; // validation device if (!await _deviceValidationService.Validation(submissionParameter.Platform, submissionParameter, requestTime)) { _logger.LogInformation($"Invalid Device"); return(new StatusCodeResult((int)HttpStatusCode.BadRequest)); } var timestamp = (ulong)DateTimeOffset.UtcNow.ToUnixTimeSeconds(); using (SHA256 sha256 = SHA256.Create()) { foreach (var eventLog in submissionParameter.EventLogs) { // For considering user-privacy safe. if (!eventLog.HasConsent) { _logger.LogError("No consent log detected."); continue; } string id = ByteArrayUtils.ToHexString(sha256.ComputeHash(Encoding.ASCII.GetBytes(eventLog.ClearText))); var eventLogModel = new EventLogModel( eventLog.HasConsent, eventLog.Epoch, eventLog.Type, eventLog.Subtype, eventLog.Content, eventLog.Timestamp ) { id = id, Created = timestamp, }; await _eventLogRepository.UpsertAsync(eventLogModel); } } return(new StatusCodeResult((int)HttpStatusCode.Created)); }
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 = "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))); }