diff --git a/scnserver/.idea/sqldialects.xml b/scnserver/.idea/sqldialects.xml index 4a1c2d7..cb98251 100644 --- a/scnserver/.idea/sqldialects.xml +++ b/scnserver/.idea/sqldialects.xml @@ -1,7 +1,7 @@ - + diff --git a/scnserver/cmd/dbhash/main.go b/scnserver/cmd/dbhash/main.go new file mode 100644 index 0000000..b460bca --- /dev/null +++ b/scnserver/cmd/dbhash/main.go @@ -0,0 +1,53 @@ +package main + +import ( + "blackforestbytes.com/simplecloudnotifier/db/schema" + "context" + "fmt" + "github.com/mattn/go-sqlite3" + "gogs.mikescher.com/BlackForestBytes/goext/sq" + "time" +) + +func main() { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + sqlite3.Version() // ensure slite3 loaded + + { + h0, err := sq.HashSqliteSchema(ctx, schema.PrimarySchema1) + if err != nil { + h0 = "ERR" + } + fmt.Printf("PrimarySchema1 := %s\n", h0) + } + { + h0, err := sq.HashSqliteSchema(ctx, schema.PrimarySchema2) + if err != nil { + h0 = "ERR" + } + fmt.Printf("PrimarySchema2 := %s\n", h0) + } + { + h0, err := sq.HashSqliteSchema(ctx, schema.PrimarySchema3) + if err != nil { + h0 = "ERR" + } + fmt.Printf("PrimarySchema3 := %s\n", h0) + } + { + h0, err := sq.HashSqliteSchema(ctx, schema.RequestsSchema1) + if err != nil { + h0 = "ERR" + } + fmt.Printf("RequestsSchema1 := %s\n", h0) + } + { + h0, err := sq.HashSqliteSchema(ctx, schema.LogsSchema1) + if err != nil { + h0 = "ERR" + } + fmt.Printf("LogsSchema1 := %s\n", h0) + } +} diff --git a/scnserver/db/impl/logs/database.go b/scnserver/db/impl/logs/database.go index 6b6d749..700e214 100644 --- a/scnserver/db/impl/logs/database.go +++ b/scnserver/db/impl/logs/database.go @@ -3,13 +3,14 @@ package logs import ( server "blackforestbytes.com/simplecloudnotifier" "blackforestbytes.com/simplecloudnotifier/db/dbtools" - "blackforestbytes.com/simplecloudnotifier/db/impl/logs/schema" + "blackforestbytes.com/simplecloudnotifier/db/schema" "context" "database/sql" "errors" "fmt" "github.com/jmoiron/sqlx" _ "github.com/mattn/go-sqlite3" + "github.com/rs/zerolog/log" "gogs.mikescher.com/BlackForestBytes/goext/langext" "gogs.mikescher.com/BlackForestBytes/goext/sq" "time" @@ -67,9 +68,20 @@ func (db *Database) Migrate(ctx context.Context) error { defer cancel() currschema, err := db.ReadSchema(ctx) + if err != nil { + return err + } + if currschema == 0 { - _, err = db.db.Exec(ctx, schema.LogsSchema1, sq.PP{}) + schemastr := schema.LogsSchema1 + + schemahash, err := sq.HashSqliteSchema(ctx, schemastr) + if err != nil { + return err + } + + _, err = db.db.Exec(ctx, schemastr, sq.PP{}) if err != nil { return err } @@ -79,7 +91,12 @@ func (db *Database) Migrate(ctx context.Context) error { return err } - err = db.pp.Init(ctx) + err = db.WriteMetaString(ctx, "schema_hash", schemahash) + if err != nil { + return err + } + + err = db.pp.Init(ctx) // Re-Init if err != nil { return err } @@ -87,6 +104,31 @@ func (db *Database) Migrate(ctx context.Context) error { return nil } else if currschema == 1 { + + schemHashDB, err := sq.HashSqliteDatabase(ctx, db.db) + if err != nil { + return err + } + + schemaHashMeta, err := db.ReadMetaString(ctx, "schema_hash") + if err != nil { + return err + } + + schemHashAsset := schema.LogsHash1 + if err != nil { + return err + } + + if schemHashDB != langext.Coalesce(schemaHashMeta, "") || langext.Coalesce(schemaHashMeta, "") != schemHashAsset { + log.Debug().Str("schemHashDB", schemHashDB).Msg("Schema (logs db)") + log.Debug().Str("schemaHashMeta", langext.Coalesce(schemaHashMeta, "")).Msg("Schema (logs db)") + log.Debug().Str("schemHashAsset", schemHashAsset).Msg("Schema (logs db)") + return errors.New("database schema does not match (logs db)") + } else { + log.Debug().Str("schemHash", schemHashDB).Msg("Verified Schema consistency (logs db)") + } + return nil // current } else { return errors.New(fmt.Sprintf("Unknown DB schema: %d", currschema)) diff --git a/scnserver/db/impl/logs/schema/assets.go b/scnserver/db/impl/logs/schema/assets.go deleted file mode 100644 index abec6ad..0000000 --- a/scnserver/db/impl/logs/schema/assets.go +++ /dev/null @@ -1,6 +0,0 @@ -package schema - -import _ "embed" - -//go:embed schema_1.ddl -var LogsSchema1 string diff --git a/scnserver/db/impl/primary/database.go b/scnserver/db/impl/primary/database.go index 1f2259f..1978d45 100644 --- a/scnserver/db/impl/primary/database.go +++ b/scnserver/db/impl/primary/database.go @@ -3,13 +3,14 @@ package primary import ( server "blackforestbytes.com/simplecloudnotifier" "blackforestbytes.com/simplecloudnotifier/db/dbtools" - "blackforestbytes.com/simplecloudnotifier/db/impl/primary/schema" + "blackforestbytes.com/simplecloudnotifier/db/schema" "context" "database/sql" "errors" "fmt" "github.com/jmoiron/sqlx" _ "github.com/mattn/go-sqlite3" + "github.com/rs/zerolog/log" "gogs.mikescher.com/BlackForestBytes/goext/langext" "gogs.mikescher.com/BlackForestBytes/goext/sq" "time" @@ -67,9 +68,20 @@ func (db *Database) Migrate(ctx context.Context) error { defer cancel() currschema, err := db.ReadSchema(ctx) + if err != nil { + return err + } + if currschema == 0 { - _, err = db.db.Exec(ctx, schema.PrimarySchema3, sq.PP{}) + schemastr := schema.PrimarySchema3 + + schemahash, err := sq.HashSqliteSchema(ctx, schemastr) + if err != nil { + return err + } + + _, err = db.db.Exec(ctx, schemastr, sq.PP{}) if err != nil { return err } @@ -79,7 +91,12 @@ func (db *Database) Migrate(ctx context.Context) error { return err } - err = db.pp.Init(ctx) + err = db.WriteMetaString(ctx, "schema_hash", schemahash) + if err != nil { + return err + } + + err = db.pp.Init(ctx) // Re-Init if err != nil { return err } @@ -89,8 +106,33 @@ func (db *Database) Migrate(ctx context.Context) error { } else if currschema == 1 { return errors.New("cannot autom. upgrade schema 1") } else if currschema == 2 { - return errors.New("cannot autom. upgrade schema 2") //TODO + return errors.New("cannot autom. upgrade schema 2") } else if currschema == 3 { + + schemHashDB, err := sq.HashSqliteDatabase(ctx, db.db) + if err != nil { + return err + } + + schemaHashMeta, err := db.ReadMetaString(ctx, "schema_hash") + if err != nil { + return err + } + + schemHashAsset := schema.PrimaryHash3 + if err != nil { + return err + } + + if schemHashDB != langext.Coalesce(schemaHashMeta, "") || langext.Coalesce(schemaHashMeta, "") != schemHashAsset { + log.Debug().Str("schemHashDB", schemHashDB).Msg("Schema (primary db)") + log.Debug().Str("schemaHashMeta", langext.Coalesce(schemaHashMeta, "")).Msg("Schema (primary db)") + log.Debug().Str("schemHashAsset", schemHashAsset).Msg("Schema (primary db)") + return errors.New("database schema does not match (primary db)") + } else { + log.Debug().Str("schemHash", schemHashDB).Msg("Verified Schema consistency (primary db)") + } + return nil // current } else { return errors.New(fmt.Sprintf("Unknown DB schema: %d", currschema)) diff --git a/scnserver/db/impl/primary/schema/assets.go b/scnserver/db/impl/primary/schema/assets.go deleted file mode 100644 index 871e237..0000000 --- a/scnserver/db/impl/primary/schema/assets.go +++ /dev/null @@ -1,12 +0,0 @@ -package schema - -import _ "embed" - -//go:embed schema_1.ddl -var PrimarySchema1 string - -//go:embed schema_2.ddl -var PrimarySchema2 string - -//go:embed schema_3.ddl -var PrimarySchema3 string diff --git a/scnserver/db/impl/primary/schema/schema_sqlite.ddl b/scnserver/db/impl/primary/schema/schema_sqlite.ddl deleted file mode 100644 index 5194e91..0000000 --- a/scnserver/db/impl/primary/schema/schema_sqlite.ddl +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE sqlite_master ( - type text, - name text, - tbl_name text, - rootpage integer, - sql text -); \ No newline at end of file diff --git a/scnserver/db/impl/requests/database.go b/scnserver/db/impl/requests/database.go index 1361336..c7f5c38 100644 --- a/scnserver/db/impl/requests/database.go +++ b/scnserver/db/impl/requests/database.go @@ -3,13 +3,14 @@ package requests import ( server "blackforestbytes.com/simplecloudnotifier" "blackforestbytes.com/simplecloudnotifier/db/dbtools" - "blackforestbytes.com/simplecloudnotifier/db/impl/requests/schema" + "blackforestbytes.com/simplecloudnotifier/db/schema" "context" "database/sql" "errors" "fmt" "github.com/jmoiron/sqlx" _ "github.com/mattn/go-sqlite3" + "github.com/rs/zerolog/log" "gogs.mikescher.com/BlackForestBytes/goext/langext" "gogs.mikescher.com/BlackForestBytes/goext/sq" "time" @@ -67,9 +68,20 @@ func (db *Database) Migrate(ctx context.Context) error { defer cancel() currschema, err := db.ReadSchema(ctx) + if err != nil { + return err + } + if currschema == 0 { - _, err = db.db.Exec(ctx, schema.RequestsSchema1, sq.PP{}) + schemastr := schema.RequestsSchema1 + + schemahash, err := sq.HashSqliteSchema(ctx, schemastr) + if err != nil { + return err + } + + _, err = db.db.Exec(ctx, schemastr, sq.PP{}) if err != nil { return err } @@ -79,7 +91,12 @@ func (db *Database) Migrate(ctx context.Context) error { return err } - err = db.pp.Init(ctx) + err = db.WriteMetaString(ctx, "schema_hash", schemahash) + if err != nil { + return err + } + + err = db.pp.Init(ctx) // Re-Init if err != nil { return err } @@ -87,6 +104,31 @@ func (db *Database) Migrate(ctx context.Context) error { return nil } else if currschema == 1 { + + schemHashDB, err := sq.HashSqliteDatabase(ctx, db.db) + if err != nil { + return err + } + + schemaHashMeta, err := db.ReadMetaString(ctx, "schema_hash") + if err != nil { + return err + } + + schemHashAsset := schema.RequestsHash1 + if err != nil { + return err + } + + if schemHashDB != langext.Coalesce(schemaHashMeta, "") || langext.Coalesce(schemaHashMeta, "") != schemHashAsset { + log.Debug().Str("schemHashDB", schemHashDB).Msg("Schema (requests db)") + log.Debug().Str("schemaHashMeta", langext.Coalesce(schemaHashMeta, "")).Msg("Schema (requests db)") + log.Debug().Str("schemHashAsset", schemHashAsset).Msg("Schema (requests db)") + return errors.New("database schema does not match (requests db)") + } else { + log.Debug().Str("schemHash", schemHashDB).Msg("Verified Schema consistency (requests db)") + } + return nil // current } else { return errors.New(fmt.Sprintf("Unknown DB schema: %d", currschema)) diff --git a/scnserver/db/impl/requests/schema/assets.go b/scnserver/db/impl/requests/schema/assets.go deleted file mode 100644 index 30e913f..0000000 --- a/scnserver/db/impl/requests/schema/assets.go +++ /dev/null @@ -1,6 +0,0 @@ -package schema - -import _ "embed" - -//go:embed schema_1.ddl -var RequestsSchema1 string diff --git a/scnserver/db/impl/requests/schema/schema_sqlite.ddl b/scnserver/db/impl/requests/schema/schema_sqlite.ddl deleted file mode 100644 index 5194e91..0000000 --- a/scnserver/db/impl/requests/schema/schema_sqlite.ddl +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE sqlite_master ( - type text, - name text, - tbl_name text, - rootpage integer, - sql text -); \ No newline at end of file diff --git a/scnserver/db/schema/assets.go b/scnserver/db/schema/assets.go new file mode 100644 index 0000000..ce8d563 --- /dev/null +++ b/scnserver/db/schema/assets.go @@ -0,0 +1,28 @@ +package schema + +import _ "embed" + +//go:embed primary_1.ddl +var PrimarySchema1 string + +const PrimaryHash1 = "f2b2847f32681a7178e405553beea4a324034915a0c5a5dc70b3c6abbcc852f2" + +//go:embed primary_2.ddl +var PrimarySchema2 string + +const PrimaryHash2 = "07ed1449114416ed043084a30e0722a5f97bf172161338d2f7106a8dfd387d0a" + +//go:embed primary_3.ddl +var PrimarySchema3 string + +const PrimaryHash3 = "a4851e7953d3423622555cde03d2d0ea2ca367fbe28aa3e363771f1d04bed90a" + +//go:embed requests_1.ddl +var RequestsSchema1 string + +const RequestsHash1 = "ebb0a5748b605e8215437413b738279670190ca8159b6227cfc2aa13418b41e9" + +//go:embed logs_1.ddl +var LogsSchema1 string + +const LogsHash1 = "65fba477c04095effc3a8e1bb79fe7547b8e52e983f776f156266eddc4f201d7" diff --git a/scnserver/db/impl/logs/schema/schema_1.ddl b/scnserver/db/schema/logs_1.ddl similarity index 100% rename from scnserver/db/impl/logs/schema/schema_1.ddl rename to scnserver/db/schema/logs_1.ddl diff --git a/scnserver/db/impl/primary/schema/schema_1.ddl b/scnserver/db/schema/primary_1.ddl similarity index 100% rename from scnserver/db/impl/primary/schema/schema_1.ddl rename to scnserver/db/schema/primary_1.ddl diff --git a/scnserver/db/impl/primary/schema/schema_2.ddl b/scnserver/db/schema/primary_2.ddl similarity index 100% rename from scnserver/db/impl/primary/schema/schema_2.ddl rename to scnserver/db/schema/primary_2.ddl diff --git a/scnserver/db/impl/primary/schema/schema_3.ddl b/scnserver/db/schema/primary_3.ddl similarity index 100% rename from scnserver/db/impl/primary/schema/schema_3.ddl rename to scnserver/db/schema/primary_3.ddl diff --git a/scnserver/db/impl/requests/schema/schema_1.ddl b/scnserver/db/schema/requests_1.ddl similarity index 100% rename from scnserver/db/impl/requests/schema/schema_1.ddl rename to scnserver/db/schema/requests_1.ddl diff --git a/scnserver/db/impl/logs/schema/schema_sqlite.ddl b/scnserver/db/schema/sqlite.ddl similarity index 100% rename from scnserver/db/impl/logs/schema/schema_sqlite.ddl rename to scnserver/db/schema/sqlite.ddl diff --git a/scnserver/go.mod b/scnserver/go.mod index 44a5e7d..ebdd02d 100644 --- a/scnserver/go.mod +++ b/scnserver/go.mod @@ -9,7 +9,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/mattn/go-sqlite3 v1.14.16 github.com/rs/zerolog v1.28.0 - gogs.mikescher.com/BlackForestBytes/goext v0.0.103 + gogs.mikescher.com/BlackForestBytes/goext v0.0.126 gopkg.in/loremipsum.v1 v1.1.0 ) diff --git a/scnserver/go.sum b/scnserver/go.sum index 13fbe2a..e1b2fb1 100644 --- a/scnserver/go.sum +++ b/scnserver/go.sum @@ -75,6 +75,12 @@ github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0 github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= gogs.mikescher.com/BlackForestBytes/goext v0.0.103 h1:CkRVpRrTlq9k3mdTNGQAr4cxaXHsKdUJNjHt5Maas4k= gogs.mikescher.com/BlackForestBytes/goext v0.0.103/go.mod h1:w8JlyUHpoOJmW5GxsiheZkFh3vn8Mp80ynSVOFLszL0= +gogs.mikescher.com/BlackForestBytes/goext v0.0.124 h1:wYP6+qNS+kd9Ht78cdzIpeXf5PM87iQppe6LS2H2W60= +gogs.mikescher.com/BlackForestBytes/goext v0.0.124/go.mod h1:w8JlyUHpoOJmW5GxsiheZkFh3vn8Mp80ynSVOFLszL0= +gogs.mikescher.com/BlackForestBytes/goext v0.0.125 h1:l4C5/CQS/IVm364oZa8MqiG62+NYBF0/jPJWsKQ3k2c= +gogs.mikescher.com/BlackForestBytes/goext v0.0.125/go.mod h1:w8JlyUHpoOJmW5GxsiheZkFh3vn8Mp80ynSVOFLszL0= +gogs.mikescher.com/BlackForestBytes/goext v0.0.126 h1:o3u0STRaPkmNBenqzvXAOPALSyRswuDwl3Y/0MVHAx4= +gogs.mikescher.com/BlackForestBytes/goext v0.0.126/go.mod h1:w8JlyUHpoOJmW5GxsiheZkFh3vn8Mp80ynSVOFLszL0= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=