-
Notifications
You must be signed in to change notification settings - Fork 5
/
client.go
129 lines (116 loc) · 3.12 KB
/
client.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
122
123
124
125
126
127
128
129
package main
import (
"bytes"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
"go.mozilla.org/hawk"
)
type signaturerequest struct {
Input string `json:"input"`
KeyID string `json:"keyid"`
Options interface{}
}
type signatureresponse struct {
Ref string `json:"ref"`
Type string `json:"type"`
SignerID string `json:"signer_id"`
PublicKey string `json:"public_key,omitempty"`
Signature string `json:"signature"`
SignedFile string `json:"signed_file"`
X5U string `json:"x5u,omitempty"`
}
// xpiOptions contains specific parameters used to sign XPIs
type xpiOptions struct {
// ID is the add-on ID which is stored in the end-entity subject CN
ID string `json:"id"`
// COSEAlgorithms is an optional list of strings referring to IANA algorithms to use for COSE signatures
COSEAlgorithms []string `json:"cose_algorithms"`
// PKCS7Digest is a string required for /sign/file referring to algorithm to use for the PKCS7 signature digest
PKCS7Digest string `json:"pkcs7_digest"`
}
func callAutograph(auth authorization, body []byte, xff string) (signedBody []byte, err error) {
var requests []signaturerequest
request := signaturerequest{
Input: base64.StdEncoding.EncodeToString(body),
KeyID: auth.Signer,
}
if auth.AddonID != "" {
opt := xpiOptions{
ID: auth.AddonID,
PKCS7Digest: "SHA1",
}
if auth.AddonPKCS7Digest != "" {
opt.PKCS7Digest = auth.AddonPKCS7Digest
}
if len(auth.AddonCOSEAlgorithms) > 0 {
opt.COSEAlgorithms = auth.AddonCOSEAlgorithms
}
request.Options = opt
}
requests = append(requests, request)
reqBody, err := json.Marshal(requests)
if err != nil {
return
}
rdr := bytes.NewReader(reqBody)
req, err := http.NewRequest(http.MethodPost, conf.BaseURL+"sign/file", rdr)
if err != nil {
return
}
req.Header.Set("Content-Type", "application/json")
// make the hawk auth header
hawkAuth := hawk.NewRequestAuth(req,
&hawk.Credentials{
ID: auth.User,
Key: auth.Key,
Hash: sha256.New},
0)
hawkAuth.Ext = fmt.Sprintf("%d", time.Now().Nanosecond())
payloadhash := hawkAuth.PayloadHash("application/json")
payloadhash.Write(reqBody)
hawkAuth.SetHash(payloadhash)
req.Header.Set("Authorization", hawkAuth.RequestHeader())
// Reuse the X-Forwarded-For received from the client over to
// autograph so we can trace requests back to client from its logs
req.Header.Set("X-Forwarded-For", xff)
// make the request
cli := &http.Client{}
resp, err := cli.Do(req)
if err != nil {
return
}
if resp == nil {
err = errAutographEmptyResponse
return
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
if resp.StatusCode != http.StatusCreated {
err = errAutographBadStatusCode
return
}
var responses []signatureresponse
err = json.Unmarshal(respBody, &responses)
if err != nil {
return
}
if len(responses) != 1 {
err = errAutographBadResponseCount
return
}
return base64.StdEncoding.DecodeString(responses[0].SignedFile)
}
type heartbeatRequester interface {
Get(string) (*http.Response, error)
}
type heartbeatClient struct {
*http.Client
}