270 lines
8.1 KiB
Go
270 lines
8.1 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"path/filepath"
|
|
|
|
"github.com/status-im/status-go/geth/account"
|
|
"github.com/status-im/status-go/geth/common"
|
|
"github.com/status-im/status-go/geth/params"
|
|
"gopkg.in/urfave/cli.v1"
|
|
)
|
|
|
|
var (
|
|
// WhisperEchoModeFlag enables/disables Echo mode (arguments are printed for diagnostics)
|
|
WhisperEchoModeFlag = cli.BoolTFlag{
|
|
Name: "echo",
|
|
Usage: "Echo mode, prints some arguments for diagnostics (default: true)",
|
|
}
|
|
|
|
// WhisperBootstrapNodeFlag marks node as not actively listening for incoming connections
|
|
WhisperBootstrapNodeFlag = cli.BoolTFlag{
|
|
Name: "bootstrap",
|
|
Usage: "Don't actively connect to peers, wait for incoming connections (default: true)",
|
|
}
|
|
|
|
// WhisperNotificationServerNodeFlag enables/disables Push Notifications services
|
|
WhisperNotificationServerNodeFlag = cli.BoolFlag{
|
|
Name: "notify",
|
|
Usage: "Node is capable of sending Push Notifications",
|
|
}
|
|
|
|
// WhisperForwarderNodeFlag enables/disables message forwarding
|
|
// (when neither sends nor decrypts envelopes, just forwards them)
|
|
WhisperForwarderNodeFlag = cli.BoolFlag{
|
|
Name: "forward",
|
|
Usage: "Only forward messages, neither send nor decrypt messages",
|
|
}
|
|
|
|
// WhisperMailserverNodeFlag enables/disables Inboxing services
|
|
WhisperMailserverNodeFlag = cli.BoolFlag{
|
|
Name: "mailserver",
|
|
Usage: "Delivers expired messages on demand",
|
|
}
|
|
|
|
// WhisperIdentityFile is path to file containing private key of the node (for asymmetric encryption)
|
|
WhisperIdentityFile = cli.StringFlag{
|
|
Name: "identity",
|
|
Usage: "Protocol identity file (private key used for asymmetric encryption)",
|
|
}
|
|
|
|
// WhisperPasswordFile is password used to do a symmetric encryption
|
|
WhisperPasswordFile = cli.StringFlag{
|
|
Name: "password",
|
|
Usage: "Password file (password is used for symmetric encryption)",
|
|
}
|
|
|
|
// WhisperPortFlag defines port on which Whisper protocol is listening
|
|
WhisperPortFlag = cli.IntFlag{
|
|
Name: "port",
|
|
Usage: "Whisper node's listening port",
|
|
Value: params.WhisperPort,
|
|
}
|
|
|
|
// WhisperPoWFlag is the minimum PoW required by the node
|
|
WhisperPoWFlag = cli.Float64Flag{
|
|
Name: "pow",
|
|
Usage: "PoW for messages to be added to queue, in float format",
|
|
Value: params.WhisperMinimumPoW,
|
|
}
|
|
|
|
// WhisperTTLFlag defines node's default TTL for envelopes
|
|
WhisperTTLFlag = cli.IntFlag{
|
|
Name: "ttl",
|
|
Usage: "Time to live for messages, in seconds",
|
|
Value: params.WhisperTTL,
|
|
}
|
|
|
|
// WhisperInjectTestAccounts if set, then test accounts will be imported
|
|
// into node's key store, and then will be injected as key pairs (identities)
|
|
// into the Whisper as well.
|
|
WhisperInjectTestAccounts = cli.BoolTFlag{
|
|
Name: "injectaccounts",
|
|
Usage: "Whether test account should be injected or not (default: true)",
|
|
}
|
|
|
|
// FirebaseAuthorizationKey path to file containing FCM password
|
|
FirebaseAuthorizationKey = cli.StringFlag{
|
|
Name: "firebaseauth",
|
|
Usage: "FCM Authorization Key used for sending Push Notifications",
|
|
}
|
|
)
|
|
|
|
var (
|
|
wnodeCommand = cli.Command{
|
|
Action: wnode,
|
|
Name: "wnode",
|
|
Usage: "Starts Whisper/5 node",
|
|
Flags: []cli.Flag{
|
|
WhisperEchoModeFlag,
|
|
WhisperBootstrapNodeFlag,
|
|
WhisperNotificationServerNodeFlag,
|
|
WhisperForwarderNodeFlag,
|
|
WhisperMailserverNodeFlag,
|
|
WhisperIdentityFile,
|
|
WhisperPasswordFile,
|
|
WhisperPoWFlag,
|
|
WhisperPortFlag,
|
|
WhisperTTLFlag,
|
|
WhisperInjectTestAccounts,
|
|
FirebaseAuthorizationKey,
|
|
HTTPEnabledFlag,
|
|
HTTPPortFlag,
|
|
},
|
|
}
|
|
)
|
|
|
|
// version displays app version
|
|
func wnode(ctx *cli.Context) error {
|
|
config, err := makeWhisperNodeConfig(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("can not parse config: %v", err)
|
|
}
|
|
|
|
wnodePrintHeader(config)
|
|
|
|
// import test accounts
|
|
if ctx.BoolT(WhisperInjectTestAccounts.Name) {
|
|
if err = common.ImportTestAccount(filepath.Join(config.DataDir, "keystore"), "test-account1.pk"); err != nil {
|
|
return err
|
|
}
|
|
if err = common.ImportTestAccount(filepath.Join(config.DataDir, "keystore"), "test-account2.pk"); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err = statusAPI.StartNode(config); err != nil {
|
|
return err
|
|
}
|
|
|
|
// inject test accounts into Whisper
|
|
if ctx.BoolT(WhisperInjectTestAccounts.Name) {
|
|
testConfig, _ := common.LoadTestConfig()
|
|
if err = injectAccountIntoWhisper(testConfig.Account1.Address, testConfig.Account1.Password); err != nil {
|
|
return err
|
|
}
|
|
if err = injectAccountIntoWhisper(testConfig.Account2.Address, testConfig.Account2.Password); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// wait till node has been stopped
|
|
node, err := statusAPI.NodeManager().Node()
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
node.Wait()
|
|
|
|
return nil
|
|
}
|
|
|
|
// wnodePrintHeader prints command header
|
|
func wnodePrintHeader(nodeConfig *params.NodeConfig) {
|
|
fmt.Println("Starting Whisper/5 node..")
|
|
|
|
whisperConfig := nodeConfig.WhisperConfig
|
|
|
|
if whisperConfig.EchoMode {
|
|
fmt.Printf("Whisper Config: %s\n", whisperConfig)
|
|
}
|
|
}
|
|
|
|
// makeWhisperNodeConfig parses incoming CLI options and returns node configuration object
|
|
func makeWhisperNodeConfig(ctx *cli.Context) (*params.NodeConfig, error) {
|
|
nodeConfig, err := makeNodeConfig(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
nodeConfig.LightEthConfig.Enabled = false
|
|
|
|
whisperConfig := nodeConfig.WhisperConfig
|
|
|
|
whisperConfig.Enabled = true
|
|
whisperConfig.IdentityFile = ctx.String(WhisperIdentityFile.Name)
|
|
whisperConfig.PasswordFile = ctx.String(WhisperPasswordFile.Name)
|
|
whisperConfig.EchoMode = ctx.BoolT(WhisperEchoModeFlag.Name)
|
|
whisperConfig.BootstrapNode = ctx.BoolT(WhisperBootstrapNodeFlag.Name)
|
|
whisperConfig.ForwarderNode = ctx.Bool(WhisperForwarderNodeFlag.Name)
|
|
whisperConfig.NotificationServerNode = ctx.Bool(WhisperNotificationServerNodeFlag.Name)
|
|
whisperConfig.MailServerNode = ctx.Bool(WhisperMailserverNodeFlag.Name)
|
|
whisperConfig.Port = ctx.Int(WhisperPortFlag.Name)
|
|
whisperConfig.TTL = ctx.Int(WhisperTTLFlag.Name)
|
|
whisperConfig.MinimumPoW = ctx.Float64(WhisperPoWFlag.Name)
|
|
|
|
if whisperConfig.MailServerNode && len(whisperConfig.PasswordFile) == 0 {
|
|
return nil, errors.New("mail server requires --password to be specified")
|
|
}
|
|
|
|
if whisperConfig.NotificationServerNode && len(whisperConfig.IdentityFile) == 0 {
|
|
return nil, errors.New("notification server requires either --identity file to be specified")
|
|
}
|
|
|
|
if len(whisperConfig.PasswordFile) > 0 { // make sure that we can load password file
|
|
if whisperConfig.PasswordFile, err = filepath.Abs(whisperConfig.PasswordFile); err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err = whisperConfig.ReadPasswordFile(); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if len(whisperConfig.IdentityFile) > 0 { // make sure that we can load identity file
|
|
if whisperConfig.IdentityFile, err = filepath.Abs(whisperConfig.IdentityFile); err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err = whisperConfig.ReadIdentityFile(); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
firebaseConfig := whisperConfig.FirebaseConfig
|
|
firebaseConfig.AuthorizationKeyFile = ctx.String(FirebaseAuthorizationKey.Name)
|
|
if len(firebaseConfig.AuthorizationKeyFile) > 0 { // make sure authorization key can be loaded
|
|
if firebaseConfig.AuthorizationKeyFile, err = filepath.Abs(firebaseConfig.AuthorizationKeyFile); err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := firebaseConfig.ReadAuthorizationKeyFile(); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// RPC configuration
|
|
if !ctx.Bool(HTTPEnabledFlag.Name) {
|
|
nodeConfig.HTTPHost = "" // HTTP RPC is disabled
|
|
}
|
|
nodeConfig.HTTPPort = ctx.Int(HTTPPortFlag.Name)
|
|
|
|
return nodeConfig, nil
|
|
}
|
|
|
|
// injectAccountIntoWhisper adds key pair into Whisper. Similar to Select/Login,
|
|
// but allows multiple accounts to be injected.
|
|
func injectAccountIntoWhisper(address, password string) error {
|
|
nodeManager := statusAPI.NodeManager()
|
|
keyStore, err := nodeManager.AccountKeyStore()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
acct, err := common.ParseAccountString(address)
|
|
if err != nil {
|
|
return account.ErrAddressToAccountMappingFailure
|
|
}
|
|
|
|
_, accountKey, err := keyStore.AccountDecryptedKey(acct, password)
|
|
if err != nil {
|
|
return fmt.Errorf("%s: %v", account.ErrAccountToKeyMappingFailure.Error(), err)
|
|
}
|
|
|
|
whisperService, err := nodeManager.WhisperService()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err = whisperService.AddKeyPair(accountKey.PrivateKey); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|