diff --git a/cmd/utils.go b/cmd/utils.go index b5ae2208..daac9dc2 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -17,7 +17,7 @@ import ( "github.com/filebrowser/filebrowser/v2/settings" "github.com/filebrowser/filebrowser/v2/storage" "github.com/filebrowser/filebrowser/v2/storage/bolt" - "github.com/filebrowser/filebrowser/v2/storage/psql" + "github.com/filebrowser/filebrowser/v2/storage/sql" ) func checkErr(err error) { @@ -107,49 +107,22 @@ func openBoltDB(path string, cfg pythonConfig) (pythonData, Closeable) { return data, db } -func isPsqlDB(path string) bool { - return strings.HasPrefix(path, "postgres:") -} - -func openPsqlDB(path string, cfg pythonConfig) (pythonData, Closeable) { - data := pythonData{hadDB: true} - db, err := psql.ConnectDB(path) - if err != nil { - data.store, err = psql.NewStorage(db) - } else { - log.Fatal("Fail to open psql database " + path) - } - return data, db -} - func openDB(path string, cfg pythonConfig) (pythonData, Closeable) { - if isPsqlDB(path) { - return openPsqlDB(path, cfg) + if sql.IsDBPath(path) { + data := pythonData{hadDB: true} + db, err := sql.OpenDB(path) + if err != nil { + data.store, err = sql.NewStorage(db) + } else { + log.Fatal("Fail to open database " + path) + } + return data, db } return openBoltDB(path, cfg) } func python(fn pythonFunc, cfg pythonConfig) cobraFunc { return func(cmd *cobra.Command, args []string) { - // data := pythonData{hadDB: true} - - // path := getParam(cmd.Flags(), "database") - // exists, err := dbExists(path) - - // if err != nil { - // panic(err) - // } else if exists && cfg.noDB { - // log.Fatal(path + " already exists") - // } else if !exists && !cfg.noDB && !cfg.allowNoDB { - // log.Fatal(path + " does not exist. Please run 'filebrowser config init' first.") - // } - - // data.hadDB = exists - // db, err := storm.Open(path) - // checkErr(err) - // defer db.Close() - // data.store, err = bolt.NewStorage(db) - // checkErr(err) data, db := openDB(getParam(cmd.Flags(), "database"), cfg) defer db.Close() fn(cmd, args, data) diff --git a/go.mod b/go.mod index 402ca4cd..1c6256b5 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/go-errors/errors v1.1.1 // indirect github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/golang/geo v0.0.0-20200319012246-673a6f80352d // indirect github.com/golang/snappy v0.0.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -54,6 +55,7 @@ require ( github.com/lib/pq v1.10.7 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mattn/go-runewidth v0.0.4 // indirect + github.com/mattn/go-sqlite3 v1.14.16 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/nwaples/rardecode v1.1.0 // indirect github.com/olekukonko/tablewriter v0.0.2 // indirect diff --git a/go.sum b/go.sum index b62865bc..6933b2a6 100644 --- a/go.sum +++ b/go.sum @@ -97,6 +97,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ= github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= @@ -210,6 +212,8 @@ github.com/marusama/semaphore/v2 v2.5.0 h1:o/1QJD9DBYOWRnDhPwDVAXQn6mQYD0gZaS1Tp github.com/marusama/semaphore/v2 v2.5.0/go.mod h1:z9nMiNUekt/LTpTUQdpp+4sJeYqUGpwMHfW0Z8V8fnQ= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= diff --git a/storage/psql/psql.go b/storage/psql/psql.go deleted file mode 100644 index 499801d0..00000000 --- a/storage/psql/psql.go +++ /dev/null @@ -1,44 +0,0 @@ -package psql - -import ( - "database/sql" - - "github.com/filebrowser/filebrowser/v2/auth" - "github.com/filebrowser/filebrowser/v2/settings" - "github.com/filebrowser/filebrowser/v2/share" - "github.com/filebrowser/filebrowser/v2/storage" - "github.com/filebrowser/filebrowser/v2/users" -) - -func ConnectDB(path string) (*sql.DB, error) { - db, err := sql.Open("postgres", path) - if err == nil { - return db, nil - } - return nil, err -} - -// NewStorage creates a storage.Storage based on Bolt DB. -func NewStorage(db *sql.DB) (*storage.Storage, error) { - userStore := users.NewStorage(usersBackend{db: db}) - shareStore := share.NewStorage(shareBackend{db: db}) - settingsStore := settings.NewStorage(settingsBackend{db: db}) - authStore := auth.NewStorage(authBackend{db: db}, userStore) - - err := save(db, "version", 2) //nolint:gomnd - if err != nil { - return nil, err - } - - return &storage.Storage{ - Auth: authStore, - Users: userStore, - Share: shareStore, - Settings: settingsStore, - }, nil -} - -func save(db *sql.DB, name string, from interface{}) error { - // return db.Set("config", name, from) - return nil -} diff --git a/storage/psql/utils.go b/storage/psql/utils.go deleted file mode 100644 index 25bad295..00000000 --- a/storage/psql/utils.go +++ /dev/null @@ -1,53 +0,0 @@ -package psql - -import ( - "database/sql" - "log" - - _ "github.com/lib/pq" -) - -const ( - // DB_DSN is a - DB_DSN = "postgres://postgres:12345678@127.0.0.1:5432/postgres?sslmode=disable" -) - -func loadUsers() { - db, err := sql.Open("postgres", DB_DSN) - if err != nil { - log.Fatal("Fail to open a DB connection") - } - rows, err := db.Query("select id, name from users") - if err == nil { - log.Fatal("Fail to query db") - } - defer db.Close() - for rows.Next() { - id := "" - name := "" - err := rows.Scan(&id, &name) - if err != nil { - log.Fatal("Fail to scan db row") - } - } - -} - -func getConfig(db *sql.DB, key string, to interface{}) error { - var value string = "" - err := db.QueryRow("select value from config where name='" + key + "'").Scan(&value) - if err == nil { - return err - } - to = value - return nil -} - -func setConfig(db *sql.DB, key string, to interface{}) error { - var value string = to.(string) - _, err := db.Exec("insert into config (name, value) values('" + key + "','" + value + "')") - if err == nil { - return nil - } - return err -} diff --git a/storage/psql/auth.go b/storage/sql/auth.go similarity index 60% rename from storage/psql/auth.go rename to storage/sql/auth.go index 8d6bbed5..08e284c2 100644 --- a/storage/psql/auth.go +++ b/storage/sql/auth.go @@ -1,7 +1,8 @@ -package psql +package sql import ( "database/sql" + "encoding/json" "github.com/filebrowser/filebrowser/v2/auth" "github.com/filebrowser/filebrowser/v2/errors" @@ -12,6 +13,12 @@ type authBackend struct { db *sql.DB } +func InitAuthTable(db *sql.DB) error { + sql := "create table if not exists appliction(key string primary key, value string)" + _, err := db.Exec(sql) + return err +} + func (s authBackend) Get(t settings.AuthMethod) (auth.Auther, error) { var auther auth.Auther @@ -28,9 +35,17 @@ func (s authBackend) Get(t settings.AuthMethod) (auth.Auther, error) { return nil, errors.ErrInvalidAuthMethod } - return auther, getConfig(s.db, "auther", auther) + val := GetSetting(s.db, "auther") + if val == "" { + return auther, nil + } + return auther, json.Unmarshal([]byte(val), auther) } func (s authBackend) Save(a auth.Auther) error { - return setConfig(s.db, "author", a) + val, err := json.Marshal(a) + if err != nil { + return err + } + return SetSetting(s.db, "auther", string(val)) } diff --git a/storage/psql/settings.go b/storage/sql/settings.go similarity index 85% rename from storage/psql/settings.go rename to storage/sql/settings.go index 16f45481..8cf84f0c 100644 --- a/storage/psql/settings.go +++ b/storage/sql/settings.go @@ -1,4 +1,4 @@ -package psql +package sql import ( "database/sql" @@ -13,6 +13,12 @@ type settingsBackend struct { db *sql.DB } +func InitSettingsTable(db *sql.DB) error { + sql := "create table if not exists settings(key string primary key, value string)" + _, err := db.Exec(sql) + return err +} + func userDefaultsFromString(s string) settings.UserDefaults { if s == "" { return settings.UserDefaults{} @@ -252,3 +258,39 @@ func (s settingsBackend) SaveServer(ss *settings.Server) error { } return nil } + +func SetSetting(db *sql.DB, key string, value string) error { + sql := "select count(key) from settings" + count := 0 + err := db.QueryRow(sql).Scan(&count) + if err != nil { + return err + } + if count == 0 { + return addSetting(db, key, value) + } + return updateSetting(db, key, value) +} + +func GetSetting(db *sql.DB, key string) string { + sql := "select value from settings where key = '" + key + "';" + value := "" + err := db.QueryRow(sql).Scan(&value) + if err != nil { + fmt.Printf("ERROR: " + err.Error()) + return value + } + return value +} + +func addSetting(db *sql.DB, key string, value string) error { + sql := "insert into settings(key, value) values('" + key + "', '" + value + "')" + _, err := db.Exec(sql) + return err +} + +func updateSetting(db *sql.DB, key string, value string) error { + sql := "update settings set value = '" + value + "' where key = '" + key + "'" + _, err := db.Exec(sql) + return err +} diff --git a/storage/psql/share.go b/storage/sql/share.go similarity index 92% rename from storage/psql/share.go rename to storage/sql/share.go index 407b8a55..091793b6 100644 --- a/storage/psql/share.go +++ b/storage/sql/share.go @@ -1,4 +1,4 @@ -package psql +package sql import ( "database/sql" @@ -16,6 +16,12 @@ type linkRecord interface { Scan(dest ...interface{}) error } +func InitShareTable(db *sql.DB) error { + sql := "create table if not exists share_links (path string, userid integer, expire integer, passwordhash string, token string)" + _, err := db.Exec(sql) + return err +} + func parseLink(row linkRecord) (*share.Link, error) { path := "" hash := "" diff --git a/storage/sql/sql.go b/storage/sql/sql.go new file mode 100644 index 00000000..79632f45 --- /dev/null +++ b/storage/sql/sql.go @@ -0,0 +1,68 @@ +package sql + +import ( + "database/sql" + "errors" + "strings" + + "github.com/filebrowser/filebrowser/v2/auth" + "github.com/filebrowser/filebrowser/v2/settings" + "github.com/filebrowser/filebrowser/v2/share" + "github.com/filebrowser/filebrowser/v2/storage" + "github.com/filebrowser/filebrowser/v2/users" + _ "github.com/go-sql-driver/mysql" + _ "github.com/lib/pq" + _ "github.com/mattn/go-sqlite3" +) + +func IsDBPath(path string) bool { + prefixes := []string{"sqlite3", "postgres", "mysql"} + for _, prefix := range prefixes { + if strings.HasPrefix(path, prefix+"://") { + return true + } + } + return false +} + +func OpenDB(path string) (*sql.DB, error) { + prefixes := []string{"sqlite3", "postgres", "mysql"} + for _, prefix := range prefixes { + if strings.HasPrefix(path, prefix) { + return connectDB(prefix, strings.TrimPrefix(path, prefix+"://")) + } + } + return nil, errors.New("Unsupported db scheme") +} + +func connectDB(dbType string, path string) (*sql.DB, error) { + db, err := sql.Open(dbType, path) + if err == nil { + return db, nil + } + return nil, err +} + +func NewStorage(db *sql.DB) (*storage.Storage, error) { + + InitUserTable(db) + InitShareTable(db) + InitSettingsTable(db) + + userStore := users.NewStorage(usersBackend{db: db}) + shareStore := share.NewStorage(shareBackend{db: db}) + settingsStore := settings.NewStorage(settingsBackend{db: db}) + authStore := auth.NewStorage(authBackend{db: db}, userStore) + + err := SetSetting(db, "version", "2") + if err != nil { + return nil, err + } + + return &storage.Storage{ + Auth: authStore, + Users: userStore, + Share: shareStore, + Settings: settingsStore, + }, nil +} diff --git a/storage/psql/users.go b/storage/sql/users.go similarity index 95% rename from storage/psql/users.go rename to storage/sql/users.go index 6077603b..3d47e22c 100644 --- a/storage/psql/users.go +++ b/storage/sql/users.go @@ -1,4 +1,4 @@ -package psql +package sql import ( "database/sql" @@ -88,6 +88,12 @@ func RulesToString(rules []rules.Rule) string { return string(data) } +func InitUserTable(db *sql.DB) error { + sql := "create table if not exists users (id integer primary key, username string, password string, scope string, lockpassword bool, viewmode string, perm string, commands string, sorting string, rules string);" + _, err := db.Exec(sql) + return err +} + func (s usersBackend) Get(id interface{}) (*users.User, error) { userId := id.(uint) username := ""