github.com/status-im/status-go@v1.1.0/protocol/encryption/persistence_test.go (about)

     1  package encryption
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/suite"
     8  
     9  	"github.com/status-im/status-go/appdatabase"
    10  	"github.com/status-im/status-go/eth-node/crypto"
    11  	"github.com/status-im/status-go/t/helpers"
    12  
    13  	"github.com/status-im/status-go/protocol/encryption/multidevice"
    14  	"github.com/status-im/status-go/protocol/sqlite"
    15  )
    16  
    17  func TestSQLLitePersistenceTestSuite(t *testing.T) {
    18  	suite.Run(t, new(SQLLitePersistenceTestSuite))
    19  }
    20  
    21  type SQLLitePersistenceTestSuite struct {
    22  	suite.Suite
    23  	service *sqlitePersistence
    24  }
    25  
    26  func (s *SQLLitePersistenceTestSuite) SetupTest() {
    27  	db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{})
    28  	s.Require().NoError(err)
    29  	err = sqlite.Migrate(db)
    30  	s.Require().NoError(err)
    31  
    32  	s.service = newSQLitePersistence(db)
    33  }
    34  
    35  func (s *SQLLitePersistenceTestSuite) TestPrivateBundle() {
    36  	installationID := "1"
    37  
    38  	key, err := crypto.GenerateKey()
    39  	s.Require().NoError(err)
    40  
    41  	actualKey, err := s.service.GetPrivateKeyBundle([]byte("non-existing"))
    42  	s.Require().NoError(err, "Error was not returned even though bundle is not there")
    43  	s.Nil(actualKey)
    44  
    45  	anyPrivateBundle, err := s.service.GetAnyPrivateBundle([]byte("non-existing-id"), []*multidevice.Installation{{ID: installationID, Version: 1}})
    46  	s.Require().NoError(err)
    47  	s.Nil(anyPrivateBundle)
    48  
    49  	bundle, err := NewBundleContainer(key, installationID)
    50  	s.Require().NoError(err)
    51  
    52  	err = s.service.AddPrivateBundle(bundle)
    53  	s.Require().NoError(err)
    54  
    55  	bundleID := bundle.GetBundle().GetSignedPreKeys()[installationID].GetSignedPreKey()
    56  
    57  	actualKey, err = s.service.GetPrivateKeyBundle(bundleID)
    58  	s.Require().NoError(err)
    59  	s.Equal(bundle.GetPrivateSignedPreKey(), actualKey, "It returns the same key")
    60  
    61  	identity := crypto.CompressPubkey(&key.PublicKey)
    62  	anyPrivateBundle, err = s.service.GetAnyPrivateBundle(identity, []*multidevice.Installation{{ID: installationID, Version: 1}})
    63  	s.Require().NoError(err)
    64  	s.NotNil(anyPrivateBundle)
    65  	s.Equal(bundle.GetBundle().GetSignedPreKeys()[installationID].SignedPreKey, anyPrivateBundle.GetBundle().GetSignedPreKeys()[installationID].SignedPreKey, "It returns the same bundle")
    66  }
    67  
    68  func (s *SQLLitePersistenceTestSuite) TestPublicBundle() {
    69  	key, err := crypto.GenerateKey()
    70  	s.Require().NoError(err)
    71  
    72  	actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}})
    73  	s.Require().NoError(err, "Error was not returned even though bundle is not there")
    74  	s.Nil(actualBundle)
    75  
    76  	bundleContainer, err := NewBundleContainer(key, "1")
    77  	s.Require().NoError(err)
    78  
    79  	bundle := bundleContainer.GetBundle()
    80  	err = s.service.AddPublicBundle(bundle)
    81  	s.Require().NoError(err)
    82  
    83  	actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}})
    84  	s.Require().NoError(err)
    85  	s.Equal(bundle.GetIdentity(), actualBundle.GetIdentity(), "It sets the right identity")
    86  	s.Equal(bundle.GetSignedPreKeys(), actualBundle.GetSignedPreKeys(), "It sets the right prekeys")
    87  }
    88  
    89  func (s *SQLLitePersistenceTestSuite) TestUpdatedBundle() {
    90  	key, err := crypto.GenerateKey()
    91  	s.Require().NoError(err)
    92  
    93  	actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}})
    94  	s.Require().NoError(err, "Error was not returned even though bundle is not there")
    95  	s.Nil(actualBundle)
    96  
    97  	// Create & add initial bundle
    98  	bundleContainer, err := NewBundleContainer(key, "1")
    99  	s.Require().NoError(err)
   100  
   101  	bundle := bundleContainer.GetBundle()
   102  	err = s.service.AddPublicBundle(bundle)
   103  	s.Require().NoError(err)
   104  
   105  	// Create & add a new bundle
   106  	bundleContainer, err = NewBundleContainer(key, "1")
   107  	s.Require().NoError(err)
   108  	bundle = bundleContainer.GetBundle()
   109  	// We set the version
   110  	bundle.GetSignedPreKeys()["1"].Version = 1
   111  
   112  	err = s.service.AddPublicBundle(bundle)
   113  	s.Require().NoError(err)
   114  
   115  	actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}})
   116  	s.Require().NoError(err)
   117  	s.Equal(bundle.GetIdentity(), actualBundle.GetIdentity(), "It sets the right identity")
   118  	s.Equal(bundle.GetSignedPreKeys(), actualBundle.GetSignedPreKeys(), "It sets the right prekeys")
   119  }
   120  
   121  func (s *SQLLitePersistenceTestSuite) TestOutOfOrderBundles() {
   122  	key, err := crypto.GenerateKey()
   123  	s.Require().NoError(err)
   124  
   125  	actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}})
   126  	s.Require().NoError(err, "Error was not returned even though bundle is not there")
   127  	s.Nil(actualBundle)
   128  
   129  	// Create & add initial bundle
   130  	bundleContainer, err := NewBundleContainer(key, "1")
   131  	s.Require().NoError(err)
   132  
   133  	bundle1 := bundleContainer.GetBundle()
   134  	err = s.service.AddPublicBundle(bundle1)
   135  	s.Require().NoError(err)
   136  
   137  	// Create & add a new bundle
   138  	bundleContainer, err = NewBundleContainer(key, "1")
   139  	s.Require().NoError(err)
   140  
   141  	bundle2 := bundleContainer.GetBundle()
   142  	// We set the version
   143  	bundle2.GetSignedPreKeys()["1"].Version = 1
   144  
   145  	err = s.service.AddPublicBundle(bundle2)
   146  	s.Require().NoError(err)
   147  
   148  	// Add again the initial bundle
   149  	err = s.service.AddPublicBundle(bundle1)
   150  	s.Require().NoError(err)
   151  
   152  	actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}})
   153  	s.Require().NoError(err)
   154  	s.Equal(bundle2.GetIdentity(), actualBundle.GetIdentity(), "It sets the right identity")
   155  	s.Equal(bundle2.GetSignedPreKeys()["1"].GetVersion(), uint32(1))
   156  	s.Equal(bundle2.GetSignedPreKeys()["1"].GetSignedPreKey(), actualBundle.GetSignedPreKeys()["1"].GetSignedPreKey(), "It sets the right prekeys")
   157  }
   158  
   159  func (s *SQLLitePersistenceTestSuite) TestMultiplePublicBundle() {
   160  	key, err := crypto.GenerateKey()
   161  	s.Require().NoError(err)
   162  
   163  	actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}})
   164  	s.Require().NoError(err, "Error was not returned even though bundle is not there")
   165  	s.Nil(actualBundle)
   166  
   167  	bundleContainer, err := NewBundleContainer(key, "1")
   168  	s.Require().NoError(err)
   169  
   170  	bundle := bundleContainer.GetBundle()
   171  	err = s.service.AddPublicBundle(bundle)
   172  	s.Require().NoError(err)
   173  
   174  	// Adding it again does not throw an error
   175  	err = s.service.AddPublicBundle(bundle)
   176  	s.Require().NoError(err)
   177  
   178  	// Adding a different bundle
   179  	bundleContainer, err = NewBundleContainer(key, "1")
   180  	s.Require().NoError(err)
   181  	// We set the version
   182  	bundle = bundleContainer.GetBundle()
   183  	bundle.GetSignedPreKeys()["1"].Version = 1
   184  
   185  	err = s.service.AddPublicBundle(bundle)
   186  	s.Require().NoError(err)
   187  
   188  	// Returns the most recent bundle
   189  	actualBundle, err = s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}})
   190  	s.Require().NoError(err)
   191  
   192  	s.Equal(bundle.GetIdentity(), actualBundle.GetIdentity(), "It sets the identity")
   193  	s.Equal(bundle.GetSignedPreKeys(), actualBundle.GetSignedPreKeys(), "It sets the signed pre keys")
   194  
   195  }
   196  
   197  func (s *SQLLitePersistenceTestSuite) TestMultiDevicePublicBundle() {
   198  	key, err := crypto.GenerateKey()
   199  	s.Require().NoError(err)
   200  
   201  	actualBundle, err := s.service.GetPublicBundle(&key.PublicKey, []*multidevice.Installation{{ID: "1", Version: 1}})
   202  	s.Require().NoError(err, "Error was not returned even though bundle is not there")
   203  	s.Nil(actualBundle)
   204  
   205  	bundleContainer, err := NewBundleContainer(key, "1")
   206  	s.Require().NoError(err)
   207  
   208  	bundle := bundleContainer.GetBundle()
   209  	err = s.service.AddPublicBundle(bundle)
   210  	s.Require().NoError(err)
   211  
   212  	// Adding it again does not throw an error
   213  	err = s.service.AddPublicBundle(bundle)
   214  	s.Require().NoError(err)
   215  
   216  	// Adding a different bundle from a different instlation id
   217  	bundleContainer, err = NewBundleContainer(key, "2")
   218  	s.Require().NoError(err)
   219  
   220  	bundle = bundleContainer.GetBundle()
   221  	err = s.service.AddPublicBundle(bundle)
   222  	s.Require().NoError(err)
   223  
   224  	// Returns the most recent bundle
   225  	actualBundle, err = s.service.GetPublicBundle(&key.PublicKey,
   226  		[]*multidevice.Installation{
   227  			{ID: "1", Version: 1},
   228  			{ID: "2", Version: 1},
   229  		})
   230  	s.Require().NoError(err)
   231  
   232  	s.Equal(bundle.GetIdentity(), actualBundle.GetIdentity(), "It sets the identity")
   233  	s.NotNil(actualBundle.GetSignedPreKeys()["1"])
   234  	s.NotNil(actualBundle.GetSignedPreKeys()["2"])
   235  }
   236  
   237  func (s *SQLLitePersistenceTestSuite) TestRatchetInfoPrivateBundle() {
   238  	key, err := crypto.GenerateKey()
   239  	s.Require().NoError(err)
   240  
   241  	// Add a private bundle
   242  	bundle, err := NewBundleContainer(key, "2")
   243  	s.Require().NoError(err)
   244  
   245  	err = s.service.AddPrivateBundle(bundle)
   246  	s.Require().NoError(err)
   247  
   248  	err = s.service.AddRatchetInfo(
   249  		[]byte("symmetric-key"),
   250  		[]byte("their-public-key"),
   251  		bundle.GetBundle().GetSignedPreKeys()["2"].GetSignedPreKey(),
   252  		[]byte("ephemeral-public-key"),
   253  		"1",
   254  	)
   255  	s.Require().NoError(err)
   256  
   257  	ratchetInfo, err := s.service.GetRatchetInfo(bundle.GetBundle().GetSignedPreKeys()["2"].GetSignedPreKey(), []byte("their-public-key"), "1")
   258  
   259  	s.Require().NoError(err)
   260  	s.Require().NotNil(ratchetInfo)
   261  	s.NotNil(ratchetInfo.ID, "It adds an id")
   262  	s.Equal(ratchetInfo.PrivateKey, bundle.GetPrivateSignedPreKey(), "It returns the private key")
   263  	s.Equal(ratchetInfo.Sk, []byte("symmetric-key"), "It returns the symmetric key")
   264  	s.Equal(ratchetInfo.Identity, []byte("their-public-key"), "It returns the identity of the contact")
   265  	s.Equal(ratchetInfo.PublicKey, bundle.GetBundle().GetSignedPreKeys()["2"].GetSignedPreKey(), "It  returns the public key of the bundle")
   266  	s.Equal(bundle.GetBundle().GetSignedPreKeys()["2"].GetSignedPreKey(), ratchetInfo.BundleID, "It returns the bundle id")
   267  	s.Equal([]byte("ephemeral-public-key"), ratchetInfo.EphemeralKey, "It returns the ratchet ephemeral key")
   268  	s.Equal("1", ratchetInfo.InstallationID, "It returns the right installation id")
   269  }
   270  
   271  func (s *SQLLitePersistenceTestSuite) TestRatchetInfoPublicBundle() {
   272  	installationID := "1"
   273  	theirPublicKey := []byte("their-public-key")
   274  	key, err := crypto.GenerateKey()
   275  	s.Require().NoError(err)
   276  
   277  	// Add a private bundle
   278  	bundle, err := NewBundleContainer(key, installationID)
   279  	s.Require().NoError(err)
   280  
   281  	err = s.service.AddPublicBundle(bundle.GetBundle())
   282  	s.Require().NoError(err)
   283  
   284  	signedPreKey := bundle.GetBundle().GetSignedPreKeys()[installationID].GetSignedPreKey()
   285  
   286  	err = s.service.AddRatchetInfo(
   287  		[]byte("symmetric-key"),
   288  		theirPublicKey,
   289  		signedPreKey,
   290  		[]byte("public-ephemeral-key"),
   291  		installationID,
   292  	)
   293  	s.Require().NoError(err)
   294  
   295  	ratchetInfo, err := s.service.GetRatchetInfo(signedPreKey, theirPublicKey, installationID)
   296  
   297  	s.Require().NoError(err)
   298  	s.Require().NotNil(ratchetInfo, "It returns the ratchet info")
   299  
   300  	s.NotNil(ratchetInfo.ID, "It adds an id")
   301  	s.Nil(ratchetInfo.PrivateKey, "It does not return the private key")
   302  	s.Equal(ratchetInfo.Sk, []byte("symmetric-key"), "It returns the symmetric key")
   303  	s.Equal(ratchetInfo.Identity, theirPublicKey, "It returns the identity of the contact")
   304  	s.Equal(ratchetInfo.PublicKey, signedPreKey, "It  returns the public key of the bundle")
   305  	s.Equal(installationID, ratchetInfo.InstallationID, "It returns the right installationID")
   306  	s.Nilf(ratchetInfo.PrivateKey, "It does not return the private key")
   307  
   308  	ratchetInfo, err = s.service.GetAnyRatchetInfo(theirPublicKey, installationID)
   309  	s.Require().NoError(err)
   310  	s.Require().NotNil(ratchetInfo, "It returns the ratchet info")
   311  	s.NotNil(ratchetInfo.ID, "It adds an id")
   312  	s.Nil(ratchetInfo.PrivateKey, "It does not return the private key")
   313  	s.Equal(ratchetInfo.Sk, []byte("symmetric-key"), "It returns the symmetric key")
   314  	s.Equal(ratchetInfo.Identity, theirPublicKey, "It returns the identity of the contact")
   315  	s.Equal(ratchetInfo.PublicKey, signedPreKey, "It  returns the public key of the bundle")
   316  	s.Equal(signedPreKey, ratchetInfo.BundleID, "It returns the bundle id")
   317  	s.Equal(installationID, ratchetInfo.InstallationID, "It saves the right installation ID")
   318  }
   319  
   320  func (s *SQLLitePersistenceTestSuite) TestRatchetInfoNoBundle() {
   321  	err := s.service.AddRatchetInfo(
   322  		[]byte("symmetric-key"),
   323  		[]byte("their-public-key"),
   324  		[]byte("non-existing-bundle"),
   325  		[]byte("non-existing-ephemeral-key"),
   326  		"none",
   327  	)
   328  
   329  	s.Error(err, "It returns an error")
   330  
   331  	_, err = s.service.GetRatchetInfo([]byte("non-existing-bundle"), []byte("their-public-key"), "none")
   332  	s.Require().NoError(err)
   333  
   334  	ratchetInfo, err := s.service.GetAnyRatchetInfo([]byte("their-public-key"), "4")
   335  	s.Require().NoError(err)
   336  	s.Nil(ratchetInfo, "It returns nil when no bundle is there")
   337  }
   338  
   339  // TODO: Add test for MarkBundleExpired
   340  
   341  func (s *SQLLitePersistenceTestSuite) TestGetHashRatchetKeyByID() {
   342  	key := &HashRatchetKeyCompatibility{
   343  		GroupID:   []byte{1, 2, 3},
   344  		keyID:     []byte{4, 5, 6},
   345  		Timestamp: 1,
   346  		Key:       []byte{7, 8, 9},
   347  	}
   348  	err := s.service.SaveHashRatchetKey(key)
   349  	s.Require().NoError(err)
   350  
   351  	retrievedKey, err := s.service.GetHashRatchetKeyByID(key.keyID)
   352  	s.Require().NoError(err)
   353  	s.Require().True(reflect.DeepEqual(key.GroupID, retrievedKey.GroupID))
   354  	s.Require().True(reflect.DeepEqual(key.keyID, retrievedKey.keyID))
   355  	s.Require().True(reflect.DeepEqual(key.Key, retrievedKey.Key))
   356  	s.Require().Equal(key.Timestamp, retrievedKey.Timestamp)
   357  
   358  	cachedKey, err := s.service.GetHashRatchetCache(retrievedKey, 0)
   359  	s.Require().NoError(err)
   360  	s.Require().True(reflect.DeepEqual(key.keyID, cachedKey.KeyID))
   361  	s.Require().True(reflect.DeepEqual(key.Key, cachedKey.Key))
   362  	s.Require().EqualValues(0, cachedKey.SeqNo)
   363  
   364  	var newSeqNo uint32 = 1
   365  	newHash := []byte{10, 11, 12}
   366  	err = s.service.SaveHashRatchetKeyHash(key, newHash, newSeqNo)
   367  	s.Require().NoError(err)
   368  
   369  	cachedKey, err = s.service.GetHashRatchetCache(retrievedKey, 0)
   370  	s.Require().NoError(err)
   371  	s.Require().True(reflect.DeepEqual(key.keyID, cachedKey.KeyID))
   372  	s.Require().True(reflect.DeepEqual(key.Key, cachedKey.Key))
   373  	s.Require().EqualValues(1, cachedKey.SeqNo)
   374  
   375  	newSeqNo = 4
   376  	newHash = []byte{10, 11, 13}
   377  	err = s.service.SaveHashRatchetKeyHash(key, newHash, newSeqNo)
   378  	s.Require().NoError(err)
   379  
   380  	cachedKey, err = s.service.GetHashRatchetCache(retrievedKey, 0)
   381  	s.Require().NoError(err)
   382  	s.Require().True(reflect.DeepEqual(key.keyID, cachedKey.KeyID))
   383  	s.Require().True(reflect.DeepEqual(key.Key, cachedKey.Key))
   384  	s.Require().EqualValues(4, cachedKey.SeqNo)
   385  
   386  	cachedKey, err = s.service.GetHashRatchetCache(retrievedKey, 1)
   387  	s.Require().NoError(err)
   388  	s.Require().True(reflect.DeepEqual(key.keyID, cachedKey.KeyID))
   389  	s.Require().True(reflect.DeepEqual(key.Key, cachedKey.Key))
   390  	s.Require().EqualValues(1, cachedKey.SeqNo)
   391  }