github.com/0chain/gosdk@v1.17.11/zcncore/zauth.go (about) 1 package zcncore 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "net/http" 9 10 "github.com/0chain/gosdk/core/sys" 11 "github.com/0chain/gosdk/zboxcore/client" 12 "github.com/pkg/errors" 13 ) 14 15 // SplitWallet represents wallet info for split wallet 16 // The client id and client key are the same as the primary wallet client id and client key 17 type SplitWallet struct { 18 ClientID string `json:"client_id"` 19 ClientKey string `json:"client_key"` 20 PublicKey string `json:"public_key"` 21 PrivateKey string `json:"private_key"` 22 PeerPublicKey string `json:"peer_public_key"` 23 IsRevoked bool `json:"is_revoked"` 24 ExpiredAt int64 `json:"expired_at"` 25 } 26 27 // CallZauthSetup calls the zauth setup endpoint 28 func CallZauthSetup(serverAddr string, token string, splitWallet SplitWallet) error { 29 // Add your code here 30 endpoint := serverAddr + "/setup" 31 wData, err := json.Marshal(splitWallet) 32 if err != nil { 33 return errors.Wrap(err, "failed to marshal split wallet") 34 } 35 36 req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(wData)) 37 if err != nil { 38 return errors.Wrap(err, "failed to create HTTP request") 39 } 40 41 req.Header.Set("Content-Type", "application/json") 42 req.Header.Set("X-Jwt-Token", token) 43 44 client := &http.Client{} 45 resp, err := client.Do(req) 46 if err != nil { 47 return errors.Wrap(err, "failed to send HTTP request") 48 } 49 defer resp.Body.Close() 50 51 if resp.StatusCode != http.StatusOK { 52 errMsg, _ := io.ReadAll(resp.Body) 53 if len(errMsg) > 0 { 54 return errors.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg)) 55 } 56 57 return errors.Errorf("code: %d", resp.StatusCode) 58 } 59 60 var rsp struct { 61 Result string `json:"result"` 62 } 63 if err := json.NewDecoder(resp.Body).Decode(&rsp); err != nil { 64 return errors.Wrap(err, "failed to decode response body") 65 } 66 67 if rsp.Result != "success" { 68 return errors.New("failed to setup zauth server") 69 } 70 71 return nil 72 } 73 74 func CallZauthRevoke(serverAddr, token, clientID, publicKey string) error { 75 endpoint := serverAddr + "/revoke/" + clientID 76 endpoint += "?peer_public_key=" + publicKey 77 req, err := http.NewRequest("POST", endpoint, nil) 78 if err != nil { 79 return errors.Wrap(err, "failed to create HTTP request") 80 } 81 82 req.Header.Set("Content-Type", "application/json") 83 req.Header.Set("X-Jwt-Token", token) 84 85 client := &http.Client{} 86 resp, err := client.Do(req) 87 if err != nil { 88 return errors.Wrap(err, "failed to send HTTP request") 89 } 90 defer resp.Body.Close() 91 92 if resp.StatusCode != http.StatusOK { 93 errMsg, _ := io.ReadAll(resp.Body) 94 if len(errMsg) > 0 { 95 return errors.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg)) 96 } 97 98 return errors.Errorf("code: %d", resp.StatusCode) 99 } 100 101 var rsp struct { 102 Result string `json:"result"` 103 } 104 if err := json.NewDecoder(resp.Body).Decode(&rsp); err != nil { 105 return errors.Wrap(err, "failed to decode response body") 106 } 107 108 if rsp.Result != "success" { 109 return errors.New("failed to setup zauth server") 110 } 111 112 return nil 113 } 114 115 func CallZauthDelete(serverAddr, token, clientID string) error { 116 endpoint := serverAddr + "/delete/" + clientID 117 req, err := http.NewRequest("POST", endpoint, nil) 118 if err != nil { 119 return errors.Wrap(err, "failed to create HTTP request") 120 } 121 122 req.Header.Set("Content-Type", "application/json") 123 req.Header.Set("X-Jwt-Token", token) 124 125 client := &http.Client{} 126 resp, err := client.Do(req) 127 if err != nil { 128 return errors.Wrap(err, "failed to send HTTP request") 129 } 130 131 defer resp.Body.Close() 132 if resp.StatusCode != http.StatusOK { 133 errMsg, _ := io.ReadAll(resp.Body) 134 if len(errMsg) > 0 { 135 return errors.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg)) 136 } 137 138 return errors.Errorf("code: %d", resp.StatusCode) 139 } 140 141 var rsp struct { 142 Result string `json:"result"` 143 } 144 if err := json.NewDecoder(resp.Body).Decode(&rsp); err != nil { 145 return errors.Wrap(err, "failed to decode response body") 146 } 147 148 if rsp.Result != "success" { 149 return errors.New("failed to setup zauth server") 150 } 151 152 return nil 153 } 154 155 func CallZvaultNewWalletString(serverAddr, token, clientID string) (string, error) { 156 // Add your code here 157 endpoint := serverAddr + "/generate" 158 if clientID != "" { 159 endpoint = endpoint + "/" + clientID 160 } 161 162 req, err := http.NewRequest("POST", endpoint, nil) 163 if err != nil { 164 return "", errors.Wrap(err, "failed to create HTTP request") 165 } 166 167 fmt.Println("new wallet endpoint:", endpoint) 168 fmt.Println("new wallet: serverAddr:", serverAddr) 169 fmt.Println("new wallet: clientID:", clientID) 170 171 req.Header.Set("Content-Type", "application/json") 172 req.Header.Set("X-Jwt-Token", token) 173 174 client := &http.Client{} 175 resp, err := client.Do(req) 176 if err != nil { 177 return "", errors.Wrap(err, "failed to send HTTP request") 178 } 179 defer resp.Body.Close() 180 181 if resp.StatusCode != http.StatusOK { 182 errMsg, _ := io.ReadAll(resp.Body) 183 if len(errMsg) > 0 { 184 return "", errors.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg)) 185 } 186 187 return "", errors.Errorf("code: %d", resp.StatusCode) 188 } 189 190 d, err := io.ReadAll(resp.Body) 191 if err != nil { 192 return "", errors.Wrap(err, "failed to read response body") 193 } 194 195 return string(d), nil 196 } 197 198 func CallZvaultStoreKeyString(serverAddr, token, privateKey string) (string, error) { 199 // Add your code here 200 endpoint := serverAddr + "/store" 201 202 reqData := struct { 203 PrivateKey string `json:"private_key"` 204 }{ 205 PrivateKey: privateKey, 206 } 207 208 var buff bytes.Buffer 209 210 encoder := json.NewEncoder(&buff) 211 212 err := encoder.Encode(reqData) 213 if err != nil { 214 return "", errors.Wrap(err, "failed to create HTTP request") 215 } 216 217 var req *http.Request 218 219 req, err = http.NewRequest("POST", endpoint, &buff) 220 if err != nil { 221 return "", errors.Wrap(err, "failed to create HTTP request") 222 } 223 224 fmt.Println("call zvault /store:", endpoint) 225 req.Header.Set("Content-Type", "application/json") 226 req.Header.Set("X-Jwt-Token", token) 227 228 fmt.Println(req) 229 230 client := &http.Client{} 231 resp, err := client.Do(req) 232 if err != nil { 233 fmt.Println(err.Error()) 234 235 return "", errors.Wrap(err, "failed to send HTTP request") 236 } 237 defer resp.Body.Close() 238 239 if resp.StatusCode != http.StatusOK { 240 errMsg, _ := io.ReadAll(resp.Body) 241 if len(errMsg) > 0 { 242 return "", errors.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg)) 243 } 244 245 return "", errors.Errorf("code: %d", resp.StatusCode) 246 } 247 248 d, err := io.ReadAll(resp.Body) 249 if err != nil { 250 return "", errors.Wrap(err, "failed to read response body") 251 } 252 253 return string(d), nil 254 } 255 256 func CallZvaultRetrieveKeys(serverAddr, token, clientID string) (string, error) { 257 // Add your code here 258 endpoint := fmt.Sprintf("%s/keys/%s", serverAddr, clientID) 259 req, err := http.NewRequest("GET", endpoint, nil) 260 if err != nil { 261 return "", errors.Wrap(err, "failed to create HTTP request") 262 } 263 264 fmt.Println("call zvault /keys:", endpoint) 265 req.Header.Set("Content-Type", "application/json") 266 req.Header.Set("X-Jwt-Token", token) 267 268 client := &http.Client{} 269 resp, err := client.Do(req) 270 if err != nil { 271 return "", errors.Wrap(err, "failed to send HTTP request") 272 } 273 defer resp.Body.Close() 274 275 if resp.StatusCode != http.StatusOK { 276 errMsg, _ := io.ReadAll(resp.Body) 277 return "", fmt.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg)) 278 } 279 280 d, err := io.ReadAll(resp.Body) 281 if err != nil { 282 return "", errors.Wrap(err, "failed to read response body") 283 } 284 285 return string(d), nil 286 } 287 288 func CallZvaultDeletePrimaryKey(serverAddr, token, clientID string) error { 289 // Add your code here 290 endpoint := serverAddr + "/delete/" + clientID 291 req, err := http.NewRequest("POST", endpoint, nil) 292 if err != nil { 293 return errors.Wrap(err, "failed to create HTTP request") 294 } 295 296 fmt.Println("call zvault /delete:", endpoint) 297 req.Header.Set("Content-Type", "application/json") 298 req.Header.Set("X-Jwt-Token", token) 299 300 client := &http.Client{} 301 resp, err := client.Do(req) 302 if err != nil { 303 return errors.Wrap(err, "failed to send HTTP request") 304 } 305 defer resp.Body.Close() 306 307 if resp.StatusCode != http.StatusOK { 308 errMsg, _ := io.ReadAll(resp.Body) 309 return fmt.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg)) 310 } 311 312 _, err = io.ReadAll(resp.Body) 313 if err != nil { 314 return errors.Wrap(err, "failed to read response body") 315 } 316 317 return nil 318 } 319 320 func CallZvaultRevokeKey(serverAddr, token, clientID, publicKey string) error { 321 // Add your code here 322 endpoint := fmt.Sprintf("%s/revoke/%s?public_key=%s", serverAddr, clientID, publicKey) 323 req, err := http.NewRequest("POST", endpoint, nil) 324 if err != nil { 325 return errors.Wrap(err, "failed to create HTTP request") 326 } 327 328 fmt.Println("call zvault /revoke:", endpoint) 329 req.Header.Set("Content-Type", "application/json") 330 req.Header.Set("X-Jwt-Token", token) 331 332 client := &http.Client{} 333 resp, err := client.Do(req) 334 if err != nil { 335 return errors.Wrap(err, "failed to send HTTP request") 336 } 337 defer resp.Body.Close() 338 339 if resp.StatusCode != http.StatusOK { 340 errMsg, _ := io.ReadAll(resp.Body) 341 return fmt.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg)) 342 } 343 344 _, err = io.ReadAll(resp.Body) 345 if err != nil { 346 return errors.Wrap(err, "failed to read response body") 347 } 348 349 return nil 350 } 351 352 func CallZvaultRetrieveWallets(serverAddr, token string) (string, error) { 353 // Add your code here 354 endpoint := fmt.Sprintf("%s/wallets", serverAddr) 355 req, err := http.NewRequest("GET", endpoint, nil) 356 if err != nil { 357 return "", errors.Wrap(err, "failed to create HTTP request") 358 } 359 360 fmt.Println("call zvault /keys:", endpoint) 361 req.Header.Set("Content-Type", "application/json") 362 req.Header.Set("X-Jwt-Token", token) 363 364 client := &http.Client{} 365 resp, err := client.Do(req) 366 if err != nil { 367 return "", errors.Wrap(err, "failed to send HTTP request") 368 } 369 defer resp.Body.Close() 370 371 if resp.StatusCode != http.StatusOK { 372 errMsg, _ := io.ReadAll(resp.Body) 373 return "", fmt.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg)) 374 } 375 376 d, err := io.ReadAll(resp.Body) 377 if err != nil { 378 return "", errors.Wrap(err, "failed to read response body") 379 } 380 381 return string(d), nil 382 } 383 384 func CallZvaultRetrieveSharedWallets(serverAddr, token string) (string, error) { 385 // Add your code here 386 endpoint := fmt.Sprintf("%s/wallets/shared", serverAddr) 387 req, err := http.NewRequest("GET", endpoint, nil) 388 if err != nil { 389 return "", errors.Wrap(err, "failed to create HTTP request") 390 } 391 392 fmt.Println("call zvault /keys:", endpoint) 393 req.Header.Set("Content-Type", "application/json") 394 req.Header.Set("X-Jwt-Token", token) 395 396 client := &http.Client{} 397 resp, err := client.Do(req) 398 if err != nil { 399 return "", errors.Wrap(err, "failed to send HTTP request") 400 } 401 defer resp.Body.Close() 402 403 if resp.StatusCode != http.StatusOK { 404 errMsg, _ := io.ReadAll(resp.Body) 405 return "", fmt.Errorf("code: %d, err: %s", resp.StatusCode, string(errMsg)) 406 } 407 408 d, err := io.ReadAll(resp.Body) 409 if err != nil { 410 return "", errors.Wrap(err, "failed to read response body") 411 } 412 413 return string(d), nil 414 } 415 416 // ZauthSignTxn returns a function that sends a txn signing request to the zauth server 417 func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc { 418 return func(msg string) (string, error) { 419 fmt.Println("zvault sign txn - in sign txn...") 420 req, err := http.NewRequest("POST", serverAddr+"/sign/txn", bytes.NewBuffer([]byte(msg))) 421 if err != nil { 422 return "", errors.Wrap(err, "failed to create HTTP request") 423 } 424 req.Header.Set("Content-Type", "application/json") 425 c := client.GetClient() 426 pubkey := c.Keys[0].PublicKey 427 req.Header.Set("X-Peer-Public-Key", pubkey) 428 429 client := &http.Client{} 430 resp, err := client.Do(req) 431 if err != nil { 432 return "", errors.Wrap(err, "failed to send HTTP request") 433 } 434 defer resp.Body.Close() 435 if resp.StatusCode != http.StatusOK { 436 rsp, err := io.ReadAll(resp.Body) 437 if err != nil { 438 return "", errors.Wrap(err, "failed to read response body") 439 } 440 441 return "", errors.Errorf("unexpected status code: %d, res: %s", resp.StatusCode, string(rsp)) 442 } 443 444 d, err := io.ReadAll(resp.Body) 445 if err != nil { 446 return "", errors.Wrap(err, "failed to read response body") 447 } 448 449 return string(d), nil 450 } 451 } 452 453 func ZauthAuthCommon(serverAddr string) sys.AuthorizeFunc { 454 return func(msg string) (string, error) { 455 // return func(msg string) (string, error) { 456 req, err := http.NewRequest("POST", serverAddr+"/sign/msg", bytes.NewBuffer([]byte(msg))) 457 if err != nil { 458 return "", errors.Wrap(err, "failed to create HTTP request") 459 } 460 461 c := client.GetClient() 462 pubkey := c.Keys[0].PublicKey 463 req.Header.Set("Content-Type", "application/json") 464 req.Header.Set("X-Peer-Public-Key", pubkey) 465 466 client := &http.Client{} 467 resp, err := client.Do(req) 468 if err != nil { 469 return "", errors.Wrap(err, "failed to send HTTP request") 470 } 471 defer resp.Body.Close() 472 if resp.StatusCode != http.StatusOK { 473 rsp, err := io.ReadAll(resp.Body) 474 if err != nil { 475 return "", errors.Wrap(err, "failed to read response body") 476 } 477 478 return "", errors.Errorf("unexpected status code: %d, res: %s", resp.StatusCode, string(rsp)) 479 } 480 481 d, err := io.ReadAll(resp.Body) 482 if err != nil { 483 return "", errors.Wrap(err, "failed to read response body") 484 } 485 486 return string(d), nil 487 } 488 } 489 490 type AuthMessage struct { 491 Hash string `json:"hash"` 492 Signature string `json:"signature"` 493 ClientID string `json:"client_id"` 494 } 495 496 type AuthResponse struct { 497 Sig string `json:"sig"` 498 } 499 500 func ZauthSignMsg(serverAddr string) sys.SignFunc { 501 return func(hash string, signatureScheme string, keys []sys.KeyPair) (string, error) { 502 sig, err := SignWithKey(keys[0].PrivateKey, hash) 503 if err != nil { 504 return "", err 505 } 506 507 data, err := json.Marshal(AuthMessage{ 508 Hash: hash, 509 Signature: sig, 510 ClientID: client.GetClient().ClientID, 511 }) 512 if err != nil { 513 return "", err 514 } 515 516 // fmt.Println("auth - sys.AuthCommon:", sys.AuthCommon) 517 if sys.AuthCommon == nil { 518 return "", errors.New("authCommon is not set") 519 } 520 521 rsp, err := sys.AuthCommon(string(data)) 522 if err != nil { 523 return "", err 524 } 525 526 var ar AuthResponse 527 err = json.Unmarshal([]byte(rsp), &ar) 528 if err != nil { 529 return "", err 530 } 531 532 return AddSignature(client.GetClientPrivateKey(), ar.Sig, hash) 533 } 534 }