1package state
2
3import (
4 "bytes"
5 "crypto/hmac"
6 "crypto/sha256"
7 "encoding/hex"
8 "encoding/json"
9 "fmt"
10 "net/http"
11 "net/url"
12 "time"
13)
14
15type SignerTransport struct {
16 Secret string
17}
18
19func (s SignerTransport) RoundTrip(req *http.Request) (*http.Response, error) {
20 timestamp := time.Now().Format(time.RFC3339)
21 mac := hmac.New(sha256.New, []byte(s.Secret))
22 message := req.Method + req.URL.Path + timestamp
23 mac.Write([]byte(message))
24 signature := hex.EncodeToString(mac.Sum(nil))
25 req.Header.Set("X-Signature", signature)
26 req.Header.Set("X-Timestamp", timestamp)
27 return http.DefaultTransport.RoundTrip(req)
28}
29
30type SignedClient struct {
31 Secret string
32 Url *url.URL
33 client *http.Client
34}
35
36func NewSignedClient(domain, secret string) (*SignedClient, error) {
37 client := &http.Client{
38 Timeout: 5 * time.Second,
39 Transport: SignerTransport{
40 Secret: secret,
41 },
42 }
43
44 url, err := url.Parse(fmt.Sprintf("http://%s", domain))
45 if err != nil {
46 return nil, err
47 }
48
49 signedClient := &SignedClient{
50 Secret: secret,
51 client: client,
52 Url: url,
53 }
54
55 return signedClient, nil
56}
57
58func (s *SignedClient) newRequest(method, endpoint string, body []byte) (*http.Request, error) {
59 return http.NewRequest(method, s.Url.JoinPath(endpoint).String(), bytes.NewReader(body))
60}
61
62func (s *SignedClient) Init(did string) (*http.Response, error) {
63 const (
64 Method = "POST"
65 Endpoint = "/init"
66 )
67
68 body, _ := json.Marshal(map[string]interface{}{
69 "did": did,
70 })
71
72 req, err := s.newRequest(Method, Endpoint, body)
73 if err != nil {
74 return nil, err
75 }
76
77 return s.client.Do(req)
78}
79
80func (s *SignedClient) NewRepo(did, repoName string) (*http.Response, error) {
81 const (
82 Method = "PUT"
83 Endpoint = "/repo/new"
84 )
85
86 body, _ := json.Marshal(map[string]interface{}{
87 "did": did,
88 "name": repoName,
89 })
90
91 req, err := s.newRequest(Method, Endpoint, body)
92 if err != nil {
93 return nil, err
94 }
95
96 return s.client.Do(req)
97}
98
99func (s *SignedClient) AddMember(did string) (*http.Response, error) {
100 const (
101 Method = "PUT"
102 Endpoint = "/member/add"
103 )
104
105 body, _ := json.Marshal(map[string]interface{}{
106 "did": did,
107 })
108
109 req, err := s.newRequest(Method, Endpoint, body)
110 if err != nil {
111 return nil, err
112 }
113
114 return s.client.Do(req)
115}
116
117func (s *SignedClient) AddCollaborator(ownerDid, repoName, memberDid string) (*http.Response, error) {
118 const (
119 Method = "POST"
120 )
121 endpoint := fmt.Sprintf("/%s/%s/collaborator/add", ownerDid, repoName)
122
123 body, _ := json.Marshal(map[string]interface{}{
124 "did": memberDid,
125 })
126
127 req, err := s.newRequest(Method, endpoint, body)
128 if err != nil {
129 return nil, err
130 }
131
132 return s.client.Do(req)
133}