Ejemplo n.º 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());
        }
Ejemplo n.º 2
0
        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));
        }
Ejemplo n.º 3
0
        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));
        }
Ejemplo n.º 4
0
        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());
        }
Ejemplo n.º 5
0
        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));
        }
Ejemplo n.º 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());
        }
Ejemplo n.º 7
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)));
        }