sqlite.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. package dataprovider
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "path/filepath"
  6. "strings"
  7. "github.com/drakkan/sftpgo/logger"
  8. "github.com/drakkan/sftpgo/utils"
  9. )
  10. const (
  11. sqliteUsersTableSQL = `CREATE TABLE "{{users}}" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "username" varchar(255)
  12. NOT NULL UNIQUE, "password" varchar(255) NULL, "public_keys" text NULL, "home_dir" varchar(255) NOT NULL, "uid" integer NOT NULL,
  13. "gid" integer NOT NULL, "max_sessions" integer NOT NULL, "quota_size" bigint NOT NULL, "quota_files" integer NOT NULL,
  14. "permissions" text NOT NULL, "used_quota_size" bigint NOT NULL, "used_quota_files" integer NOT NULL,
  15. "last_quota_update" bigint NOT NULL, "upload_bandwidth" integer NOT NULL, "download_bandwidth" integer NOT NULL,
  16. "expiration_date" bigint NOT NULL, "last_login" bigint NOT NULL, "status" integer NOT NULL, "filters" text NULL,
  17. "filesystem" text NULL);`
  18. sqliteSchemaTableSQL = `CREATE TABLE "schema_version" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "version" integer NOT NULL);`
  19. sqliteUsersV2SQL = `ALTER TABLE "{{users}}" ADD COLUMN "virtual_folders" text NULL;`
  20. )
  21. // SQLiteProvider auth provider for SQLite database
  22. type SQLiteProvider struct {
  23. dbHandle *sql.DB
  24. }
  25. func initializeSQLiteProvider(basePath string) error {
  26. var err error
  27. var connectionString string
  28. logSender = fmt.Sprintf("dataprovider_%v", SQLiteDataProviderName)
  29. if len(config.ConnectionString) == 0 {
  30. dbPath := config.Name
  31. if !utils.IsFileInputValid(dbPath) {
  32. return fmt.Errorf("Invalid database path: %#v", dbPath)
  33. }
  34. if !filepath.IsAbs(dbPath) {
  35. dbPath = filepath.Join(basePath, dbPath)
  36. }
  37. connectionString = fmt.Sprintf("file:%v?cache=shared", dbPath)
  38. } else {
  39. connectionString = config.ConnectionString
  40. }
  41. dbHandle, err := sql.Open("sqlite3", connectionString)
  42. if err == nil {
  43. providerLog(logger.LevelDebug, "sqlite database handle created, connection string: %#v", connectionString)
  44. dbHandle.SetMaxOpenConns(1)
  45. provider = SQLiteProvider{dbHandle: dbHandle}
  46. } else {
  47. providerLog(logger.LevelWarn, "error creating sqlite database handler, connection string: %#v, error: %v",
  48. connectionString, err)
  49. }
  50. return err
  51. }
  52. func (p SQLiteProvider) checkAvailability() error {
  53. return sqlCommonCheckAvailability(p.dbHandle)
  54. }
  55. func (p SQLiteProvider) validateUserAndPass(username string, password string) (User, error) {
  56. return sqlCommonValidateUserAndPass(username, password, p.dbHandle)
  57. }
  58. func (p SQLiteProvider) validateUserAndPubKey(username string, publicKey []byte) (User, string, error) {
  59. return sqlCommonValidateUserAndPubKey(username, publicKey, p.dbHandle)
  60. }
  61. func (p SQLiteProvider) getUserByID(ID int64) (User, error) {
  62. return sqlCommonGetUserByID(ID, p.dbHandle)
  63. }
  64. func (p SQLiteProvider) updateQuota(username string, filesAdd int, sizeAdd int64, reset bool) error {
  65. return sqlCommonUpdateQuota(username, filesAdd, sizeAdd, reset, p.dbHandle)
  66. }
  67. func (p SQLiteProvider) updateLastLogin(username string) error {
  68. return sqlCommonUpdateLastLogin(username, p.dbHandle)
  69. }
  70. func (p SQLiteProvider) getUsedQuota(username string) (int, int64, error) {
  71. return sqlCommonGetUsedQuota(username, p.dbHandle)
  72. }
  73. func (p SQLiteProvider) userExists(username string) (User, error) {
  74. return sqlCommonCheckUserExists(username, p.dbHandle)
  75. }
  76. func (p SQLiteProvider) addUser(user User) error {
  77. return sqlCommonAddUser(user, p.dbHandle)
  78. }
  79. func (p SQLiteProvider) updateUser(user User) error {
  80. return sqlCommonUpdateUser(user, p.dbHandle)
  81. }
  82. func (p SQLiteProvider) deleteUser(user User) error {
  83. return sqlCommonDeleteUser(user, p.dbHandle)
  84. }
  85. func (p SQLiteProvider) dumpUsers() ([]User, error) {
  86. return sqlCommonDumpUsers(p.dbHandle)
  87. }
  88. func (p SQLiteProvider) getUsers(limit int, offset int, order string, username string) ([]User, error) {
  89. return sqlCommonGetUsers(limit, offset, order, username, p.dbHandle)
  90. }
  91. func (p SQLiteProvider) close() error {
  92. return p.dbHandle.Close()
  93. }
  94. func (p SQLiteProvider) reloadConfig() error {
  95. return nil
  96. }
  97. // initializeDatabase creates the initial database structure
  98. func (p SQLiteProvider) initializeDatabase() error {
  99. sqlUsers := strings.Replace(sqliteUsersTableSQL, "{{users}}", config.UsersTable, 1)
  100. sql := sqlUsers + " " + sqliteSchemaTableSQL + " " + initialDBVersionSQL
  101. _, err := p.dbHandle.Exec(sql)
  102. return err
  103. }
  104. func (p SQLiteProvider) migrateDatabase() error {
  105. dbVersion, err := sqlCommonGetDatabaseVersion(p.dbHandle)
  106. if err != nil {
  107. return err
  108. }
  109. if dbVersion.Version == sqlDatabaseVersion {
  110. providerLog(logger.LevelDebug, "sql database is updated, current version: %v", dbVersion.Version)
  111. return nil
  112. }
  113. if dbVersion.Version == 1 {
  114. return updateSQLiteDatabaseFrom1To2(p.dbHandle)
  115. }
  116. return nil
  117. }
  118. func updateSQLiteDatabaseFrom1To2(dbHandle *sql.DB) error {
  119. providerLog(logger.LevelInfo, "updating database version: 1 -> 2")
  120. sql := strings.Replace(sqliteUsersV2SQL, "{{users}}", config.UsersTable, 1)
  121. _, err := dbHandle.Exec(sql)
  122. if err != nil {
  123. return err
  124. }
  125. return sqlCommonUpdateDatabaseVersion(dbHandle, 2)
  126. }