Return decrypted options on validation

This commit is contained in:
Andrea Maria Piana 2020-07-01 10:53:05 +02:00
parent c5077609ee
commit eed0df3420
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
2 changed files with 54 additions and 40 deletions

View File

@ -60,61 +60,60 @@ func (p *Server) validateUUID(u string) error {
return err
}
func (p *Server) ValidateRegistration(previousPreferences *protobuf.PushNotificationOptions, publicKey *ecdsa.PublicKey, payload []byte) error {
// 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) {
if payload == nil {
return ErrEmptyPushNotificationOptionsPayload
return nil, ErrEmptyPushNotificationOptionsPayload
}
if publicKey == nil {
return ErrEmptyPushNotificationOptionsPublicKey
return nil, ErrEmptyPushNotificationOptionsPublicKey
}
sharedKey, err := p.generateSharedKey(publicKey)
if err != nil {
return err
return nil, err
}
decryptedPayload, err := decrypt(payload, sharedKey)
if err != nil {
return err
return nil, err
}
preferences := &protobuf.PushNotificationOptions{}
options := &protobuf.PushNotificationOptions{}
if err := proto.Unmarshal(decryptedPayload, preferences); err != nil {
return ErrCouldNotUnmarshalPushNotificationOptions
if err := proto.Unmarshal(decryptedPayload, options); err != nil {
return nil, ErrCouldNotUnmarshalPushNotificationOptions
}
if preferences.Version < 1 {
return ErrInvalidPushNotificationOptionsVersion
if options.Version < 1 {
return nil, ErrInvalidPushNotificationOptionsVersion
}
if previousPreferences != nil && preferences.Version <= previousPreferences.Version {
return ErrInvalidPushNotificationOptionsVersion
if previousOptions != nil && options.Version <= previousOptions.Version {
return nil, ErrInvalidPushNotificationOptionsVersion
}
if err := p.validateUUID(preferences.InstallationId); err != nil {
return ErrMalformedPushNotificationOptionsInstallationID
if err := p.validateUUID(options.InstallationId); err != nil {
return nil, ErrMalformedPushNotificationOptionsInstallationID
}
// Unregistering message
if preferences.Unregister {
return nil
if options.Unregister {
return options, nil
}
if err := p.validateUUID(preferences.AccessToken); err != nil {
return ErrMalformedPushNotificationOptionsAccessToken
if err := p.validateUUID(options.AccessToken); err != nil {
return nil, ErrMalformedPushNotificationOptionsAccessToken
}
if len(preferences.Token) == 0 {
return ErrMalformedPushNotificationOptionsDeviceToken
if len(options.Token) == 0 {
return nil, ErrMalformedPushNotificationOptionsDeviceToken
}
fmt.Println(decryptedPayload)
/*if newRegistration.Version < 1 {
return ErrInvalidPushNotificationOptionsVersion
}*/
return nil
return options, nil
}
func decrypt(cyphertext []byte, key []byte) ([]byte, error) {

View File

@ -30,29 +30,36 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
require.NoError(t, err)
// Empty payload
require.Equal(t, ErrEmptyPushNotificationOptionsPayload, server.ValidateRegistration(nil, &key.PublicKey, nil))
_, err = server.ValidateRegistration(nil, &key.PublicKey, nil)
require.Equal(t, ErrEmptyPushNotificationOptionsPayload, err)
// Empty key
require.Equal(t, ErrEmptyPushNotificationOptionsPublicKey, server.ValidateRegistration(nil, nil, []byte("payload")))
_, err = server.ValidateRegistration(nil, nil, []byte("payload"))
require.Equal(t, ErrEmptyPushNotificationOptionsPublicKey, err)
// Invalid cyphertext length
require.Equal(t, ErrInvalidCiphertextLength, server.ValidateRegistration(nil, &key.PublicKey, []byte("too short")))
_, err = server.ValidateRegistration(nil, &key.PublicKey, []byte("too short"))
require.Equal(t, ErrInvalidCiphertextLength, err)
// Invalid cyphertext length
require.Equal(t, ErrInvalidCiphertextLength, server.ValidateRegistration(nil, &key.PublicKey, []byte("too short")))
_, err = server.ValidateRegistration(nil, &key.PublicKey, []byte("too short"))
require.Equal(t, ErrInvalidCiphertextLength, err)
// Invalid ciphertext
require.Error(t, ErrInvalidCiphertextLength, server.ValidateRegistration(nil, &key.PublicKey, []byte("not too short but invalid")))
_, err = server.ValidateRegistration(nil, &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)
require.Error(t, server.ValidateRegistration(nil, &key.PublicKey, cyphertext))
_, err = server.ValidateRegistration(nil, &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)
require.Equal(t, ErrCouldNotUnmarshalPushNotificationOptions, server.ValidateRegistration(nil, &key.PublicKey, cyphertext))
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
require.Equal(t, ErrCouldNotUnmarshalPushNotificationOptions, err)
// Missing installationID
payload, err := proto.Marshal(&protobuf.PushNotificationOptions{
@ -63,7 +70,8 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
require.Equal(t, ErrMalformedPushNotificationOptionsInstallationID, server.ValidateRegistration(nil, &key.PublicKey, cyphertext))
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
require.Equal(t, ErrMalformedPushNotificationOptionsInstallationID, err)
// Malformed installationID
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
@ -73,7 +81,8 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
})
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
require.Equal(t, ErrMalformedPushNotificationOptionsInstallationID, server.ValidateRegistration(nil, &key.PublicKey, cyphertext))
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
require.Equal(t, ErrMalformedPushNotificationOptionsInstallationID, err)
// Version set to 0
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
@ -84,7 +93,8 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
require.Equal(t, ErrInvalidPushNotificationOptionsVersion, server.ValidateRegistration(nil, &key.PublicKey, cyphertext))
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
require.Equal(t, ErrInvalidPushNotificationOptionsVersion, err)
// Version lower than previous one
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
@ -96,10 +106,11 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
require.Equal(t, ErrInvalidPushNotificationOptionsVersion, server.ValidateRegistration(&protobuf.PushNotificationOptions{
_, err = server.ValidateRegistration(&protobuf.PushNotificationOptions{
AccessToken: accessToken,
InstallationId: installationID,
Version: 2}, &key.PublicKey, cyphertext))
Version: 2}, &key.PublicKey, cyphertext)
require.Equal(t, ErrInvalidPushNotificationOptionsVersion, err)
// Unregistering message
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
@ -111,7 +122,8 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
require.Nil(t, server.ValidateRegistration(nil, &key.PublicKey, cyphertext))
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
require.Nil(t, err)
// Missing access token
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
@ -122,7 +134,8 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
require.Equal(t, ErrMalformedPushNotificationOptionsAccessToken, server.ValidateRegistration(nil, &key.PublicKey, cyphertext))
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
require.Equal(t, ErrMalformedPushNotificationOptionsAccessToken, err)
// Invalid access token
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
@ -134,7 +147,8 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
require.Equal(t, ErrMalformedPushNotificationOptionsAccessToken, server.ValidateRegistration(nil, &key.PublicKey, cyphertext))
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
require.Equal(t, ErrMalformedPushNotificationOptionsAccessToken, err)
// Missing device token
payload, err = proto.Marshal(&protobuf.PushNotificationOptions{
@ -146,6 +160,7 @@ func TestPushNotificationServerValidateRegistration(t *testing.T) {
cyphertext, err = encrypt(payload, sharedKey, rand.Reader)
require.NoError(t, err)
require.Equal(t, ErrMalformedPushNotificationOptionsDeviceToken, server.ValidateRegistration(nil, &key.PublicKey, cyphertext))
_, err = server.ValidateRegistration(nil, &key.PublicKey, cyphertext)
require.Equal(t, ErrMalformedPushNotificationOptionsDeviceToken, err)
}