2020-07-01 12:04:09 +00:00
|
|
|
package push_notification_server
|
2020-06-30 08:30:58 +00:00
|
|
|
|
|
|
|
import (
|
2020-06-30 14:55:24 +00:00
|
|
|
"crypto/rand"
|
2020-07-01 12:04:09 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2020-06-30 08:30:58 +00:00
|
|
|
"testing"
|
|
|
|
|
2020-06-30 13:14:25 +00:00
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
2020-06-30 14:55:24 +00:00
|
|
|
"github.com/golang/protobuf/proto"
|
2020-07-01 12:04:09 +00:00
|
|
|
"github.com/stretchr/testify/suite"
|
2020-06-30 14:55:24 +00:00
|
|
|
|
|
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
2020-07-01 12:04:09 +00:00
|
|
|
"github.com/status-im/status-go/protocol/sqlite"
|
2020-06-30 08:30:58 +00:00
|
|
|
)
|
|
|
|
|
2020-07-01 12:04:09 +00:00
|
|
|
func TestServerSuite(t *testing.T) {
|
|
|
|
suite.Run(t, new(ServerSuite))
|
2020-07-01 10:09:40 +00:00
|
|
|
}
|
|
|
|
|
2020-07-01 12:04:09 +00:00
|
|
|
type ServerSuite struct {
|
|
|
|
suite.Suite
|
|
|
|
tmpFile *os.File
|
|
|
|
persistence Persistence
|
2020-07-01 10:09:40 +00:00
|
|
|
}
|
|
|
|
|
2020-07-01 12:04:09 +00:00
|
|
|
func (s *ServerSuite) SetupTest() {
|
|
|
|
tmpFile, err := ioutil.TempFile("", "")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.tmpFile = tmpFile
|
|
|
|
|
|
|
|
database, err := sqlite.Open(s.tmpFile.Name(), "")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.persistence = NewSQLitePersistence(database)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *ServerSuite) TestPushNotificationServerValidateRegistration() {
|
2020-07-01 08:37:54 +00:00
|
|
|
accessToken := "b6ae4fde-bb65-11ea-b3de-0242ac130004"
|
|
|
|
installationID := "c6ae4fde-bb65-11ea-b3de-0242ac130004"
|
2020-06-30 13:14:25 +00:00
|
|
|
identity, err := crypto.GenerateKey()
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-06-30 13:14:25 +00:00
|
|
|
|
|
|
|
config := &Config{
|
|
|
|
Identity: identity,
|
|
|
|
}
|
|
|
|
|
2020-07-01 12:04:09 +00:00
|
|
|
server := New(config, s.persistence)
|
2020-06-30 13:14:25 +00:00
|
|
|
|
2020-06-30 14:55:24 +00:00
|
|
|
key, err := crypto.GenerateKey()
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-06-30 14:55:24 +00:00
|
|
|
|
|
|
|
sharedKey, err := server.generateSharedKey(&key.PublicKey)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-06-30 14:55:24 +00:00
|
|
|
|
2020-06-30 13:14:25 +00:00
|
|
|
// Empty payload
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, nil)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Equal(ErrEmptyPushNotificationOptionsPayload, err)
|
2020-06-30 13:14:25 +00:00
|
|
|
|
|
|
|
// Empty key
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(nil, []byte("payload"))
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Equal(ErrEmptyPushNotificationOptionsPublicKey, err)
|
2020-06-30 13:14:25 +00:00
|
|
|
|
2020-06-30 14:55:24 +00:00
|
|
|
// Invalid cyphertext length
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, []byte("too short"))
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Equal(ErrInvalidCiphertextLength, err)
|
2020-06-30 13:14:25 +00:00
|
|
|
|
2020-06-30 14:55:24 +00:00
|
|
|
// Invalid cyphertext length
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, []byte("too short"))
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Equal(ErrInvalidCiphertextLength, err)
|
2020-06-30 08:30:58 +00:00
|
|
|
|
2020-06-30 14:55:24 +00:00
|
|
|
// Invalid ciphertext
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, []byte("not too short but invalid"))
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Error(ErrInvalidCiphertextLength, err)
|
2020-06-30 14:55:24 +00:00
|
|
|
|
|
|
|
// Different key ciphertext
|
|
|
|
cyphertext, err := encrypt([]byte("plaintext"), make([]byte, 32), rand.Reader)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Error(err)
|
2020-06-30 14:55:24 +00:00
|
|
|
|
|
|
|
// Right cyphertext but non unmarshable payload
|
|
|
|
cyphertext, err = encrypt([]byte("plaintext"), sharedKey, rand.Reader)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Equal(ErrCouldNotUnmarshalPushNotificationOptions, err)
|
2020-07-01 08:37:54 +00:00
|
|
|
|
|
|
|
// Missing installationID
|
|
|
|
payload, err := proto.Marshal(&protobuf.PushNotificationOptions{
|
|
|
|
AccessToken: accessToken,
|
|
|
|
Version: 1,
|
|
|
|
})
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 08:37:54 +00:00
|
|
|
|
|
|
|
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Equal(ErrMalformedPushNotificationOptionsInstallationID, err)
|
2020-07-01 08:37:54 +00:00
|
|
|
|
|
|
|
// Malformed installationID
|
|
|
|
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
|
|
|
|
AccessToken: accessToken,
|
|
|
|
InstallationId: "abc",
|
|
|
|
Version: 1,
|
|
|
|
})
|
|
|
|
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Equal(ErrMalformedPushNotificationOptionsInstallationID, err)
|
2020-06-30 14:55:24 +00:00
|
|
|
|
|
|
|
// Version set to 0
|
2020-07-01 08:37:54 +00:00
|
|
|
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
|
|
|
|
AccessToken: accessToken,
|
|
|
|
InstallationId: installationID,
|
|
|
|
})
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 08:37:54 +00:00
|
|
|
|
|
|
|
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Equal(ErrInvalidPushNotificationOptionsVersion, err)
|
2020-07-01 08:37:54 +00:00
|
|
|
|
|
|
|
// Version lower than previous one
|
|
|
|
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
|
|
|
|
AccessToken: accessToken,
|
|
|
|
InstallationId: installationID,
|
|
|
|
Version: 1,
|
|
|
|
})
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 08:37:54 +00:00
|
|
|
|
|
|
|
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 10:09:40 +00:00
|
|
|
|
|
|
|
// Setup mock
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(s.persistence.SavePushNotificationOptions(&key.PublicKey, &protobuf.PushNotificationOptions{
|
2020-07-01 08:37:54 +00:00
|
|
|
AccessToken: accessToken,
|
|
|
|
InstallationId: installationID,
|
2020-07-01 12:04:09 +00:00
|
|
|
Version: 2}))
|
2020-07-01 10:09:40 +00:00
|
|
|
|
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Equal(ErrInvalidPushNotificationOptionsVersion, err)
|
2020-07-01 08:37:54 +00:00
|
|
|
|
2020-07-01 10:09:40 +00:00
|
|
|
// Cleanup mock
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(s.persistence.DeletePushNotificationOptions(&key.PublicKey, installationID))
|
2020-07-01 10:09:40 +00:00
|
|
|
|
2020-07-01 08:37:54 +00:00
|
|
|
// Unregistering message
|
|
|
|
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
|
|
|
|
InstallationId: installationID,
|
|
|
|
Unregister: true,
|
|
|
|
Version: 1,
|
|
|
|
})
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-06-30 14:55:24 +00:00
|
|
|
|
|
|
|
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Nil(err)
|
2020-07-01 08:37:54 +00:00
|
|
|
|
|
|
|
// Missing access token
|
|
|
|
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
|
|
|
|
InstallationId: installationID,
|
|
|
|
Version: 1,
|
|
|
|
})
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 08:37:54 +00:00
|
|
|
|
|
|
|
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Equal(ErrMalformedPushNotificationOptionsAccessToken, err)
|
2020-07-01 08:37:54 +00:00
|
|
|
|
|
|
|
// Invalid access token
|
|
|
|
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
|
|
|
|
AccessToken: "bc",
|
|
|
|
InstallationId: installationID,
|
|
|
|
Version: 1,
|
|
|
|
})
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 08:37:54 +00:00
|
|
|
|
|
|
|
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Equal(ErrMalformedPushNotificationOptionsAccessToken, err)
|
2020-07-01 08:37:54 +00:00
|
|
|
|
|
|
|
// Missing device token
|
|
|
|
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
|
|
|
|
AccessToken: accessToken,
|
|
|
|
InstallationId: installationID,
|
|
|
|
Version: 1,
|
|
|
|
})
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 08:37:54 +00:00
|
|
|
|
|
|
|
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().NoError(err)
|
2020-07-01 10:09:40 +00:00
|
|
|
_, err = server.ValidateRegistration(&key.PublicKey, cyphertext)
|
2020-07-01 12:04:09 +00:00
|
|
|
s.Require().Equal(ErrMalformedPushNotificationOptionsDeviceToken, err)
|
2020-06-30 08:30:58 +00:00
|
|
|
}
|