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) ForkRepo(ownerDid, source, name string) (*http.Response, error) { 107 const ( 108 Method = "POST" 109 Endpoint = "/repo/fork" 110 ) 111 112 body, _ := json.Marshal(map[string]any{ 113 "did": ownerDid, 114 "source": source, 115 "name": name, 116 }) 117 118 req, err := s.newRequest(Method, Endpoint, body) 119 if err != nil { 120 return nil, err 121 } 122 123 return s.client.Do(req) 124} 125 126func (s *SignedClient) RemoveRepo(did, repoName string) (*http.Response, error) { 127 const ( 128 Method = "DELETE" 129 Endpoint = "/repo" 130 ) 131 132 body, _ := json.Marshal(map[string]any{ 133 "did": did, 134 "name": repoName, 135 }) 136 137 req, err := s.newRequest(Method, Endpoint, body) 138 if err != nil { 139 return nil, err 140 } 141 142 return s.client.Do(req) 143} 144 145func (s *SignedClient) AddMember(did string) (*http.Response, error) { 146 const ( 147 Method = "PUT" 148 Endpoint = "/member/add" 149 ) 150 151 body, _ := json.Marshal(map[string]any{ 152 "did": did, 153 }) 154 155 req, err := s.newRequest(Method, Endpoint, body) 156 if err != nil { 157 return nil, err 158 } 159 160 return s.client.Do(req) 161} 162 163func (s *SignedClient) SetDefaultBranch(ownerDid, repoName, branch string) (*http.Response, error) { 164 const ( 165 Method = "PUT" 166 ) 167 endpoint := fmt.Sprintf("/%s/%s/branches/default", ownerDid, repoName) 168 169 body, _ := json.Marshal(map[string]any{ 170 "branch": branch, 171 }) 172 173 req, err := s.newRequest(Method, endpoint, body) 174 if err != nil { 175 return nil, err 176 } 177 178 return s.client.Do(req) 179} 180 181func (s *SignedClient) AddCollaborator(ownerDid, repoName, memberDid string) (*http.Response, error) { 182 const ( 183 Method = "POST" 184 ) 185 endpoint := fmt.Sprintf("/%s/%s/collaborator/add", ownerDid, repoName) 186 187 body, _ := json.Marshal(map[string]any{ 188 "did": memberDid, 189 }) 190 191 req, err := s.newRequest(Method, endpoint, body) 192 if err != nil { 193 return nil, err 194 } 195 196 return s.client.Do(req) 197} 198 199func (s *SignedClient) Merge( 200 patch []byte, 201 ownerDid, targetRepo, branch, commitMessage, commitBody, authorName, authorEmail string, 202) (*http.Response, error) { 203 const ( 204 Method = "POST" 205 ) 206 endpoint := fmt.Sprintf("/%s/%s/merge", ownerDid, targetRepo) 207 208 mr := types.MergeRequest{ 209 Branch: branch, 210 CommitMessage: commitMessage, 211 CommitBody: commitBody, 212 AuthorName: authorName, 213 AuthorEmail: authorEmail, 214 Patch: string(patch), 215 } 216 217 body, _ := json.Marshal(mr) 218 219 req, err := s.newRequest(Method, endpoint, body) 220 if err != nil { 221 return nil, err 222 } 223 224 return s.client.Do(req) 225} 226 227func (s *SignedClient) MergeCheck(patch []byte, ownerDid, targetRepo, branch string) (*http.Response, error) { 228 const ( 229 Method = "POST" 230 ) 231 endpoint := fmt.Sprintf("/%s/%s/merge/check", ownerDid, targetRepo) 232 233 body, _ := json.Marshal(map[string]any{ 234 "patch": string(patch), 235 "branch": branch, 236 }) 237 238 req, err := s.newRequest(Method, endpoint, body) 239 if err != nil { 240 return nil, err 241 } 242 243 return s.client.Do(req) 244} 245 246func (s *SignedClient) NewHiddenRef(ownerDid, targetRepo, forkBranch, remoteBranch string) (*http.Response, error) { 247 const ( 248 Method = "POST" 249 ) 250 endpoint := fmt.Sprintf("/%s/%s/hidden-ref/%s/%s", ownerDid, targetRepo, forkBranch, remoteBranch) 251 252 req, err := s.newRequest(Method, endpoint, nil) 253 if err != nil { 254 return nil, err 255 } 256 257 return s.client.Do(req) 258} 259 260type UnsignedClient struct { 261 Url *url.URL 262 client *http.Client 263} 264 265func NewUnsignedClient(domain string, dev bool) (*UnsignedClient, error) { 266 client := &http.Client{ 267 Timeout: 5 * time.Second, 268 } 269 270 scheme := "https" 271 if dev { 272 scheme = "http" 273 } 274 url, err := url.Parse(fmt.Sprintf("%s://%s", scheme, domain)) 275 if err != nil { 276 return nil, err 277 } 278 279 unsignedClient := &UnsignedClient{ 280 client: client, 281 Url: url, 282 } 283 284 return unsignedClient, nil 285} 286 287func (us *UnsignedClient) newRequest(method, endpoint string, body []byte) (*http.Request, error) { 288 return http.NewRequest(method, us.Url.JoinPath(endpoint).String(), bytes.NewReader(body)) 289} 290 291func (us *UnsignedClient) Index(ownerDid, repoName, ref string) (*http.Response, error) { 292 const ( 293 Method = "GET" 294 ) 295 296 endpoint := fmt.Sprintf("/%s/%s/tree/%s", ownerDid, repoName, ref) 297 if ref == "" { 298 endpoint = fmt.Sprintf("/%s/%s", ownerDid, repoName) 299 } 300 301 req, err := us.newRequest(Method, endpoint, nil) 302 if err != nil { 303 return nil, err 304 } 305 306 return us.client.Do(req) 307} 308 309func (us *UnsignedClient) Branches(ownerDid, repoName string) (*http.Response, error) { 310 const ( 311 Method = "GET" 312 ) 313 314 endpoint := fmt.Sprintf("/%s/%s/branches", ownerDid, repoName) 315 316 req, err := us.newRequest(Method, endpoint, nil) 317 if err != nil { 318 return nil, err 319 } 320 321 return us.client.Do(req) 322} 323 324func (us *UnsignedClient) Branch(ownerDid, repoName, branch string) (*http.Response, error) { 325 const ( 326 Method = "GET" 327 ) 328 329 endpoint := fmt.Sprintf("/%s/%s/branches/%s", ownerDid, repoName, branch) 330 331 req, err := us.newRequest(Method, endpoint, nil) 332 if err != nil { 333 return nil, err 334 } 335 336 return us.client.Do(req) 337} 338 339func (us *UnsignedClient) DefaultBranch(ownerDid, repoName string) (*types.RepoDefaultBranchResponse, error) { 340 const ( 341 Method = "GET" 342 ) 343 344 endpoint := fmt.Sprintf("/%s/%s/branches/default", ownerDid, repoName) 345 346 req, err := us.newRequest(Method, endpoint, nil) 347 if err != nil { 348 return nil, err 349 } 350 351 resp, err := us.client.Do(req) 352 if err != nil { 353 return nil, err 354 } 355 defer resp.Body.Close() 356 357 var branchResponse types.RepoDefaultBranchResponse 358 if err := json.NewDecoder(resp.Body).Decode(&branchResponse); err != nil { 359 return nil, err 360 } 361 362 return &branchResponse, nil 363} 364 365func (us *UnsignedClient) Capabilities() (*types.Capabilities, error) { 366 const ( 367 Method = "GET" 368 Endpoint = "/capabilities" 369 ) 370 371 req, err := us.newRequest(Method, Endpoint, nil) 372 if err != nil { 373 return nil, err 374 } 375 376 resp, err := us.client.Do(req) 377 if err != nil { 378 return nil, err 379 } 380 defer resp.Body.Close() 381 382 var capabilities types.Capabilities 383 if err := json.NewDecoder(resp.Body).Decode(&capabilities); err != nil { 384 return nil, err 385 } 386 387 return &capabilities, nil 388} 389 390func (us *UnsignedClient) Compare(ownerDid, repoName, rev1, rev2 string) (*http.Response, error) { 391 const ( 392 Method = "GET" 393 ) 394 395 endpoint := fmt.Sprintf("/%s/%s/compare/%s/%s", ownerDid, repoName, url.PathEscape(rev1), url.PathEscape(rev2)) 396 397 req, err := us.newRequest(Method, endpoint, nil) 398 if err != nil { 399 return nil, err 400 } 401 402 return us.client.Do(req) 403}