this repo has no description
1package knotclient 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) RepoForkAheadBehind(ownerDid, source, name, branch, hiddenRef string) (*http.Response, error) { 107 const ( 108 Method = "GET" 109 ) 110 endpoint := fmt.Sprintf("/repo/fork/sync/%s", url.PathEscape(branch)) 111 112 body, _ := json.Marshal(map[string]any{ 113 "did": ownerDid, 114 "source": source, 115 "name": name, 116 "hiddenref": hiddenRef, 117 }) 118 119 req, err := s.newRequest(Method, endpoint, body) 120 if err != nil { 121 return nil, err 122 } 123 124 return s.client.Do(req) 125} 126 127func (s *SignedClient) SyncRepoFork(ownerDid, source, name, branch string) (*http.Response, error) { 128 const ( 129 Method = "POST" 130 ) 131 endpoint := fmt.Sprintf("/repo/fork/sync/%s", url.PathEscape(branch)) 132 133 body, _ := json.Marshal(map[string]any{ 134 "did": ownerDid, 135 "source": source, 136 "name": name, 137 }) 138 139 req, err := s.newRequest(Method, endpoint, body) 140 if err != nil { 141 return nil, err 142 } 143 144 return s.client.Do(req) 145} 146 147func (s *SignedClient) ForkRepo(ownerDid, source, name string) (*http.Response, error) { 148 const ( 149 Method = "POST" 150 Endpoint = "/repo/fork" 151 ) 152 153 body, _ := json.Marshal(map[string]any{ 154 "did": ownerDid, 155 "source": source, 156 "name": name, 157 }) 158 159 req, err := s.newRequest(Method, Endpoint, body) 160 if err != nil { 161 return nil, err 162 } 163 164 return s.client.Do(req) 165} 166 167func (s *SignedClient) RemoveRepo(did, repoName string) (*http.Response, error) { 168 const ( 169 Method = "DELETE" 170 Endpoint = "/repo" 171 ) 172 173 body, _ := json.Marshal(map[string]any{ 174 "did": did, 175 "name": repoName, 176 }) 177 178 req, err := s.newRequest(Method, Endpoint, body) 179 if err != nil { 180 return nil, err 181 } 182 183 return s.client.Do(req) 184} 185 186func (s *SignedClient) AddMember(did string) (*http.Response, error) { 187 const ( 188 Method = "PUT" 189 Endpoint = "/member/add" 190 ) 191 192 body, _ := json.Marshal(map[string]any{ 193 "did": did, 194 }) 195 196 req, err := s.newRequest(Method, Endpoint, body) 197 if err != nil { 198 return nil, err 199 } 200 201 return s.client.Do(req) 202} 203 204func (s *SignedClient) SetDefaultBranch(ownerDid, repoName, branch string) (*http.Response, error) { 205 const ( 206 Method = "PUT" 207 ) 208 endpoint := fmt.Sprintf("/%s/%s/branches/default", ownerDid, repoName) 209 210 body, _ := json.Marshal(map[string]any{ 211 "branch": branch, 212 }) 213 214 req, err := s.newRequest(Method, endpoint, body) 215 if err != nil { 216 return nil, err 217 } 218 219 return s.client.Do(req) 220} 221 222func (s *SignedClient) AddCollaborator(ownerDid, repoName, memberDid string) (*http.Response, error) { 223 const ( 224 Method = "POST" 225 ) 226 endpoint := fmt.Sprintf("/%s/%s/collaborator/add", ownerDid, repoName) 227 228 body, _ := json.Marshal(map[string]any{ 229 "did": memberDid, 230 }) 231 232 req, err := s.newRequest(Method, endpoint, body) 233 if err != nil { 234 return nil, err 235 } 236 237 return s.client.Do(req) 238} 239 240func (s *SignedClient) Merge( 241 patch []byte, 242 ownerDid, targetRepo, branch, commitMessage, commitBody, authorName, authorEmail string, 243) (*http.Response, error) { 244 const ( 245 Method = "POST" 246 ) 247 endpoint := fmt.Sprintf("/%s/%s/merge", ownerDid, targetRepo) 248 249 mr := types.MergeRequest{ 250 Branch: branch, 251 CommitMessage: commitMessage, 252 CommitBody: commitBody, 253 AuthorName: authorName, 254 AuthorEmail: authorEmail, 255 Patch: string(patch), 256 } 257 258 body, _ := json.Marshal(mr) 259 260 req, err := s.newRequest(Method, endpoint, body) 261 if err != nil { 262 return nil, err 263 } 264 265 return s.client.Do(req) 266} 267 268func (s *SignedClient) MergeCheck(patch []byte, ownerDid, targetRepo, branch string) (*http.Response, error) { 269 const ( 270 Method = "POST" 271 ) 272 endpoint := fmt.Sprintf("/%s/%s/merge/check", ownerDid, targetRepo) 273 274 body, _ := json.Marshal(map[string]any{ 275 "patch": string(patch), 276 "branch": branch, 277 }) 278 279 req, err := s.newRequest(Method, endpoint, body) 280 if err != nil { 281 return nil, err 282 } 283 284 return s.client.Do(req) 285} 286 287func (s *SignedClient) NewHiddenRef(ownerDid, targetRepo, forkBranch, remoteBranch string) (*http.Response, error) { 288 const ( 289 Method = "POST" 290 ) 291 endpoint := fmt.Sprintf("/%s/%s/hidden-ref/%s/%s", ownerDid, targetRepo, url.PathEscape(forkBranch), url.PathEscape(remoteBranch)) 292 293 req, err := s.newRequest(Method, endpoint, nil) 294 if err != nil { 295 return nil, err 296 } 297 298 return s.client.Do(req) 299}