Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
whqwjb
go-ethereum
提交
690f6ea1
G
go-ethereum
项目概览
whqwjb
/
go-ethereum
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
go-ethereum
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
690f6ea1
编写于
1月 31, 2017
作者:
G
gluk256
提交者:
Felix Lange
1月 31, 2017
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
cmd/wnode, whisper: add whisper CLI tool and mail server (#3580)
上级
1c140f73
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
769 addition
and
30 deletion
+769
-30
cmd/wnode/main.go
cmd/wnode/main.go
+537
-0
whisper/mailserver/mailserver.go
whisper/mailserver/mailserver.go
+170
-0
whisper/shhapi/api.go
whisper/shhapi/api.go
+6
-6
whisper/whisperv5/doc.go
whisper/whisperv5/doc.go
+1
-1
whisper/whisperv5/message_test.go
whisper/whisperv5/message_test.go
+33
-0
whisper/whisperv5/peer.go
whisper/whisperv5/peer.go
+5
-0
whisper/whisperv5/whisper.go
whisper/whisperv5/whisper.go
+17
-17
whisper/whisperv5/whisper_test.go
whisper/whisperv5/whisper_test.go
+0
-6
未找到文件。
cmd/wnode/main.go
0 → 100644
浏览文件 @
690f6ea1
// Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
// This is a simple Whisper node. It could be used as a stand-alone bootstrap node.
// Also, could be used for different test and diagnostics purposes.
package
main
import
(
"bufio"
"crypto/ecdsa"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/binary"
"encoding/hex"
"flag"
"fmt"
"os"
"strconv"
"strings"
"time"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/console"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/whisper/mailserver"
whisper
"github.com/ethereum/go-ethereum/whisper/whisperv5"
"golang.org/x/crypto/pbkdf2"
)
const
quitCommand
=
"~Q"
// singletons
var
(
server
*
p2p
.
Server
shh
*
whisper
.
Whisper
done
chan
struct
{}
mailServer
mailserver
.
WMailServer
input
=
bufio
.
NewReader
(
os
.
Stdin
)
)
// encryption
var
(
symKey
[]
byte
pub
*
ecdsa
.
PublicKey
asymKey
*
ecdsa
.
PrivateKey
nodeid
*
ecdsa
.
PrivateKey
topic
whisper
.
TopicType
filterID
uint32
msPassword
string
)
// 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"
)
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)"
)
argSalt
=
flag
.
String
(
"salt"
,
""
,
"salt (for topic and key derivation)"
)
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)"
)
)
func
main
()
{
processArgs
()
initialize
()
run
()
}
func
processArgs
()
{
flag
.
Parse
()
if
len
(
*
argIDFile
)
>
0
{
var
err
error
nodeid
,
err
=
crypto
.
LoadECDSA
(
*
argIDFile
)
if
err
!=
nil
{
utils
.
Fatalf
(
"Failed to load file [%s]: %s."
,
*
argIDFile
,
err
)
}
}
const
enodePrefix
=
"enode://"
if
len
(
*
argEnode
)
>
0
{
if
(
*
argEnode
)[
:
len
(
enodePrefix
)]
!=
enodePrefix
{
*
argEnode
=
enodePrefix
+
*
argEnode
}
}
if
len
(
*
argTopic
)
>
0
{
x
,
err
:=
hex
.
DecodeString
(
*
argTopic
)
if
err
!=
nil
{
utils
.
Fatalf
(
"Failed to parse the topic: %s"
,
err
)
}
topic
=
whisper
.
BytesToTopic
(
x
)
}
if
*
asymmetricMode
&&
len
(
*
argPub
)
>
0
{
pub
=
crypto
.
ToECDSAPub
(
common
.
FromHex
(
*
argPub
))
if
!
isKeyValid
(
pub
)
{
utils
.
Fatalf
(
"invalid public key"
)
}
}
if
*
echoMode
{
echo
()
}
}
func
echo
()
{
fmt
.
Printf
(
"ttl = %d
\n
"
,
*
argTTL
)
fmt
.
Printf
(
"workTime = %d
\n
"
,
*
argWorkTime
)
fmt
.
Printf
(
"pow = %f
\n
"
,
*
argPoW
)
fmt
.
Printf
(
"mspow = %f
\n
"
,
*
argServerPoW
)
fmt
.
Printf
(
"ip = %s
\n
"
,
*
argIP
)
fmt
.
Printf
(
"salt = %s
\n
"
,
*
argSalt
)
fmt
.
Printf
(
"pub = %s
\n
"
,
common
.
ToHex
(
crypto
.
FromECDSAPub
(
pub
)))
fmt
.
Printf
(
"idfile = %s
\n
"
,
*
argIDFile
)
fmt
.
Printf
(
"dbpath = %s
\n
"
,
*
argDBPath
)
fmt
.
Printf
(
"boot = %s
\n
"
,
*
argEnode
)
}
func
initialize
()
{
glog
.
SetV
(
logger
.
Warn
)
glog
.
SetToStderr
(
true
)
done
=
make
(
chan
struct
{})
var
peers
[]
*
discover
.
Node
var
err
error
if
*
generateKey
{
key
,
err
:=
crypto
.
GenerateKey
()
if
err
!=
nil
{
utils
.
Fatalf
(
"Failed to generate private key: %s"
,
err
)
}
k
:=
hex
.
EncodeToString
(
crypto
.
FromECDSA
(
key
))
fmt
.
Printf
(
"Random private key: %s
\n
"
,
k
)
os
.
Exit
(
0
)
}
if
*
testMode
{
password
:=
[]
byte
(
"test password for symmetric encryption"
)
salt
:=
[]
byte
(
"test salt for symmetric encryption"
)
symKey
=
pbkdf2
.
Key
(
password
,
salt
,
64
,
32
,
sha256
.
New
)
topic
=
whisper
.
TopicType
{
0xFF
,
0xFF
,
0xFF
,
0xFF
}
msPassword
=
"mail server test password"
}
if
*
bootstrapMode
{
if
len
(
*
argIP
)
==
0
{
argIP
=
scanLineA
(
"Please enter your IP and port (e.g. 127.0.0.1:30348): "
)
}
}
else
{
if
len
(
*
argEnode
)
==
0
{
argEnode
=
scanLineA
(
"Please enter the peer's enode: "
)
}
peer
:=
discover
.
MustParseNode
(
*
argEnode
)
peers
=
append
(
peers
,
peer
)
}
if
*
mailServerMode
{
if
len
(
msPassword
)
==
0
{
msPassword
,
err
=
console
.
Stdin
.
PromptPassword
(
"Please enter the Mail Server password: "
)
if
err
!=
nil
{
utils
.
Fatalf
(
"Failed to read Mail Server password: %s"
,
err
)
}
}
shh
=
whisper
.
NewWhisper
(
&
mailServer
)
mailServer
.
Init
(
shh
,
*
argDBPath
,
msPassword
,
*
argServerPoW
)
}
else
{
shh
=
whisper
.
NewWhisper
(
nil
)
}
asymKey
=
shh
.
NewIdentity
()
if
nodeid
==
nil
{
nodeid
=
shh
.
NewIdentity
()
}
server
=
&
p2p
.
Server
{
Config
:
p2p
.
Config
{
PrivateKey
:
nodeid
,
MaxPeers
:
128
,
Name
:
common
.
MakeName
(
"whisper-go"
,
"5.0"
),
Protocols
:
shh
.
Protocols
(),
ListenAddr
:
*
argIP
,
NAT
:
nat
.
Any
(),
BootstrapNodes
:
peers
,
StaticNodes
:
peers
,
TrustedNodes
:
peers
,
},
}
}
func
startServer
()
{
err
:=
server
.
Start
()
if
err
!=
nil
{
utils
.
Fatalf
(
"Failed to start Whisper peer: %s."
,
err
)
}
fmt
.
Printf
(
"my public key: %s
\n
"
,
common
.
ToHex
(
crypto
.
FromECDSAPub
(
&
asymKey
.
PublicKey
)))
fmt
.
Println
(
server
.
NodeInfo
()
.
Enode
)
if
*
bootstrapMode
{
configureNode
()
fmt
.
Println
(
"Bootstrap Whisper node started"
)
}
else
{
fmt
.
Println
(
"Whisper node started"
)
// first see if we can establish connection, then ask for user input
waitForConnection
(
true
)
configureNode
()
}
if
!*
forwarderMode
{
fmt
.
Printf
(
"Please type the message. To quit type: '%s'
\n
"
,
quitCommand
)
}
}
func
isKeyValid
(
k
*
ecdsa
.
PublicKey
)
bool
{
return
k
.
X
!=
nil
&&
k
.
Y
!=
nil
}
func
configureNode
()
{
var
err
error
var
p2pAccept
bool
if
*
forwarderMode
{
return
}
if
*
asymmetricMode
{
if
len
(
*
argPub
)
==
0
{
s
:=
scanLine
(
"Please enter the peer's public key: "
)
pub
=
crypto
.
ToECDSAPub
(
common
.
FromHex
(
s
))
if
!
isKeyValid
(
pub
)
{
utils
.
Fatalf
(
"Error: invalid public key"
)
}
}
}
if
*
requestMail
{
p2pAccept
=
true
if
len
(
msPassword
)
==
0
{
msPassword
,
err
=
console
.
Stdin
.
PromptPassword
(
"Please enter the Mail Server password: "
)
if
err
!=
nil
{
utils
.
Fatalf
(
"Failed to read Mail Server password: %s"
,
err
)
}
}
}
if
!*
asymmetricMode
&&
!*
forwarderMode
&&
!*
testMode
{
pass
,
err
:=
console
.
Stdin
.
PromptPassword
(
"Please enter the password: "
)
if
err
!=
nil
{
utils
.
Fatalf
(
"Failed to read passphrase: %v"
,
err
)
}
if
len
(
*
argSalt
)
==
0
{
argSalt
=
scanLineA
(
"Please enter the salt: "
)
}
symKey
=
pbkdf2
.
Key
([]
byte
(
pass
),
[]
byte
(
*
argSalt
),
65356
,
32
,
sha256
.
New
)
if
len
(
*
argTopic
)
==
0
{
generateTopic
([]
byte
(
pass
),
[]
byte
(
*
argSalt
))
}
}
if
*
mailServerMode
{
if
len
(
*
argDBPath
)
==
0
{
argDBPath
=
scanLineA
(
"Please enter the path to DB file: "
)
}
}
filter
:=
whisper
.
Filter
{
KeySym
:
symKey
,
KeyAsym
:
asymKey
,
Topics
:
[]
whisper
.
TopicType
{
topic
},
AcceptP2P
:
p2pAccept
,
}
filterID
=
shh
.
Watch
(
&
filter
)
fmt
.
Printf
(
"Filter is configured for the topic: %x
\n
"
,
topic
)
}
func
generateTopic
(
password
,
salt
[]
byte
)
{
const
rounds
=
4000
const
size
=
128
x1
:=
pbkdf2
.
Key
(
password
,
salt
,
rounds
,
size
,
sha512
.
New
)
x2
:=
pbkdf2
.
Key
(
password
,
salt
,
rounds
,
size
,
sha1
.
New
)
x3
:=
pbkdf2
.
Key
(
x1
,
x2
,
rounds
,
size
,
sha256
.
New
)
for
i
:=
0
;
i
<
size
;
i
++
{
topic
[
i
%
whisper
.
TopicLength
]
^=
x3
[
i
]
}
}
func
waitForConnection
(
timeout
bool
)
{
var
cnt
int
var
connected
bool
for
!
connected
{
time
.
Sleep
(
time
.
Millisecond
*
50
)
connected
=
server
.
PeerCount
()
>
0
if
timeout
{
cnt
++
if
cnt
>
1000
{
utils
.
Fatalf
(
"Timeout expired, failed to connect"
)
}
}
}
fmt
.
Println
(
"Connected to peer."
)
}
func
run
()
{
defer
mailServer
.
Close
()
startServer
()
defer
server
.
Stop
()
shh
.
Start
(
nil
)
defer
shh
.
Stop
()
if
!*
forwarderMode
{
go
messageLoop
()
}
if
*
requestMail
{
requestExpiredMessagesLoop
()
}
else
{
sendLoop
()
}
}
func
sendLoop
()
{
for
{
s
:=
scanLine
(
""
)
if
s
==
quitCommand
{
fmt
.
Println
(
"Quit command received"
)
close
(
done
)
break
}
sendMsg
([]
byte
(
s
))
if
*
asymmetricMode
{
// print your own message for convenience,
// because in asymmetric mode it is impossible to decrypt it
hour
,
min
,
sec
:=
time
.
Now
()
.
Clock
()
from
:=
crypto
.
PubkeyToAddress
(
asymKey
.
PublicKey
)
fmt
.
Printf
(
"
\n
%02d:%02d:%02d <%x>: %s
\n
"
,
hour
,
min
,
sec
,
from
,
s
)
}
}
}
func
scanLine
(
prompt
string
)
string
{
if
len
(
prompt
)
>
0
{
fmt
.
Print
(
prompt
)
}
txt
,
err
:=
input
.
ReadString
(
'\n'
)
if
err
!=
nil
{
utils
.
Fatalf
(
"input error: %s"
,
err
)
}
txt
=
strings
.
TrimRight
(
txt
,
"
\n\r
"
)
return
txt
}
func
scanLineA
(
prompt
string
)
*
string
{
s
:=
scanLine
(
prompt
)
return
&
s
}
func
scanUint
(
prompt
string
)
uint32
{
s
:=
scanLine
(
prompt
)
i
,
err
:=
strconv
.
Atoi
(
s
)
if
err
!=
nil
{
utils
.
Fatalf
(
"Fail to parse the lower time limit: %s"
,
err
)
}
return
uint32
(
i
)
}
func
sendMsg
(
payload
[]
byte
)
{
params
:=
whisper
.
MessageParams
{
Src
:
asymKey
,
Dst
:
pub
,
KeySym
:
symKey
,
Payload
:
payload
,
Topic
:
topic
,
TTL
:
uint32
(
*
argTTL
),
PoW
:
*
argPoW
,
WorkTime
:
uint32
(
*
argWorkTime
),
}
msg
:=
whisper
.
NewSentMessage
(
&
params
)
envelope
,
err
:=
msg
.
Wrap
(
&
params
)
if
err
!=
nil
{
fmt
.
Printf
(
"failed to seal message: %v
\n
"
,
err
)
return
}
err
=
shh
.
Send
(
envelope
)
if
err
!=
nil
{
fmt
.
Printf
(
"failed to send message: %v
\n
"
,
err
)
}
}
func
messageLoop
()
{
f
:=
shh
.
GetFilter
(
filterID
)
if
f
==
nil
{
utils
.
Fatalf
(
"filter is not installed"
)
}
ticker
:=
time
.
NewTicker
(
time
.
Millisecond
*
50
)
for
{
select
{
case
<-
ticker
.
C
:
messages
:=
f
.
Retrieve
()
for
_
,
msg
:=
range
messages
{
printMessageInfo
(
msg
)
}
case
<-
done
:
return
}
}
}
func
printMessageInfo
(
msg
*
whisper
.
ReceivedMessage
)
{
timestamp
:=
fmt
.
Sprintf
(
"%d"
,
msg
.
Sent
)
// unix timestamp for diagnostics
text
:=
string
(
msg
.
Payload
)
var
address
common
.
Address
if
msg
.
Src
!=
nil
{
address
=
crypto
.
PubkeyToAddress
(
*
msg
.
Src
)
}
if
whisper
.
IsPubKeyEqual
(
msg
.
Src
,
&
asymKey
.
PublicKey
)
{
fmt
.
Printf
(
"
\n
%s <%x>: %s
\n
"
,
timestamp
,
address
,
text
)
// message from myself
}
else
{
fmt
.
Printf
(
"
\n
%s [%x]: %s
\n
"
,
timestamp
,
address
,
text
)
// message from a peer
}
}
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
))
if
err
!=
nil
{
utils
.
Fatalf
(
"Failed to create symmetric key for mail request: %s"
,
err
)
}
key
=
shh
.
GetSymKey
(
mailserver
.
MailServerKeyName
)
peerID
=
extractIdFromEnode
(
*
argEnode
)
shh
.
MarkPeerTrusted
(
peerID
)
for
{
timeLow
=
scanUint
(
"Please enter the lower limit of the time range (unix timestamp): "
)
timeUpp
=
scanUint
(
"Please enter the upper limit of the time range (unix timestamp): "
)
t
=
scanLine
(
"Please enter the topic (hexadecimal): "
)
if
len
(
t
)
>=
whisper
.
TopicLength
*
2
{
x
,
err
:=
hex
.
DecodeString
(
t
)
if
err
!=
nil
{
utils
.
Fatalf
(
"Failed to parse the topic: %s"
,
err
)
}
xt
=
whisper
.
BytesToTopic
(
x
)
}
if
timeUpp
==
0
{
timeUpp
=
0xFFFFFFFF
}
data
:=
make
([]
byte
,
8
+
whisper
.
TopicLength
)
binary
.
BigEndian
.
PutUint32
(
data
,
timeLow
)
binary
.
BigEndian
.
PutUint32
(
data
[
4
:
],
timeUpp
)
copy
(
data
[
8
:
],
xt
[
:
])
if
xt
==
empty
{
data
=
data
[
:
8
]
}
var
params
whisper
.
MessageParams
params
.
PoW
=
*
argServerPoW
params
.
Payload
=
data
params
.
KeySym
=
key
params
.
Src
=
nodeid
params
.
WorkTime
=
5
msg
:=
whisper
.
NewSentMessage
(
&
params
)
env
,
err
:=
msg
.
Wrap
(
&
params
)
if
err
!=
nil
{
utils
.
Fatalf
(
"Wrap failed: %s"
,
err
)
}
err
=
shh
.
RequestHistoricMessages
(
peerID
,
env
)
if
err
!=
nil
{
utils
.
Fatalf
(
"Failed to send P2P message: %s"
,
err
)
}
time
.
Sleep
(
time
.
Second
*
5
)
}
}
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
[
:
]
}
whisper/mailserver/mailserver.go
0 → 100644
浏览文件 @
690f6ea1
// Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package
mailserver
import
(
"bytes"
"encoding/binary"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rlp"
whisper
"github.com/ethereum/go-ethereum/whisper/whisperv5"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/util"
)
const
MailServerKeyName
=
"958e04ab302fb36ad2616a352cbac79d"
type
WMailServer
struct
{
db
*
leveldb
.
DB
w
*
whisper
.
Whisper
pow
float64
key
[]
byte
}
type
DBKey
struct
{
timestamp
uint32
hash
common
.
Hash
raw
[]
byte
}
func
NewDbKey
(
t
uint32
,
h
common
.
Hash
)
*
DBKey
{
const
sz
=
common
.
HashLength
+
4
var
k
DBKey
k
.
timestamp
=
t
k
.
hash
=
h
k
.
raw
=
make
([]
byte
,
sz
)
binary
.
BigEndian
.
PutUint32
(
k
.
raw
,
k
.
timestamp
)
copy
(
k
.
raw
[
4
:
],
k
.
hash
[
:
])
return
&
k
}
func
(
s
*
WMailServer
)
Init
(
shh
*
whisper
.
Whisper
,
path
string
,
password
string
,
pow
float64
)
{
var
err
error
if
len
(
path
)
==
0
{
utils
.
Fatalf
(
"DB file is not specified"
)
}
if
len
(
password
)
==
0
{
utils
.
Fatalf
(
"Password is not specified for MailServer"
)
}
s
.
db
,
err
=
leveldb
.
OpenFile
(
path
,
nil
)
if
err
!=
nil
{
utils
.
Fatalf
(
"Failed to open DB file: %s"
,
err
)
}
s
.
w
=
shh
s
.
pow
=
pow
err
=
s
.
w
.
AddSymKey
(
MailServerKeyName
,
[]
byte
(
password
))
if
err
!=
nil
{
utils
.
Fatalf
(
"Failed to create symmetric key for MailServer: %s"
,
err
)
}
s
.
key
=
s
.
w
.
GetSymKey
(
MailServerKeyName
)
}
func
(
s
*
WMailServer
)
Close
()
{
if
s
.
db
!=
nil
{
s
.
db
.
Close
()
}
}
func
(
s
*
WMailServer
)
Archive
(
env
*
whisper
.
Envelope
)
{
key
:=
NewDbKey
(
env
.
Expiry
-
env
.
TTL
,
env
.
Hash
())
rawEnvelope
,
err
:=
rlp
.
EncodeToBytes
(
env
)
if
err
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"rlp.EncodeToBytes failed: %s"
,
err
)
}
else
{
err
=
s
.
db
.
Put
(
key
.
raw
,
rawEnvelope
,
nil
)
if
err
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Writing to DB failed: %s"
,
err
)
}
}
}
func
(
s
*
WMailServer
)
DeliverMail
(
peer
*
whisper
.
Peer
,
request
*
whisper
.
Envelope
)
{
ok
,
lower
,
upper
,
topic
:=
s
.
validate
(
peer
,
request
)
if
!
ok
{
return
}
var
err
error
var
zero
common
.
Hash
var
empty
whisper
.
TopicType
kl
:=
NewDbKey
(
lower
,
zero
)
ku
:=
NewDbKey
(
upper
,
zero
)
i
:=
s
.
db
.
NewIterator
(
&
util
.
Range
{
Start
:
kl
.
raw
,
Limit
:
ku
.
raw
},
nil
)
defer
i
.
Release
()
for
i
.
Next
()
{
var
envelope
whisper
.
Envelope
err
=
rlp
.
DecodeBytes
(
i
.
Value
(),
&
envelope
)
if
err
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"RLP decoding failed: %s"
,
err
)
}
if
topic
==
empty
||
envelope
.
Topic
==
topic
{
err
=
s
.
w
.
SendP2PDirect
(
peer
,
&
envelope
)
if
err
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Failed to send direct message to peer: %s"
,
err
)
return
}
}
}
err
=
i
.
Error
()
if
err
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Level DB iterator error: %s"
,
err
)
}
}
func
(
s
*
WMailServer
)
validate
(
peer
*
whisper
.
Peer
,
request
*
whisper
.
Envelope
)
(
bool
,
uint32
,
uint32
,
whisper
.
TopicType
)
{
var
topic
whisper
.
TopicType
if
s
.
pow
>
0.0
&&
request
.
PoW
()
<
s
.
pow
{
return
false
,
0
,
0
,
topic
}
f
:=
whisper
.
Filter
{
KeySym
:
s
.
key
}
decrypted
:=
request
.
Open
(
&
f
)
if
decrypted
==
nil
{
glog
.
V
(
logger
.
Warn
)
.
Infof
(
"Failed to decrypt p2p request"
)
return
false
,
0
,
0
,
topic
}
if
len
(
decrypted
.
Payload
)
<
8
{
glog
.
V
(
logger
.
Warn
)
.
Infof
(
"Undersized p2p request"
)
return
false
,
0
,
0
,
topic
}
if
bytes
.
Equal
(
peer
.
ID
(),
decrypted
.
Signature
)
{
glog
.
V
(
logger
.
Warn
)
.
Infof
(
"Wrong signature of p2p request"
)
return
false
,
0
,
0
,
topic
}
lower
:=
binary
.
BigEndian
.
Uint32
(
decrypted
.
Payload
[
:
4
])
upper
:=
binary
.
BigEndian
.
Uint32
(
decrypted
.
Payload
[
4
:
8
])
if
len
(
decrypted
.
Payload
)
>=
8
+
whisper
.
TopicLength
{
topic
=
whisper
.
BytesToTopic
(
decrypted
.
Payload
[
8
:
])
}
return
true
,
lower
,
upper
,
topic
}
whisper/shhapi/api.go
浏览文件 @
690f6ea1
...
...
@@ -93,12 +93,12 @@ func (api *PublicWhisperAPI) MarkPeerTrusted(peerID hexutil.Bytes) error {
// data contains parameters (time frame, payment details, etc.), required
// by the remote email-like server. Whisper is not aware about the data format,
// it will just forward the raw data to the server.
func
(
api
*
PublicWhisperAPI
)
RequestHistoricMessages
(
peerID
hexutil
.
Bytes
,
data
hexutil
.
Bytes
)
error
{
if
api
.
whisper
==
nil
{
return
whisperOffLineErr
}
return
api
.
whisper
.
RequestHistoricMessages
(
peerID
,
data
)
}
//
func (api *PublicWhisperAPI) RequestHistoricMessages(peerID hexutil.Bytes, data hexutil.Bytes) error {
//
if api.whisper == nil {
//
return whisperOffLineErr
//
}
//
return api.whisper.RequestHistoricMessages(peerID, data)
//
}
// HasIdentity checks if the whisper node is configured with the private key
// of the specified public pair.
...
...
whisper/whisperv5/doc.go
浏览文件 @
690f6ea1
...
...
@@ -83,5 +83,5 @@ func (e unknownVersionError) Error() string {
// in order to bypass the expiry checks.
type
MailServer
interface
{
Archive
(
env
*
Envelope
)
DeliverMail
(
whisperPeer
*
Peer
,
data
[]
byt
e
)
DeliverMail
(
whisperPeer
*
Peer
,
request
*
Envelop
e
)
}
whisper/whisperv5/message_test.go
浏览文件 @
690f6ea1
...
...
@@ -22,6 +22,7 @@ import (
"testing"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
)
func
copyFromBuf
(
dst
[]
byte
,
src
[]
byte
,
beg
int
)
int
{
...
...
@@ -311,3 +312,35 @@ func TestEncryptWithZeroKey(t *testing.T) {
t
.
Fatalf
(
"wrapped with nil key, seed: %d."
,
seed
)
}
}
func
TestRlpEncode
(
t
*
testing
.
T
)
{
InitSingleTest
()
params
,
err
:=
generateMessageParams
()
if
err
!=
nil
{
t
.
Fatalf
(
"failed generateMessageParams with seed %d: %s."
,
seed
,
err
)
}
msg
:=
NewSentMessage
(
params
)
env
,
err
:=
msg
.
Wrap
(
params
)
if
err
!=
nil
{
t
.
Fatalf
(
"wrapped with zero key, seed: %d."
,
seed
)
}
raw
,
err
:=
rlp
.
EncodeToBytes
(
env
)
if
err
!=
nil
{
t
.
Fatalf
(
"RLP encode failed: %s."
,
err
)
}
var
decoded
Envelope
rlp
.
DecodeBytes
(
raw
,
&
decoded
)
if
err
!=
nil
{
t
.
Fatalf
(
"RLP decode failed: %s."
,
err
)
}
he
:=
env
.
Hash
()
hd
:=
decoded
.
Hash
()
if
he
!=
hd
{
t
.
Fatalf
(
"Hashes are not equal: %x vs. %x"
,
he
,
hd
)
}
}
whisper/whisperv5/peer.go
浏览文件 @
690f6ea1
...
...
@@ -175,3 +175,8 @@ func (p *Peer) broadcast() error {
glog
.
V
(
logger
.
Detail
)
.
Infoln
(
p
.
peer
,
"broadcasted"
,
len
(
transmit
),
"message(s)"
)
return
nil
}
func
(
p
*
Peer
)
ID
()
[]
byte
{
id
:=
p
.
peer
.
ID
()
return
id
[
:
]
}
whisper/whisperv5/whisper.go
浏览文件 @
690f6ea1
...
...
@@ -31,7 +31,6 @@ import (
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rlp"
"golang.org/x/crypto/pbkdf2"
set
"gopkg.in/fatih/set.v0"
)
...
...
@@ -125,13 +124,13 @@ func (w *Whisper) MarkPeerTrusted(peerID []byte) error {
return
nil
}
func
(
w
*
Whisper
)
RequestHistoricMessages
(
peerID
[]
byte
,
data
[]
byt
e
)
error
{
func
(
w
*
Whisper
)
RequestHistoricMessages
(
peerID
[]
byte
,
envelope
*
Envelop
e
)
error
{
p
,
err
:=
w
.
getPeer
(
peerID
)
if
err
!=
nil
{
return
err
}
p
.
trusted
=
true
return
p2p
.
Send
(
p
.
ws
,
p2pRequestCode
,
data
)
return
p2p
.
Send
(
p
.
ws
,
p2pRequestCode
,
envelope
)
}
func
(
w
*
Whisper
)
SendP2PMessage
(
peerID
[]
byte
,
envelope
*
Envelope
)
error
{
...
...
@@ -142,6 +141,10 @@ func (w *Whisper) SendP2PMessage(peerID []byte, envelope *Envelope) error {
return
p2p
.
Send
(
p
.
ws
,
p2pCode
,
envelope
)
}
func
(
w
*
Whisper
)
SendP2PDirect
(
peer
*
Peer
,
envelope
*
Envelope
)
error
{
return
p2p
.
Send
(
peer
.
ws
,
p2pCode
,
envelope
)
}
// NewIdentity generates a new cryptographic identity for the client, and injects
// it into the known identities for message decryption.
func
(
w
*
Whisper
)
NewIdentity
()
*
ecdsa
.
PrivateKey
{
...
...
@@ -347,9 +350,6 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
return
fmt
.
Errorf
(
"invalid envelope"
)
}
p
.
mark
(
envelope
)
if
wh
.
mailServer
!=
nil
{
wh
.
mailServer
.
Archive
(
envelope
)
}
}
case
p2pCode
:
// peer-to-peer message, sent directly to peer bypassing PoW checks, etc.
...
...
@@ -357,25 +357,22 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
// therefore might not satisfy the PoW, expiry and other requirements.
// these messages are only accepted from the trusted peer.
if
p
.
trusted
{
var
envelope
s
[]
*
Envelope
if
err
:=
packet
.
Decode
(
&
envelope
s
);
err
!=
nil
{
var
envelope
Envelope
if
err
:=
packet
.
Decode
(
&
envelope
);
err
!=
nil
{
glog
.
V
(
logger
.
Warn
)
.
Infof
(
"%v: failed to decode direct message: [%v], peer will be disconnected"
,
p
.
peer
,
err
)
return
fmt
.
Errorf
(
"garbage received (directMessage)"
)
}
for
_
,
envelope
:=
range
envelopes
{
wh
.
postEvent
(
envelope
,
true
)
}
wh
.
postEvent
(
&
envelope
,
true
)
}
case
p2pRequestCode
:
// Must be processed if mail server is implemented. Otherwise ignore.
if
wh
.
mailServer
!=
nil
{
s
:=
rlp
.
NewStream
(
packet
.
Payload
,
uint64
(
packet
.
Size
))
data
,
err
:=
s
.
Bytes
()
if
err
==
nil
{
wh
.
mailServer
.
DeliverMail
(
p
,
data
)
}
else
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"%v: bad requestHistoricMessages received: [%v]"
,
p
.
peer
,
err
)
var
request
Envelope
if
err
:=
packet
.
Decode
(
&
request
);
err
!=
nil
{
glog
.
V
(
logger
.
Warn
)
.
Infof
(
"%v: failed to decode p2p request message: [%v], peer will be disconnected"
,
p
.
peer
,
err
)
return
fmt
.
Errorf
(
"garbage received (p2p request)"
)
}
wh
.
mailServer
.
DeliverMail
(
p
,
&
request
)
}
default
:
// New message types might be implemented in the future versions of Whisper.
...
...
@@ -454,6 +451,9 @@ func (wh *Whisper) add(envelope *Envelope) error {
}
else
{
glog
.
V
(
logger
.
Detail
)
.
Infof
(
"cached whisper envelope [%x]: %v
\n
"
,
envelope
.
Hash
(),
envelope
)
wh
.
postEvent
(
envelope
,
false
)
// notify the local node about the new message
if
wh
.
mailServer
!=
nil
{
wh
.
mailServer
.
Archive
(
envelope
)
}
}
return
nil
}
...
...
whisper/whisperv5/whisper_test.go
浏览文件 @
690f6ea1
...
...
@@ -57,12 +57,6 @@ func TestWhisperBasic(t *testing.T) {
if
err
:=
w
.
MarkPeerTrusted
(
peerID
);
err
==
nil
{
t
.
Fatalf
(
"failed MarkPeerTrusted."
)
}
if
err
:=
w
.
RequestHistoricMessages
(
peerID
,
peerID
);
err
==
nil
{
t
.
Fatalf
(
"failed RequestHistoricMessages."
)
}
if
err
:=
w
.
SendP2PMessage
(
peerID
,
nil
);
err
==
nil
{
t
.
Fatalf
(
"failed SendP2PMessage."
)
}
exist
:=
w
.
HasSymKey
(
"non-existing"
)
if
exist
{
t
.
Fatalf
(
"failed HasSymKey."
)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录