Installation
You can clone the repository by using this code
git clone "https://github.com/ito-org/api-backend"
To start with this application, download the current version by using git clone
.
The recommended way to install the API server is to use docker with docker-compose
.
Docker Compose
To start docker-compose
you need to set the following environment variables so that the server knows how to connect to your Postgres database. For that you can add an .env
file to the root of the api-backend folder with the following lines.
Environment Variables
Example
.env
file
POSTGRES_HOST=<Database host>
POSTGRES_DB=<Database name>
POSTGRES_USER=<Username for db>
POSTGRES_PASSWORD=<secretpw>
Parameter | Required | Description |
---|---|---|
POSTGRES_HOST | yes | The host of the Postgres database |
POSTGRES_DB | yes | The name of the Postgres database |
POSTGRES_USER | yes | A Postgres user with access to the database |
POSTGRES_PASSWORD | yes | The database user's secret password |
Configuration
Example
docker-compose.yaml
version: "3.7"
services:
go-backend:
build:
context: .
dockerfile: Dockerfile
ports:
- 8080:8080
environment:
- POSTGRES_PASSWORD
- POSTGRES_USER
- POSTGRES_DB
depends_on:
- postgres
networks:
- itonet
postgres:
image: postgres:12
environment:
- POSTGRES_PASSWORD
- POSTGRES_USER
- POSTGRES_DB
ports:
- 5432:5432
volumes:
- ./db/db.sql:/docker-entrypoint-initdb.d/db.sql
- dbvol:/var/lib/postgresql/data
networks:
- itonet
restart: always
networks:
itonet:
volumes:
dbvol:
You can copy the docker-compose.yml.example
file in the repository to docker-compose.yml
to configure a fully working backend with the default configuration.
Run docker-compose up
to start the containers in foreground mode or use docker-compose up -d
to start them as daemons (in detached mode).
In the default configuration, the HTTP server will be accessible on port 8080
.
API
The ito API has intentionally been kept lean, so there is just one endpoint: https://tcn.ito-app.org/tcnreport
This way our code stays easy to understand and to audit.
Initialization of a basic client
package main
import (
"bytes"
"net/http"
"github.com/ito-org/go-backend/tcn"
)
const baseUrl = "https://tcn.ito-app.org"
public class ItoApi {
private static final String BASE_URL
= "https://tcn.ito-app.org";
}
Here's how to setup a basic ito client.
Fetching reports
With a GET
request you can download all recent reports of infected users. Those are returned as a bytestream (MIME type application/octet-stream
) of TCN reports as per the protocol definition.
Example client code for fetching recent reports
private static final int BASELENGTH = 70;
public static List<byte[]> getReports() {
List<byte[]> reports = new LinkedList<>();
HttpURLConnection urlConnection = null;
try {
URL url = new URL(BASE_URL + "/tcnreport");
urlConnection
= (HttpURLConnection) url.openConnection();
urlConnection.addRequestProperty(
"Accept",
"application/octet-stream"
);
InputStream in = urlConnection.getInputStream();
byte[] base = new byte[BASELENGTH];
byte[] memo;
int readBytes;
while ((readBytes = in.read(base, 0, BASELENGTH))
== BASELENGTH) {
int memolength
= (int) base[BASELENGTH - 1] & 0xFF;
memo = new byte[memolength];
if (in.read(memo, 0, memolength)
< memolength) {
throw new RuntimeException(
"Parsing from server failed"
);
}
System.out.println(
"Downloaded TCN Report: "
+ encodeHexString(base)
+ encodeHexString(memo)
);
ByteBuffer report = ByteBuffer.allocate(
BASELENGTH + memolength
);
report.put(base);
report.put(memo);
reports.add(report.array());
}
if (readBytes > 0)
throw new RuntimeException(
"Parsing from server failed"
);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return reports;
}
func main() {
_, rak, report, err := tcn.GenerateReport(0, 1, []byte("symptom data"))
if err != nil {
t.Error(err)
return
}
signedReport, err := tcn.GenerateSignedReport(rak, report)
if err != nil {
t.Error(err)
return
}
b, err := signedReport.Bytes()
if err != nil {
t.Error(err)
return
}
rec, req := http.NewRequest("POST", "/tcnreport", bytes.NewReader(b))
req, _ := http.NewRequest("GET", "/tcnreport", nil)
}
Publishing a report
With a POST
request you can report yourself as infected.
Example client code for submitting a report
public static void publishReport(
byte[] report
) throws IOException {
HttpURLConnection urlConnection = null;
try {
URL url = new URL(BASE_URL + "/tcnreport");
urlConnection
= (HttpURLConnection) url.openConnection();
urlConnection.setDoOutput(true);
urlConnection.addRequestProperty(
"Content-Type",
"application/octet-stream"
);
OutputStream outputStream
= new BufferedOutputStream(
urlConnection.getOutputStream()
);
outputStream.write(report);
outputStream.close();
InputStream inputStream
= urlConnection.getInputStream();
inputStream.read();
inputStream.close();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} finally {
if (urlConnection != null)
urlConnection.disconnect();
}
}