fix: chat2 rln credentials

This commit is contained in:
Richard Ramos 2022-11-08 16:20:08 -04:00 committed by RichΛrd
parent 448781687e
commit dc0968ca0a
9 changed files with 60 additions and 143 deletions

View File

@ -14,6 +14,7 @@ import (
"github.com/status-im/go-waku/waku/v2/protocol/lightpush" "github.com/status-im/go-waku/waku/v2/protocol/lightpush"
"github.com/status-im/go-waku/waku/v2/protocol/pb" "github.com/status-im/go-waku/waku/v2/protocol/pb"
"github.com/status-im/go-waku/waku/v2/protocol/store" "github.com/status-im/go-waku/waku/v2/protocol/store"
"github.com/status-im/go-waku/waku/v2/utils"
) )
func execute(options Options) { func execute(options Options) {
@ -48,7 +49,13 @@ func execute(options Options) {
} }
if options.RLNRelay.Dynamic { if options.RLNRelay.Dynamic {
membershipCredentials, err := getMembershipCredentials(options.RLNRelay) membershipCredentials, err := node.GetMembershipCredentials(
utils.Logger(),
options.RLNRelay.CredentialsPath,
options.RLNRelay.CredentialsPassword,
options.RLNRelay.MembershipContractAddress,
uint(options.RLNRelay.MembershipIndex),
)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
@ -114,7 +121,7 @@ func execute(options Options) {
} }
if options.RLNRelay.Enable && options.RLNRelay.Dynamic { if options.RLNRelay.Enable && options.RLNRelay.Dynamic {
err := writeRLNMembershipCredentialsToFile(options.RLNRelay.CredentialsPath, wakuNode.RLNRelay().MembershipKeyPair(), wakuNode.RLNRelay().MembershipIndex(), wakuNode.RLNRelay().MembershipContractAddress()) err := node.WriteRLNMembershipCredentialsToFile(wakuNode.RLNRelay().MembershipKeyPair(), wakuNode.RLNRelay().MembershipIndex(), wakuNode.RLNRelay().MembershipContractAddress(), options.RLNRelay.CredentialsPath, []byte(options.RLNRelay.CredentialsPassword))
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
return return

View File

@ -218,6 +218,12 @@ func getFlags() []cli.Flag {
Value: "", Value: "",
Destination: &options.RLNRelay.CredentialsPath, Destination: &options.RLNRelay.CredentialsPath,
}, },
&cli.StringFlag{
Name: "rln-relay-cred-password",
Value: "",
Usage: "Password for encrypting RLN credentials",
Destination: &options.RLNRelay.CredentialsPassword,
},
// TODO: this is a good candidate option for subcommands // TODO: this is a good candidate option for subcommands
// TODO: consider accepting a private key file and passwd // TODO: consider accepting a private key file and passwd
&cli.GenericFlag{ &cli.GenericFlag{

View File

@ -30,6 +30,7 @@ type RelayOptions struct {
type RLNRelayOptions struct { type RLNRelayOptions struct {
Enable bool Enable bool
CredentialsPath string CredentialsPath string
CredentialsPassword string
MembershipIndex int MembershipIndex int
PubsubTopic string PubsubTopic string
ContentTopic string ContentTopic string

View File

@ -1,102 +0,0 @@
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/ethereum/go-ethereum/common"
"github.com/status-im/go-waku/waku/v2/node"
"github.com/waku-org/go-zerokit-rln/rln"
)
const RLN_CREDENTIALS_FILENAME = "rlnCredentials.txt"
func fileExists(path string) bool {
if _, err := os.Stat(path); err == nil {
return false
} else if errors.Is(err, os.ErrNotExist) {
return false
} else {
return false
}
}
func writeRLNMembershipCredentialsToFile(path string, keyPair *rln.MembershipKeyPair, idx rln.MembershipIndex, contractAddress common.Address) error {
if path == "" {
return nil // No path to save file
}
path = filepath.Join(path, RLN_CREDENTIALS_FILENAME)
if fileExists(path) {
return nil
}
if keyPair == nil {
return nil // No credentials to write
}
credentialsJSON, err := json.Marshal(node.MembershipCredentials{
Keypair: &rln.MembershipKeyPair{
IDKey: keyPair.IDKey,
IDCommitment: keyPair.IDCommitment,
},
Index: idx,
Contract: contractAddress,
})
if err != nil {
return err
}
return ioutil.WriteFile(path, credentialsJSON, 0600)
}
func loadMembershipCredentialsFromFile(rlnCredentialsPath string) (node.MembershipCredentials, error) {
src, err := ioutil.ReadFile(rlnCredentialsPath)
if err != nil {
return node.MembershipCredentials{}, err
}
var credentials node.MembershipCredentials
err = json.Unmarshal(src, &credentials)
return credentials, err
}
func getMembershipCredentials(options RLNRelayOptions) (credentials node.MembershipCredentials, err error) {
path := options.CredentialsPath
if path == "" {
return node.MembershipCredentials{
Contract: options.MembershipContractAddress,
}, nil
}
path = filepath.Join(path, RLN_CREDENTIALS_FILENAME)
_, osErr := os.Stat(path)
if osErr == nil {
if credentials, err := loadMembershipCredentialsFromFile(path); err != nil {
return node.MembershipCredentials{}, fmt.Errorf("could not read membership credentials file: %w", err)
} else {
if (bytes.Equal(credentials.Contract.Bytes(), common.Address{}.Bytes())) {
credentials.Contract = options.MembershipContractAddress
}
return credentials, nil
}
}
if os.IsNotExist(osErr) {
return node.MembershipCredentials{
Index: uint(options.MembershipIndex),
Contract: options.MembershipContractAddress,
}, nil
}
return node.MembershipCredentials{}, fmt.Errorf("could not read membership credentials file: %w", err)
}

View File

@ -12,8 +12,6 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
var loadedCredentialsFromFile bool = false
func checkForRLN(logger *zap.Logger, options Options, nodeOpts *[]node.WakuNodeOption) { func checkForRLN(logger *zap.Logger, options Options, nodeOpts *[]node.WakuNodeOption) {
if options.RLNRelay.Enable { if options.RLNRelay.Enable {
if !options.Relay.Enable { if !options.Relay.Enable {
@ -27,12 +25,15 @@ func checkForRLN(logger *zap.Logger, options Options, nodeOpts *[]node.WakuNodeO
if options.RLNRelay.ETHPrivateKey != nil { if options.RLNRelay.ETHPrivateKey != nil {
ethPrivKey = options.RLNRelay.ETHPrivateKey ethPrivKey = options.RLNRelay.ETHPrivateKey
} }
membershipCredentials, err := node.GetMembershipCredentials(
loaded, membershipCredentials, err := getMembershipCredentials(logger, options) logger,
options.RLNRelay.CredentialsPath,
options.RLNRelay.CredentialsPassword,
options.RLNRelay.MembershipContractAddress,
uint(options.RLNRelay.MembershipIndex),
)
failOnErr(err, "Invalid membership credentials") failOnErr(err, "Invalid membership credentials")
loadedCredentialsFromFile = loaded
*nodeOpts = append(*nodeOpts, node.WithDynamicRLNRelay( *nodeOpts = append(*nodeOpts, node.WithDynamicRLNRelay(
options.RLNRelay.PubsubTopic, options.RLNRelay.PubsubTopic,
options.RLNRelay.ContentTopic, options.RLNRelay.ContentTopic,
@ -47,8 +48,8 @@ func checkForRLN(logger *zap.Logger, options Options, nodeOpts *[]node.WakuNodeO
} }
func onStartRLN(wakuNode *node.WakuNode, options Options) { func onStartRLN(wakuNode *node.WakuNode, options Options) {
if options.RLNRelay.Enable && options.RLNRelay.Dynamic && !loadedCredentialsFromFile && options.RLNRelay.CredentialsPath != "" { if options.RLNRelay.Enable && options.RLNRelay.Dynamic && options.RLNRelay.CredentialsPath != "" {
err := writeRLNMembershipCredentialsToFile(wakuNode.RLNRelay().MembershipKeyPair(), wakuNode.RLNRelay().MembershipIndex(), wakuNode.RLNRelay().MembershipContractAddress(), options.RLNRelay.CredentialsPath, []byte(options.KeyPasswd), options.Overwrite) err := node.WriteRLNMembershipCredentialsToFile(wakuNode.RLNRelay().MembershipKeyPair(), wakuNode.RLNRelay().MembershipIndex(), wakuNode.RLNRelay().MembershipContractAddress(), options.RLNRelay.CredentialsPath, []byte(options.RLNRelay.CredentialsPassword))
failOnErr(err, "Could not write membership credentials file") failOnErr(err, "Could not write membership credentials file")
} }
} }

View File

@ -31,6 +31,7 @@ type RelayOptions struct {
type RLNRelayOptions struct { type RLNRelayOptions struct {
Enable bool Enable bool
CredentialsPath string CredentialsPath string
CredentialsPassword string
MembershipIndex int MembershipIndex int
PubsubTopic string PubsubTopic string
ContentTopic string ContentTopic string

View File

@ -1,11 +1,12 @@
//go:build gowaku_rln //go:build gowaku_rln
// +build gowaku_rln // +build gowaku_rln
package waku package node
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
@ -13,14 +14,13 @@ import (
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/status-im/go-waku/waku/v2/node"
"github.com/waku-org/go-zerokit-rln/rln" "github.com/waku-org/go-zerokit-rln/rln"
"go.uber.org/zap" "go.uber.org/zap"
) )
const RLN_CREDENTIALS_FILENAME = "rlnCredentials.txt" const RLN_CREDENTIALS_FILENAME = "rlnCredentials.txt"
func writeRLNMembershipCredentialsToFile(keyPair *rln.MembershipKeyPair, idx rln.MembershipIndex, contractAddress common.Address, path string, passwd []byte, overwrite bool) error { func WriteRLNMembershipCredentialsToFile(keyPair *rln.MembershipKeyPair, idx rln.MembershipIndex, contractAddress common.Address, path string, passwd []byte) error {
if path == "" { if path == "" {
return nil // we dont want to use a credentials file return nil // we dont want to use a credentials file
} }
@ -29,19 +29,12 @@ func writeRLNMembershipCredentialsToFile(keyPair *rln.MembershipKeyPair, idx rln
return nil // no credentials to store return nil // no credentials to store
} }
path = filepath.Join(path, RLN_CREDENTIALS_FILENAME) credentialsJSON, err := json.Marshal(MembershipCredentials{
if err := checkForFileExistence(path, overwrite); err != nil {
return err
}
credentialsJSON, err := json.Marshal(node.MembershipCredentials{
Keypair: keyPair, Keypair: keyPair,
Index: idx, Index: idx,
Contract: contractAddress, Contract: contractAddress,
}) })
fmt.Println(string(credentialsJSON))
if err != nil { if err != nil {
return err return err
} }
@ -56,60 +49,65 @@ func writeRLNMembershipCredentialsToFile(keyPair *rln.MembershipKeyPair, idx rln
return err return err
} }
path = filepath.Join(path, RLN_CREDENTIALS_FILENAME)
return ioutil.WriteFile(path, output, 0600) return ioutil.WriteFile(path, output, 0600)
} }
func loadMembershipCredentialsFromFile(credentialsFilePath string, passwd string) (node.MembershipCredentials, error) { func loadMembershipCredentialsFromFile(credentialsFilePath string, passwd string) (MembershipCredentials, error) {
src, err := ioutil.ReadFile(credentialsFilePath) src, err := ioutil.ReadFile(credentialsFilePath)
if err != nil { if err != nil {
return node.MembershipCredentials{}, err return MembershipCredentials{}, err
} }
var encryptedK keystore.CryptoJSON var encryptedK keystore.CryptoJSON
err = json.Unmarshal(src, &encryptedK) err = json.Unmarshal(src, &encryptedK)
if err != nil { if err != nil {
return node.MembershipCredentials{}, err return MembershipCredentials{}, err
} }
credentialsBytes, err := keystore.DecryptDataV3(encryptedK, passwd) credentialsBytes, err := keystore.DecryptDataV3(encryptedK, passwd)
if err != nil { if err != nil {
return node.MembershipCredentials{}, err return MembershipCredentials{}, err
} }
var credentials node.MembershipCredentials var credentials MembershipCredentials
err = json.Unmarshal(credentialsBytes, &credentials) err = json.Unmarshal(credentialsBytes, &credentials)
return credentials, err return credentials, err
} }
func getMembershipCredentials(logger *zap.Logger, options Options) (fromFile bool, credentials node.MembershipCredentials, err error) { func GetMembershipCredentials(logger *zap.Logger, credentialsPath string, password string, membershipContract common.Address, membershipIndex uint) (credentials MembershipCredentials, err error) {
if options.RLNRelay.CredentialsPath == "" { // Not using a file if credentialsPath == "" { // Not using a file
return false, node.MembershipCredentials{ return MembershipCredentials{
Contract: options.RLNRelay.MembershipContractAddress, Contract: membershipContract,
}, nil }, nil
} }
credentialsFilePath := filepath.Join(options.RLNRelay.CredentialsPath, RLN_CREDENTIALS_FILENAME) credentialsFilePath := filepath.Join(credentialsPath, RLN_CREDENTIALS_FILENAME)
if _, err = os.Stat(credentialsFilePath); err == nil { if _, err = os.Stat(credentialsFilePath); err == nil {
if credentials, err := loadMembershipCredentialsFromFile(credentialsFilePath, options.KeyPasswd); err != nil { if credentials, err := loadMembershipCredentialsFromFile(credentialsFilePath, password); err != nil {
return false, node.MembershipCredentials{}, fmt.Errorf("could not read membership credentials file: %w", err) return MembershipCredentials{}, fmt.Errorf("could not read membership credentials file: %w", err)
} else { } else {
logger.Info("loaded rln credentials", zap.String("filepath", credentialsFilePath)) logger.Info("loaded rln credentials", zap.String("filepath", credentialsFilePath))
if (bytes.Equal(credentials.Contract.Bytes(), common.Address{}.Bytes())) { if (bytes.Equal(credentials.Contract.Bytes(), common.Address{}.Bytes())) {
credentials.Contract = options.RLNRelay.MembershipContractAddress credentials.Contract = membershipContract
} }
return true, credentials, nil if (bytes.Equal(membershipContract.Bytes(), common.Address{}.Bytes())) {
return MembershipCredentials{}, errors.New("no contract address specified")
}
return credentials, nil
} }
} }
if os.IsNotExist(err) { if os.IsNotExist(err) {
return false, node.MembershipCredentials{ return MembershipCredentials{
Keypair: nil, Keypair: nil,
Index: uint(options.RLNRelay.MembershipIndex), Index: membershipIndex,
Contract: options.RLNRelay.MembershipContractAddress, Contract: membershipContract,
}, nil }, nil
} }
return false, node.MembershipCredentials{}, fmt.Errorf("could not read membership credentials file: %w", err) return MembershipCredentials{}, fmt.Errorf("could not read membership credentials file: %w", err)
} }

View File

@ -195,10 +195,9 @@ func (rln *WakuRLNRelay) watchNewEvents(rlnContract *contracts.RLN, handler Regi
} }
errCh <- err errCh <- err
subs.Unsubscribe() subs.Unsubscribe()
rln.log.Error("subscribing to rln events", zap.Error(err))
} }
rln.log.Error("subscribing to rln events", zap.Error(err))
return subs, err return subs, err
}) })
defer subs.Unsubscribe() defer subs.Unsubscribe()

View File

@ -45,6 +45,12 @@ func rlnFlags() []cli.Flag {
Value: "", Value: "",
Destination: &options.RLNRelay.CredentialsPath, Destination: &options.RLNRelay.CredentialsPath,
}, },
&cli.StringFlag{
Name: "rln-relay-cred-password",
Value: "",
Usage: "Password for encrypting RLN credentials",
Destination: &options.RLNRelay.CredentialsPassword,
},
// TODO: this is a good candidate option for subcommands // TODO: this is a good candidate option for subcommands
// TODO: consider accepting a private key file and passwd // TODO: consider accepting a private key file and passwd
&cli.GenericFlag{ &cli.GenericFlag{