This repository has been archived by the owner on Nov 16, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
server.go
121 lines (102 loc) · 2.73 KB
/
server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main
import (
"encoding/hex"
"io/ioutil"
"net/http"
"github.com/gin-gonic/gin"
"github.com/ito-org/go-backend/tcn"
)
const (
requestBodyReadError = "Failed to read request body"
invalidRequestError = "Invalid request"
reportVerificationError = "Failed to verify report"
)
// GetRouter returns the Gin router.
func GetRouter(port string, dbConnection *DBConnection) *gin.Engine {
h := &TCNReportHandler{
dbConn: dbConnection,
}
r := gin.Default()
r.POST("/tcnreport", h.postTCNReport)
r.GET("/tcnreport", h.getTCNReport)
return r
}
// TCNReportHandler implements the handler functions for the API endpoints.
// It also holds the database connection that's used by the handler functions.
type TCNReportHandler struct {
dbConn *DBConnection
}
func (h *TCNReportHandler) postTCNReport(c *gin.Context) {
body := c.Request.Body
data, err := ioutil.ReadAll(body)
if err != nil {
c.String(http.StatusBadRequest, requestBodyReadError)
return
}
signedReport, err := tcn.GetSignedReport(data)
if err != nil {
c.String(http.StatusBadRequest, err.Error())
return
}
// If the memo field doesn't exist or the memo type is not ito's code, we
// simply ignore the request.
if signedReport.Report.Memo == nil || signedReport.Report.Memo.Type != 0x2 {
c.String(http.StatusBadRequest, invalidRequestError)
return
}
ok, err := signedReport.Verify()
if err != nil {
c.String(http.StatusBadRequest, err.Error())
return
}
if !ok {
c.String(http.StatusBadRequest, reportVerificationError)
return
}
if err := h.dbConn.insertSignedReport(signedReport); err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
c.Status(http.StatusOK)
}
func (h *TCNReportHandler) getTCNReport(c *gin.Context) {
var signedReports []*tcn.SignedReport
var err error
// The 'from' query param is used to only get reports that were made after
// the one in 'from'.
from := c.Query("from")
if from == "" {
signedReports, err = h.dbConn.getSignedReports()
} else {
fromBytes, err := hex.DecodeString(from)
if err != nil {
c.String(http.StatusBadRequest, err.Error())
return
}
var report *tcn.Report
report, err = tcn.GetReport(fromBytes)
if err != nil {
c.String(http.StatusBadRequest, err.Error())
return
}
signedReports, err = h.dbConn.getNewSignedReports(report)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
}
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
data := []byte{}
for _, sr := range signedReports {
b, err := sr.Bytes()
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
data = append(data, b...)
}
c.Data(http.StatusOK, "application/octet-stream", data)
}