Pull push notification options from persistence

This commit is contained in:
Andrea Maria Piana 2020-07-01 12:09:40 +02:00
parent eed0df3420
commit 24df11bcf9
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
3 changed files with 80 additions and 37 deletions

View File

@ -2,7 +2,6 @@ package protocol
import (
"errors"
"fmt"
"io"
"crypto/aes"
@ -36,12 +35,12 @@ type Config struct {
}
type Server struct {
persistence *Persistence
persistence Persistence
config *Config
}
func New(persistence *Persistence) *Server {
return &Server{persistence: persistence}
func New(config *Config, persistence Persistence) *Server {
return &Server{persistence: persistence, config: config}
}
func (p *Server) generateSharedKey(publicKey *ecdsa.PublicKey) ([]byte, error) {
@ -60,9 +59,18 @@ func (p *Server) validateUUID(u string) error {
return err
}
func (p *Server) decryptRegistration(publicKey *ecdsa.PublicKey, payload []byte) ([]byte, error) {
sharedKey, err := p.generateSharedKey(publicKey)
if err != nil {
return nil, err
}
return decrypt(payload, sharedKey)
}
// ValidateRegistration validates a new message against the last one received for a given installationID and and public key
// and return the decrypted message
func (p *Server) ValidateRegistration(previousOptions *protobuf.PushNotificationOptions, publicKey *ecdsa.PublicKey, payload []byte) (*protobuf.PushNotificationOptions, error) {
func (p *Server) ValidateRegistration(publicKey *ecdsa.PublicKey, payload []byte) (*protobuf.PushNotificationOptions, error) {
if payload == nil {
return nil, ErrEmptyPushNotificationOptionsPayload
}
@ -71,12 +79,7 @@ func (p *Server) ValidateRegistration(previousOptions *protobuf.PushNotification
return nil, ErrEmptyPushNotificationOptionsPublicKey
}
sharedKey, err := p.generateSharedKey(publicKey)
if err != nil {
return nil, err
}
decryptedPayload, err := decrypt(payload, sharedKey)
decryptedPayload, err := p.decryptRegistration(publicKey, payload)
if err != nil {
return nil, err
}
@ -91,14 +94,19 @@ func (p *Server) ValidateRegistration(previousOptions *protobuf.PushNotification
return nil, ErrInvalidPushNotificationOptionsVersion
}
if previousOptions != nil && options.Version <= previousOptions.Version {
return nil, ErrInvalidPushNotificationOptionsVersion
}
if err := p.validateUUID(options.InstallationId); err != nil {
return nil, ErrMalformedPushNotificationOptionsInstallationID
}
previousOptions, err := p.persistence.GetPushNotificationOptions(publicKey, options.InstallationId)
if err != nil {
return nil, err
}
if previousOptions != nil && options.Version <= previousOptions.Version {
return nil, ErrInvalidPushNotificationOptionsVersion
}
// Unregistering message
if options.Unregister {
return options, nil
@ -111,11 +119,19 @@ func (p *Server) ValidateRegistration(previousOptions *protobuf.PushNotification
if len(options.Token) == 0 {
return nil, ErrMalformedPushNotificationOptionsDeviceToken
}
fmt.Println(decryptedPayload)
return options, nil
}
func (p *Server) HandlePushNotificationOptions(publicKey *ecdsa.PublicKey, payload []byte) error {
_, err := p.ValidateRegistration(publicKey, payload)
if err != nil {
return err
}
return nil
}
func decrypt(cyphertext []byte, key []byte) ([]byte, error) {
if len(cyphertext) < nonceLength {
return nil, ErrInvalidCiphertextLength

View File

@ -1,13 +1,24 @@
package protocol
import (
"crypto/ecdsa"
"database/sql"
"github.com/status-im/status-go/protocol/protobuf"
)
type Persistence struct {
type Persistence interface {
GetPushNotificationOptions(publicKey *ecdsa.PublicKey, installationID string) (*protobuf.PushNotificationOptions, error)
}
type SQLitePersistence struct {
db *sql.DB
}
func NewPersistence(db *sql.DB) *Persistence {
return &Persistence{db: db}
func NewSQLitePersistence(db *sql.DB) Persistence {
return &SQLitePersistence{db: db}
}
func (p *SQLitePersistence) GetPushNotificationOptions(publicKey *ecdsa.PublicKey, installationID string) (*protobuf.PushNotificationOptions, error) {
return nil, nil
}

View File

@ -1,6 +1,7 @@
package protocol
import (
"crypto/ecdsa"
"crypto/rand"
"testing"
@ -11,6 +12,14 @@ import (
"github.com/status-im/status-go/protocol/protobuf"
)
type MockPersistence struct {
pno *protobuf.PushNotificationOptions
}
func (p *MockPersistence) GetPushNotificationOptions(publicKey *ecdsa.PublicKey, installationID string) (*protobuf.PushNotificationOptions, error) {
return p.pno, nil
}
func TestPushNotificationServerValidateRegistration(t *testing.T) {
accessToken := "b6ae4fde-bb65-11ea-b3de-0242ac130004"
installationID := "c6ae4fde-bb65-11ea-b3de-0242ac130004"
@ -21,7 +30,8 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
Identity: identity,
}
server := Server{config: config}
mockPersistence := &MockPersistence{}
server := New(config, mockPersistence)
key, err := crypto.GenerateKey()
require.NoError(t, err)
@ -30,35 +40,35 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
require.NoError(t, err)
// Empty payload
_, err = server.ValidateRegistration(nil, &key.PublicKey, nil)
_, err = server.ValidateRegistration(&key.PublicKey, nil)
require.Equal(t, ErrEmptyPushNotificationOptionsPayload, err)
// Empty key
_, err = server.ValidateRegistration(nil, nil, []byte("payload"))
_, err = server.ValidateRegistration(nil, []byte("payload"))
require.Equal(t, ErrEmptyPushNotificationOptionsPublicKey, err)
// Invalid cyphertext length
_, err = server.ValidateRegistration(nil, &key.PublicKey, []byte("too short"))
_, err = server.ValidateRegistration(&key.PublicKey, []byte("too short"))
require.Equal(t, ErrInvalidCiphertextLength, err)
// Invalid cyphertext length
_, err = server.ValidateRegistration(nil, &key.PublicKey, []byte("too short"))
_, err = server.ValidateRegistration(&key.PublicKey, []byte("too short"))
require.Equal(t, ErrInvalidCiphertextLength, err)
// Invalid ciphertext
_, err = server.ValidateRegistration(nil, &key.PublicKey, []byte("not too short but invalid"))
_, err = server.ValidateRegistration(&key.PublicKey, []byte("not too short but invalid"))
require.Error(t, ErrInvalidCiphertextLength, err)
// Different key ciphertext
cyphertext, err := encrypt([]byte("plaintext"), make([]byte, 32), rand.Reader)
require.NoError(t, err)
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
require.Error(t, err)
// Right cyphertext but non unmarshable payload
cyphertext, err = encrypt([]byte("plaintext"), sharedKey, rand.Reader)
require.NoError(t, err)
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
require.Equal(t, ErrCouldNotUnmarshalPushNotificationOptions, err)
// Missing installationID
@ -70,7 +80,7 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
require.Equal(t, ErrMalformedPushNotificationOptionsInstallationID, err)
// Malformed installationID
@ -81,7 +91,7 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
})
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
require.Equal(t, ErrMalformedPushNotificationOptionsInstallationID, err)
// Version set to 0
@ -93,7 +103,7 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
require.Equal(t, ErrInvalidPushNotificationOptionsVersion, err)
// Version lower than previous one
@ -106,12 +116,19 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
_, err = server.ValidateRegistration(&protobuf.PushNotificationOptions{
// Setup mock
mockPersistence.pno = &protobuf.PushNotificationOptions{
AccessToken: accessToken,
InstallationId: installationID,
Version: 2}, &key.PublicKey, cyphertext)
Version: 2}
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
require.Equal(t, ErrInvalidPushNotificationOptionsVersion, err)
// Cleanup mock
mockPersistence.pno = nil
// Unregistering message
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
InstallationId: installationID,
@ -122,7 +139,7 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
require.Nil(t, err)
// Missing access token
@ -134,7 +151,7 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
require.Equal(t, ErrMalformedPushNotificationOptionsAccessToken, err)
// Invalid access token
@ -147,7 +164,7 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
require.Equal(t, ErrMalformedPushNotificationOptionsAccessToken, err)
// Missing device token
@ -160,7 +177,6 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
require.Equal(t, ErrMalformedPushNotificationOptionsDeviceToken, err)
}