aboutsummaryrefslogtreecommitdiffstats
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/wnode/main.go195
1 files changed, 157 insertions, 38 deletions
diff --git a/cmd/wnode/main.go b/cmd/wnode/main.go
index 82d7eda3c..7431980b5 100644
--- a/cmd/wnode/main.go
+++ b/cmd/wnode/main.go
@@ -27,7 +27,9 @@ import (
"encoding/hex"
"flag"
"fmt"
+ "io/ioutil"
"os"
+ "path/filepath"
"strconv"
"strings"
"time"
@@ -46,7 +48,6 @@ import (
)
const quitCommand = "~Q"
-const symKeyName = "da919ea33001b04dfc630522e33078ec0df11"
// singletons
var (
@@ -64,7 +65,8 @@ var (
pub *ecdsa.PublicKey
asymKey *ecdsa.PrivateKey
nodeid *ecdsa.PrivateKey
- topic whisper.TopicType
+ topic []byte
+ asymKeyID string
filterID string
symPass string
msPassword string
@@ -72,27 +74,30 @@ var (
// cmd arguments
var (
- echoMode = flag.Bool("e", false, "echo mode: prints some arguments for diagnostics")
- bootstrapMode = flag.Bool("b", false, "boostrap node: don't actively connect to peers, wait for incoming connections")
- forwarderMode = flag.Bool("f", false, "forwarder mode: only forward messages, neither send nor decrypt messages")
- mailServerMode = flag.Bool("s", false, "mail server mode: delivers expired messages on demand")
- requestMail = flag.Bool("r", false, "request expired messages from the bootstrap server")
- asymmetricMode = flag.Bool("a", false, "use asymmetric encryption")
- testMode = flag.Bool("t", false, "use of predefined parameters for diagnostics")
- generateKey = flag.Bool("k", false, "generate and show the private key")
+ bootstrapMode = flag.Bool("standalone", false, "boostrap node: don't actively connect to peers, wait for incoming connections")
+ forwarderMode = flag.Bool("forwarder", false, "forwarder mode: only forward messages, neither send nor decrypt messages")
+ mailServerMode = flag.Bool("mailserver", false, "mail server mode: delivers expired messages on demand")
+ requestMail = flag.Bool("mailclient", false, "request expired messages from the bootstrap server")
+ asymmetricMode = flag.Bool("asym", false, "use asymmetric encryption")
+ generateKey = flag.Bool("generatekey", false, "generate and show the private key")
+ fileExMode = flag.Bool("fileexchange", false, "file exchange mode")
+ testMode = flag.Bool("test", false, "use of predefined parameters for diagnostics")
+ echoMode = flag.Bool("echo", false, "echo mode: prints some arguments for diagnostics")
argVerbosity = flag.Int("verbosity", int(log.LvlWarn), "log verbosity level")
argTTL = flag.Uint("ttl", 30, "time-to-live for messages in seconds")
argWorkTime = flag.Uint("work", 5, "work time in seconds")
- argPoW = flag.Float64("pow", whisper.MinimumPoW, "PoW for normal messages in float format (e.g. 2.7)")
- argServerPoW = flag.Float64("mspow", whisper.MinimumPoW, "PoW requirement for Mail Server request")
-
- argIP = flag.String("ip", "", "IP address and port of this node (e.g. 127.0.0.1:30303)")
- argPub = flag.String("pub", "", "public key for asymmetric encryption")
- argDBPath = flag.String("dbpath", "", "path to the server's DB directory")
- argIDFile = flag.String("idfile", "", "file name with node id (private key)")
- argEnode = flag.String("boot", "", "bootstrap node you want to connect to (e.g. enode://e454......08d50@52.176.211.200:16428)")
- argTopic = flag.String("topic", "", "topic in hexadecimal format (e.g. 70a4beef)")
+ argMaxSize = flag.Int("maxsize", whisper.DefaultMaxMessageLength, "max size of message")
+ argPoW = flag.Float64("pow", whisper.DefaultMinimumPoW, "PoW for normal messages in float format (e.g. 2.7)")
+ argServerPoW = flag.Float64("mspow", whisper.DefaultMinimumPoW, "PoW requirement for Mail Server request")
+
+ argIP = flag.String("ip", "", "IP address and port of this node (e.g. 127.0.0.1:30303)")
+ argPub = flag.String("pub", "", "public key for asymmetric encryption")
+ argDBPath = flag.String("dbpath", "", "path to the server's DB directory")
+ argIDFile = flag.String("idfile", "", "file name with node id (private key)")
+ argEnode = flag.String("boot", "", "bootstrap node you want to connect to (e.g. enode://e454......08d50@52.176.211.200:16428)")
+ argTopic = flag.String("topic", "", "topic in hexadecimal format (e.g. 70a4beef)")
+ argSaveDir = flag.String("savedir", "", "directory where incoming messages will be saved as files")
)
func main() {
@@ -124,7 +129,7 @@ func processArgs() {
if err != nil {
utils.Fatalf("Failed to parse the topic: %s", err)
}
- topic = whisper.BytesToTopic(x)
+ topic = x
}
if *asymmetricMode && len(*argPub) > 0 {
@@ -134,6 +139,14 @@ func processArgs() {
}
}
+ if len(*argSaveDir) > 0 {
+ if _, err := os.Stat(*argSaveDir); os.IsNotExist(err) {
+ utils.Fatalf("Download directory '%s' does not exist", *argSaveDir)
+ }
+ } else if *fileExMode {
+ utils.Fatalf("Parameter 'savedir' is mandatory for file exchange mode")
+ }
+
if *echoMode {
echo()
}
@@ -199,9 +212,40 @@ func initialize() {
shh = whisper.New()
}
- asymKey = shh.NewIdentity()
+ if *argPoW != whisper.DefaultMinimumPoW {
+ err := shh.SetMinimumPoW(*argPoW)
+ if err != nil {
+ utils.Fatalf("Failed to set PoW: %s", err)
+ }
+ }
+
+ if *argMaxSize != whisper.DefaultMaxMessageLength {
+ err := shh.SetMaxMessageLength(*argMaxSize)
+ if err != nil {
+ utils.Fatalf("Failed to set max message size: %s", err)
+ }
+ }
+
+ asymKeyID, err = shh.NewKeyPair()
+ if err != nil {
+ utils.Fatalf("Failed to generate a new key pair: %s", err)
+ }
+
+ asymKey, err = shh.GetPrivateKey(asymKeyID)
+ if err != nil {
+ utils.Fatalf("Failed to retrieve a new key pair: %s", err)
+ }
+
if nodeid == nil {
- nodeid = shh.NewIdentity()
+ tmpID, err := shh.NewKeyPair()
+ if err != nil {
+ utils.Fatalf("Failed to generate a new key pair: %s", err)
+ }
+
+ nodeid, err = shh.GetPrivateKey(tmpID)
+ if err != nil {
+ utils.Fatalf("Failed to retrieve a new key pair: %s", err)
+ }
}
maxPeers := 80
@@ -213,7 +257,8 @@ func initialize() {
Config: p2p.Config{
PrivateKey: nodeid,
MaxPeers: maxPeers,
- Name: common.MakeName("whisper-go", "5.0"),
+ Discovery: true,
+ Name: common.MakeName("wnode", "5.0"),
Protocols: shh.Protocols(),
ListenAddr: *argIP,
NAT: nat.Any(),
@@ -288,8 +333,14 @@ func configureNode() {
}
}
- shh.AddSymKey(symKeyName, []byte(symPass))
- symKey = shh.GetSymKey(symKeyName)
+ symKeyID, err := shh.AddSymKeyFromPassword(symPass)
+ if err != nil {
+ utils.Fatalf("Failed to create symmetric key: %s", err)
+ }
+ symKey, err = shh.GetSymKey(symKeyID)
+ if err != nil {
+ utils.Fatalf("Failed to save symmetric key: %s", err)
+ }
if len(*argTopic) == 0 {
generateTopic([]byte(symPass))
}
@@ -302,12 +353,12 @@ func configureNode() {
}
filter := whisper.Filter{
- KeySym: symKey,
- KeyAsym: asymKey,
- Topics: []whisper.TopicType{topic},
- AcceptP2P: p2pAccept,
+ KeySym: symKey,
+ KeyAsym: asymKey,
+ Topics: [][]byte{topic},
+ AllowP2P: p2pAccept,
}
- filterID, err = shh.Watch(&filter)
+ filterID, err = shh.Subscribe(&filter)
if err != nil {
utils.Fatalf("Failed to install filter: %s", err)
}
@@ -351,6 +402,8 @@ func run() {
if *requestMail {
requestExpiredMessagesLoop()
+ } else if *fileExMode {
+ sendFilesLoop()
} else {
sendLoop()
}
@@ -376,6 +429,31 @@ func sendLoop() {
}
}
+func sendFilesLoop() {
+ for {
+ s := scanLine("")
+ if s == quitCommand {
+ fmt.Println("Quit command received")
+ close(done)
+ break
+ }
+ b, err := ioutil.ReadFile(s)
+ if err != nil {
+ fmt.Printf(">>> Error: %s \n", err)
+ continue
+ } else {
+ h := sendMsg(b)
+ if (h == common.Hash{}) {
+ fmt.Printf(">>> Error: message was not sent \n")
+ } else {
+ timestamp := time.Now().Unix()
+ from := crypto.PubkeyToAddress(asymKey.PublicKey)
+ fmt.Printf("\n%d <%x>: sent message with hash %x\n", timestamp, from, h)
+ }
+ }
+ }
+}
+
func scanLine(prompt string) string {
if len(prompt) > 0 {
fmt.Print(prompt)
@@ -402,29 +480,36 @@ func scanUint(prompt string) uint32 {
return uint32(i)
}
-func sendMsg(payload []byte) {
+func sendMsg(payload []byte) common.Hash {
params := whisper.MessageParams{
Src: asymKey,
Dst: pub,
KeySym: symKey,
Payload: payload,
- Topic: topic,
+ Topic: whisper.BytesToTopic(topic),
TTL: uint32(*argTTL),
PoW: *argPoW,
WorkTime: uint32(*argWorkTime),
}
msg := whisper.NewSentMessage(&params)
+ if msg == nil {
+ fmt.Printf("failed to create new message (OS level error)")
+ os.Exit(0)
+ }
envelope, err := msg.Wrap(&params)
if err != nil {
fmt.Printf("failed to seal message: %v \n", err)
- return
+ return common.Hash{}
}
err = shh.Send(envelope)
if err != nil {
fmt.Printf("failed to send message: %v \n", err)
+ return common.Hash{}
}
+
+ return envelope.Hash()
}
func messageLoop() {
@@ -440,7 +525,11 @@ func messageLoop() {
case <-ticker.C:
messages := f.Retrieve()
for _, msg := range messages {
- printMessageInfo(msg)
+ if *fileExMode || len(msg.Payload) > 2048 {
+ writeMessageToFile(*argSaveDir, msg)
+ } else {
+ printMessageInfo(msg)
+ }
}
case <-done:
return
@@ -464,19 +553,47 @@ func printMessageInfo(msg *whisper.ReceivedMessage) {
}
}
+func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) {
+ timestamp := fmt.Sprintf("%d", msg.Sent)
+ name := fmt.Sprintf("%x", msg.EnvelopeHash)
+
+ var address common.Address
+ if msg.Src != nil {
+ address = crypto.PubkeyToAddress(*msg.Src)
+ }
+
+ if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) {
+ // message from myself: don't save, only report
+ fmt.Printf("\n%s <%x>: message received: '%s'\n", timestamp, address, name)
+ } else if len(dir) > 0 {
+ fullpath := filepath.Join(dir, name)
+ err := ioutil.WriteFile(fullpath, msg.Payload, 0644)
+ if err != nil {
+ fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
+ } else {
+ fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(msg.Payload))
+ }
+ } else {
+ fmt.Printf("\n%s {%x}: big message received (%d bytes), but not saved: %s\n", timestamp, address, len(msg.Payload), name)
+ }
+}
+
func requestExpiredMessagesLoop() {
var key, peerID []byte
var timeLow, timeUpp uint32
var t string
var xt, empty whisper.TopicType
- err := shh.AddSymKey(mailserver.MailServerKeyName, []byte(msPassword))
+ keyID, err := shh.AddSymKeyFromPassword(msPassword)
if err != nil {
utils.Fatalf("Failed to create symmetric key for mail request: %s", err)
}
- key = shh.GetSymKey(mailserver.MailServerKeyName)
+ key, err = shh.GetSymKey(keyID)
+ if err != nil {
+ utils.Fatalf("Failed to save symmetric key for mail request: %s", err)
+ }
peerID = extractIdFromEnode(*argEnode)
- shh.MarkPeerTrusted(peerID)
+ shh.AllowP2PMessagesFromPeer(peerID)
for {
timeLow = scanUint("Please enter the lower limit of the time range (unix timestamp): ")
@@ -509,6 +626,9 @@ func requestExpiredMessagesLoop() {
params.WorkTime = 5
msg := whisper.NewSentMessage(&params)
+ if msg == nil {
+ utils.Fatalf("failed to create new message (OS level error)")
+ }
env, err := msg.Wrap(&params)
if err != nil {
utils.Fatalf("Wrap failed: %s", err)
@@ -527,7 +647,6 @@ func extractIdFromEnode(s string) []byte {
n, err := discover.ParseNode(s)
if err != nil {
utils.Fatalf("Failed to parse enode: %s", err)
- return nil
}
return n.ID[:]
}