2020-07-01 12:04:09 +00:00
package push_notification_server
2020-06-30 08:30:58 +00:00
import (
2020-07-01 10:09:40 +00:00
"crypto/ecdsa"
2020-06-30 08:30:58 +00:00
"database/sql"
2020-07-02 13:57:50 +00:00
"strings"
2020-07-01 10:09:40 +00:00
2020-07-01 12:04:09 +00:00
"github.com/golang/protobuf/proto"
"github.com/status-im/status-go/eth-node/crypto"
2020-07-01 10:09:40 +00:00
"github.com/status-im/status-go/protocol/protobuf"
2020-06-30 08:30:58 +00:00
)
2020-07-01 10:09:40 +00:00
type Persistence interface {
2020-07-02 13:57:50 +00:00
// GetPushNotificationRegistrationByPublicKeyAndInstallationID retrieve a push notification registration from storage given a public key and installation id
GetPushNotificationRegistrationByPublicKeyAndInstallationID ( publicKey * ecdsa . PublicKey , installationID string ) ( * protobuf . PushNotificationRegistration , error )
// GetPushNotificationRegistrationByPublicKey retrieve all the push notification registrations from storage given a public key
GetPushNotificationRegistrationByPublicKeys ( publicKeys [ ] [ ] byte ) ( [ ] * PushNotificationIDAndRegistration , error )
2020-07-02 08:08:19 +00:00
// DeletePushNotificationRegistration deletes a push notification registration from storage given a public key and installation id
DeletePushNotificationRegistration ( publicKey * ecdsa . PublicKey , installationID string ) error
// SavePushNotificationRegistration saves a push notification option to the db
SavePushNotificationRegistration ( publicKey * ecdsa . PublicKey , registration * protobuf . PushNotificationRegistration ) error
2020-07-01 10:09:40 +00:00
}
type SQLitePersistence struct {
2020-06-30 08:30:58 +00:00
db * sql . DB
}
2020-07-01 10:09:40 +00:00
func NewSQLitePersistence ( db * sql . DB ) Persistence {
return & SQLitePersistence { db : db }
}
2020-07-02 13:57:50 +00:00
func ( p * SQLitePersistence ) GetPushNotificationRegistrationByPublicKeyAndInstallationID ( publicKey * ecdsa . PublicKey , installationID string ) ( * protobuf . PushNotificationRegistration , error ) {
2020-07-02 08:08:19 +00:00
var marshaledRegistration [ ] byte
2020-07-02 13:57:50 +00:00
err := p . db . QueryRow ( ` SELECT registration FROM push_notification_server_registrations WHERE public_key = ? AND installation_id = ? ` , hashPublicKey ( publicKey ) , installationID ) . Scan ( & marshaledRegistration )
2020-07-01 12:04:09 +00:00
if err == sql . ErrNoRows {
return nil , nil
} else if err != nil {
return nil , err
}
2020-07-02 08:08:19 +00:00
registration := & protobuf . PushNotificationRegistration { }
2020-07-01 12:04:09 +00:00
2020-07-02 08:08:19 +00:00
if err := proto . Unmarshal ( marshaledRegistration , registration ) ; err != nil {
2020-07-01 12:04:09 +00:00
return nil , err
}
2020-07-02 08:08:19 +00:00
return registration , nil
2020-07-01 12:04:09 +00:00
}
2020-07-02 13:57:50 +00:00
type PushNotificationIDAndRegistration struct {
ID [ ] byte
Registration * protobuf . PushNotificationRegistration
}
func ( p * SQLitePersistence ) GetPushNotificationRegistrationByPublicKeys ( publicKeys [ ] [ ] byte ) ( [ ] * PushNotificationIDAndRegistration , error ) {
// TODO: check for a max number of keys
publicKeyArgs := make ( [ ] interface { } , 0 , len ( publicKeys ) )
for _ , pk := range publicKeys {
publicKeyArgs = append ( publicKeyArgs , pk )
}
inVector := strings . Repeat ( "?, " , len ( publicKeys ) - 1 ) + "?"
rows , err := p . db . Query ( ` SELECT public_key,registration FROM push_notification_server_registrations WHERE public_key IN ( ` + inVector + ` ) ` , publicKeyArgs ... )
if err != nil {
return nil , err
}
defer rows . Close ( )
var registrations [ ] * PushNotificationIDAndRegistration
for rows . Next ( ) {
response := & PushNotificationIDAndRegistration { }
var marshaledRegistration [ ] byte
err := rows . Scan ( & response . ID , & marshaledRegistration )
if err != nil {
return nil , err
}
registration := & protobuf . PushNotificationRegistration { }
if err := proto . Unmarshal ( marshaledRegistration , registration ) ; err != nil {
return nil , err
}
response . Registration = registration
registrations = append ( registrations , response )
}
return registrations , nil
}
2020-07-02 08:08:19 +00:00
func ( p * SQLitePersistence ) SavePushNotificationRegistration ( publicKey * ecdsa . PublicKey , registration * protobuf . PushNotificationRegistration ) error {
marshaledRegistration , err := proto . Marshal ( registration )
2020-07-01 12:04:09 +00:00
if err != nil {
return err
}
2020-07-02 13:57:50 +00:00
_ , err = p . db . Exec ( ` INSERT INTO push_notification_server_registrations (public_key, installation_id, version, registration) VALUES (?, ?, ?, ?) ` , hashPublicKey ( publicKey ) , registration . InstallationId , registration . Version , marshaledRegistration )
2020-07-01 12:04:09 +00:00
return err
}
2020-07-02 08:08:19 +00:00
func ( p * SQLitePersistence ) DeletePushNotificationRegistration ( publicKey * ecdsa . PublicKey , installationID string ) error {
2020-07-02 13:57:50 +00:00
_ , err := p . db . Exec ( ` DELETE FROM push_notification_server_registrations WHERE public_key = ? AND installation_id = ? ` , hashPublicKey ( publicKey ) , installationID )
2020-07-01 12:04:09 +00:00
return err
2020-06-30 08:30:58 +00:00
}
2020-07-02 10:49:04 +00:00
2020-07-02 13:57:50 +00:00
func hashPublicKey ( pk * ecdsa . PublicKey ) [ ] byte {
2020-07-02 10:49:04 +00:00
return shake256 ( crypto . CompressPubkey ( pk ) )
}