-
Notifications
You must be signed in to change notification settings - Fork 262
refactor: introduce encryption persistence interface #6998
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
Jenkins BuildsClick to see older builds (34)
|
0ee8ad6
to
459e2ec
Compare
- modularize messaging Persistence with wakuPersistence, encryptionPersistence, etc. - separate migration table for encryption migrations - inject encryption sqlite persistence through the interface iterates: #6792
459e2ec
to
78d6e84
Compare
@igor-sirotin @dlipicar it is now ready for review 🙏 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't look the whole code yet, this is the first part of comments
if _, err := db.Exec(createIndex); err != nil { | ||
return err | ||
} | ||
insertVersion := fmt.Sprintf(`INSERT INTO %s (version, dirty) VALUES (?, ?)`, name) // nolint:gosec |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about this to avoid // nolint
?
insertVersion := fmt.Sprintf(`INSERT INTO %s (version, dirty) VALUES (?, ?)`, name) // nolint:gosec | |
insertVersion := fmt.Sprintf(`INSERT INTO %s (version, dirty)`, name) + "VALUES (?, ?)" |
type Persistence interface { | ||
wakuPersistence | ||
WakuStorage() WakuPersistence | ||
SegmentationStorage() SegmentationPersistence | ||
EncryptionStorage() EncryptionPersistence |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it not be simpler to compose instead?
type Persistence interface { | |
wakuPersistence | |
WakuStorage() WakuPersistence | |
SegmentationStorage() SegmentationPersistence | |
EncryptionStorage() EncryptionPersistence | |
type Persistence interface { | |
WakuPersistence | |
SegmentationPersistence | |
EncryptionPersistence |
In case of status-go
it is going to be a single implementation, right?
And in case they're separate, one could still compose all implementations into one
migrations.AssetNames(), | ||
func(name string) ([]byte, error) { | ||
return migrations.Asset(name) | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
migrations.AssetNames(), | |
func(name string) ([]byte, error) { | |
return migrations.Asset(name) | |
}, | |
migrations.AssetNames(), | |
migrations.Asset, |
) | ||
|
||
const ( | ||
uuid = "7676fd0c" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this magic string coming from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it's just a random value, but please add some comment clarifying it
if version > 0 { | ||
err := createMigrationTables(database, version) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic with version
seem to be quite convoluted here and in LatestMigrationUpToVersion
🤔
But I see GetLastMigrationVersion
returns migrationTableExists
here, which we ignore:
status-go/protocol/sqlite/db.go
Line 19 in 78d6e84
version, _, err := sqlite.GetLastMigrationVersion(database, migrationsTable) |
Maybe just check it and create the tables if they don't exist?
func EncryptionPersistence(p types.Persistence) encryption.Persistence { | ||
encryptionStorage := p.EncryptionStorage() | ||
if encryptionStorage == nil { | ||
return nil | ||
} | ||
internal, ok := encryptionStorage.(*internal.SQLiteEncryptionPersistence) | ||
if !ok { | ||
panic("custom EncryptionPersistence implementations are not supported yet") | ||
} | ||
return internal.SQLitePersistence | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part confuses me.
Sorry I had to write it down to consume, you probably know all of this 😄
Part 1. Interfaces
-
In
newCore
we get apersistence
pointer from the user as part ofparams
:
Line 79 in 78d6e84
func newCore(waku wakutypes.Waku, params CoreParams, config *config) (*Core, error) { Line 70 in 78d6e84
Persistence types.Persistence -
types.Persistence
is expected to provideEncryptionPersistence
:
status-go/messaging/types/persistence.go
Line 10 in 78d6e84
EncryptionStorage() EncryptionPersistence -
Yet the
encryption
package expects it's own internalPersistence
interface:
status-go/messaging/layers/encryption/persistence.go
Lines 33 to 37 in 78d6e84
type Persistence interface { KeysStorage() dr.KeysStorage SessionStorage() dr.SessionStorage SharedSecretStorage() sharedsecret.Persistence MultideviceStorage() multidevice.Persistence -
That's why we use this
EncryptionPersistence
adapter here
Lines 92 to 93 in 78d6e84
encryptor := encryption.New( adapters.EncryptionPersistence(params.Persistence),
Part 2. Adapter.
-
The adapter works, because
status-go
uses the default sqlite encryption persistence:
status-go/protocol/messaging_persistence.go
Lines 253 to 255 in 78d6e84
func (m *messagingPersistence) EncryptionStorage() messagingtypes.EncryptionPersistence { return messaging.NewEncryptionSQLitePersistence(m.db) } ... which, by the way is marked as "internal implementation" 🤔
status-go/messaging/sqlite_persistence.go
Lines 58 to 64 in 78d6e84
// Returns internal implementation of EncryptionPersistence. // Clients should not use this interface directly. func NewEncryptionSQLitePersistence(db *sql.DB) types.EncryptionPersistence { return &internal.SQLiteEncryptionPersistence{ SQLitePersistence: encryption.NewSQLitePersistence(db), } } -
The implementation of
SQLiteEncryptionPersistence
is simply empty:
status-go/messaging/internal/sqlite_encryption_persistence.go
Lines 7 to 37 in 78d6e84
// Implements the EncryptionPersistence interface using SQLite. type SQLiteEncryptionPersistence struct { *encryption.SQLitePersistence } var _ types.EncryptionPersistence = (*SQLiteEncryptionPersistence)(nil) func (e *SQLiteEncryptionPersistence) X3DHBundlesStorage() types.X3DHBundlesPersistence { return nil } func (e *SQLiteEncryptionPersistence) DRKeysStorage() types.DRKeysPersistence { return nil } func (e *SQLiteEncryptionPersistence) DRSessionStorage() types.DRSessionPersistence { return nil } func (e *SQLiteEncryptionPersistence) SharedSecretStorage() types.SharedSecretPersistence { return nil } func (e *SQLiteEncryptionPersistence) MultideviceStorage() types.MultidevicePersistence { return nil } func (e *SQLiteEncryptionPersistence) HashRatchetStorage() types.HashRatchetPersistence { return nil } ... yet it composes
encryption.SQLitePersistence
.
And this is what the adapter relies on.
Part 3. Question
messagingtypes.EncryptionPersistence
seem to be completely unused 🤔
Do we really need it? And the other persistence adapters?
Maybe we could just re-export the internal interfaces from messaging
module?
encryptionPersistence, etc.
iterates: #6792