github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/cmd/wnode/main.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 // This is a simple Whisper node. It could be used as a stand-alone bootstrap node. 18 // Also, could be used for different test and diagnostics purposes. 19 20 package main 21 22 import ( 23 "bufio" 24 "crypto/ecdsa" 25 "crypto/sha1" 26 "crypto/sha256" 27 "crypto/sha512" 28 "encoding/binary" 29 "encoding/hex" 30 "flag" 31 "fmt" 32 "os" 33 "strconv" 34 "strings" 35 "time" 36 37 "github.com/atheioschain/go-atheios/cmd/utils" 38 "github.com/atheioschain/go-atheios/common" 39 "github.com/atheioschain/go-atheios/console" 40 "github.com/atheioschain/go-atheios/crypto" 41 "github.com/atheioschain/go-atheios/logger" 42 "github.com/atheioschain/go-atheios/logger/glog" 43 "github.com/atheioschain/go-atheios/p2p" 44 "github.com/atheioschain/go-atheios/p2p/discover" 45 "github.com/atheioschain/go-atheios/p2p/nat" 46 "github.com/atheioschain/go-atheios/whisper/mailserver" 47 whisper "github.com/atheioschain/go-atheios/whisper/whisperv5" 48 "golang.org/x/crypto/pbkdf2" 49 ) 50 51 const quitCommand = "~Q" 52 53 // singletons 54 var ( 55 server *p2p.Server 56 shh *whisper.Whisper 57 done chan struct{} 58 mailServer mailserver.WMailServer 59 60 input = bufio.NewReader(os.Stdin) 61 ) 62 63 // encryption 64 var ( 65 symKey []byte 66 pub *ecdsa.PublicKey 67 asymKey *ecdsa.PrivateKey 68 nodeid *ecdsa.PrivateKey 69 topic whisper.TopicType 70 filterID uint32 71 msPassword string 72 ) 73 74 // cmd arguments 75 var ( 76 echoMode = flag.Bool("e", false, "echo mode: prints some arguments for diagnostics") 77 bootstrapMode = flag.Bool("b", false, "boostrap node: don't actively connect to peers, wait for incoming connections") 78 forwarderMode = flag.Bool("f", false, "forwarder mode: only forward messages, neither send nor decrypt messages") 79 mailServerMode = flag.Bool("s", false, "mail server mode: delivers expired messages on demand") 80 requestMail = flag.Bool("r", false, "request expired messages from the bootstrap server") 81 asymmetricMode = flag.Bool("a", false, "use asymmetric encryption") 82 testMode = flag.Bool("t", false, "use of predefined parameters for diagnostics") 83 generateKey = flag.Bool("k", false, "generate and show the private key") 84 85 argTTL = flag.Uint("ttl", 30, "time-to-live for messages in seconds") 86 argWorkTime = flag.Uint("work", 5, "work time in seconds") 87 argPoW = flag.Float64("pow", whisper.MinimumPoW, "PoW for normal messages in float format (e.g. 2.7)") 88 argServerPoW = flag.Float64("mspow", whisper.MinimumPoW, "PoW requirement for Mail Server request") 89 90 argIP = flag.String("ip", "", "IP address and port of this node (e.g. 127.0.0.1:30303)") 91 argSalt = flag.String("salt", "", "salt (for topic and key derivation)") 92 argPub = flag.String("pub", "", "public key for asymmetric encryption") 93 argDBPath = flag.String("dbpath", "", "path to the server's DB directory") 94 argIDFile = flag.String("idfile", "", "file name with node id (private key)") 95 argEnode = flag.String("boot", "", "bootstrap node you want to connect to (e.g. enode://e454......08d50@52.176.211.200:16428)") 96 argTopic = flag.String("topic", "", "topic in hexadecimal format (e.g. 70a4beef)") 97 ) 98 99 func main() { 100 processArgs() 101 initialize() 102 run() 103 } 104 105 func processArgs() { 106 flag.Parse() 107 108 if len(*argIDFile) > 0 { 109 var err error 110 nodeid, err = crypto.LoadECDSA(*argIDFile) 111 if err != nil { 112 utils.Fatalf("Failed to load file [%s]: %s.", *argIDFile, err) 113 } 114 } 115 116 const enodePrefix = "enode://" 117 if len(*argEnode) > 0 { 118 if (*argEnode)[:len(enodePrefix)] != enodePrefix { 119 *argEnode = enodePrefix + *argEnode 120 } 121 } 122 123 if len(*argTopic) > 0 { 124 x, err := hex.DecodeString(*argTopic) 125 if err != nil { 126 utils.Fatalf("Failed to parse the topic: %s", err) 127 } 128 topic = whisper.BytesToTopic(x) 129 } 130 131 if *asymmetricMode && len(*argPub) > 0 { 132 pub = crypto.ToECDSAPub(common.FromHex(*argPub)) 133 if !isKeyValid(pub) { 134 utils.Fatalf("invalid public key") 135 } 136 } 137 138 if *echoMode { 139 echo() 140 } 141 } 142 143 func echo() { 144 fmt.Printf("ttl = %d \n", *argTTL) 145 fmt.Printf("workTime = %d \n", *argWorkTime) 146 fmt.Printf("pow = %f \n", *argPoW) 147 fmt.Printf("mspow = %f \n", *argServerPoW) 148 fmt.Printf("ip = %s \n", *argIP) 149 fmt.Printf("salt = %s \n", *argSalt) 150 fmt.Printf("pub = %s \n", common.ToHex(crypto.FromECDSAPub(pub))) 151 fmt.Printf("idfile = %s \n", *argIDFile) 152 fmt.Printf("dbpath = %s \n", *argDBPath) 153 fmt.Printf("boot = %s \n", *argEnode) 154 } 155 156 func initialize() { 157 glog.SetV(logger.Warn) 158 glog.SetToStderr(true) 159 160 done = make(chan struct{}) 161 var peers []*discover.Node 162 var err error 163 164 if *generateKey { 165 key, err := crypto.GenerateKey() 166 if err != nil { 167 utils.Fatalf("Failed to generate private key: %s", err) 168 } 169 k := hex.EncodeToString(crypto.FromECDSA(key)) 170 fmt.Printf("Random private key: %s \n", k) 171 os.Exit(0) 172 } 173 174 if *testMode { 175 password := []byte("test password for symmetric encryption") 176 salt := []byte("test salt for symmetric encryption") 177 symKey = pbkdf2.Key(password, salt, 64, 32, sha256.New) 178 topic = whisper.TopicType{0xFF, 0xFF, 0xFF, 0xFF} 179 msPassword = "mail server test password" 180 } 181 182 if *bootstrapMode { 183 if len(*argIP) == 0 { 184 argIP = scanLineA("Please enter your IP and port (e.g. 127.0.0.1:30348): ") 185 } 186 } else { 187 if len(*argEnode) == 0 { 188 argEnode = scanLineA("Please enter the peer's enode: ") 189 } 190 peer := discover.MustParseNode(*argEnode) 191 peers = append(peers, peer) 192 } 193 194 if *mailServerMode { 195 if len(msPassword) == 0 { 196 msPassword, err = console.Stdin.PromptPassword("Please enter the Mail Server password: ") 197 if err != nil { 198 utils.Fatalf("Failed to read Mail Server password: %s", err) 199 } 200 } 201 shh = whisper.NewWhisper(&mailServer) 202 mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW) 203 } else { 204 shh = whisper.NewWhisper(nil) 205 } 206 207 asymKey = shh.NewIdentity() 208 if nodeid == nil { 209 nodeid = shh.NewIdentity() 210 } 211 212 maxPeers := 80 213 if *bootstrapMode { 214 maxPeers = 800 215 } 216 217 server = &p2p.Server{ 218 Config: p2p.Config{ 219 PrivateKey: nodeid, 220 MaxPeers: maxPeers, 221 Name: common.MakeName("whisper-go", "5.0"), 222 Protocols: shh.Protocols(), 223 ListenAddr: *argIP, 224 NAT: nat.Any(), 225 BootstrapNodes: peers, 226 StaticNodes: peers, 227 TrustedNodes: peers, 228 }, 229 } 230 } 231 232 func startServer() { 233 err := server.Start() 234 if err != nil { 235 utils.Fatalf("Failed to start Whisper peer: %s.", err) 236 } 237 238 fmt.Printf("my public key: %s \n", common.ToHex(crypto.FromECDSAPub(&asymKey.PublicKey))) 239 fmt.Println(server.NodeInfo().Enode) 240 241 if *bootstrapMode { 242 configureNode() 243 fmt.Println("Bootstrap Whisper node started") 244 } else { 245 fmt.Println("Whisper node started") 246 // first see if we can establish connection, then ask for user input 247 waitForConnection(true) 248 configureNode() 249 } 250 251 if !*forwarderMode { 252 fmt.Printf("Please type the message. To quit type: '%s'\n", quitCommand) 253 } 254 } 255 256 func isKeyValid(k *ecdsa.PublicKey) bool { 257 return k.X != nil && k.Y != nil 258 } 259 260 func configureNode() { 261 var err error 262 var p2pAccept bool 263 264 if *forwarderMode { 265 return 266 } 267 268 if *asymmetricMode { 269 if len(*argPub) == 0 { 270 s := scanLine("Please enter the peer's public key: ") 271 pub = crypto.ToECDSAPub(common.FromHex(s)) 272 if !isKeyValid(pub) { 273 utils.Fatalf("Error: invalid public key") 274 } 275 } 276 } 277 278 if *requestMail { 279 p2pAccept = true 280 if len(msPassword) == 0 { 281 msPassword, err = console.Stdin.PromptPassword("Please enter the Mail Server password: ") 282 if err != nil { 283 utils.Fatalf("Failed to read Mail Server password: %s", err) 284 } 285 } 286 } 287 288 if !*asymmetricMode && !*forwarderMode && !*testMode { 289 pass, err := console.Stdin.PromptPassword("Please enter the password: ") 290 if err != nil { 291 utils.Fatalf("Failed to read passphrase: %v", err) 292 } 293 294 if len(*argSalt) == 0 { 295 argSalt = scanLineA("Please enter the salt: ") 296 } 297 298 symKey = pbkdf2.Key([]byte(pass), []byte(*argSalt), 65356, 32, sha256.New) 299 300 if len(*argTopic) == 0 { 301 generateTopic([]byte(pass), []byte(*argSalt)) 302 } 303 } 304 305 if *mailServerMode { 306 if len(*argDBPath) == 0 { 307 argDBPath = scanLineA("Please enter the path to DB file: ") 308 } 309 } 310 311 filter := whisper.Filter{ 312 KeySym: symKey, 313 KeyAsym: asymKey, 314 Topics: []whisper.TopicType{topic}, 315 AcceptP2P: p2pAccept, 316 } 317 filterID = shh.Watch(&filter) 318 fmt.Printf("Filter is configured for the topic: %x \n", topic) 319 } 320 321 func generateTopic(password, salt []byte) { 322 const rounds = 4000 323 const size = 128 324 x1 := pbkdf2.Key(password, salt, rounds, size, sha512.New) 325 x2 := pbkdf2.Key(password, salt, rounds, size, sha1.New) 326 x3 := pbkdf2.Key(x1, x2, rounds, size, sha256.New) 327 328 for i := 0; i < size; i++ { 329 topic[i%whisper.TopicLength] ^= x3[i] 330 } 331 } 332 333 func waitForConnection(timeout bool) { 334 var cnt int 335 var connected bool 336 for !connected { 337 time.Sleep(time.Millisecond * 50) 338 connected = server.PeerCount() > 0 339 if timeout { 340 cnt++ 341 if cnt > 1000 { 342 utils.Fatalf("Timeout expired, failed to connect") 343 } 344 } 345 } 346 347 fmt.Println("Connected to peer.") 348 } 349 350 func run() { 351 defer mailServer.Close() 352 startServer() 353 defer server.Stop() 354 shh.Start(nil) 355 defer shh.Stop() 356 357 if !*forwarderMode { 358 go messageLoop() 359 } 360 361 if *requestMail { 362 requestExpiredMessagesLoop() 363 } else { 364 sendLoop() 365 } 366 } 367 368 func sendLoop() { 369 for { 370 s := scanLine("") 371 if s == quitCommand { 372 fmt.Println("Quit command received") 373 close(done) 374 break 375 } 376 sendMsg([]byte(s)) 377 378 if *asymmetricMode { 379 // print your own message for convenience, 380 // because in asymmetric mode it is impossible to decrypt it 381 hour, min, sec := time.Now().Clock() 382 from := crypto.PubkeyToAddress(asymKey.PublicKey) 383 fmt.Printf("\n%02d:%02d:%02d <%x>: %s\n", hour, min, sec, from, s) 384 } 385 } 386 } 387 388 func scanLine(prompt string) string { 389 if len(prompt) > 0 { 390 fmt.Print(prompt) 391 } 392 txt, err := input.ReadString('\n') 393 if err != nil { 394 utils.Fatalf("input error: %s", err) 395 } 396 txt = strings.TrimRight(txt, "\n\r") 397 return txt 398 } 399 400 func scanLineA(prompt string) *string { 401 s := scanLine(prompt) 402 return &s 403 } 404 405 func scanUint(prompt string) uint32 { 406 s := scanLine(prompt) 407 i, err := strconv.Atoi(s) 408 if err != nil { 409 utils.Fatalf("Fail to parse the lower time limit: %s", err) 410 } 411 return uint32(i) 412 } 413 414 func sendMsg(payload []byte) { 415 params := whisper.MessageParams{ 416 Src: asymKey, 417 Dst: pub, 418 KeySym: symKey, 419 Payload: payload, 420 Topic: topic, 421 TTL: uint32(*argTTL), 422 PoW: *argPoW, 423 WorkTime: uint32(*argWorkTime), 424 } 425 426 msg := whisper.NewSentMessage(¶ms) 427 envelope, err := msg.Wrap(¶ms) 428 if err != nil { 429 fmt.Printf("failed to seal message: %v \n", err) 430 return 431 } 432 433 err = shh.Send(envelope) 434 if err != nil { 435 fmt.Printf("failed to send message: %v \n", err) 436 } 437 } 438 439 func messageLoop() { 440 f := shh.GetFilter(filterID) 441 if f == nil { 442 utils.Fatalf("filter is not installed") 443 } 444 445 ticker := time.NewTicker(time.Millisecond * 50) 446 447 for { 448 select { 449 case <-ticker.C: 450 messages := f.Retrieve() 451 for _, msg := range messages { 452 printMessageInfo(msg) 453 } 454 case <-done: 455 return 456 } 457 } 458 } 459 460 func printMessageInfo(msg *whisper.ReceivedMessage) { 461 timestamp := fmt.Sprintf("%d", msg.Sent) // unix timestamp for diagnostics 462 text := string(msg.Payload) 463 464 var address common.Address 465 if msg.Src != nil { 466 address = crypto.PubkeyToAddress(*msg.Src) 467 } 468 469 if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) { 470 fmt.Printf("\n%s <%x>: %s\n", timestamp, address, text) // message from myself 471 } else { 472 fmt.Printf("\n%s [%x]: %s\n", timestamp, address, text) // message from a peer 473 } 474 } 475 476 func requestExpiredMessagesLoop() { 477 var key, peerID []byte 478 var timeLow, timeUpp uint32 479 var t string 480 var xt, empty whisper.TopicType 481 482 err := shh.AddSymKey(mailserver.MailServerKeyName, []byte(msPassword)) 483 if err != nil { 484 utils.Fatalf("Failed to create symmetric key for mail request: %s", err) 485 } 486 key = shh.GetSymKey(mailserver.MailServerKeyName) 487 peerID = extractIdFromEnode(*argEnode) 488 shh.MarkPeerTrusted(peerID) 489 490 for { 491 timeLow = scanUint("Please enter the lower limit of the time range (unix timestamp): ") 492 timeUpp = scanUint("Please enter the upper limit of the time range (unix timestamp): ") 493 t = scanLine("Please enter the topic (hexadecimal): ") 494 if len(t) >= whisper.TopicLength*2 { 495 x, err := hex.DecodeString(t) 496 if err != nil { 497 utils.Fatalf("Failed to parse the topic: %s", err) 498 } 499 xt = whisper.BytesToTopic(x) 500 } 501 if timeUpp == 0 { 502 timeUpp = 0xFFFFFFFF 503 } 504 505 data := make([]byte, 8+whisper.TopicLength) 506 binary.BigEndian.PutUint32(data, timeLow) 507 binary.BigEndian.PutUint32(data[4:], timeUpp) 508 copy(data[8:], xt[:]) 509 if xt == empty { 510 data = data[:8] 511 } 512 513 var params whisper.MessageParams 514 params.PoW = *argServerPoW 515 params.Payload = data 516 params.KeySym = key 517 params.Src = nodeid 518 params.WorkTime = 5 519 520 msg := whisper.NewSentMessage(¶ms) 521 env, err := msg.Wrap(¶ms) 522 if err != nil { 523 utils.Fatalf("Wrap failed: %s", err) 524 } 525 526 err = shh.RequestHistoricMessages(peerID, env) 527 if err != nil { 528 utils.Fatalf("Failed to send P2P message: %s", err) 529 } 530 531 time.Sleep(time.Second * 5) 532 } 533 } 534 535 func extractIdFromEnode(s string) []byte { 536 n, err := discover.ParseNode(s) 537 if err != nil { 538 utils.Fatalf("Failed to parse enode: %s", err) 539 return nil 540 } 541 return n.ID[:] 542 }