github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/cmd/smc/securitycmd.go (about) 1 package main 2 3 import ( 4 "crypto/ecdsa" 5 "encoding/hex" 6 "fmt" 7 "github.com/SmartMeshFoundation/Spectrum/accounts/keystore" 8 "github.com/SmartMeshFoundation/Spectrum/cmd/utils" 9 "github.com/SmartMeshFoundation/Spectrum/crypto" 10 "github.com/SmartMeshFoundation/Spectrum/node" 11 "github.com/pborman/uuid" 12 "gopkg.in/urfave/cli.v1" 13 "io/ioutil" 14 "os" 15 "path/filepath" 16 ) 17 18 const PWD_MIN_LEN = 6 19 20 var ( 21 security = new(Security) 22 securityCommand = cli.Command{ 23 Before: func(ctx *cli.Context) error { 24 fmt.Println("-----------------------") 25 if ctx.Bool(utils.TestnetFlag.Name) { 26 fmt.Println("- TESTNET ") 27 os.Setenv("TESTNET", "1") 28 } else if ctx.Bool(utils.DevnetFlag.Name) { 29 fmt.Println("- DEVNET ") 30 os.Setenv("DEVNET", "1") 31 } else { 32 fmt.Println("- MAINNET ") 33 } 34 security.homeDir = node.DefaultNodekeyDir() 35 fmt.Println("home_dir :", security.homeDir) 36 fmt.Println("-----------------------") 37 security.nodekey = filepath.Join(security.homeDir, "nodekey") 38 security.nodekeyPrv = filepath.Join(security.homeDir, "nodekey.prv") 39 return nil 40 }, 41 Action: security.run, 42 Name: "security", 43 Usage: "encrypt / decrypt nodekey, params mutual exclusion, only one choice", 44 ArgsUsage: "<TODO>", 45 Flags: []cli.Flag{ 46 cli.BoolFlag{ 47 Name: "testnet,t", 48 Usage: "", 49 }, 50 cli.BoolFlag{ 51 Name: "unlock,l", 52 Usage: "unlock nodekey with password", 53 Destination: &security.l, 54 }, 55 cli.BoolFlag{ 56 Name: "passwd,p", 57 Usage: "set or reset password", 58 Destination: &security.p, 59 }, 60 }, 61 Category: "BLOCKCHAIN COMMANDS", 62 Description: `TODO`, 63 } 64 ) 65 66 type Security struct { 67 homeDir, nodekey, nodekeyPrv string 68 l, p bool 69 prv *ecdsa.PrivateKey 70 } 71 72 func (self *Security) run(ctx *cli.Context) error { 73 if security.l && security.p { 74 fmt.Println("================================================================================") 75 fmt.Println(" INPUT : unlock=", security.l, " ; passwd=", security.p) 76 fmt.Println(" ERROR : params mutual exclusion, only one choice") 77 fmt.Println("================================================================================") 78 } 79 switch { 80 case security.l: 81 self.unlockCmd() 82 case security.p: 83 self.passwdCmd() 84 } 85 return nil 86 } 87 88 func (self *Security) unlockCmd() { 89 var ( 90 pwd string 91 counter int 92 pwdfile = filepath.Join(security.homeDir, "nodekey.pwd") 93 ) 94 data, err := ioutil.ReadFile(self.nodekeyPrv) 95 if err != nil { 96 fmt.Println("Please set password first.") 97 fmt.Println("ERROR :", err) 98 } 99 kjson, err := hex.DecodeString(string(data)) 100 if err != nil { 101 fmt.Println("ERROR:", err) 102 return 103 } 104 INPUT: 105 fmt.Println("Please input password : ") 106 fmt.Scanln(&pwd) 107 if _, err := keystore.DecryptKey(kjson, pwd); err != nil { 108 counter++ 109 fmt.Println(counter, "❌ Wrong password .") 110 if counter < 3 { 111 goto INPUT 112 } 113 return 114 } 115 os.Remove(pwdfile) 116 pwdhex := hex.EncodeToString([]byte(pwd)) 117 if err := ioutil.WriteFile(pwdfile, []byte(pwdhex), 0666); err == nil { 118 fmt.Println("😊 Success.") 119 } else { 120 fmt.Println("😢 Error :", err) 121 } 122 } 123 124 func (self *Security) passwdCmd() { 125 var ( 126 oldpwd, pwd string 127 ) 128 data, err := ioutil.ReadFile(self.nodekeyPrv) 129 if err != nil { 130 counter := 0 131 // set password and move nodekey to nodekey.prv 132 if err := self.loadNodekey(self.nodekey); err != nil { 133 fmt.Println("ERROR ::", err) 134 return 135 } 136 defer os.Remove(self.nodekey) 137 INPUT: 138 fmt.Println("Please input password : ") 139 fmt.Scanln(&pwd) 140 if len(pwd) < PWD_MIN_LEN { 141 counter++ 142 fmt.Println(counter, "❌ The password length needs to be greater than", PWD_MIN_LEN) 143 if counter < 3 { 144 goto INPUT 145 } 146 return 147 } 148 self.storeKey(self.nodekeyPrv, pwd) 149 } else { 150 // reset password 151 counter := 0 152 fmt.Println("Please input old password : ") 153 fmt.Scanln(&oldpwd) 154 kjson, err := hex.DecodeString(string(data)) 155 if err != nil { 156 fmt.Println("ERROR:", err) 157 return 158 } 159 160 key, err := keystore.DecryptKey(kjson, oldpwd) 161 if err != nil { 162 fmt.Println("ERROR:", err) 163 return 164 } 165 NEWPWD: 166 fmt.Println("Please input new password : ") 167 fmt.Scanln(&pwd) 168 if len(pwd) < PWD_MIN_LEN { 169 counter++ 170 fmt.Println(counter, "❌ The new password length needs to be greater than", PWD_MIN_LEN) 171 if counter < 3 { 172 goto NEWPWD 173 } 174 return 175 } 176 self.prv = key.PrivateKey 177 os.Remove(self.nodekeyPrv) 178 self.storeKey(self.nodekeyPrv, pwd) 179 } 180 181 } 182 183 func (self *Security) loadNodekey(path string) error { 184 f, err := os.Open(path) 185 if err != nil { 186 prv, err := crypto.GenerateKey() 187 if err != nil { 188 return err 189 } 190 self.prv = prv 191 } 192 buf := make([]byte, 512) 193 if n, err := f.Read(buf); err == nil { 194 k := string(buf[0:n]) 195 data, _ := hex.DecodeString(k) 196 prv, err := crypto.ToECDSA(data) 197 if err != nil { 198 return err 199 } 200 self.prv = prv 201 } 202 return nil 203 } 204 205 func (self *Security) storeKey(path, passphrase string) { 206 id := uuid.NewRandom() 207 key := &keystore.Key{ 208 Id: id, 209 Address: crypto.PubkeyToAddress(self.prv.PublicKey), 210 PrivateKey: self.prv, 211 } 212 keyjson, _ := keystore.EncryptKey(key, passphrase, keystore.StandardScryptN, keystore.StandardScryptP) 213 hexkey := hex.EncodeToString(keyjson) 214 if err := ioutil.WriteFile(path, []byte(hexkey), 0666); err == nil { 215 fmt.Println("😊 Success.") 216 } else { 217 fmt.Println("😢 Error :", err) 218 } 219 }