Skip to content

matishadow/Fhi.Smittestopp.Backend

 
 

Repository files navigation

Smittestopp Backend

badge Fhi.Smittestopp Fhi.Smittestopp Fhi.Smittestopp

WebAPI project, which facilitates receiving, storing and distributing Temporary Exposure Keys [1].

Mobile devices can use these keys to detect exposures and send notifications to the users. To do that, the devices utilize Exposure Notification API [2] provided by Apple and Google.

Installation

Installation process goes in the same way as with any other WebAPI project. For example, you could use Web Deploy feature of IIS but other methods work fine as well.

web deploy

Keep in mind that routes to all endpoints already have api prefix in them. Remove the suggested api from Application Path when importing in order to not have this prefix duplicated.

Requirements

To run the project you need the ASP.NET Core Runtime. Any version starting with 3.1 should work fine i.e., 3.1.10. Choose Hosting Bundle when choosing a runtime version.

The project unfortunately has a couple of Windows dependencies and because of that, you need to run it on Windows.

Windows dependencies
  1. It uses Data Protection API [3] for encryption.

  2. It runs Hangfire [4] as a Windows service.

  3. It writes logs to Windows EventLog [5], if configured to do so.

Registering EventLog

To initiate EventLog for settings mentioned above you can run this PowerShell script with administrator rights:

$file = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\EventLogMessages.dll"
New-EventLog -ComputerName . -Source "SS-API-DIGNDB.App.SmitteStop" -LogName Application -MessageResourceFile $file -CategoryResourceFile $file
New-EventLog -ComputerName . -Source "SS-Jobs-DIGNDB.App.SmitteStop" -LogName Application -MessageResourceFile $file -CategoryResourceFile $file

Without this initialization no logs will appear in the Event Viewer.

Hangfire as a service

To create a service, which will run Hangfire execute the command below (in Command Prompt).

sc create "SmittestopHangfire" binpath="C:\SmittestopHangFire\DIGNDB.APP.SmitteStop.Jobs.exe"

Creating cleaning SQL job

To ensure that keys older than 14 days won’t clutter the database, run the SQL command from this file sql/create-cleaning-sql-job.sql.

Usage

To use this WebAPI project you need an HTTP Client. Both mobile devices and frontend frameworks can use some HTTP Client to consume the API.

Swagger

To describe API endpoints, the project makes use of Swagger.

Request on root endpoint / will result in getting Swagger UI page, presented below.

swagger demo

Swagger along with the documentation also provides a functionality called playground. Click Try it out and then Execute to send an HTTP request without a need for any HTTP client.

swagger try it out
swagger execute

For security reasons, this functionality works only in development environments.

Hangfire

Jobs

On 14.12.2020 Hangfire exposes 3 jobs, which you can execute.

  1. validate-keys-on-database - removes invalid keys from the database.

  2. update-zip-files - generates zip files from existing keys.

  3. remove-old-keys - removes old zip files from the disk.

Configuration

The project uses the standard ASP.NET Core mechanism for splitting configuration for different environments. To get yourself familiar with the concept take a look at this article Use multiple environments in ASP.NET Core

Mobile token

Some endpoints require a mobile token because of MobileAuthorizationAttribute attribute. This token provides static authentication mechanism between the backend and the mobile app.

You need to provide this token to appsettings.json configuration for all environments apart from development.

appsettings.json
{
  "AppSettings": {
    "AuthorizationMobile": "To be replaced in Pipelines"
  }
}

To generate this token just pick a random string (treat it like a password, the longer and higher the entropy the better), share it with the mobile team, encrypt it using ConfigEncryptionHelper.ProtectString and put it as AuthorizationMobile value. This method ProtectString uses Data Protection API under the hood, so you need to repeat this encryption for each server.

If the API application runs as apppool user then this user needs to perform the encryption (call to ProtectString). If user A performs the encryption and user B will try to decrypt the token then the decryption will fail.

JWT validation

Endpoint POST /diagnostickeys uses JWT token to authenticate the client.

You can configure some JWT validation rules using the configuration below.

appsettings.json
{
  "JwtAuthorization" : {
    "JwtValidationRules": {
      "ClientId": "To be replaced in Pipelines",
      "SupportedAlgorithm": "RS256",
      "Issuer": "To be replaced in Pipelines"
    },
    "JwkUrl": "To be replaced in Pipelines"
  }
}
  • ClientId - Client id from the token, which we consider valid.

  • SupportedAlgorithm - Supported signature algorithm, which we consider valid.

  • Issuer - Issuer from the token, which we consider valid.

  • JwkUrl - Url from which the validator service will retrieve the public key.

API version deprecation

AppSettings section of appsettings.json configuration enables setting a specific version of API as deprecated.

To set version 1 and version 2 as deprecated put "1" and "2" strings into DeprecatedVersions array. Use example below for reference.

appsettings.json
{
  "AppSettings": {
    "DeprecatedVersions": [
      "1",
      "2"
    ]
  }
}

Calling an endpoint in deprecated version will result in getting a response with the code 410 and content API is deprecated.

Logging configuration

The project uses different logging solutions when it comes to backend logs and mobile logs.

Backend logs

Backend uses solution provided by the framework, described in Logging in .NET Core and ASP.NET Core. Startup class calls AddFile extension method to also save logs to a file.

Mobile logs

Application running on devices pushes its logs using /logging/logMessages endpoint. LoggingController receives those logs and saves them using log4net package. This package uses log4net.config configuration file.

Shared folder for zips

To accomplish failure resilience, configure appsettings configuration (of Jobs project) to have multiple record in ZipFilesFolders array.

{
  "ZipFilesFolders": [
    "C:\\SmitteStopNO\\SmittestopTemporaryExposureKeyZipFiles"
  ]
}

Contributing

Unused code

Don’t feel surprised to find some portions of unused code. As an example, you won’t find any logical usages of Translation table or whole FederationGatewayApi project. Development team removed the code using it because the project should not integrate with EU Federation Gateway Service for now.

Patterns used in the project

Generic repository

To access the database please use GenericRepository<T> class. Feel free to create a custom repository class based on the generic one if needed.

Dependency registration

Each module should have its dependencies registered in a separate extension method.

For example in DIGNDB.App.SmitteStop.DAL module we have a method presented below.

public static class ContainerRegistration
{
    public static IServiceCollection AddDALDependencies(this IServiceCollection services)
    {
        services.AddScoped<IJwtTokenRepository, JwtTokenRepository>();
        services.AddScoped<ICountryRepository, CountryRepository>();
        services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));

        return services;
    }
}

This pattern provides a number of benefits.

  1. It keeps all the registration calls in one place per module.

  2. It enables marking some implementation classes as internal (encapsulation).

  3. It the need for mocking in unit tests (see JWT validation tests as an example).

Database connection

To develop the project you need a working SQL Server instance. You can either use a local instance or a Docker container.

Entity Framework Code First

The project utilizes Code First with Migrations approach when using Entity Framework package.

Please pay attention when running dotnet ef commands. The database context lays in different project (DIGNDB.App.SmitteStop.DAL) than the API so you need to specify the context project each time.

For example to create a new migration run the following command:

DIGNDB.App.SmitteStop\DIGNDB.App.SmitteStop.API>dotnet ef migrations add <MigrationName> --project ../DIGNDB.App.SmitteStop.DAL

License

Copyright (c) 2020 Agency for Digitisation (Denmark), 2020 Norwegian Institute of Public Health (Norway), 2020 Netcompany Group AS

Smittestopp is Open Source software released under the MIT license

About

Smittestopp 2 backend application

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C# 99.4%
  • Other 0.6%