forked from tangled.org/core
this repo has no description
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 "tangled.sh/tangled.sh/core/types" 15) 16 17type SignerTransport struct { 18 Secret string 19} 20 21func (s SignerTransport) RoundTrip(req *http.Request) (*http.Response, error) { 22 timestamp := time.Now().Format(time.RFC3339) 23 mac := hmac.New(sha256.New, []byte(s.Secret)) 24 message := req.Method + req.URL.Path + timestamp 25 mac.Write([]byte(message)) 26 signature := hex.EncodeToString(mac.Sum(nil)) 27 req.Header.Set("X-Signature", signature) 28 req.Header.Set("X-Timestamp", timestamp) 29 return http.DefaultTransport.RoundTrip(req) 30} 31 32type SignedClient struct { 33 Secret string 34 Url *url.URL 35 client *http.Client 36} 37 38func NewSignedClient(domain, secret string, dev bool) (*SignedClient, error) { 39 client := &http.Client{ 40 Timeout: 5 * time.Second, 41 Transport: SignerTransport{ 42 Secret: secret, 43 }, 44 } 45 46 scheme := "https" 47 if dev { 48 scheme = "http" 49 } 50 url, err := url.Parse(fmt.Sprintf("%s://%s", scheme, domain)) 51 if err != nil { 52 return nil, err 53 } 54 55 signedClient := &SignedClient{ 56 Secret: secret, 57 client: client, 58 Url: url, 59 } 60 61 return signedClient, nil 62} 63 64func (s *SignedClient) newRequest(method, endpoint string, body []byte) (*http.Request, error) { 65 return http.NewRequest(method, s.Url.JoinPath(endpoint).String(), bytes.NewReader(body)) 66} 67 68func (s *SignedClient) Init(did string) (*http.Response, error) { 69 const ( 70 Method = "POST" 71 Endpoint = "/init" 72 ) 73 74 body, _ := json.Marshal(map[string]any{ 75 "did": did, 76 }) 77 78 req, err := s.newRequest(Method, Endpoint, body) 79 if err != nil { 80 return nil, err 81 } 82 83 return s.client.Do(req) 84} 85 86func (s *SignedClient) NewRepo(did, repoName, defaultBranch string) (*http.Response, error) { 87 const ( 88 Method = "PUT" 89 Endpoint = "/repo/new" 90 ) 91 92 body, _ := json.Marshal(map[string]any{ 93 "did": did, 94 "name": repoName, 95 "default_branch": defaultBranch, 96 }) 97 98 req, err := s.newRequest(Method, Endpoint, body) 99 if err != nil { 100 return nil, err 101 } 102 103 return s.client.Do(req) 104} 105 106func (s *SignedClient) RemoveRepo(did, repoName string) (*http.Response, error) { 107 const ( 108 Method = "DELETE" 109 Endpoint = "/repo" 110 ) 111 112 body, _ := json.Marshal(map[string]any{ 113 "did": did, 114 "name": repoName, 115 }) 116 117 req, err := s.newRequest(Method, Endpoint, body) 118 if err != nil { 119 return nil, err 120 } 121 122 return s.client.Do(req) 123} 124 125func (s *SignedClient) AddMember(did string) (*http.Response, error) { 126 const ( 127 Method = "PUT" 128 Endpoint = "/member/add" 129 ) 130 131 body, _ := json.Marshal(map[string]any{ 132 "did": did, 133 }) 134 135 req, err := s.newRequest(Method, Endpoint, body) 136 if err != nil { 137 return nil, err 138 } 139 140 return s.client.Do(req) 141} 142 143func (s *SignedClient) SetDefaultBranch(ownerDid, repoName, branch string) (*http.Response, error) { 144 const ( 145 Method = "PUT" 146 ) 147 endpoint := fmt.Sprintf("/%s/%s/branches/default", ownerDid, repoName) 148 149 body, _ := json.Marshal(map[string]any{ 150 "branch": branch, 151 }) 152 153 req, err := s.newRequest(Method, endpoint, body) 154 if err != nil { 155 return nil, err 156 } 157 158 return s.client.Do(req) 159} 160 161func (s *SignedClient) AddCollaborator(ownerDid, repoName, memberDid string) (*http.Response, error) { 162 const ( 163 Method = "POST" 164 ) 165 endpoint := fmt.Sprintf("/%s/%s/collaborator/add", ownerDid, repoName) 166 167 body, _ := json.Marshal(map[string]any{ 168 "did": memberDid, 169 }) 170 171 req, err := s.newRequest(Method, endpoint, body) 172 if err != nil { 173 return nil, err 174 } 175 176 return s.client.Do(req) 177} 178 179func (s *SignedClient) Merge( 180 patch []byte, 181 ownerDid, targetRepo, branch, commitMessage, commitBody, authorName, authorEmail string, 182) (*http.Response, error) { 183 const ( 184 Method = "POST" 185 ) 186 endpoint := fmt.Sprintf("/%s/%s/merge", ownerDid, targetRepo) 187 188 mr := types.MergeRequest{ 189 Branch: branch, 190 CommitMessage: commitMessage, 191 CommitBody: commitBody, 192 AuthorName: authorName, 193 AuthorEmail: authorEmail, 194 Patch: string(patch), 195 } 196 197 body, _ := json.Marshal(mr) 198 199 req, err := s.newRequest(Method, endpoint, body) 200 if err != nil { 201 return nil, err 202 } 203 204 return s.client.Do(req) 205} 206 207func (s *SignedClient) MergeCheck(patch []byte, ownerDid, targetRepo, branch string) (*http.Response, error) { 208 const ( 209 Method = "POST" 210 ) 211 endpoint := fmt.Sprintf("/%s/%s/merge/check", ownerDid, targetRepo) 212 213 body, _ := json.Marshal(map[string]any{ 214 "patch": string(patch), 215 "branch": branch, 216 }) 217 218 req, err := s.newRequest(Method, endpoint, body) 219 if err != nil { 220 return nil, err 221 } 222 223 return s.client.Do(req) 224} 225 226type UnsignedClient struct { 227 Url *url.URL 228 client *http.Client 229} 230 231func NewUnsignedClient(domain string, dev bool) (*UnsignedClient, error) { 232 client := &http.Client{ 233 Timeout: 5 * time.Second, 234 } 235 236 scheme := "https" 237 if dev { 238 scheme = "http" 239 } 240 url, err := url.Parse(fmt.Sprintf("%s://%s", scheme, domain)) 241 if err != nil { 242 return nil, err 243 } 244 245 unsignedClient := &UnsignedClient{ 246 client: client, 247 Url: url, 248 } 249 250 return unsignedClient, nil 251} 252 253func (us *UnsignedClient) newRequest(method, endpoint string, body []byte) (*http.Request, error) { 254 return http.NewRequest(method, us.Url.JoinPath(endpoint).String(), bytes.NewReader(body)) 255} 256 257func (us *UnsignedClient) Index(ownerDid, repoName, ref string) (*http.Response, error) { 258 const ( 259 Method = "GET" 260 ) 261 262 endpoint := fmt.Sprintf("/%s/%s/tree/%s", ownerDid, repoName, ref) 263 if ref == "" { 264 endpoint = fmt.Sprintf("/%s/%s", ownerDid, repoName) 265 } 266 267 req, err := us.newRequest(Method, endpoint, nil) 268 if err != nil { 269 return nil, err 270 } 271 272 return us.client.Do(req) 273} 274 275func (us *UnsignedClient) Branches(ownerDid, repoName string) (*http.Response, error) { 276 const ( 277 Method = "GET" 278 ) 279 280 endpoint := fmt.Sprintf("/%s/%s/branches", ownerDid, repoName) 281 282 req, err := us.newRequest(Method, endpoint, nil) 283 if err != nil { 284 return nil, err 285 } 286 287 return us.client.Do(req) 288} 289 290func (us *UnsignedClient) Branch(ownerDid, repoName, branch string) (*http.Response, error) { 291 const ( 292 Method = "GET" 293 ) 294 295 endpoint := fmt.Sprintf("/%s/%s/branches/%s", ownerDid, repoName, branch) 296 297 req, err := us.newRequest(Method, endpoint, nil) 298 if err != nil { 299 return nil, err 300 } 301 302 return us.client.Do(req) 303} 304 305func (us *UnsignedClient) DefaultBranch(ownerDid, repoName string) (*http.Response, error) { 306 const ( 307 Method = "GET" 308 ) 309 310 endpoint := fmt.Sprintf("/%s/%s/branches/default", ownerDid, repoName) 311 312 req, err := us.newRequest(Method, endpoint, nil) 313 if err != nil { 314 return nil, err 315 } 316 317 return us.client.Do(req) 318} 319 320func (us *UnsignedClient) Capabilities(ownerDid, repoName string) (*http.Response, error) { 321 const ( 322 Method = "GET" 323 Endpoint = "/capabilities" 324 ) 325 326 req, err := us.newRequest(Method, Endpoint, nil) 327 if err != nil { 328 return nil, err 329 } 330 331 return us.client.Do(req) 332} 333 334func (us *UnsignedClient) Compare(ownerDid, repoName, rev1, rev2 string) (*http.Response, error) { 335 const ( 336 Method = "GET" 337 ) 338 339 endpoint := fmt.Sprintf("/%s/%s/compare/%s/%s", ownerDid, repoName, rev1, rev2) 340 341 req, err := us.newRequest(Method, endpoint, nil) 342 if err != nil { 343 return nil, err 344 } 345 346 return us.client.Do(req) 347}