Pull push notification options from persistence
This commit is contained in:
parent
eed0df3420
commit
24df11bcf9
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue