2019-05-17 13:06:56 +02:00
|
|
|
package filter
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/ecdsa"
|
|
|
|
"encoding/hex"
|
2019-05-23 10:47:20 +02:00
|
|
|
"errors"
|
2019-05-17 13:06:56 +02:00
|
|
|
"fmt"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
|
|
"github.com/ethereum/go-ethereum/log"
|
2019-07-03 21:13:11 +02:00
|
|
|
"github.com/status-im/status-go/messaging/sharedsecret"
|
2019-05-17 13:06:56 +02:00
|
|
|
whisper "github.com/status-im/whisper/whisperv6"
|
|
|
|
"math/big"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
discoveryTopic = "contact-discovery"
|
|
|
|
)
|
|
|
|
|
|
|
|
// The number of partitions
|
|
|
|
var nPartitions = big.NewInt(5000)
|
2019-05-23 10:47:20 +02:00
|
|
|
var minPow = 0.0
|
2019-05-17 13:06:56 +02:00
|
|
|
|
2019-05-23 09:54:28 +02:00
|
|
|
type Filter struct {
|
2019-05-17 13:06:56 +02:00
|
|
|
FilterID string
|
2019-05-23 10:47:20 +02:00
|
|
|
Topic whisper.TopicType
|
2019-05-17 13:06:56 +02:00
|
|
|
SymKeyID string
|
|
|
|
}
|
|
|
|
|
|
|
|
type Chat struct {
|
|
|
|
// ChatID is the identifier of the chat
|
2019-05-23 10:47:20 +02:00
|
|
|
ChatID string `json:"chatId"`
|
2019-05-17 13:06:56 +02:00
|
|
|
// SymKeyID is the symmetric key id used for symmetric chats
|
2019-05-23 10:47:20 +02:00
|
|
|
SymKeyID string `json:"symKeyId"`
|
2019-05-17 13:06:56 +02:00
|
|
|
// OneToOne tells us if we need to use asymmetric encryption for this chat
|
2019-05-23 10:47:20 +02:00
|
|
|
OneToOne bool `json:"oneToOne"`
|
2019-05-17 13:06:56 +02:00
|
|
|
// Listen is whether we are actually listening for messages on this chat, or the filter is only created in order to be able to post on the topic
|
2019-05-23 10:47:20 +02:00
|
|
|
Listen bool `json:"listen"`
|
2019-05-17 13:06:56 +02:00
|
|
|
// FilterID the whisper filter id generated
|
2019-05-23 10:47:20 +02:00
|
|
|
FilterID string `json:"filterId"`
|
2019-05-17 13:06:56 +02:00
|
|
|
// Identity is the public key of the other recipient for non-public chats
|
2019-05-23 10:47:20 +02:00
|
|
|
Identity string `json:"identity"`
|
2019-05-17 13:06:56 +02:00
|
|
|
// Topic is the whisper topic
|
2019-05-23 10:47:20 +02:00
|
|
|
Topic whisper.TopicType `json:"topic"`
|
2019-06-03 16:29:14 +02:00
|
|
|
// Discovery is whether this is a discovery topic
|
|
|
|
Discovery bool `json:"discovery"`
|
|
|
|
// Negotiated tells us whether is a negotiated topic
|
|
|
|
Negotiated bool `json:"negotiated"`
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type Service struct {
|
2019-06-24 09:26:25 +02:00
|
|
|
whisper *whisper.Whisper
|
|
|
|
secret *sharedsecret.Service
|
|
|
|
chats map[string]*Chat
|
|
|
|
persistence Persistence
|
|
|
|
mutex sync.Mutex
|
|
|
|
keys map[string][]byte
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
// New returns a new filter service
|
2019-06-24 09:26:25 +02:00
|
|
|
func New(w *whisper.Whisper, p Persistence, s *sharedsecret.Service) *Service {
|
2019-05-17 13:06:56 +02:00
|
|
|
return &Service{
|
2019-06-24 09:26:25 +02:00
|
|
|
whisper: w,
|
|
|
|
secret: s,
|
|
|
|
mutex: sync.Mutex{},
|
|
|
|
persistence: p,
|
|
|
|
chats: make(map[string]*Chat),
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
// LoadChat should return a list of newly chats loaded
|
|
|
|
func (s *Service) Init(chats []*Chat) ([]*Chat, error) {
|
|
|
|
log.Debug("Initializing filter service", "chats", chats)
|
2019-06-24 09:26:25 +02:00
|
|
|
|
|
|
|
keys, err := s.persistence.All()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
s.keys = keys
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
keyID := s.whisper.SelectedKeyPairID()
|
|
|
|
if keyID == "" {
|
|
|
|
return nil, errors.New("no key selected")
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
2019-05-23 10:47:20 +02:00
|
|
|
myKey, err := s.whisper.GetPrivateKey(keyID)
|
2019-05-17 13:06:56 +02:00
|
|
|
if err != nil {
|
2019-05-23 10:47:20 +02:00
|
|
|
return nil, err
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add our own topic
|
|
|
|
log.Debug("Loading one to one chats")
|
|
|
|
identityStr := fmt.Sprintf("%x", crypto.FromECDSAPub(&myKey.PublicKey))
|
2019-05-23 10:47:20 +02:00
|
|
|
_, err = s.loadOneToOne(myKey, identityStr, true)
|
2019-05-17 13:06:56 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Error("Error loading one to one chats", "err", err)
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
return nil, err
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add discovery topic
|
|
|
|
log.Debug("Loading discovery topics")
|
2019-05-23 10:47:20 +02:00
|
|
|
err = s.loadDiscovery(myKey)
|
2019-05-17 13:06:56 +02:00
|
|
|
if err != nil {
|
2019-05-23 10:47:20 +02:00
|
|
|
return nil, err
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add the various one to one and public chats
|
|
|
|
log.Debug("Loading chats")
|
|
|
|
for _, chat := range chats {
|
2019-05-23 10:47:20 +02:00
|
|
|
_, err = s.load(myKey, chat)
|
2019-05-17 13:06:56 +02:00
|
|
|
if err != nil {
|
2019-05-23 10:47:20 +02:00
|
|
|
return nil, err
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
// Add the negotiated secrets
|
2019-05-17 13:06:56 +02:00
|
|
|
log.Debug("Loading negotiated topics")
|
2019-05-23 10:47:20 +02:00
|
|
|
secrets, err := s.secret.All()
|
2019-05-17 13:06:56 +02:00
|
|
|
if err != nil {
|
2019-05-23 10:47:20 +02:00
|
|
|
return nil, err
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, secret := range secrets {
|
2019-05-23 10:47:20 +02:00
|
|
|
if _, err := s.ProcessNegotiatedSecret(secret); err != nil {
|
|
|
|
return nil, err
|
2019-05-23 09:54:28 +02:00
|
|
|
}
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
|
|
|
|
|
|
|
var allChats []*Chat
|
|
|
|
for _, chat := range s.chats {
|
|
|
|
allChats = append(allChats, chat)
|
|
|
|
}
|
2019-06-24 09:26:25 +02:00
|
|
|
log.Debug("Loaded chats")
|
2019-05-23 10:47:20 +02:00
|
|
|
return allChats, nil
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
// Stop removes all the filters
|
2019-05-17 13:06:56 +02:00
|
|
|
func (s *Service) Stop() error {
|
2019-06-03 16:29:14 +02:00
|
|
|
var chats []*Chat
|
2019-05-17 13:06:56 +02:00
|
|
|
for _, chat := range s.chats {
|
2019-06-03 16:29:14 +02:00
|
|
|
chats = append(chats, chat)
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
2019-06-03 16:29:14 +02:00
|
|
|
return s.Remove(chats)
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
// Remove remove all the filters associated with a chat/identity
|
2019-06-03 16:29:14 +02:00
|
|
|
func (s *Service) Remove(chats []*Chat) error {
|
2019-05-17 13:06:56 +02:00
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
2019-06-03 16:29:14 +02:00
|
|
|
log.Debug("Removing chats", "chats", chats)
|
2019-05-17 13:06:56 +02:00
|
|
|
|
2019-06-03 16:29:14 +02:00
|
|
|
for _, chat := range chats {
|
|
|
|
log.Debug("Removing chat", "chat", chat)
|
|
|
|
if err := s.whisper.Unsubscribe(chat.FilterID); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if chat.SymKeyID != "" {
|
|
|
|
s.whisper.DeleteSymKey(chat.SymKeyID)
|
|
|
|
}
|
|
|
|
delete(s.chats, chat.ChatID)
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2019-05-23 10:47:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// LoadPartitioned creates a filter for a partitioned topic
|
|
|
|
func (s *Service) LoadPartitioned(myKey *ecdsa.PrivateKey, theirPublicKey *ecdsa.PublicKey, listen bool) (*Chat, error) {
|
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
|
|
|
|
|
|
|
chatID := PublicKeyToPartitionedTopic(theirPublicKey)
|
|
|
|
|
|
|
|
if _, ok := s.chats[chatID]; ok {
|
|
|
|
return s.chats[chatID], nil
|
|
|
|
}
|
2019-05-17 13:06:56 +02:00
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
// We set up a filter so we can publish, but we discard envelopes if listen is false
|
|
|
|
filter, err := s.addAsymmetricFilter(myKey, chatID, listen)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-06-03 16:29:14 +02:00
|
|
|
identityStr := fmt.Sprintf("%x", crypto.FromECDSAPub(theirPublicKey))
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
chat := &Chat{
|
2019-06-03 16:29:14 +02:00
|
|
|
ChatID: chatID,
|
|
|
|
FilterID: filter.FilterID,
|
|
|
|
Topic: filter.Topic,
|
|
|
|
Listen: listen,
|
|
|
|
Identity: identityStr,
|
|
|
|
Discovery: true,
|
2019-05-23 10:47:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
s.chats[chatID] = chat
|
|
|
|
|
|
|
|
return chat, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load creates filters for a given chat, and returns all the created filters
|
|
|
|
func (s *Service) Load(chat *Chat) ([]*Chat, error) {
|
|
|
|
keyID := s.whisper.SelectedKeyPairID()
|
|
|
|
if keyID == "" {
|
|
|
|
return nil, errors.New("no key selected")
|
|
|
|
}
|
|
|
|
myKey, err := s.whisper.GetPrivateKey(keyID)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return s.load(myKey, chat)
|
|
|
|
}
|
|
|
|
|
2019-06-03 16:29:14 +02:00
|
|
|
func ContactCodeTopic(identity string) string {
|
|
|
|
return "0x" + identity + "-contact-code"
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get returns a negotiated chat given an identity
|
2019-05-23 10:47:20 +02:00
|
|
|
func (s *Service) GetNegotiated(identity *ecdsa.PublicKey) *Chat {
|
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
|
|
|
|
|
|
|
return s.chats[negotiatedID(identity)]
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
2019-06-03 16:29:14 +02:00
|
|
|
// GetByID returns a chat by chatID
|
2019-05-23 10:47:20 +02:00
|
|
|
func (s *Service) GetByID(chatID string) *Chat {
|
2019-05-17 13:06:56 +02:00
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
return s.chats[chatID]
|
|
|
|
}
|
|
|
|
|
|
|
|
// ProcessNegotiatedSecret adds a filter based on the agreed secret
|
|
|
|
func (s *Service) ProcessNegotiatedSecret(secret *sharedsecret.Secret) (*Chat, error) {
|
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
|
|
|
|
|
|
|
chatID := negotiatedID(secret.Identity)
|
2019-06-03 16:29:14 +02:00
|
|
|
// If we already have a chat do nothing
|
2019-05-23 10:47:20 +02:00
|
|
|
if _, ok := s.chats[chatID]; ok {
|
|
|
|
return s.chats[chatID], nil
|
|
|
|
}
|
|
|
|
|
|
|
|
keyString := fmt.Sprintf("%x", secret.Key)
|
|
|
|
filter, err := s.addSymmetric(keyString)
|
2019-05-17 13:06:56 +02:00
|
|
|
if err != nil {
|
2019-05-23 10:47:20 +02:00
|
|
|
return nil, err
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
identityStr := fmt.Sprintf("%x", crypto.FromECDSAPub(secret.Identity))
|
|
|
|
|
|
|
|
chat := &Chat{
|
2019-06-03 16:29:14 +02:00
|
|
|
ChatID: chatID,
|
|
|
|
Topic: filter.Topic,
|
|
|
|
SymKeyID: filter.SymKeyID,
|
|
|
|
FilterID: filter.FilterID,
|
|
|
|
Identity: identityStr,
|
|
|
|
Listen: true,
|
|
|
|
Negotiated: true,
|
2019-05-23 10:47:20 +02:00
|
|
|
}
|
|
|
|
|
2019-06-03 16:29:14 +02:00
|
|
|
log.Debug("Processing negotiated secret", "chat-id", chatID, "topic", filter.Topic)
|
2019-05-23 10:47:20 +02:00
|
|
|
|
|
|
|
s.chats[chat.ChatID] = chat
|
|
|
|
return chat, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToTopic converts a string to a whisper topic
|
|
|
|
func ToTopic(s string) []byte {
|
|
|
|
return crypto.Keccak256([]byte(s))[:whisper.TopicLength]
|
|
|
|
}
|
|
|
|
|
|
|
|
// PublicKeyToPartitionedTopic returns the associated partitioned topic string
|
|
|
|
// with the given public key
|
|
|
|
func PublicKeyToPartitionedTopic(publicKey *ecdsa.PublicKey) string {
|
|
|
|
partition := big.NewInt(0)
|
|
|
|
partition.Mod(publicKey.X, nPartitions)
|
|
|
|
return fmt.Sprintf("contact-discovery-%d", partition.Int64())
|
|
|
|
}
|
|
|
|
|
|
|
|
// PublicKeyToPartitionedTopicBytes returns the bytes of the partitioned topic
|
|
|
|
// associated with the given public key
|
|
|
|
func PublicKeyToPartitionedTopicBytes(publicKey *ecdsa.PublicKey) []byte {
|
|
|
|
return ToTopic(PublicKeyToPartitionedTopic(publicKey))
|
|
|
|
}
|
|
|
|
|
|
|
|
// loadDiscovery adds the discovery filter
|
|
|
|
func (s *Service) loadDiscovery(myKey *ecdsa.PrivateKey) error {
|
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
|
|
|
|
|
|
|
if _, ok := s.chats[discoveryTopic]; ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-06-03 16:29:14 +02:00
|
|
|
identityStr := fmt.Sprintf("%x", crypto.FromECDSAPub(&myKey.PublicKey))
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
discoveryChat := &Chat{
|
2019-06-03 16:29:14 +02:00
|
|
|
ChatID: discoveryTopic,
|
|
|
|
Listen: true,
|
|
|
|
Identity: identityStr,
|
|
|
|
Discovery: true,
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
discoveryResponse, err := s.addAsymmetricFilter(myKey, discoveryChat.ChatID, true)
|
2019-05-17 13:06:56 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-05-23 10:47:20 +02:00
|
|
|
|
|
|
|
discoveryChat.Topic = discoveryResponse.Topic
|
|
|
|
discoveryChat.FilterID = discoveryResponse.FilterID
|
|
|
|
|
|
|
|
s.chats[discoveryChat.ChatID] = discoveryChat
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// loadPublic adds a filter for a public chat
|
|
|
|
func (s *Service) loadPublic(chat *Chat) error {
|
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
|
|
|
|
|
|
|
if _, ok := s.chats[chat.ChatID]; ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
filterAndTopic, err := s.addSymmetric(chat.ChatID)
|
2019-05-17 13:06:56 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-05-23 10:47:20 +02:00
|
|
|
|
|
|
|
chat.FilterID = filterAndTopic.FilterID
|
|
|
|
chat.SymKeyID = filterAndTopic.SymKeyID
|
|
|
|
chat.Topic = filterAndTopic.Topic
|
|
|
|
chat.Listen = true
|
|
|
|
|
|
|
|
s.chats[chat.ChatID] = chat
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// loadOneToOne creates two filters for a given chat, one listening to the contact codes
|
|
|
|
// and another on the partitioned topic, if listen is specified.
|
|
|
|
func (s *Service) loadOneToOne(myKey *ecdsa.PrivateKey, identity string, listen bool) ([]*Chat, error) {
|
|
|
|
var chats []*Chat
|
|
|
|
contactCodeChat, err := s.loadContactCode(identity)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
chats = append(chats, contactCodeChat)
|
|
|
|
|
|
|
|
if listen {
|
|
|
|
publicKeyBytes, err := hex.DecodeString(identity)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
publicKey, err := crypto.UnmarshalPubkey(publicKeyBytes)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
partitionedChat, err := s.LoadPartitioned(myKey, publicKey, listen)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
chats = append(chats, partitionedChat)
|
|
|
|
}
|
|
|
|
return chats, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// loadContactCode creates a filter for the topic are advertised for a given identity
|
|
|
|
func (s *Service) loadContactCode(identity string) (*Chat, error) {
|
|
|
|
s.mutex.Lock()
|
|
|
|
defer s.mutex.Unlock()
|
|
|
|
|
2019-06-03 16:29:14 +02:00
|
|
|
chatID := ContactCodeTopic(identity)
|
2019-05-23 10:47:20 +02:00
|
|
|
if _, ok := s.chats[chatID]; ok {
|
|
|
|
return s.chats[chatID], nil
|
|
|
|
}
|
|
|
|
|
|
|
|
contactCodeFilter, err := s.addSymmetric(chatID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
chat := &Chat{
|
|
|
|
ChatID: chatID,
|
|
|
|
FilterID: contactCodeFilter.FilterID,
|
|
|
|
Topic: contactCodeFilter.Topic,
|
|
|
|
SymKeyID: contactCodeFilter.SymKeyID,
|
2019-05-17 13:06:56 +02:00
|
|
|
Identity: identity,
|
2019-05-23 10:47:20 +02:00
|
|
|
Listen: true,
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
s.chats[chatID] = chat
|
|
|
|
return chat, nil
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
// addSymmetric adds a symmetric key filter
|
|
|
|
func (s *Service) addSymmetric(chatID string) (*Filter, error) {
|
2019-06-24 09:26:25 +02:00
|
|
|
var symKeyID string
|
|
|
|
var err error
|
2019-05-17 13:06:56 +02:00
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
topic := ToTopic(chatID)
|
2019-05-17 13:06:56 +02:00
|
|
|
topics := [][]byte{topic}
|
|
|
|
|
2019-06-24 09:26:25 +02:00
|
|
|
symKey, ok := s.keys[chatID]
|
|
|
|
if ok {
|
|
|
|
log.Debug("Loading from cache", "chat-id", chatID)
|
|
|
|
symKeyID, err = s.whisper.AddSymKeyDirect(symKey)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Adding symkey failed", "err", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Debug("Generating symkey", "chat-id", chatID)
|
|
|
|
symKeyID, err = s.whisper.AddSymKeyFromPassword(chatID)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Adding symkey from password failed", "err", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if symKey, err = s.whisper.GetSymKey(symKeyID); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
s.keys[chatID] = symKey
|
2019-05-17 13:06:56 +02:00
|
|
|
|
2019-06-24 09:26:25 +02:00
|
|
|
err = s.persistence.Add(chatID, symKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
f := &whisper.Filter{
|
|
|
|
KeySym: symKey,
|
2019-05-23 10:47:20 +02:00
|
|
|
PoW: minPow,
|
2019-05-17 13:06:56 +02:00
|
|
|
AllowP2P: true,
|
|
|
|
Topics: topics,
|
|
|
|
Messages: s.whisper.NewMessageStore(),
|
|
|
|
}
|
|
|
|
|
|
|
|
id, err := s.whisper.Subscribe(f)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-05-23 09:54:28 +02:00
|
|
|
return &Filter{
|
2019-05-17 13:06:56 +02:00
|
|
|
FilterID: id,
|
|
|
|
SymKeyID: symKeyID,
|
2019-05-23 10:47:20 +02:00
|
|
|
Topic: whisper.BytesToTopic(topic),
|
2019-05-17 13:06:56 +02:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
// addAsymmetricFilter adds a filter with our privatekey, and set minPow according to the listen parameter
|
|
|
|
func (s *Service) addAsymmetricFilter(keyAsym *ecdsa.PrivateKey, chatID string, listen bool) (*Filter, error) {
|
2019-05-17 13:06:56 +02:00
|
|
|
var err error
|
|
|
|
var pow float64
|
|
|
|
|
|
|
|
if listen {
|
2019-05-23 10:47:20 +02:00
|
|
|
pow = minPow
|
2019-05-17 13:06:56 +02:00
|
|
|
} else {
|
|
|
|
// Set high pow so we discard messages
|
|
|
|
pow = 1
|
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
topic := ToTopic(chatID)
|
2019-05-17 13:06:56 +02:00
|
|
|
topics := [][]byte{topic}
|
|
|
|
|
|
|
|
f := &whisper.Filter{
|
|
|
|
KeyAsym: keyAsym,
|
|
|
|
PoW: pow,
|
2019-05-23 10:47:20 +02:00
|
|
|
AllowP2P: true,
|
2019-05-17 13:06:56 +02:00
|
|
|
Topics: topics,
|
|
|
|
Messages: s.whisper.NewMessageStore(),
|
|
|
|
}
|
|
|
|
|
|
|
|
id, err := s.whisper.Subscribe(f)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
return &Filter{FilterID: id, Topic: whisper.BytesToTopic(topic)}, nil
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func negotiatedID(identity *ecdsa.PublicKey) string {
|
2019-05-23 10:47:20 +02:00
|
|
|
return fmt.Sprintf("0x%x-negotiated", crypto.FromECDSAPub(identity))
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
func (s *Service) load(myKey *ecdsa.PrivateKey, chat *Chat) ([]*Chat, error) {
|
|
|
|
log.Debug("Loading chat", "chatID", chat.ChatID)
|
2019-05-17 13:06:56 +02:00
|
|
|
|
2019-05-23 10:47:20 +02:00
|
|
|
if chat.OneToOne {
|
|
|
|
return s.loadOneToOne(myKey, chat.Identity, false)
|
2019-05-17 13:06:56 +02:00
|
|
|
|
|
|
|
}
|
2019-05-23 10:47:20 +02:00
|
|
|
return []*Chat{chat}, s.loadPublic(chat)
|
2019-05-17 13:06:56 +02:00
|
|
|
}
|