16
16
// well as between mobile devices and the server.
17
17
package api
18
18
19
- import "fmt"
19
+ import (
20
+ "crypto/rand"
21
+ "encoding/base64"
22
+ "fmt"
23
+ "math/big"
24
+ )
20
25
21
26
const (
22
27
// TestTypeConfirmed is the string that represents a confirmed covid-19 test.
@@ -98,13 +103,35 @@ func (e *ErrorReturn) WithCode(code string) *ErrorReturn {
98
103
// It's arbitrary bytes that should be ignored or discarded. It primarily exists
99
104
// to prevent a network observer from building a model based on request or
100
105
// response sizes.
101
- type Padding struct {
102
- Padding string `json:"padding,omitempty"`
106
+ type Padding []byte
107
+
108
+ // MarshalJSON is a custom JSON marshaler for padding. It generates and returns
109
+ // 1-2kb (random) of base64-encoded bytes.
110
+ func (p Padding ) MarshalJSON () ([]byte , error ) {
111
+ bi , err := rand .Int (rand .Reader , big .NewInt (1024 ))
112
+ if err != nil {
113
+ return nil , fmt .Errorf ("padding: failed to generate random number: %w" , err )
114
+ }
115
+
116
+ // rand.Int is [0, max), so add 1kb to set the range from 1-2kb.
117
+ i := int (bi .Int64 () + 1024 )
118
+
119
+ b := make ([]byte , i )
120
+ n , err := rand .Read (b )
121
+ if err != nil {
122
+ return nil , fmt .Errorf ("padding: failed to read bytes: %w" , err )
123
+ }
124
+ if n < i {
125
+ return nil , fmt .Errorf ("padding: wrote less bytes than expected" )
126
+ }
127
+
128
+ s := fmt .Sprintf ("%q" , base64 .StdEncoding .EncodeToString (b ))
129
+ return []byte (s ), nil
103
130
}
104
131
105
132
// CSRFResponse is the return type when requesting an AJAX CSRF token.
106
133
type CSRFResponse struct {
107
- Padding
134
+ Padding Padding `json:"padding"`
108
135
109
136
CSRFToken string `json:"csrftoken"`
110
137
Error string `json:"error"`
@@ -115,7 +142,7 @@ type CSRFResponse struct {
115
142
// code. This is called by the Web frontend.
116
143
// API is served at /api/issue
117
144
type IssueCodeRequest struct {
118
- Padding
145
+ Padding Padding `json:"padding"`
119
146
120
147
SymptomDate string `json:"symptomDate"` // ISO 8601 formatted date, YYYY-MM-DD
121
148
TestDate string `json:"testDate"`
@@ -128,7 +155,7 @@ type IssueCodeRequest struct {
128
155
129
156
// IssueCodeResponse defines the response type for IssueCodeRequest.
130
157
type IssueCodeResponse struct {
131
- Padding
158
+ Padding Padding `json:"padding"`
132
159
133
160
// UUID is a handle which allows the issuer to track status of the issued verification code.
134
161
UUID string `json:"uuid"`
@@ -157,15 +184,15 @@ type IssueCodeResponse struct {
157
184
// previously issued OTP code. This is called by the Web frontend.
158
185
// API is served at /api/checkcodestatus
159
186
type CheckCodeStatusRequest struct {
160
- Padding
187
+ Padding Padding `json:"padding"`
161
188
162
189
// UUID is a handle which allows the issuer to track status of the issued verification code.
163
190
UUID string `json:"uuid"`
164
191
}
165
192
166
193
// CheckCodeStatusResponse defines the response type for CheckCodeStatusRequest.
167
194
type CheckCodeStatusResponse struct {
168
- Padding
195
+ Padding Padding `json:"padding"`
169
196
170
197
// Claimed is true if a user has used the OTP code to get a token via the VerifyCode api.
171
198
Claimed bool `json:"claimed"`
@@ -186,15 +213,15 @@ type CheckCodeStatusResponse struct {
186
213
// This is called by the Web frontend.
187
214
// API is served at /api/expirecode
188
215
type ExpireCodeRequest struct {
189
- Padding
216
+ Padding Padding `json:"padding"`
190
217
191
218
// UUID is a handle which allows the issuer to track status of the issued verification code.
192
219
UUID string `json:"uuid"`
193
220
}
194
221
195
222
// ExpireCodeResponse defines the response type for ExpireCodeRequest.
196
223
type ExpireCodeResponse struct {
197
- Padding
224
+ Padding Padding `json:"padding"`
198
225
199
226
// ExpiresAtTimestamp represents Unix, seconds since the epoch. Still UTC.
200
227
// After this time the code will no longer be accepted and is eligible for deletion.
@@ -226,7 +253,7 @@ type ExpireCodeResponse struct {
226
253
//
227
254
// Requires API key in a HTTP header, X-API-Key: APIKEY
228
255
type VerifyCodeRequest struct {
229
- Padding
256
+ Padding Padding `json:"padding"`
230
257
231
258
VerificationCode string `json:"code"`
232
259
AcceptTestTypes []string `json:"accept"`
@@ -236,7 +263,7 @@ type VerifyCodeRequest struct {
236
263
// (type and [optional] date) as well as the verification token. The verification token
237
264
// may be sent back on a valid VerificationCertificateRequest later.
238
265
type VerifyCodeResponse struct {
239
- Padding
266
+ Padding Padding `json:"padding"`
240
267
241
268
TestType string `json:"testtype,omitempty"`
242
269
SymptomDate string `json:"symptomDate,omitempty"` // ISO 8601 formatted date, YYYY-MM-DD
@@ -252,7 +279,7 @@ type VerifyCodeResponse struct {
252
279
//
253
280
// Requires API key in a HTTP header, X-API-Key: APIKEY
254
281
type VerificationCertificateRequest struct {
255
- Padding
282
+ Padding Padding `json:"padding"`
256
283
257
284
VerificationToken string `json:"token"`
258
285
ExposureKeyHMAC string `json:"ekeyhmac"`
@@ -262,7 +289,7 @@ type VerificationCertificateRequest struct {
262
289
// a signed certificate that can be presented to the configured exposure
263
290
// notifications server to publish keys along w/ the certified diagnosis.
264
291
type VerificationCertificateResponse struct {
265
- Padding
292
+ Padding Padding `json:"padding"`
266
293
267
294
Certificate string `json:"certificate,omitempty"`
268
295
Error string `json:"error,omitempty"`
0 commit comments