github.com/decred/politeia@v1.4.0/politeiawww/cmd/pictl/usernew.go (about) 1 // Copyright (c) 2017-2019 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 "encoding/hex" 9 "fmt" 10 "strconv" 11 12 v1 "github.com/decred/politeia/politeiawww/api/www/v1" 13 "github.com/decred/politeia/politeiawww/cmd/shared" 14 "github.com/decred/politeia/util" 15 ) 16 17 // userNewCmd creates a new politeia user. 18 type userNewCmd struct { 19 Args struct { 20 Email string `positional-arg-name:"email"` // Email address 21 Username string `positional-arg-name:"username"` // Username 22 Password string `positional-arg-name:"password"` // Password 23 } `positional-args:"true"` 24 Random bool `long:"random" optional:"true"` // Generate random user credentials 25 Paywall bool `long:"paywall" optional:"true"` // Use faucet to pay paywall (tesnet only) 26 Verify bool `long:"verify" optional:"true"` // Verify user email address (testnet only) 27 NoSave bool `long:"nosave" optional:"true"` // Don't save user identity to disk 28 } 29 30 // Execute executes the userNewCmd command. 31 // 32 // This function satisfies the go-flags Commander interface. 33 func (cmd *userNewCmd) Execute(args []string) error { 34 email := cmd.Args.Email 35 username := cmd.Args.Username 36 password := cmd.Args.Password 37 38 if !cmd.Random && (email == "" || username == "" || password == "") { 39 return fmt.Errorf("invalid credentials: you must either specify user " + 40 "credentials (email, username, password) or use the --random flag") 41 } 42 43 // Fetch CSRF tokens 44 _, err := client.Version() 45 if err != nil { 46 return fmt.Errorf("Version: %v", err) 47 } 48 49 // Fetch policy for password requirements 50 pr, err := client.Policy() 51 if err != nil { 52 return fmt.Errorf("Policy: %v", err) 53 } 54 55 // Create new user credentials if required 56 if cmd.Random { 57 b, err := util.Random(int(pr.MinPasswordLength)) 58 if err != nil { 59 return err 60 } 61 62 email = hex.EncodeToString(b) + "@example.com" 63 username = hex.EncodeToString(b) 64 password = hex.EncodeToString(b) 65 } 66 67 // Validate password 68 if uint(len(password)) < pr.MinPasswordLength { 69 return fmt.Errorf("password must be %v characters long", 70 pr.MinPasswordLength) 71 } 72 73 // Create user identity and save it to disk 74 id, err := shared.NewIdentity() 75 if err != nil { 76 return err 77 } 78 79 // Setup new user request 80 nu := &v1.NewUser{ 81 Email: email, 82 Username: username, 83 Password: shared.DigestSHA3(password), 84 PublicKey: hex.EncodeToString(id.Public.Key[:]), 85 } 86 87 // Print request details 88 err = shared.PrintJSON(nu) 89 if err != nil { 90 return err 91 } 92 93 // Send request 94 nur, err := client.NewUser(nu) 95 if err != nil { 96 return fmt.Errorf("NewUser: %v", err) 97 } 98 99 // Save user identity to disk 100 if !cmd.NoSave { 101 err = cfg.SaveIdentity(nu.Username, id) 102 if err != nil { 103 return err 104 } 105 } 106 107 // Print response details 108 err = shared.PrintJSON(nur) 109 if err != nil { 110 return err 111 } 112 113 // Verify user's email address 114 if cmd.Verify { 115 sig := id.SignMessage([]byte(nur.VerificationToken)) 116 vnur, err := client.VerifyNewUser(&v1.VerifyNewUser{ 117 Email: email, 118 VerificationToken: nur.VerificationToken, 119 Signature: hex.EncodeToString(sig[:]), 120 }) 121 if err != nil { 122 return fmt.Errorf("VerifyNewUser: %v", err) 123 } 124 125 err = shared.PrintJSON(vnur) 126 if err != nil { 127 return err 128 } 129 } 130 131 // Login to politeia 132 l := &v1.Login{ 133 Email: email, 134 Password: shared.DigestSHA3(password), 135 } 136 137 lr, err := client.Login(l) 138 if err != nil { 139 return err 140 } 141 142 // Pays paywall fee using faucet 143 if pr.PaywallEnabled && cmd.Paywall { 144 // The faucet has a floating point precision bug as of 145 // Oct 2021. Add an extra DCR to the amount to ensure 146 // the paywall gets fully paid. 147 dcrAmount := float64(lr.PaywallAmount)/1e8 + 1 148 faucet := cmdSendFaucetTx{} 149 faucet.Args.Address = lr.PaywallAddress 150 faucet.Args.Amount = strconv.FormatFloat(dcrAmount, 'f', -1, 64) 151 err = faucet.Execute(nil) 152 if err != nil { 153 return err 154 } 155 } 156 157 return nil 158 } 159 160 // userNewHelpMsg is the output of the help command when 'usernew' is 161 // specified. 162 const userNewHelpMsg = `usernew [flags] "email" "username" "password" 163 164 Create a new Politeia user. Users can be created by supplying all the arguments 165 below, or supplying the --random flag. If --random is used, Politeia will 166 generate a random email, username and password. 167 168 Arguments: 169 1. email (string, required) Email address 170 2. username (string, required) Username 171 3. password (string, required) Password 172 173 Flags: 174 --random (bool, optional) Generate a random email/password for the user 175 --paywall (bool, optional) Satisfy the paywall fee using testnet faucet 176 --verify (bool, optional) Verify the user's email address 177 --nosave (bool, optional) Do not save the user identity to disk`