api.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. // Copyright 2016 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser 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. // The go-ethereum library 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 Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package whisperv5
  17. import (
  18. "encoding/json"
  19. "errors"
  20. "fmt"
  21. mathrand "math/rand"
  22. "github.com/ethereum/go-ethereum/common"
  23. "github.com/ethereum/go-ethereum/common/hexutil"
  24. "github.com/ethereum/go-ethereum/crypto"
  25. "github.com/ethereum/go-ethereum/logger"
  26. "github.com/ethereum/go-ethereum/logger/glog"
  27. )
  28. var whisperOffLineErr = errors.New("whisper is offline")
  29. // PublicWhisperAPI provides the whisper RPC service.
  30. type PublicWhisperAPI struct {
  31. whisper *Whisper
  32. }
  33. // NewPublicWhisperAPI create a new RPC whisper service.
  34. func NewPublicWhisperAPI(w *Whisper) *PublicWhisperAPI {
  35. return &PublicWhisperAPI{whisper: w}
  36. }
  37. // Start starts the Whisper worker threads.
  38. func (api *PublicWhisperAPI) Start() error {
  39. if api.whisper == nil {
  40. return whisperOffLineErr
  41. }
  42. return api.whisper.Start(nil)
  43. }
  44. // Stop stops the Whisper worker threads.
  45. func (api *PublicWhisperAPI) Stop() error {
  46. if api.whisper == nil {
  47. return whisperOffLineErr
  48. }
  49. return api.whisper.Stop()
  50. }
  51. // Version returns the Whisper version this node offers.
  52. func (api *PublicWhisperAPI) Version() (hexutil.Uint, error) {
  53. if api.whisper == nil {
  54. return 0, whisperOffLineErr
  55. }
  56. return hexutil.Uint(api.whisper.Version()), nil
  57. }
  58. // MarkPeerTrusted marks specific peer trusted, which will allow it
  59. // to send historic (expired) messages.
  60. func (api *PublicWhisperAPI) MarkPeerTrusted(peerID hexutil.Bytes) error {
  61. if api.whisper == nil {
  62. return whisperOffLineErr
  63. }
  64. return api.whisper.MarkPeerTrusted(peerID)
  65. }
  66. // RequestHistoricMessages requests the peer to deliver the old (expired) messages.
  67. // data contains parameters (time frame, payment details, etc.), required
  68. // by the remote email-like server. Whisper is not aware about the data format,
  69. // it will just forward the raw data to the server.
  70. //func (api *PublicWhisperAPI) RequestHistoricMessages(peerID hexutil.Bytes, data hexutil.Bytes) error {
  71. // if api.whisper == nil {
  72. // return whisperOffLineErr
  73. // }
  74. // return api.whisper.RequestHistoricMessages(peerID, data)
  75. //}
  76. // HasIdentity checks if the whisper node is configured with the private key
  77. // of the specified public pair.
  78. func (api *PublicWhisperAPI) HasIdentity(identity string) (bool, error) {
  79. if api.whisper == nil {
  80. return false, whisperOffLineErr
  81. }
  82. return api.whisper.HasIdentity(identity), nil
  83. }
  84. // DeleteIdentity deletes the specifies key if it exists.
  85. func (api *PublicWhisperAPI) DeleteIdentity(identity string) error {
  86. if api.whisper == nil {
  87. return whisperOffLineErr
  88. }
  89. api.whisper.DeleteIdentity(identity)
  90. return nil
  91. }
  92. // NewIdentity generates a new cryptographic identity for the client, and injects
  93. // it into the known identities for message decryption.
  94. func (api *PublicWhisperAPI) NewIdentity() (string, error) {
  95. if api.whisper == nil {
  96. return "", whisperOffLineErr
  97. }
  98. identity := api.whisper.NewIdentity()
  99. return common.ToHex(crypto.FromECDSAPub(&identity.PublicKey)), nil
  100. }
  101. // GenerateSymKey generates a random symmetric key and stores it under
  102. // the 'name' id. Will be used in the future for session key exchange.
  103. func (api *PublicWhisperAPI) GenerateSymKey(name string) error {
  104. if api.whisper == nil {
  105. return whisperOffLineErr
  106. }
  107. return api.whisper.GenerateSymKey(name)
  108. }
  109. // AddSymKey stores the key under the 'name' id.
  110. func (api *PublicWhisperAPI) AddSymKey(name string, key []byte) error {
  111. if api.whisper == nil {
  112. return whisperOffLineErr
  113. }
  114. return api.whisper.AddSymKey(name, key)
  115. }
  116. // HasSymKey returns true if there is a key associated with the name string.
  117. // Otherwise returns false.
  118. func (api *PublicWhisperAPI) HasSymKey(name string) (bool, error) {
  119. if api.whisper == nil {
  120. return false, whisperOffLineErr
  121. }
  122. res := api.whisper.HasSymKey(name)
  123. return res, nil
  124. }
  125. // DeleteSymKey deletes the key associated with the name string if it exists.
  126. func (api *PublicWhisperAPI) DeleteSymKey(name string) error {
  127. if api.whisper == nil {
  128. return whisperOffLineErr
  129. }
  130. api.whisper.DeleteSymKey(name)
  131. return nil
  132. }
  133. // NewWhisperFilter creates and registers a new message filter to watch for inbound whisper messages.
  134. // Returns the ID of the newly created Filter.
  135. func (api *PublicWhisperAPI) NewFilter(args WhisperFilterArgs) (uint32, error) {
  136. if api.whisper == nil {
  137. return 0, whisperOffLineErr
  138. }
  139. filter := Filter{
  140. Src: crypto.ToECDSAPub(common.FromHex(args.From)),
  141. KeySym: api.whisper.GetSymKey(args.KeyName),
  142. PoW: args.PoW,
  143. Messages: make(map[common.Hash]*ReceivedMessage),
  144. AcceptP2P: args.AcceptP2P,
  145. }
  146. if len(filter.KeySym) > 0 {
  147. filter.SymKeyHash = crypto.Keccak256Hash(filter.KeySym)
  148. }
  149. filter.Topics = append(filter.Topics, args.Topics...)
  150. if len(args.Topics) == 0 {
  151. info := "NewFilter: at least one topic must be specified"
  152. glog.V(logger.Error).Infof(info)
  153. return 0, errors.New(info)
  154. }
  155. if len(args.KeyName) != 0 && len(filter.KeySym) == 0 {
  156. info := "NewFilter: key was not found by name: " + args.KeyName
  157. glog.V(logger.Error).Infof(info)
  158. return 0, errors.New(info)
  159. }
  160. if len(args.To) == 0 && len(filter.KeySym) == 0 {
  161. info := "NewFilter: filter must contain either symmetric or asymmetric key"
  162. glog.V(logger.Error).Infof(info)
  163. return 0, errors.New(info)
  164. }
  165. if len(args.To) != 0 && len(filter.KeySym) != 0 {
  166. info := "NewFilter: filter must not contain both symmetric and asymmetric key"
  167. glog.V(logger.Error).Infof(info)
  168. return 0, errors.New(info)
  169. }
  170. if len(args.To) > 0 {
  171. dst := crypto.ToECDSAPub(common.FromHex(args.To))
  172. if !ValidatePublicKey(dst) {
  173. info := "NewFilter: Invalid 'To' address"
  174. glog.V(logger.Error).Infof(info)
  175. return 0, errors.New(info)
  176. }
  177. filter.KeyAsym = api.whisper.GetIdentity(string(args.To))
  178. if filter.KeyAsym == nil {
  179. info := "NewFilter: non-existent identity provided"
  180. glog.V(logger.Error).Infof(info)
  181. return 0, errors.New(info)
  182. }
  183. }
  184. if len(args.From) > 0 {
  185. if !ValidatePublicKey(filter.Src) {
  186. info := "NewFilter: Invalid 'From' address"
  187. glog.V(logger.Error).Infof(info)
  188. return 0, errors.New(info)
  189. }
  190. }
  191. id := api.whisper.Watch(&filter)
  192. return id, nil
  193. }
  194. // UninstallFilter disables and removes an existing filter.
  195. func (api *PublicWhisperAPI) UninstallFilter(filterId uint32) {
  196. api.whisper.Unwatch(filterId)
  197. }
  198. // GetFilterChanges retrieves all the new messages matched by a filter since the last retrieval.
  199. func (api *PublicWhisperAPI) GetFilterChanges(filterId uint32) []WhisperMessage {
  200. f := api.whisper.GetFilter(filterId)
  201. if f != nil {
  202. newMail := f.Retrieve()
  203. return toWhisperMessages(newMail)
  204. }
  205. return toWhisperMessages(nil)
  206. }
  207. // GetMessages retrieves all the known messages that match a specific filter.
  208. func (api *PublicWhisperAPI) GetMessages(filterId uint32) []WhisperMessage {
  209. all := api.whisper.Messages(filterId)
  210. return toWhisperMessages(all)
  211. }
  212. // toWhisperMessages converts a Whisper message to a RPC whisper message.
  213. func toWhisperMessages(messages []*ReceivedMessage) []WhisperMessage {
  214. msgs := make([]WhisperMessage, len(messages))
  215. for i, msg := range messages {
  216. msgs[i] = NewWhisperMessage(msg)
  217. }
  218. return msgs
  219. }
  220. // Post creates a whisper message and injects it into the network for distribution.
  221. func (api *PublicWhisperAPI) Post(args PostArgs) error {
  222. if api.whisper == nil {
  223. return whisperOffLineErr
  224. }
  225. params := MessageParams{
  226. TTL: args.TTL,
  227. Dst: crypto.ToECDSAPub(common.FromHex(args.To)),
  228. KeySym: api.whisper.GetSymKey(args.KeyName),
  229. Topic: args.Topic,
  230. Payload: args.Payload,
  231. Padding: args.Padding,
  232. WorkTime: args.WorkTime,
  233. PoW: args.PoW,
  234. }
  235. if len(args.From) > 0 {
  236. pub := crypto.ToECDSAPub(common.FromHex(args.From))
  237. if !ValidatePublicKey(pub) {
  238. info := "Post: Invalid 'From' address"
  239. glog.V(logger.Error).Infof(info)
  240. return errors.New(info)
  241. }
  242. params.Src = api.whisper.GetIdentity(string(args.From))
  243. if params.Src == nil {
  244. info := "Post: non-existent identity provided"
  245. glog.V(logger.Error).Infof(info)
  246. return errors.New(info)
  247. }
  248. }
  249. filter := api.whisper.GetFilter(args.FilterID)
  250. if filter == nil && args.FilterID > 0 {
  251. info := fmt.Sprintf("Post: wrong filter id %d", args.FilterID)
  252. glog.V(logger.Error).Infof(info)
  253. return errors.New(info)
  254. }
  255. if filter != nil {
  256. // get the missing fields from the filter
  257. if params.KeySym == nil && filter.KeySym != nil {
  258. params.KeySym = filter.KeySym
  259. }
  260. if params.Src == nil && filter.Src != nil {
  261. params.Src = filter.KeyAsym
  262. }
  263. if (params.Topic == TopicType{}) {
  264. sz := len(filter.Topics)
  265. if sz < 1 {
  266. info := fmt.Sprintf("Post: no topics in filter # %d", args.FilterID)
  267. glog.V(logger.Error).Infof(info)
  268. return errors.New(info)
  269. } else if sz == 1 {
  270. params.Topic = filter.Topics[0]
  271. } else {
  272. // choose randomly
  273. rnd := mathrand.Intn(sz)
  274. params.Topic = filter.Topics[rnd]
  275. }
  276. }
  277. }
  278. // validate
  279. if len(args.KeyName) != 0 && len(params.KeySym) == 0 {
  280. info := "Post: key was not found by name: " + args.KeyName
  281. glog.V(logger.Error).Infof(info)
  282. return errors.New(info)
  283. }
  284. if len(args.To) == 0 && len(params.KeySym) == 0 {
  285. info := "Post: message must be encrypted either symmetrically or asymmetrically"
  286. glog.V(logger.Error).Infof(info)
  287. return errors.New(info)
  288. }
  289. if len(args.To) != 0 && len(params.KeySym) != 0 {
  290. info := "Post: ambigous encryption method requested"
  291. glog.V(logger.Error).Infof(info)
  292. return errors.New(info)
  293. }
  294. if len(args.To) > 0 {
  295. if !ValidatePublicKey(params.Dst) {
  296. info := "Post: Invalid 'To' address"
  297. glog.V(logger.Error).Infof(info)
  298. return errors.New(info)
  299. }
  300. }
  301. // encrypt and send
  302. message := NewSentMessage(&params)
  303. envelope, err := message.Wrap(&params)
  304. if err != nil {
  305. glog.V(logger.Error).Infof(err.Error())
  306. return err
  307. }
  308. if len(envelope.Data) > MaxMessageLength {
  309. info := "Post: message is too big"
  310. glog.V(logger.Error).Infof(info)
  311. return errors.New(info)
  312. }
  313. if (envelope.Topic == TopicType{} && envelope.IsSymmetric()) {
  314. info := "Post: topic is missing for symmetric encryption"
  315. glog.V(logger.Error).Infof(info)
  316. return errors.New(info)
  317. }
  318. if args.PeerID != nil {
  319. return api.whisper.SendP2PMessage(args.PeerID, envelope)
  320. }
  321. return api.whisper.Send(envelope)
  322. }
  323. type PostArgs struct {
  324. TTL uint32 `json:"ttl"`
  325. From string `json:"from"`
  326. To string `json:"to"`
  327. KeyName string `json:"keyname"`
  328. Topic TopicType `json:"topic"`
  329. Padding hexutil.Bytes `json:"padding"`
  330. Payload hexutil.Bytes `json:"payload"`
  331. WorkTime uint32 `json:"worktime"`
  332. PoW float64 `json:"pow"`
  333. FilterID uint32 `json:"filterID"`
  334. PeerID hexutil.Bytes `json:"peerID"`
  335. }
  336. type WhisperFilterArgs struct {
  337. To string
  338. From string
  339. KeyName string
  340. PoW float64
  341. Topics []TopicType
  342. AcceptP2P bool
  343. }
  344. // UnmarshalJSON implements the json.Unmarshaler interface, invoked to convert a
  345. // JSON message blob into a WhisperFilterArgs structure.
  346. func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) {
  347. // Unmarshal the JSON message and sanity check
  348. var obj struct {
  349. To string `json:"to"`
  350. From string `json:"from"`
  351. KeyName string `json:"keyname"`
  352. PoW float64 `json:"pow"`
  353. Topics []interface{} `json:"topics"`
  354. AcceptP2P bool `json:"acceptP2P"`
  355. }
  356. if err := json.Unmarshal(b, &obj); err != nil {
  357. return err
  358. }
  359. args.To = obj.To
  360. args.From = obj.From
  361. args.KeyName = obj.KeyName
  362. args.PoW = obj.PoW
  363. args.AcceptP2P = obj.AcceptP2P
  364. // Construct the topic array
  365. if obj.Topics != nil {
  366. topics := make([]string, len(obj.Topics))
  367. for i, field := range obj.Topics {
  368. switch value := field.(type) {
  369. case string:
  370. topics[i] = value
  371. case nil:
  372. return fmt.Errorf("topic[%d] is empty", i)
  373. default:
  374. return fmt.Errorf("topic[%d] is not a string", i)
  375. }
  376. }
  377. topicsDecoded := make([]TopicType, len(topics))
  378. for j, s := range topics {
  379. x := common.FromHex(s)
  380. if x == nil || len(x) != TopicLength {
  381. return fmt.Errorf("topic[%d] is invalid", j)
  382. }
  383. topicsDecoded[j] = BytesToTopic(x)
  384. }
  385. args.Topics = topicsDecoded
  386. }
  387. return nil
  388. }
  389. // WhisperMessage is the RPC representation of a whisper message.
  390. type WhisperMessage struct {
  391. Payload string `json:"payload"`
  392. Padding string `json:"padding"`
  393. From string `json:"from"`
  394. To string `json:"to"`
  395. Sent uint32 `json:"sent"`
  396. TTL uint32 `json:"ttl"`
  397. PoW float64 `json:"pow"`
  398. Hash string `json:"hash"`
  399. }
  400. // NewWhisperMessage converts an internal message into an API version.
  401. func NewWhisperMessage(message *ReceivedMessage) WhisperMessage {
  402. return WhisperMessage{
  403. Payload: common.ToHex(message.Payload),
  404. Padding: common.ToHex(message.Padding),
  405. From: common.ToHex(crypto.FromECDSAPub(message.SigToPubKey())),
  406. To: common.ToHex(crypto.FromECDSAPub(message.Dst)),
  407. Sent: message.Sent,
  408. TTL: message.TTL,
  409. PoW: message.PoW,
  410. Hash: common.ToHex(message.EnvelopeHash.Bytes()),
  411. }
  412. }