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 }