github.com/decred/politeia@v1.4.0/politeiawww/identity.go (about) 1 // Copyright (c) 2017-2021 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bufio" 9 "bytes" 10 "encoding/hex" 11 "encoding/json" 12 "fmt" 13 "io" 14 "net/http" 15 "os" 16 "path/filepath" 17 18 v1 "github.com/decred/politeia/politeiad/api/v1" 19 "github.com/decred/politeia/politeiad/api/v1/identity" 20 "github.com/decred/politeia/util" 21 ) 22 23 // getIdentity fetches the remote identity from politeiad and saves it to 24 // disk. politeiawww loads it from disk on future startups during config 25 // initialization. 26 func getIdentity(rpcHost, rpcCert, rpcIdentityFile, interactive string) error { 27 id, err := remoteIdentity(false, rpcHost, rpcCert) 28 if err != nil { 29 return err 30 } 31 32 // Pretty print identity. 33 log.Infof("Identity fetched from politeiad") 34 log.Infof("Key : %x", id.Key) 35 log.Infof("Fingerprint: %v", id.Fingerprint()) 36 37 if interactive == "" { 38 // Ask user if we like this identity 39 log.Infof("Press enter to save to %v or ctrl-c to abort", 40 rpcIdentityFile) 41 scanner := bufio.NewScanner(os.Stdin) 42 scanner.Scan() 43 if err = scanner.Err(); err != nil { 44 return err 45 } 46 } else { 47 log.Infof("Saving identity to %v", rpcIdentityFile) 48 } 49 50 // Save identity 51 err = os.MkdirAll(filepath.Dir(rpcIdentityFile), 0700) 52 if err != nil { 53 return err 54 } 55 err = id.SavePublicIdentity(rpcIdentityFile) 56 if err != nil { 57 return err 58 } 59 log.Infof("Identity saved to: %v", rpcIdentityFile) 60 61 return nil 62 } 63 64 // remoteIdentity fetches the identity from politeiad. 65 func remoteIdentity(skipTLSVerify bool, host, cert string) (*identity.PublicIdentity, error) { 66 challenge, err := util.Random(v1.ChallengeSize) 67 if err != nil { 68 return nil, err 69 } 70 id, err := json.Marshal(v1.Identity{ 71 Challenge: hex.EncodeToString(challenge), 72 }) 73 if err != nil { 74 return nil, err 75 } 76 77 c, err := util.NewHTTPClient(skipTLSVerify, cert) 78 if err != nil { 79 return nil, err 80 } 81 r, err := c.Post(host+v1.IdentityRoute, "application/json", 82 bytes.NewReader(id)) 83 if err != nil { 84 return nil, err 85 } 86 defer r.Body.Close() 87 88 if r.StatusCode != http.StatusOK { 89 e, err := util.GetErrorFromJSON(r.Body) 90 if err != nil { 91 return nil, fmt.Errorf("%v", r.Status) 92 } 93 return nil, fmt.Errorf("%v: %v", r.Status, e) 94 } 95 96 body, err := io.ReadAll(r.Body) 97 if err != nil { 98 return nil, err 99 } 100 101 var ir v1.IdentityReply 102 err = json.Unmarshal(body, &ir) 103 if err != nil { 104 return nil, fmt.Errorf("Could node unmarshal IdentityReply: %v", 105 err) 106 } 107 108 // Convert and verify server identity 109 identity, err := identity.PublicIdentityFromString(ir.PublicKey) 110 if err != nil { 111 return nil, err 112 } 113 114 err = util.VerifyChallenge(identity, challenge, ir.Response) 115 if err != nil { 116 return nil, err 117 } 118 119 return identity, nil 120 }