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 }