2019-11-21 16:19:22 +00:00
package encryption
import (
2023-11-29 17:21:21 +00:00
"reflect"
2019-11-21 16:19:22 +00:00
"testing"
"github.com/stretchr/testify/suite"
2023-10-02 09:28:42 +00:00
"github.com/status-im/status-go/appdatabase"
2020-01-02 09:10:19 +00:00
"github.com/status-im/status-go/eth-node/crypto"
2023-10-02 09:28:42 +00:00
"github.com/status-im/status-go/t/helpers"
2020-01-02 09:10:19 +00:00
2019-11-21 16:19:22 +00:00
"github.com/status-im/status-go/protocol/encryption/multidevice"
"github.com/status-im/status-go/protocol/sqlite"
)
func TestSQLLitePersistenceTestSuite ( t * testing . T ) {
suite . Run ( t , new ( SQLLitePersistenceTestSuite ) )
}
type SQLLitePersistenceTestSuite struct {
suite . Suite
service * sqlitePersistence
}
func ( s * SQLLitePersistenceTestSuite ) SetupTest ( ) {
2023-10-02 09:28:42 +00:00
db , err := helpers . SetupTestMemorySQLDB ( appdatabase . DbInitializer { } )
s . Require ( ) . NoError ( err )
err = sqlite . Migrate ( db )
2019-11-21 16:19:22 +00:00
s . Require ( ) . NoError ( err )
s . service = newSQLitePersistence ( db )
}
func ( s * SQLLitePersistenceTestSuite ) TestPrivateBundle ( ) {
installationID := "1"
key , err := crypto . GenerateKey ( )
s . Require ( ) . NoError ( err )
actualKey , err := s . service . GetPrivateKeyBundle ( [ ] byte ( "non-existing" ) )
s . Require ( ) . NoError ( err , "Error was not returned even though bundle is not there" )
s . Nil ( actualKey )
anyPrivateBundle , err := s . service . GetAnyPrivateBundle ( [ ] byte ( "non-existing-id" ) , [ ] * multidevice . Installation { { ID : installationID , Version : 1 } } )
s . Require ( ) . NoError ( err )
s . Nil ( anyPrivateBundle )
bundle , err := NewBundleContainer ( key , installationID )
s . Require ( ) . NoError ( err )
err = s . service . AddPrivateBundle ( bundle )
s . Require ( ) . NoError ( err )
bundleID := bundle . GetBundle ( ) . GetSignedPreKeys ( ) [ installationID ] . GetSignedPreKey ( )
actualKey , err = s . service . GetPrivateKeyBundle ( bundleID )
s . Require ( ) . NoError ( err )
s . Equal ( bundle . GetPrivateSignedPreKey ( ) , actualKey , "It returns the same key" )
identity := crypto . CompressPubkey ( & key . PublicKey )
anyPrivateBundle , err = s . service . GetAnyPrivateBundle ( identity , [ ] * multidevice . Installation { { ID : installationID , Version : 1 } } )
s . Require ( ) . NoError ( err )
s . NotNil ( anyPrivateBundle )
s . Equal ( bundle . GetBundle ( ) . GetSignedPreKeys ( ) [ installationID ] . SignedPreKey , anyPrivateBundle . GetBundle ( ) . GetSignedPreKeys ( ) [ installationID ] . SignedPreKey , "It returns the same bundle" )
}
func ( s * SQLLitePersistenceTestSuite ) TestPublicBundle ( ) {
key , err := crypto . GenerateKey ( )
s . Require ( ) . NoError ( err )
actualBundle , err := s . service . GetPublicBundle ( & key . PublicKey , [ ] * multidevice . Installation { { ID : "1" , Version : 1 } } )
s . Require ( ) . NoError ( err , "Error was not returned even though bundle is not there" )
s . Nil ( actualBundle )
bundleContainer , err := NewBundleContainer ( key , "1" )
s . Require ( ) . NoError ( err )
bundle := bundleContainer . GetBundle ( )
err = s . service . AddPublicBundle ( bundle )
s . Require ( ) . NoError ( err )
actualBundle , err = s . service . GetPublicBundle ( & key . PublicKey , [ ] * multidevice . Installation { { ID : "1" , Version : 1 } } )
s . Require ( ) . NoError ( err )
s . Equal ( bundle . GetIdentity ( ) , actualBundle . GetIdentity ( ) , "It sets the right identity" )
s . Equal ( bundle . GetSignedPreKeys ( ) , actualBundle . GetSignedPreKeys ( ) , "It sets the right prekeys" )
}
func ( s * SQLLitePersistenceTestSuite ) TestUpdatedBundle ( ) {
key , err := crypto . GenerateKey ( )
s . Require ( ) . NoError ( err )
actualBundle , err := s . service . GetPublicBundle ( & key . PublicKey , [ ] * multidevice . Installation { { ID : "1" , Version : 1 } } )
s . Require ( ) . NoError ( err , "Error was not returned even though bundle is not there" )
s . Nil ( actualBundle )
// Create & add initial bundle
bundleContainer , err := NewBundleContainer ( key , "1" )
s . Require ( ) . NoError ( err )
bundle := bundleContainer . GetBundle ( )
err = s . service . AddPublicBundle ( bundle )
s . Require ( ) . NoError ( err )
// Create & add a new bundle
bundleContainer , err = NewBundleContainer ( key , "1" )
s . Require ( ) . NoError ( err )
bundle = bundleContainer . GetBundle ( )
// We set the version
bundle . GetSignedPreKeys ( ) [ "1" ] . Version = 1
err = s . service . AddPublicBundle ( bundle )
s . Require ( ) . NoError ( err )
actualBundle , err = s . service . GetPublicBundle ( & key . PublicKey , [ ] * multidevice . Installation { { ID : "1" , Version : 1 } } )
s . Require ( ) . NoError ( err )
s . Equal ( bundle . GetIdentity ( ) , actualBundle . GetIdentity ( ) , "It sets the right identity" )
s . Equal ( bundle . GetSignedPreKeys ( ) , actualBundle . GetSignedPreKeys ( ) , "It sets the right prekeys" )
}
func ( s * SQLLitePersistenceTestSuite ) TestOutOfOrderBundles ( ) {
key , err := crypto . GenerateKey ( )
s . Require ( ) . NoError ( err )
actualBundle , err := s . service . GetPublicBundle ( & key . PublicKey , [ ] * multidevice . Installation { { ID : "1" , Version : 1 } } )
s . Require ( ) . NoError ( err , "Error was not returned even though bundle is not there" )
s . Nil ( actualBundle )
// Create & add initial bundle
bundleContainer , err := NewBundleContainer ( key , "1" )
s . Require ( ) . NoError ( err )
bundle1 := bundleContainer . GetBundle ( )
err = s . service . AddPublicBundle ( bundle1 )
s . Require ( ) . NoError ( err )
// Create & add a new bundle
bundleContainer , err = NewBundleContainer ( key , "1" )
s . Require ( ) . NoError ( err )
bundle2 := bundleContainer . GetBundle ( )
// We set the version
bundle2 . GetSignedPreKeys ( ) [ "1" ] . Version = 1
err = s . service . AddPublicBundle ( bundle2 )
s . Require ( ) . NoError ( err )
// Add again the initial bundle
err = s . service . AddPublicBundle ( bundle1 )
s . Require ( ) . NoError ( err )
actualBundle , err = s . service . GetPublicBundle ( & key . PublicKey , [ ] * multidevice . Installation { { ID : "1" , Version : 1 } } )
s . Require ( ) . NoError ( err )
s . Equal ( bundle2 . GetIdentity ( ) , actualBundle . GetIdentity ( ) , "It sets the right identity" )
s . Equal ( bundle2 . GetSignedPreKeys ( ) [ "1" ] . GetVersion ( ) , uint32 ( 1 ) )
s . Equal ( bundle2 . GetSignedPreKeys ( ) [ "1" ] . GetSignedPreKey ( ) , actualBundle . GetSignedPreKeys ( ) [ "1" ] . GetSignedPreKey ( ) , "It sets the right prekeys" )
}
func ( s * SQLLitePersistenceTestSuite ) TestMultiplePublicBundle ( ) {
key , err := crypto . GenerateKey ( )
s . Require ( ) . NoError ( err )
actualBundle , err := s . service . GetPublicBundle ( & key . PublicKey , [ ] * multidevice . Installation { { ID : "1" , Version : 1 } } )
s . Require ( ) . NoError ( err , "Error was not returned even though bundle is not there" )
s . Nil ( actualBundle )
bundleContainer , err := NewBundleContainer ( key , "1" )
s . Require ( ) . NoError ( err )
bundle := bundleContainer . GetBundle ( )
err = s . service . AddPublicBundle ( bundle )
s . Require ( ) . NoError ( err )
// Adding it again does not throw an error
err = s . service . AddPublicBundle ( bundle )
s . Require ( ) . NoError ( err )
// Adding a different bundle
bundleContainer , err = NewBundleContainer ( key , "1" )
s . Require ( ) . NoError ( err )
// We set the version
bundle = bundleContainer . GetBundle ( )
bundle . GetSignedPreKeys ( ) [ "1" ] . Version = 1
err = s . service . AddPublicBundle ( bundle )
s . Require ( ) . NoError ( err )
// Returns the most recent bundle
actualBundle , err = s . service . GetPublicBundle ( & key . PublicKey , [ ] * multidevice . Installation { { ID : "1" , Version : 1 } } )
s . Require ( ) . NoError ( err )
s . Equal ( bundle . GetIdentity ( ) , actualBundle . GetIdentity ( ) , "It sets the identity" )
s . Equal ( bundle . GetSignedPreKeys ( ) , actualBundle . GetSignedPreKeys ( ) , "It sets the signed pre keys" )
}
func ( s * SQLLitePersistenceTestSuite ) TestMultiDevicePublicBundle ( ) {
key , err := crypto . GenerateKey ( )
s . Require ( ) . NoError ( err )
actualBundle , err := s . service . GetPublicBundle ( & key . PublicKey , [ ] * multidevice . Installation { { ID : "1" , Version : 1 } } )
s . Require ( ) . NoError ( err , "Error was not returned even though bundle is not there" )
s . Nil ( actualBundle )
bundleContainer , err := NewBundleContainer ( key , "1" )
s . Require ( ) . NoError ( err )
bundle := bundleContainer . GetBundle ( )
err = s . service . AddPublicBundle ( bundle )
s . Require ( ) . NoError ( err )
// Adding it again does not throw an error
err = s . service . AddPublicBundle ( bundle )
s . Require ( ) . NoError ( err )
// Adding a different bundle from a different instlation id
bundleContainer , err = NewBundleContainer ( key , "2" )
s . Require ( ) . NoError ( err )
bundle = bundleContainer . GetBundle ( )
err = s . service . AddPublicBundle ( bundle )
s . Require ( ) . NoError ( err )
// Returns the most recent bundle
actualBundle , err = s . service . GetPublicBundle ( & key . PublicKey ,
[ ] * multidevice . Installation {
{ ID : "1" , Version : 1 } ,
{ ID : "2" , Version : 1 } ,
} )
s . Require ( ) . NoError ( err )
s . Equal ( bundle . GetIdentity ( ) , actualBundle . GetIdentity ( ) , "It sets the identity" )
s . NotNil ( actualBundle . GetSignedPreKeys ( ) [ "1" ] )
s . NotNil ( actualBundle . GetSignedPreKeys ( ) [ "2" ] )
}
func ( s * SQLLitePersistenceTestSuite ) TestRatchetInfoPrivateBundle ( ) {
key , err := crypto . GenerateKey ( )
s . Require ( ) . NoError ( err )
// Add a private bundle
bundle , err := NewBundleContainer ( key , "2" )
s . Require ( ) . NoError ( err )
err = s . service . AddPrivateBundle ( bundle )
s . Require ( ) . NoError ( err )
err = s . service . AddRatchetInfo (
[ ] byte ( "symmetric-key" ) ,
[ ] byte ( "their-public-key" ) ,
bundle . GetBundle ( ) . GetSignedPreKeys ( ) [ "2" ] . GetSignedPreKey ( ) ,
[ ] byte ( "ephemeral-public-key" ) ,
"1" ,
)
s . Require ( ) . NoError ( err )
ratchetInfo , err := s . service . GetRatchetInfo ( bundle . GetBundle ( ) . GetSignedPreKeys ( ) [ "2" ] . GetSignedPreKey ( ) , [ ] byte ( "their-public-key" ) , "1" )
s . Require ( ) . NoError ( err )
s . Require ( ) . NotNil ( ratchetInfo )
s . NotNil ( ratchetInfo . ID , "It adds an id" )
s . Equal ( ratchetInfo . PrivateKey , bundle . GetPrivateSignedPreKey ( ) , "It returns the private key" )
s . Equal ( ratchetInfo . Sk , [ ] byte ( "symmetric-key" ) , "It returns the symmetric key" )
s . Equal ( ratchetInfo . Identity , [ ] byte ( "their-public-key" ) , "It returns the identity of the contact" )
s . Equal ( ratchetInfo . PublicKey , bundle . GetBundle ( ) . GetSignedPreKeys ( ) [ "2" ] . GetSignedPreKey ( ) , "It returns the public key of the bundle" )
s . Equal ( bundle . GetBundle ( ) . GetSignedPreKeys ( ) [ "2" ] . GetSignedPreKey ( ) , ratchetInfo . BundleID , "It returns the bundle id" )
s . Equal ( [ ] byte ( "ephemeral-public-key" ) , ratchetInfo . EphemeralKey , "It returns the ratchet ephemeral key" )
s . Equal ( "1" , ratchetInfo . InstallationID , "It returns the right installation id" )
}
func ( s * SQLLitePersistenceTestSuite ) TestRatchetInfoPublicBundle ( ) {
installationID := "1"
theirPublicKey := [ ] byte ( "their-public-key" )
key , err := crypto . GenerateKey ( )
s . Require ( ) . NoError ( err )
// Add a private bundle
bundle , err := NewBundleContainer ( key , installationID )
s . Require ( ) . NoError ( err )
err = s . service . AddPublicBundle ( bundle . GetBundle ( ) )
s . Require ( ) . NoError ( err )
signedPreKey := bundle . GetBundle ( ) . GetSignedPreKeys ( ) [ installationID ] . GetSignedPreKey ( )
err = s . service . AddRatchetInfo (
[ ] byte ( "symmetric-key" ) ,
theirPublicKey ,
signedPreKey ,
[ ] byte ( "public-ephemeral-key" ) ,
installationID ,
)
s . Require ( ) . NoError ( err )
ratchetInfo , err := s . service . GetRatchetInfo ( signedPreKey , theirPublicKey , installationID )
s . Require ( ) . NoError ( err )
s . Require ( ) . NotNil ( ratchetInfo , "It returns the ratchet info" )
s . NotNil ( ratchetInfo . ID , "It adds an id" )
s . Nil ( ratchetInfo . PrivateKey , "It does not return the private key" )
s . Equal ( ratchetInfo . Sk , [ ] byte ( "symmetric-key" ) , "It returns the symmetric key" )
s . Equal ( ratchetInfo . Identity , theirPublicKey , "It returns the identity of the contact" )
s . Equal ( ratchetInfo . PublicKey , signedPreKey , "It returns the public key of the bundle" )
s . Equal ( installationID , ratchetInfo . InstallationID , "It returns the right installationID" )
s . Nilf ( ratchetInfo . PrivateKey , "It does not return the private key" )
ratchetInfo , err = s . service . GetAnyRatchetInfo ( theirPublicKey , installationID )
s . Require ( ) . NoError ( err )
s . Require ( ) . NotNil ( ratchetInfo , "It returns the ratchet info" )
s . NotNil ( ratchetInfo . ID , "It adds an id" )
s . Nil ( ratchetInfo . PrivateKey , "It does not return the private key" )
s . Equal ( ratchetInfo . Sk , [ ] byte ( "symmetric-key" ) , "It returns the symmetric key" )
s . Equal ( ratchetInfo . Identity , theirPublicKey , "It returns the identity of the contact" )
s . Equal ( ratchetInfo . PublicKey , signedPreKey , "It returns the public key of the bundle" )
s . Equal ( signedPreKey , ratchetInfo . BundleID , "It returns the bundle id" )
s . Equal ( installationID , ratchetInfo . InstallationID , "It saves the right installation ID" )
}
func ( s * SQLLitePersistenceTestSuite ) TestRatchetInfoNoBundle ( ) {
err := s . service . AddRatchetInfo (
[ ] byte ( "symmetric-key" ) ,
[ ] byte ( "their-public-key" ) ,
[ ] byte ( "non-existing-bundle" ) ,
[ ] byte ( "non-existing-ephemeral-key" ) ,
"none" ,
)
s . Error ( err , "It returns an error" )
_ , err = s . service . GetRatchetInfo ( [ ] byte ( "non-existing-bundle" ) , [ ] byte ( "their-public-key" ) , "none" )
s . Require ( ) . NoError ( err )
ratchetInfo , err := s . service . GetAnyRatchetInfo ( [ ] byte ( "their-public-key" ) , "4" )
s . Require ( ) . NoError ( err )
s . Nil ( ratchetInfo , "It returns nil when no bundle is there" )
}
// TODO: Add test for MarkBundleExpired
2023-11-29 17:21:21 +00:00
func ( s * SQLLitePersistenceTestSuite ) TestGetHashRatchetKeyByID ( ) {
key := & HashRatchetKeyCompatibility {
GroupID : [ ] byte { 1 , 2 , 3 } ,
keyID : [ ] byte { 4 , 5 , 6 } ,
Timestamp : 1 ,
Key : [ ] byte { 7 , 8 , 9 } ,
}
err := s . service . SaveHashRatchetKey ( key )
s . Require ( ) . NoError ( err )
retrievedKey , err := s . service . GetHashRatchetKeyByID ( key . keyID )
s . Require ( ) . NoError ( err )
s . Require ( ) . True ( reflect . DeepEqual ( key . GroupID , retrievedKey . GroupID ) )
s . Require ( ) . True ( reflect . DeepEqual ( key . keyID , retrievedKey . keyID ) )
s . Require ( ) . True ( reflect . DeepEqual ( key . Key , retrievedKey . Key ) )
s . Require ( ) . Equal ( key . Timestamp , retrievedKey . Timestamp )
cachedKey , err := s . service . GetHashRatchetCache ( retrievedKey , 0 )
s . Require ( ) . NoError ( err )
s . Require ( ) . True ( reflect . DeepEqual ( key . keyID , cachedKey . KeyID ) )
s . Require ( ) . True ( reflect . DeepEqual ( key . Key , cachedKey . Key ) )
s . Require ( ) . EqualValues ( 0 , cachedKey . SeqNo )
2024-02-29 09:51:38 +00:00
var newSeqNo uint32 = 1
newHash := [ ] byte { 10 , 11 , 12 }
err = s . service . SaveHashRatchetKeyHash ( key , newHash , newSeqNo )
s . Require ( ) . NoError ( err )
cachedKey , err = s . service . GetHashRatchetCache ( retrievedKey , 0 )
s . Require ( ) . NoError ( err )
s . Require ( ) . True ( reflect . DeepEqual ( key . keyID , cachedKey . KeyID ) )
s . Require ( ) . True ( reflect . DeepEqual ( key . Key , cachedKey . Key ) )
s . Require ( ) . EqualValues ( 1 , cachedKey . SeqNo )
newSeqNo = 4
newHash = [ ] byte { 10 , 11 , 13 }
err = s . service . SaveHashRatchetKeyHash ( key , newHash , newSeqNo )
s . Require ( ) . NoError ( err )
cachedKey , err = s . service . GetHashRatchetCache ( retrievedKey , 0 )
s . Require ( ) . NoError ( err )
s . Require ( ) . True ( reflect . DeepEqual ( key . keyID , cachedKey . KeyID ) )
s . Require ( ) . True ( reflect . DeepEqual ( key . Key , cachedKey . Key ) )
s . Require ( ) . EqualValues ( 4 , cachedKey . SeqNo )
cachedKey , err = s . service . GetHashRatchetCache ( retrievedKey , 1 )
s . Require ( ) . NoError ( err )
s . Require ( ) . True ( reflect . DeepEqual ( key . keyID , cachedKey . KeyID ) )
s . Require ( ) . True ( reflect . DeepEqual ( key . Key , cachedKey . Key ) )
s . Require ( ) . EqualValues ( 1 , cachedKey . SeqNo )
2023-11-29 17:21:21 +00:00
}