From ce5286994560c08e45001246e649a0c0300cfe55 Mon Sep 17 00:00:00 2001 From: Alexandr Stelnykovych Date: Thu, 28 Aug 2025 17:25:16 +0300 Subject: [PATCH 1/4] fix: Some configuration data is not stored in the core database when using SQLite. https://github.com/safing/portmaster/issues/1989 --- base/database/storage/sqlite/prepared.go | 22 +++++++++++++++++++--- base/database/storage/sqlite/sqlite.go | 21 ++++++++++++++++++--- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/base/database/storage/sqlite/prepared.go b/base/database/storage/sqlite/prepared.go index 11136dd8..47052413 100644 --- a/base/database/storage/sqlite/prepared.go +++ b/base/database/storage/sqlite/prepared.go @@ -2,6 +2,7 @@ package sqlite import ( "context" + "errors" "strconv" "github.com/stephenafamo/bob" @@ -83,8 +84,23 @@ func writeWithPreparedStatement(ctx context.Context, pStmt *bob.StdPrepared, r r r.Lock() defer r.Unlock() - // Serialize to JSON. - data, err := r.MarshalDataOnly(r, dsd.JSON) + // default serialization format - JSON + format := uint8(dsd.JSON) + + // For wrapped records, check the required format + if r.IsWrapped() { + wrapper, ok := r.(*record.Wrapper) + if !ok { + return errors.New("record is malformed (reports to be wrapped but is not of type *record.Wrapper)") + } + format, ok = dsd.ValidateSerializationFormat(wrapper.Format) + if !ok { + return dsd.ErrIncompatibleFormat + } + } + + // Serialize. + data, err := r.MarshalDataOnly(r, format) if err != nil { return err } @@ -94,7 +110,7 @@ func writeWithPreparedStatement(ctx context.Context, pStmt *bob.StdPrepared, r r // Insert. if len(data) > 0 { - format := strconv.Itoa(dsd.JSON) + format := strconv.Itoa(int(format)) _, err = pStmt.ExecContext( ctx, r.DatabaseKey(), diff --git a/base/database/storage/sqlite/sqlite.go b/base/database/storage/sqlite/sqlite.go index fe5427ff..3e3f1e5c 100644 --- a/base/database/storage/sqlite/sqlite.go +++ b/base/database/storage/sqlite/sqlite.go @@ -161,13 +161,28 @@ func (db *SQLite) putRecord(r record.Record, tx *bob.Tx) (record.Record, error) defer r.Unlock() } - // Serialize to JSON. - data, err := r.MarshalDataOnly(r, dsd.JSON) + // default serialization format - JSON + format := uint8(dsd.JSON) + + // For wrapped records, check the required format + if r.IsWrapped() { + wrapper, ok := r.(*record.Wrapper) + if !ok { + return nil, errors.New("record is malformed (reports to be wrapped but is not of type *record.Wrapper)") + } + format, ok = dsd.ValidateSerializationFormat(wrapper.Format) + if !ok { + return nil, dsd.ErrIncompatibleFormat + } + } + + // Serialize. + data, err := r.MarshalDataOnly(r, format) if err != nil { return nil, err } // Prepare for setter. - setFormat := omitnull.From(int16(dsd.JSON)) + setFormat := omitnull.From(int16(format)) setData := omitnull.From(data) if len(data) == 0 { setFormat.Null() From c14eb43605fb0493563c3e50af22008023a39842 Mon Sep 17 00:00:00 2001 From: Alexandr Stelnykovych Date: Wed, 3 Sep 2025 12:44:43 +0300 Subject: [PATCH 2/4] fix: Improve error handling for malformed records in SQLite storage --- base/database/storage/errors.go | 3 ++- base/database/storage/sqlite/prepared.go | 12 ++++++------ base/database/storage/sqlite/sqlite.go | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/base/database/storage/errors.go b/base/database/storage/errors.go index ecc28530..f8534046 100644 --- a/base/database/storage/errors.go +++ b/base/database/storage/errors.go @@ -4,5 +4,6 @@ import "errors" // Errors for storages. var ( - ErrNotFound = errors.New("storage entry not found") + ErrNotFound = errors.New("storage entry not found") + ErrRecordMalformed = errors.New("record is malformed") ) diff --git a/base/database/storage/sqlite/prepared.go b/base/database/storage/sqlite/prepared.go index 47052413..b109a64b 100644 --- a/base/database/storage/sqlite/prepared.go +++ b/base/database/storage/sqlite/prepared.go @@ -2,16 +2,16 @@ package sqlite import ( "context" - "errors" + "fmt" "strconv" + "github.com/safing/portmaster/base/database/record" + "github.com/safing/portmaster/base/database/storage" + "github.com/safing/portmaster/base/database/storage/sqlite/models" + "github.com/safing/structures/dsd" "github.com/stephenafamo/bob" "github.com/stephenafamo/bob/dialect/sqlite/im" "github.com/stephenafamo/bob/expr" - - "github.com/safing/portmaster/base/database/record" - "github.com/safing/portmaster/base/database/storage/sqlite/models" - "github.com/safing/structures/dsd" ) var UsePreparedStatements bool = true @@ -91,7 +91,7 @@ func writeWithPreparedStatement(ctx context.Context, pStmt *bob.StdPrepared, r r if r.IsWrapped() { wrapper, ok := r.(*record.Wrapper) if !ok { - return errors.New("record is malformed (reports to be wrapped but is not of type *record.Wrapper)") + return fmt.Errorf("%w: reports to be wrapped but is not of type *record.Wrapper", storage.ErrRecordMalformed) } format, ok = dsd.ValidateSerializationFormat(wrapper.Format) if !ok { diff --git a/base/database/storage/sqlite/sqlite.go b/base/database/storage/sqlite/sqlite.go index 3e3f1e5c..2a54cfa8 100644 --- a/base/database/storage/sqlite/sqlite.go +++ b/base/database/storage/sqlite/sqlite.go @@ -168,7 +168,7 @@ func (db *SQLite) putRecord(r record.Record, tx *bob.Tx) (record.Record, error) if r.IsWrapped() { wrapper, ok := r.(*record.Wrapper) if !ok { - return nil, errors.New("record is malformed (reports to be wrapped but is not of type *record.Wrapper)") + return nil, fmt.Errorf("%w: reports to be wrapped but is not of type *record.Wrapper", storage.ErrRecordMalformed) } format, ok = dsd.ValidateSerializationFormat(wrapper.Format) if !ok { From b41cded4ccfb375fad6086eca25a8b91e3d96c02 Mon Sep 17 00:00:00 2001 From: Alexandr Stelnykovych Date: Wed, 3 Sep 2025 13:07:12 +0300 Subject: [PATCH 3/4] Reorder import statements for better organization and linter compliance --- base/database/storage/sqlite/prepared.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/base/database/storage/sqlite/prepared.go b/base/database/storage/sqlite/prepared.go index b109a64b..5571036d 100644 --- a/base/database/storage/sqlite/prepared.go +++ b/base/database/storage/sqlite/prepared.go @@ -5,13 +5,14 @@ import ( "fmt" "strconv" - "github.com/safing/portmaster/base/database/record" - "github.com/safing/portmaster/base/database/storage" - "github.com/safing/portmaster/base/database/storage/sqlite/models" "github.com/safing/structures/dsd" "github.com/stephenafamo/bob" "github.com/stephenafamo/bob/dialect/sqlite/im" "github.com/stephenafamo/bob/expr" + + "github.com/safing/portmaster/base/database/record" + "github.com/safing/portmaster/base/database/storage" + "github.com/safing/portmaster/base/database/storage/sqlite/models" ) var UsePreparedStatements bool = true From 015cb5a96923100f843171cbe67e1258b8b25df1 Mon Sep 17 00:00:00 2001 From: Alexandr Stelnykovych Date: Wed, 3 Sep 2025 13:16:32 +0300 Subject: [PATCH 4/4] Reorder import statements for better organization and linter compliance --- base/database/storage/sqlite/prepared.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/database/storage/sqlite/prepared.go b/base/database/storage/sqlite/prepared.go index 5571036d..797b53a4 100644 --- a/base/database/storage/sqlite/prepared.go +++ b/base/database/storage/sqlite/prepared.go @@ -5,7 +5,6 @@ import ( "fmt" "strconv" - "github.com/safing/structures/dsd" "github.com/stephenafamo/bob" "github.com/stephenafamo/bob/dialect/sqlite/im" "github.com/stephenafamo/bob/expr" @@ -13,6 +12,7 @@ import ( "github.com/safing/portmaster/base/database/record" "github.com/safing/portmaster/base/database/storage" "github.com/safing/portmaster/base/database/storage/sqlite/models" + "github.com/safing/structures/dsd" ) var UsePreparedStatements bool = true