feat: Waku v2 bridge

Issue #12610
This commit is contained in:
Michal Iskierko
2023-11-12 13:29:38 +01:00
parent 56e7bd01ca
commit 6d31343205
6716 changed files with 1982502 additions and 5891 deletions

View File

@@ -0,0 +1,120 @@
package sharedsecret
import (
"database/sql"
"strings"
)
type Response struct {
secret []byte
installationIDs map[string]bool
}
type sqlitePersistence struct {
db *sql.DB
}
func newSQLitePersistence(db *sql.DB) *sqlitePersistence {
return &sqlitePersistence{db: db}
}
func (s *sqlitePersistence) Add(identity []byte, secret []byte, installationID string) error {
tx, err := s.db.Begin()
if err != nil {
return err
}
insertSecretStmt, err := tx.Prepare("INSERT INTO secrets(identity, secret) VALUES (?, ?)")
if err != nil {
_ = tx.Rollback()
return err
}
defer insertSecretStmt.Close()
_, err = insertSecretStmt.Exec(identity, secret)
if err != nil {
_ = tx.Rollback()
return err
}
insertInstallationIDStmt, err := tx.Prepare("INSERT INTO secret_installation_ids(id, identity_id) VALUES (?, ?)")
if err != nil {
_ = tx.Rollback()
return err
}
defer insertInstallationIDStmt.Close()
_, err = insertInstallationIDStmt.Exec(installationID, identity)
if err != nil {
_ = tx.Rollback()
return err
}
return tx.Commit()
}
func (s *sqlitePersistence) Get(identity []byte, installationIDs []string) (*Response, error) {
response := &Response{
installationIDs: make(map[string]bool),
}
args := make([]interface{}, len(installationIDs)+1)
args[0] = identity
for i, installationID := range installationIDs {
args[i+1] = installationID
}
/* #nosec */
query := `SELECT secret, id
FROM secrets t
JOIN
secret_installation_ids tid
ON t.identity = tid.identity_id
WHERE
t.identity = ?
AND
tid.id IN (?` + strings.Repeat(",?", len(installationIDs)-1) + `)`
rows, err := s.db.Query(query, args...)
if err != nil && err != sql.ErrNoRows {
return nil, err
}
defer rows.Close()
for rows.Next() {
var installationID string
var secret []byte
err = rows.Scan(&secret, &installationID)
if err != nil {
return nil, err
}
response.secret = secret
response.installationIDs[installationID] = true
}
return response, nil
}
func (s *sqlitePersistence) All() ([][][]byte, error) {
query := "SELECT identity, secret FROM secrets"
var secrets [][][]byte
rows, err := s.db.Query(query)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var secret []byte
var identity []byte
err = rows.Scan(&identity, &secret)
if err != nil {
return nil, err
}
secrets = append(secrets, [][]byte{identity, secret})
}
return secrets, nil
}

View File

@@ -0,0 +1,111 @@
package sharedsecret
import (
"bytes"
"crypto/ecdsa"
"database/sql"
"errors"
"go.uber.org/zap"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/crypto/ecies"
)
const sskLen = 16
type Secret struct {
Identity *ecdsa.PublicKey
Key []byte
}
// SharedSecret generates and manages negotiated secrets.
// Identities (public keys) stored by SharedSecret
// are compressed.
// TODO: make compression of public keys a responsibility of sqlitePersistence instead of SharedSecret.
type SharedSecret struct {
persistence *sqlitePersistence
logger *zap.Logger
}
func New(db *sql.DB, logger *zap.Logger) *SharedSecret {
if logger == nil {
logger = zap.NewNop()
}
return &SharedSecret{
persistence: newSQLitePersistence(db),
logger: logger.With(zap.Namespace("SharedSecret")),
}
}
func (s *SharedSecret) generate(myPrivateKey *ecdsa.PrivateKey, theirPublicKey *ecdsa.PublicKey, installationID string) (*Secret, error) {
sharedKey, err := ecies.ImportECDSA(myPrivateKey).GenerateShared(
ecies.ImportECDSAPublic(theirPublicKey),
sskLen,
sskLen,
)
if err != nil {
return nil, err
}
theirIdentity := crypto.CompressPubkey(theirPublicKey)
if err = s.persistence.Add(theirIdentity, sharedKey, installationID); err != nil {
return nil, err
}
return &Secret{Key: sharedKey, Identity: theirPublicKey}, err
}
// Generate will generate a shared secret for a given identity, and return it.
func (s *SharedSecret) Generate(myPrivateKey *ecdsa.PrivateKey, theirPublicKey *ecdsa.PublicKey, installationID string) (*Secret, error) {
return s.generate(myPrivateKey, theirPublicKey, installationID)
}
// Agreed returns true if a secret has been acknowledged by all the installationIDs.
func (s *SharedSecret) Agreed(myPrivateKey *ecdsa.PrivateKey, myInstallationID string, theirPublicKey *ecdsa.PublicKey, theirInstallationIDs []string) (*Secret, bool, error) {
secret, err := s.generate(myPrivateKey, theirPublicKey, myInstallationID)
if err != nil {
return nil, false, err
}
if len(theirInstallationIDs) == 0 {
return secret, false, nil
}
theirIdentity := crypto.CompressPubkey(theirPublicKey)
response, err := s.persistence.Get(theirIdentity, theirInstallationIDs)
if err != nil {
return nil, false, err
}
for _, installationID := range theirInstallationIDs {
if !response.installationIDs[installationID] {
return secret, false, nil
}
}
if !bytes.Equal(secret.Key, response.secret) {
return nil, false, errors.New("computed and saved secrets are different for a given identity")
}
return secret, true, nil
}
func (s *SharedSecret) All() ([]*Secret, error) {
var secrets []*Secret
tuples, err := s.persistence.All()
if err != nil {
return nil, err
}
for _, tuple := range tuples {
key, err := crypto.DecompressPubkey(tuple[0])
if err != nil {
return nil, err
}
secrets = append(secrets, &Secret{Identity: key, Key: tuple[1]})
}
return secrets, nil
}