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`