github.com/status-im/status-go@v1.1.0/wakuv2/persistence/signed_messages.go (about)

     1  package persistence
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"database/sql"
     6  	"errors"
     7  
     8  	"go.uber.org/zap"
     9  
    10  	"github.com/ethereum/go-ethereum/crypto"
    11  )
    12  
    13  // DBStore is a MessageProvider that has a *sql.DB connection
    14  type ProtectedTopicsStore struct {
    15  	db  *sql.DB
    16  	log *zap.Logger
    17  
    18  	insertStmt       *sql.Stmt
    19  	fetchPrivKeyStmt *sql.Stmt
    20  	deleteStmt       *sql.Stmt
    21  }
    22  
    23  // Creates a new DB store using the db specified via options.
    24  // It will create a messages table if it does not exist and
    25  // clean up records according to the retention policy used
    26  func NewProtectedTopicsStore(log *zap.Logger, db *sql.DB) (*ProtectedTopicsStore, error) {
    27  	insertStmt, err := db.Prepare("INSERT OR REPLACE INTO pubsubtopic_signing_key (topic, priv_key, pub_key) VALUES (?, ?, ?)")
    28  	if err != nil {
    29  		return nil, err
    30  	}
    31  
    32  	fetchPrivKeyStmt, err := db.Prepare("SELECT priv_key FROM pubsubtopic_signing_key WHERE topic = ?")
    33  	if err != nil {
    34  		return nil, err
    35  	}
    36  
    37  	deleteStmt, err := db.Prepare("DELETE FROM pubsubtopic_signing_key WHERE topic = ?")
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  
    42  	result := new(ProtectedTopicsStore)
    43  	result.log = log.Named("protected-topics-store")
    44  	result.db = db
    45  	result.insertStmt = insertStmt
    46  	result.fetchPrivKeyStmt = fetchPrivKeyStmt
    47  	result.deleteStmt = deleteStmt
    48  
    49  	return result, nil
    50  }
    51  
    52  func (p *ProtectedTopicsStore) Close() error {
    53  	err := p.insertStmt.Close()
    54  	if err != nil {
    55  		return err
    56  	}
    57  
    58  	return p.fetchPrivKeyStmt.Close()
    59  }
    60  
    61  func (p *ProtectedTopicsStore) Insert(pubsubTopic string, privKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey) error {
    62  	var privKeyBytes []byte
    63  	if privKey != nil {
    64  		privKeyBytes = crypto.FromECDSA(privKey)
    65  	}
    66  
    67  	pubKeyBytes := crypto.FromECDSAPub(publicKey)
    68  
    69  	_, err := p.insertStmt.Exec(pubsubTopic, privKeyBytes, pubKeyBytes)
    70  
    71  	return err
    72  }
    73  
    74  func (p *ProtectedTopicsStore) Delete(pubsubTopic string) error {
    75  	_, err := p.deleteStmt.Exec(pubsubTopic)
    76  	return err
    77  }
    78  
    79  func (p *ProtectedTopicsStore) FetchPrivateKey(topic string) (privKey *ecdsa.PrivateKey, err error) {
    80  	var privKeyBytes []byte
    81  	err = p.fetchPrivKeyStmt.QueryRow(topic).Scan(&privKeyBytes)
    82  	if err != nil {
    83  		if errors.Is(err, sql.ErrNoRows) {
    84  			return nil, nil
    85  		}
    86  		return nil, err
    87  	}
    88  
    89  	return crypto.ToECDSA(privKeyBytes)
    90  }
    91  
    92  type ProtectedTopic struct {
    93  	PubKey *ecdsa.PublicKey
    94  	Topic  string
    95  }
    96  
    97  func (p *ProtectedTopicsStore) ProtectedTopics() ([]ProtectedTopic, error) {
    98  	rows, err := p.db.Query("SELECT pub_key, topic FROM pubsubtopic_signing_key")
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	defer rows.Close()
   103  
   104  	var result []ProtectedTopic
   105  	for rows.Next() {
   106  		var pubKeyBytes []byte
   107  		var topic string
   108  		err := rows.Scan(&pubKeyBytes, &topic)
   109  		if err != nil {
   110  			return nil, err
   111  		}
   112  
   113  		pubk, err := crypto.UnmarshalPubkey(pubKeyBytes)
   114  		if err != nil {
   115  			return nil, err
   116  		}
   117  
   118  		result = append(result, ProtectedTopic{
   119  			PubKey: pubk,
   120  			Topic:  topic,
   121  		})
   122  	}
   123  
   124  	return result, nil
   125  }