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

View File

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