Example #1
0
        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());
        }
Example #4
0
        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());
        }
Example #5
0
        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;
            }
        }
Example #6
0
        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());
        }
Example #7
0
        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());
        }
Example #8
0
        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)));
        }