| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397 |
- //go:build !nobolt
- // +build !nobolt
- package dataprovider
- import (
- "crypto/x509"
- "encoding/json"
- "errors"
- "fmt"
- "path/filepath"
- "time"
- bolt "go.etcd.io/bbolt"
- "github.com/drakkan/sftpgo/v2/logger"
- "github.com/drakkan/sftpgo/v2/util"
- "github.com/drakkan/sftpgo/v2/version"
- "github.com/drakkan/sftpgo/v2/vfs"
- )
- const (
- boltDatabaseVersion = 12
- )
- var (
- usersBucket = []byte("users")
- foldersBucket = []byte("folders")
- adminsBucket = []byte("admins")
- apiKeysBucket = []byte("api_keys")
- dbVersionBucket = []byte("db_version")
- dbVersionKey = []byte("version")
- )
- // BoltProvider auth provider for bolt key/value store
- type BoltProvider struct {
- dbHandle *bolt.DB
- }
- func init() {
- version.AddFeature("+bolt")
- }
- func initializeBoltProvider(basePath string) error {
- var err error
- dbPath := config.Name
- if !util.IsFileInputValid(dbPath) {
- return fmt.Errorf("invalid database path: %#v", dbPath)
- }
- if !filepath.IsAbs(dbPath) {
- dbPath = filepath.Join(basePath, dbPath)
- }
- dbHandle, err := bolt.Open(dbPath, 0600, &bolt.Options{
- NoGrowSync: false,
- FreelistType: bolt.FreelistArrayType,
- Timeout: 5 * time.Second})
- if err == nil {
- providerLog(logger.LevelDebug, "bolt key store handle created")
- err = dbHandle.Update(func(tx *bolt.Tx) error {
- _, e := tx.CreateBucketIfNotExists(usersBucket)
- return e
- })
- if err != nil {
- providerLog(logger.LevelWarn, "error creating users bucket: %v", err)
- return err
- }
- if err != nil {
- providerLog(logger.LevelWarn, "error creating username idx bucket: %v", err)
- return err
- }
- err = dbHandle.Update(func(tx *bolt.Tx) error {
- _, e := tx.CreateBucketIfNotExists(foldersBucket)
- return e
- })
- if err != nil {
- providerLog(logger.LevelWarn, "error creating folders bucket: %v", err)
- return err
- }
- err = dbHandle.Update(func(tx *bolt.Tx) error {
- _, e := tx.CreateBucketIfNotExists(adminsBucket)
- return e
- })
- if err != nil {
- providerLog(logger.LevelWarn, "error creating admins bucket: %v", err)
- return err
- }
- err = dbHandle.Update(func(tx *bolt.Tx) error {
- _, e := tx.CreateBucketIfNotExists(apiKeysBucket)
- return e
- })
- if err != nil {
- providerLog(logger.LevelWarn, "error creating api keys bucket: %v", err)
- return err
- }
- err = dbHandle.Update(func(tx *bolt.Tx) error {
- _, e := tx.CreateBucketIfNotExists(dbVersionBucket)
- return e
- })
- if err != nil {
- providerLog(logger.LevelWarn, "error creating database version bucket: %v", err)
- return err
- }
- provider = &BoltProvider{dbHandle: dbHandle}
- } else {
- providerLog(logger.LevelWarn, "error creating bolt key/value store handler: %v", err)
- }
- return err
- }
- func (p *BoltProvider) checkAvailability() error {
- _, err := getBoltDatabaseVersion(p.dbHandle)
- return err
- }
- func (p *BoltProvider) validateUserAndTLSCert(username, protocol string, tlsCert *x509.Certificate) (User, error) {
- var user User
- if tlsCert == nil {
- return user, errors.New("TLS certificate cannot be null or empty")
- }
- user, err := p.userExists(username)
- if err != nil {
- providerLog(logger.LevelWarn, "error authenticating user %#v: %v", username, err)
- return user, err
- }
- return checkUserAndTLSCertificate(&user, protocol, tlsCert)
- }
- func (p *BoltProvider) validateUserAndPass(username, password, ip, protocol string) (User, error) {
- var user User
- if password == "" {
- return user, errors.New("credentials cannot be null or empty")
- }
- user, err := p.userExists(username)
- if err != nil {
- providerLog(logger.LevelWarn, "error authenticating user %#v: %v", username, err)
- return user, err
- }
- return checkUserAndPass(&user, password, ip, protocol)
- }
- func (p *BoltProvider) validateAdminAndPass(username, password, ip string) (Admin, error) {
- admin, err := p.adminExists(username)
- if err != nil {
- providerLog(logger.LevelWarn, "error authenticating admin %#v: %v", username, err)
- return admin, ErrInvalidCredentials
- }
- err = admin.checkUserAndPass(password, ip)
- return admin, err
- }
- func (p *BoltProvider) validateUserAndPubKey(username string, pubKey []byte) (User, string, error) {
- var user User
- if len(pubKey) == 0 {
- return user, "", errors.New("credentials cannot be null or empty")
- }
- user, err := p.userExists(username)
- if err != nil {
- providerLog(logger.LevelWarn, "error authenticating user %#v: %v", username, err)
- return user, "", err
- }
- return checkUserAndPubKey(&user, pubKey)
- }
- func (p *BoltProvider) updateAPIKeyLastUse(keyID string) error {
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getAPIKeysBucket(tx)
- if err != nil {
- return err
- }
- var u []byte
- if u = bucket.Get([]byte(keyID)); u == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("key %#v does not exist, unable to update last use", keyID))
- }
- var apiKey APIKey
- err = json.Unmarshal(u, &apiKey)
- if err != nil {
- return err
- }
- apiKey.LastUseAt = util.GetTimeAsMsSinceEpoch(time.Now())
- buf, err := json.Marshal(apiKey)
- if err != nil {
- return err
- }
- err = bucket.Put([]byte(keyID), buf)
- if err != nil {
- providerLog(logger.LevelWarn, "error updating last use for key %#v: %v", keyID, err)
- return err
- }
- providerLog(logger.LevelDebug, "last use updated for key %#v", keyID)
- return nil
- })
- }
- func (p *BoltProvider) setUpdatedAt(username string) {
- p.dbHandle.Update(func(tx *bolt.Tx) error { //nolint:errcheck
- bucket, err := getUsersBucket(tx)
- if err != nil {
- return err
- }
- var u []byte
- if u = bucket.Get([]byte(username)); u == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("username %#v does not exist, unable to update updated at", username))
- }
- var user User
- err = json.Unmarshal(u, &user)
- if err != nil {
- return err
- }
- user.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
- buf, err := json.Marshal(user)
- if err != nil {
- return err
- }
- err = bucket.Put([]byte(username), buf)
- if err == nil {
- providerLog(logger.LevelDebug, "updated at set for user %#v", username)
- } else {
- providerLog(logger.LevelWarn, "error setting updated_at for user %#v: %v", username, err)
- }
- return err
- })
- }
- func (p *BoltProvider) updateLastLogin(username string) error {
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getUsersBucket(tx)
- if err != nil {
- return err
- }
- var u []byte
- if u = bucket.Get([]byte(username)); u == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("username %#v does not exist, unable to update last login", username))
- }
- var user User
- err = json.Unmarshal(u, &user)
- if err != nil {
- return err
- }
- user.LastLogin = util.GetTimeAsMsSinceEpoch(time.Now())
- buf, err := json.Marshal(user)
- if err != nil {
- return err
- }
- err = bucket.Put([]byte(username), buf)
- if err == nil {
- providerLog(logger.LevelDebug, "last login updated for user %#v", username)
- } else {
- providerLog(logger.LevelWarn, "error updating last login for user %#v: %v", username, err)
- }
- return err
- })
- }
- func (p *BoltProvider) updateAdminLastLogin(username string) error {
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getAdminsBucket(tx)
- if err != nil {
- return err
- }
- var a []byte
- if a = bucket.Get([]byte(username)); a == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("admin %#v does not exist, unable to update last login", username))
- }
- var admin Admin
- err = json.Unmarshal(a, &admin)
- if err != nil {
- return err
- }
- admin.LastLogin = util.GetTimeAsMsSinceEpoch(time.Now())
- buf, err := json.Marshal(admin)
- if err != nil {
- return err
- }
- err = bucket.Put([]byte(username), buf)
- if err == nil {
- providerLog(logger.LevelDebug, "last login updated for admin %#v", username)
- return err
- }
- providerLog(logger.LevelWarn, "error updating last login for admin %#v: %v", username, err)
- return err
- })
- }
- func (p *BoltProvider) updateQuota(username string, filesAdd int, sizeAdd int64, reset bool) error {
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getUsersBucket(tx)
- if err != nil {
- return err
- }
- var u []byte
- if u = bucket.Get([]byte(username)); u == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("username %#v does not exist, unable to update quota", username))
- }
- var user User
- err = json.Unmarshal(u, &user)
- if err != nil {
- return err
- }
- if reset {
- user.UsedQuotaSize = sizeAdd
- user.UsedQuotaFiles = filesAdd
- } else {
- user.UsedQuotaSize += sizeAdd
- user.UsedQuotaFiles += filesAdd
- }
- user.LastQuotaUpdate = util.GetTimeAsMsSinceEpoch(time.Now())
- buf, err := json.Marshal(user)
- if err != nil {
- return err
- }
- err = bucket.Put([]byte(username), buf)
- providerLog(logger.LevelDebug, "quota updated for user %#v, files increment: %v size increment: %v is reset? %v",
- username, filesAdd, sizeAdd, reset)
- return err
- })
- }
- func (p *BoltProvider) getUsedQuota(username string) (int, int64, error) {
- user, err := p.userExists(username)
- if err != nil {
- providerLog(logger.LevelWarn, "unable to get quota for user %v error: %v", username, err)
- return 0, 0, err
- }
- return user.UsedQuotaFiles, user.UsedQuotaSize, err
- }
- func (p *BoltProvider) adminExists(username string) (Admin, error) {
- var admin Admin
- err := p.dbHandle.View(func(tx *bolt.Tx) error {
- bucket, err := getAdminsBucket(tx)
- if err != nil {
- return err
- }
- a := bucket.Get([]byte(username))
- if a == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("admin %v does not exist", username))
- }
- return json.Unmarshal(a, &admin)
- })
- return admin, err
- }
- func (p *BoltProvider) addAdmin(admin *Admin) error {
- err := admin.validate()
- if err != nil {
- return err
- }
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getAdminsBucket(tx)
- if err != nil {
- return err
- }
- if a := bucket.Get([]byte(admin.Username)); a != nil {
- return fmt.Errorf("admin %v already exists", admin.Username)
- }
- id, err := bucket.NextSequence()
- if err != nil {
- return err
- }
- admin.ID = int64(id)
- admin.LastLogin = 0
- admin.CreatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
- admin.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
- buf, err := json.Marshal(admin)
- if err != nil {
- return err
- }
- return bucket.Put([]byte(admin.Username), buf)
- })
- }
- func (p *BoltProvider) updateAdmin(admin *Admin) error {
- err := admin.validate()
- if err != nil {
- return err
- }
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getAdminsBucket(tx)
- if err != nil {
- return err
- }
- var a []byte
- if a = bucket.Get([]byte(admin.Username)); a == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("admin %v does not exist", admin.Username))
- }
- var oldAdmin Admin
- err = json.Unmarshal(a, &oldAdmin)
- if err != nil {
- return err
- }
- admin.ID = oldAdmin.ID
- admin.CreatedAt = oldAdmin.CreatedAt
- admin.LastLogin = oldAdmin.LastLogin
- admin.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
- buf, err := json.Marshal(admin)
- if err != nil {
- return err
- }
- return bucket.Put([]byte(admin.Username), buf)
- })
- }
- func (p *BoltProvider) deleteAdmin(admin *Admin) error {
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getAdminsBucket(tx)
- if err != nil {
- return err
- }
- if bucket.Get([]byte(admin.Username)) == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("admin %v does not exist", admin.Username))
- }
- if err := deleteRelatedAPIKey(tx, admin.Username, APIKeyScopeAdmin); err != nil {
- return err
- }
- return bucket.Delete([]byte(admin.Username))
- })
- }
- func (p *BoltProvider) getAdmins(limit int, offset int, order string) ([]Admin, error) {
- admins := make([]Admin, 0, limit)
- err := p.dbHandle.View(func(tx *bolt.Tx) error {
- bucket, err := getAdminsBucket(tx)
- if err != nil {
- return err
- }
- cursor := bucket.Cursor()
- itNum := 0
- if order == OrderASC {
- for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
- itNum++
- if itNum <= offset {
- continue
- }
- var admin Admin
- err = json.Unmarshal(v, &admin)
- if err != nil {
- return err
- }
- admin.HideConfidentialData()
- admins = append(admins, admin)
- if len(admins) >= limit {
- break
- }
- }
- } else {
- for k, v := cursor.Last(); k != nil; k, v = cursor.Prev() {
- itNum++
- if itNum <= offset {
- continue
- }
- var admin Admin
- err = json.Unmarshal(v, &admin)
- if err != nil {
- return err
- }
- admin.HideConfidentialData()
- admins = append(admins, admin)
- if len(admins) >= limit {
- break
- }
- }
- }
- return err
- })
- return admins, err
- }
- func (p *BoltProvider) dumpAdmins() ([]Admin, error) {
- admins := make([]Admin, 0, 30)
- err := p.dbHandle.View(func(tx *bolt.Tx) error {
- bucket, err := getAdminsBucket(tx)
- if err != nil {
- return err
- }
- cursor := bucket.Cursor()
- for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
- var admin Admin
- err = json.Unmarshal(v, &admin)
- if err != nil {
- return err
- }
- admins = append(admins, admin)
- }
- return err
- })
- return admins, err
- }
- func (p *BoltProvider) userExists(username string) (User, error) {
- var user User
- err := p.dbHandle.View(func(tx *bolt.Tx) error {
- bucket, err := getUsersBucket(tx)
- if err != nil {
- return err
- }
- u := bucket.Get([]byte(username))
- if u == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("username %#v does not exist", username))
- }
- folderBucket, err := getFoldersBucket(tx)
- if err != nil {
- return err
- }
- user, err = joinUserAndFolders(u, folderBucket)
- return err
- })
- return user, err
- }
- func (p *BoltProvider) addUser(user *User) error {
- err := ValidateUser(user)
- if err != nil {
- return err
- }
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getUsersBucket(tx)
- if err != nil {
- return err
- }
- folderBucket, err := getFoldersBucket(tx)
- if err != nil {
- return err
- }
- if u := bucket.Get([]byte(user.Username)); u != nil {
- return fmt.Errorf("username %v already exists", user.Username)
- }
- id, err := bucket.NextSequence()
- if err != nil {
- return err
- }
- user.ID = int64(id)
- user.LastQuotaUpdate = 0
- user.UsedQuotaSize = 0
- user.UsedQuotaFiles = 0
- user.LastLogin = 0
- user.CreatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
- user.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
- for idx := range user.VirtualFolders {
- err = addUserToFolderMapping(&user.VirtualFolders[idx].BaseVirtualFolder, user, folderBucket)
- if err != nil {
- return err
- }
- }
- buf, err := json.Marshal(user)
- if err != nil {
- return err
- }
- return bucket.Put([]byte(user.Username), buf)
- })
- }
- func (p *BoltProvider) updateUser(user *User) error {
- err := ValidateUser(user)
- if err != nil {
- return err
- }
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getUsersBucket(tx)
- if err != nil {
- return err
- }
- folderBucket, err := getFoldersBucket(tx)
- if err != nil {
- return err
- }
- var u []byte
- if u = bucket.Get([]byte(user.Username)); u == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("username %#v does not exist", user.Username))
- }
- var oldUser User
- err = json.Unmarshal(u, &oldUser)
- if err != nil {
- return err
- }
- for idx := range oldUser.VirtualFolders {
- err = removeUserFromFolderMapping(&oldUser.VirtualFolders[idx], &oldUser, folderBucket)
- if err != nil {
- return err
- }
- }
- for idx := range user.VirtualFolders {
- err = addUserToFolderMapping(&user.VirtualFolders[idx].BaseVirtualFolder, user, folderBucket)
- if err != nil {
- return err
- }
- }
- user.ID = oldUser.ID
- user.LastQuotaUpdate = oldUser.LastQuotaUpdate
- user.UsedQuotaSize = oldUser.UsedQuotaSize
- user.UsedQuotaFiles = oldUser.UsedQuotaFiles
- user.LastLogin = oldUser.LastLogin
- user.CreatedAt = oldUser.CreatedAt
- user.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
- buf, err := json.Marshal(user)
- if err != nil {
- return err
- }
- return bucket.Put([]byte(user.Username), buf)
- })
- }
- func (p *BoltProvider) deleteUser(user *User) error {
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getUsersBucket(tx)
- if err != nil {
- return err
- }
- exists := bucket.Get([]byte(user.Username))
- if exists == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("user %#v does not exist", user.Username))
- }
- if len(user.VirtualFolders) > 0 {
- folderBucket, err := getFoldersBucket(tx)
- if err != nil {
- return err
- }
- for idx := range user.VirtualFolders {
- err = removeUserFromFolderMapping(&user.VirtualFolders[idx], user, folderBucket)
- if err != nil {
- return err
- }
- }
- }
- if err := deleteRelatedAPIKey(tx, user.Username, APIKeyScopeUser); err != nil {
- return err
- }
- return bucket.Delete([]byte(user.Username))
- })
- }
- func (p *BoltProvider) dumpUsers() ([]User, error) {
- users := make([]User, 0, 100)
- err := p.dbHandle.View(func(tx *bolt.Tx) error {
- bucket, err := getUsersBucket(tx)
- if err != nil {
- return err
- }
- folderBucket, err := getFoldersBucket(tx)
- if err != nil {
- return err
- }
- cursor := bucket.Cursor()
- for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
- user, err := joinUserAndFolders(v, folderBucket)
- if err != nil {
- return err
- }
- err = addCredentialsToUser(&user)
- if err != nil {
- return err
- }
- users = append(users, user)
- }
- return err
- })
- return users, err
- }
- func (p *BoltProvider) getUsers(limit int, offset int, order string) ([]User, error) {
- users := make([]User, 0, limit)
- var err error
- if limit <= 0 {
- return users, err
- }
- err = p.dbHandle.View(func(tx *bolt.Tx) error {
- bucket, err := getUsersBucket(tx)
- if err != nil {
- return err
- }
- folderBucket, err := getFoldersBucket(tx)
- if err != nil {
- return err
- }
- cursor := bucket.Cursor()
- itNum := 0
- if order == OrderASC {
- for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
- itNum++
- if itNum <= offset {
- continue
- }
- user, err := joinUserAndFolders(v, folderBucket)
- if err == nil {
- user.PrepareForRendering()
- users = append(users, user)
- }
- if len(users) >= limit {
- break
- }
- }
- } else {
- for k, v := cursor.Last(); k != nil; k, v = cursor.Prev() {
- itNum++
- if itNum <= offset {
- continue
- }
- user, err := joinUserAndFolders(v, folderBucket)
- if err == nil {
- user.PrepareForRendering()
- users = append(users, user)
- }
- if len(users) >= limit {
- break
- }
- }
- }
- return err
- })
- return users, err
- }
- func (p *BoltProvider) dumpFolders() ([]vfs.BaseVirtualFolder, error) {
- folders := make([]vfs.BaseVirtualFolder, 0, 50)
- err := p.dbHandle.View(func(tx *bolt.Tx) error {
- bucket, err := getFoldersBucket(tx)
- if err != nil {
- return err
- }
- cursor := bucket.Cursor()
- for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
- var folder vfs.BaseVirtualFolder
- err = json.Unmarshal(v, &folder)
- if err != nil {
- return err
- }
- folders = append(folders, folder)
- }
- return err
- })
- return folders, err
- }
- func (p *BoltProvider) getFolders(limit, offset int, order string) ([]vfs.BaseVirtualFolder, error) {
- folders := make([]vfs.BaseVirtualFolder, 0, limit)
- var err error
- if limit <= 0 {
- return folders, err
- }
- err = p.dbHandle.View(func(tx *bolt.Tx) error {
- bucket, err := getFoldersBucket(tx)
- if err != nil {
- return err
- }
- cursor := bucket.Cursor()
- itNum := 0
- if order == OrderASC {
- for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
- itNum++
- if itNum <= offset {
- continue
- }
- var folder vfs.BaseVirtualFolder
- err = json.Unmarshal(v, &folder)
- if err != nil {
- return err
- }
- folder.PrepareForRendering()
- folders = append(folders, folder)
- if len(folders) >= limit {
- break
- }
- }
- } else {
- for k, v := cursor.Last(); k != nil; k, v = cursor.Prev() {
- itNum++
- if itNum <= offset {
- continue
- }
- var folder vfs.BaseVirtualFolder
- err = json.Unmarshal(v, &folder)
- if err != nil {
- return err
- }
- folder.PrepareForRendering()
- folders = append(folders, folder)
- if len(folders) >= limit {
- break
- }
- }
- }
- return err
- })
- return folders, err
- }
- func (p *BoltProvider) getFolderByName(name string) (vfs.BaseVirtualFolder, error) {
- var folder vfs.BaseVirtualFolder
- err := p.dbHandle.View(func(tx *bolt.Tx) error {
- bucket, err := getFoldersBucket(tx)
- if err != nil {
- return err
- }
- folder, err = folderExistsInternal(name, bucket)
- return err
- })
- return folder, err
- }
- func (p *BoltProvider) addFolder(folder *vfs.BaseVirtualFolder) error {
- err := ValidateFolder(folder)
- if err != nil {
- return err
- }
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getFoldersBucket(tx)
- if err != nil {
- return err
- }
- if f := bucket.Get([]byte(folder.Name)); f != nil {
- return fmt.Errorf("folder %v already exists", folder.Name)
- }
- folder.Users = nil
- return addFolderInternal(*folder, bucket)
- })
- }
- func (p *BoltProvider) updateFolder(folder *vfs.BaseVirtualFolder) error {
- err := ValidateFolder(folder)
- if err != nil {
- return err
- }
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getFoldersBucket(tx)
- if err != nil {
- return err
- }
- var f []byte
- if f = bucket.Get([]byte(folder.Name)); f == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("folder %v does not exist", folder.Name))
- }
- var oldFolder vfs.BaseVirtualFolder
- err = json.Unmarshal(f, &oldFolder)
- if err != nil {
- return err
- }
- folder.ID = oldFolder.ID
- folder.LastQuotaUpdate = oldFolder.LastQuotaUpdate
- folder.UsedQuotaFiles = oldFolder.UsedQuotaFiles
- folder.UsedQuotaSize = oldFolder.UsedQuotaSize
- folder.Users = oldFolder.Users
- buf, err := json.Marshal(folder)
- if err != nil {
- return err
- }
- return bucket.Put([]byte(folder.Name), buf)
- })
- }
- func (p *BoltProvider) deleteFolder(folder *vfs.BaseVirtualFolder) error {
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getFoldersBucket(tx)
- if err != nil {
- return err
- }
- usersBucket, err := getUsersBucket(tx)
- if err != nil {
- return err
- }
- var f []byte
- if f = bucket.Get([]byte(folder.Name)); f == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("folder %v does not exist", folder.Name))
- }
- var folder vfs.BaseVirtualFolder
- err = json.Unmarshal(f, &folder)
- if err != nil {
- return err
- }
- for _, username := range folder.Users {
- var u []byte
- if u = usersBucket.Get([]byte(username)); u == nil {
- continue
- }
- var user User
- err = json.Unmarshal(u, &user)
- if err != nil {
- return err
- }
- var folders []vfs.VirtualFolder
- for _, userFolder := range user.VirtualFolders {
- if folder.Name != userFolder.Name {
- folders = append(folders, userFolder)
- }
- }
- user.VirtualFolders = folders
- buf, err := json.Marshal(user)
- if err != nil {
- return err
- }
- err = usersBucket.Put([]byte(user.Username), buf)
- if err != nil {
- return err
- }
- }
- return bucket.Delete([]byte(folder.Name))
- })
- }
- func (p *BoltProvider) updateFolderQuota(name string, filesAdd int, sizeAdd int64, reset bool) error {
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getFoldersBucket(tx)
- if err != nil {
- return err
- }
- var f []byte
- if f = bucket.Get([]byte(name)); f == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("folder %#v does not exist, unable to update quota", name))
- }
- var folder vfs.BaseVirtualFolder
- err = json.Unmarshal(f, &folder)
- if err != nil {
- return err
- }
- if reset {
- folder.UsedQuotaSize = sizeAdd
- folder.UsedQuotaFiles = filesAdd
- } else {
- folder.UsedQuotaSize += sizeAdd
- folder.UsedQuotaFiles += filesAdd
- }
- folder.LastQuotaUpdate = util.GetTimeAsMsSinceEpoch(time.Now())
- buf, err := json.Marshal(folder)
- if err != nil {
- return err
- }
- return bucket.Put([]byte(folder.Name), buf)
- })
- }
- func (p *BoltProvider) getUsedFolderQuota(name string) (int, int64, error) {
- folder, err := p.getFolderByName(name)
- if err != nil {
- providerLog(logger.LevelWarn, "unable to get quota for folder %#v error: %v", name, err)
- return 0, 0, err
- }
- return folder.UsedQuotaFiles, folder.UsedQuotaSize, err
- }
- func (p *BoltProvider) apiKeyExists(keyID string) (APIKey, error) {
- var apiKey APIKey
- err := p.dbHandle.View(func(tx *bolt.Tx) error {
- bucket, err := getAPIKeysBucket(tx)
- if err != nil {
- return err
- }
- k := bucket.Get([]byte(keyID))
- if k == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("API key %v does not exist", keyID))
- }
- return json.Unmarshal(k, &apiKey)
- })
- return apiKey, err
- }
- func (p *BoltProvider) addAPIKey(apiKey *APIKey) error {
- err := apiKey.validate()
- if err != nil {
- return err
- }
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getAPIKeysBucket(tx)
- if err != nil {
- return err
- }
- if a := bucket.Get([]byte(apiKey.KeyID)); a != nil {
- return fmt.Errorf("API key %v already exists", apiKey.KeyID)
- }
- id, err := bucket.NextSequence()
- if err != nil {
- return err
- }
- apiKey.ID = int64(id)
- apiKey.CreatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
- apiKey.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
- apiKey.LastUseAt = 0
- buf, err := json.Marshal(apiKey)
- if err != nil {
- return err
- }
- return bucket.Put([]byte(apiKey.KeyID), buf)
- })
- }
- func (p *BoltProvider) updateAPIKey(apiKey *APIKey) error {
- err := apiKey.validate()
- if err != nil {
- return err
- }
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getAPIKeysBucket(tx)
- if err != nil {
- return err
- }
- var a []byte
- if a = bucket.Get([]byte(apiKey.KeyID)); a == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("API key %v does not exist", apiKey.KeyID))
- }
- var oldAPIKey APIKey
- err = json.Unmarshal(a, &oldAPIKey)
- if err != nil {
- return err
- }
- apiKey.ID = oldAPIKey.ID
- apiKey.KeyID = oldAPIKey.KeyID
- apiKey.Key = oldAPIKey.Key
- apiKey.CreatedAt = oldAPIKey.CreatedAt
- apiKey.LastUseAt = oldAPIKey.LastUseAt
- apiKey.UpdatedAt = util.GetTimeAsMsSinceEpoch(time.Now())
- buf, err := json.Marshal(apiKey)
- if err != nil {
- return err
- }
- return bucket.Put([]byte(apiKey.KeyID), buf)
- })
- }
- func (p *BoltProvider) deleteAPIKeys(apiKey *APIKey) error {
- return p.dbHandle.Update(func(tx *bolt.Tx) error {
- bucket, err := getAPIKeysBucket(tx)
- if err != nil {
- return err
- }
- if bucket.Get([]byte(apiKey.KeyID)) == nil {
- return util.NewRecordNotFoundError(fmt.Sprintf("API key %v does not exist", apiKey.KeyID))
- }
- return bucket.Delete([]byte(apiKey.KeyID))
- })
- }
- func (p *BoltProvider) getAPIKeys(limit int, offset int, order string) ([]APIKey, error) {
- apiKeys := make([]APIKey, 0, limit)
- err := p.dbHandle.View(func(tx *bolt.Tx) error {
- bucket, err := getAPIKeysBucket(tx)
- if err != nil {
- return err
- }
- cursor := bucket.Cursor()
- itNum := 0
- if order == OrderASC {
- for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
- itNum++
- if itNum <= offset {
- continue
- }
- var apiKey APIKey
- err = json.Unmarshal(v, &apiKey)
- if err != nil {
- return err
- }
- apiKey.HideConfidentialData()
- apiKeys = append(apiKeys, apiKey)
- if len(apiKeys) >= limit {
- break
- }
- }
- return nil
- }
- for k, v := cursor.Last(); k != nil; k, v = cursor.Prev() {
- itNum++
- if itNum <= offset {
- continue
- }
- var apiKey APIKey
- err = json.Unmarshal(v, &apiKey)
- if err != nil {
- return err
- }
- apiKey.HideConfidentialData()
- apiKeys = append(apiKeys, apiKey)
- if len(apiKeys) >= limit {
- break
- }
- }
- return nil
- })
- return apiKeys, err
- }
- func (p *BoltProvider) dumpAPIKeys() ([]APIKey, error) {
- apiKeys := make([]APIKey, 0, 30)
- err := p.dbHandle.View(func(tx *bolt.Tx) error {
- bucket, err := getAPIKeysBucket(tx)
- if err != nil {
- return err
- }
- cursor := bucket.Cursor()
- for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
- var apiKey APIKey
- err = json.Unmarshal(v, &apiKey)
- if err != nil {
- return err
- }
- apiKeys = append(apiKeys, apiKey)
- }
- return err
- })
- return apiKeys, err
- }
- func (p *BoltProvider) close() error {
- return p.dbHandle.Close()
- }
- func (p *BoltProvider) reloadConfig() error {
- return nil
- }
- // initializeDatabase does nothing, no initilization is needed for bolt provider
- func (p *BoltProvider) initializeDatabase() error {
- return ErrNoInitRequired
- }
- func (p *BoltProvider) migrateDatabase() error {
- dbVersion, err := getBoltDatabaseVersion(p.dbHandle)
- if err != nil {
- return err
- }
- switch version := dbVersion.Version; {
- case version == boltDatabaseVersion:
- providerLog(logger.LevelDebug, "bolt database is up to date, current version: %v", version)
- return ErrNoInitRequired
- case version < 10:
- err = fmt.Errorf("database version %v is too old, please see the upgrading docs", version)
- providerLog(logger.LevelError, "%v", err)
- logger.ErrorToConsole("%v", err)
- return err
- case version == 10:
- return updateBoltDatabaseVersion(p.dbHandle, 12)
- case version == 11:
- return updateBoltDatabaseVersion(p.dbHandle, 12)
- default:
- if version > boltDatabaseVersion {
- providerLog(logger.LevelWarn, "database version %v is newer than the supported one: %v", version,
- boltDatabaseVersion)
- logger.WarnToConsole("database version %v is newer than the supported one: %v", version,
- boltDatabaseVersion)
- return nil
- }
- return fmt.Errorf("database version not handled: %v", version)
- }
- }
- func (p *BoltProvider) revertDatabase(targetVersion int) error {
- dbVersion, err := getBoltDatabaseVersion(p.dbHandle)
- if err != nil {
- return err
- }
- if dbVersion.Version == targetVersion {
- return errors.New("current version match target version, nothing to do")
- }
- switch dbVersion.Version {
- case 12:
- return updateBoltDatabaseVersion(p.dbHandle, 10)
- case 11:
- return updateBoltDatabaseVersion(p.dbHandle, 10)
- default:
- return fmt.Errorf("database version not handled: %v", dbVersion.Version)
- }
- }
- func joinUserAndFolders(u []byte, foldersBucket *bolt.Bucket) (User, error) {
- var user User
- err := json.Unmarshal(u, &user)
- if err != nil {
- return user, err
- }
- if len(user.VirtualFolders) > 0 {
- var folders []vfs.VirtualFolder
- for idx := range user.VirtualFolders {
- folder := &user.VirtualFolders[idx]
- baseFolder, err := folderExistsInternal(folder.Name, foldersBucket)
- if err != nil {
- continue
- }
- folder.BaseVirtualFolder = baseFolder
- folders = append(folders, *folder)
- }
- user.VirtualFolders = folders
- }
- user.SetEmptySecretsIfNil()
- return user, err
- }
- func folderExistsInternal(name string, bucket *bolt.Bucket) (vfs.BaseVirtualFolder, error) {
- var folder vfs.BaseVirtualFolder
- f := bucket.Get([]byte(name))
- if f == nil {
- err := util.NewRecordNotFoundError(fmt.Sprintf("folder %v does not exist", name))
- return folder, err
- }
- err := json.Unmarshal(f, &folder)
- return folder, err
- }
- func addFolderInternal(folder vfs.BaseVirtualFolder, bucket *bolt.Bucket) error {
- id, err := bucket.NextSequence()
- if err != nil {
- return err
- }
- folder.ID = int64(id)
- buf, err := json.Marshal(folder)
- if err != nil {
- return err
- }
- return bucket.Put([]byte(folder.Name), buf)
- }
- func addUserToFolderMapping(baseFolder *vfs.BaseVirtualFolder, user *User, bucket *bolt.Bucket) error {
- f := bucket.Get([]byte(baseFolder.Name))
- if f == nil {
- // folder does not exists, try to create
- baseFolder.LastQuotaUpdate = 0
- baseFolder.UsedQuotaFiles = 0
- baseFolder.UsedQuotaSize = 0
- baseFolder.Users = []string{user.Username}
- return addFolderInternal(*baseFolder, bucket)
- }
- var oldFolder vfs.BaseVirtualFolder
- err := json.Unmarshal(f, &oldFolder)
- if err != nil {
- return err
- }
- baseFolder.ID = oldFolder.ID
- baseFolder.LastQuotaUpdate = oldFolder.LastQuotaUpdate
- baseFolder.UsedQuotaFiles = oldFolder.UsedQuotaFiles
- baseFolder.UsedQuotaSize = oldFolder.UsedQuotaSize
- baseFolder.Users = oldFolder.Users
- if !util.IsStringInSlice(user.Username, baseFolder.Users) {
- baseFolder.Users = append(baseFolder.Users, user.Username)
- }
- buf, err := json.Marshal(baseFolder)
- if err != nil {
- return err
- }
- return bucket.Put([]byte(baseFolder.Name), buf)
- }
- func removeUserFromFolderMapping(folder *vfs.VirtualFolder, user *User, bucket *bolt.Bucket) error {
- var f []byte
- if f = bucket.Get([]byte(folder.Name)); f == nil {
- // the folder does not exists so there is no associated user
- return nil
- }
- var baseFolder vfs.BaseVirtualFolder
- err := json.Unmarshal(f, &baseFolder)
- if err != nil {
- return err
- }
- if util.IsStringInSlice(user.Username, baseFolder.Users) {
- var newUserMapping []string
- for _, u := range baseFolder.Users {
- if u != user.Username {
- newUserMapping = append(newUserMapping, u)
- }
- }
- baseFolder.Users = newUserMapping
- buf, err := json.Marshal(baseFolder)
- if err != nil {
- return err
- }
- return bucket.Put([]byte(folder.Name), buf)
- }
- return err
- }
- func deleteRelatedAPIKey(tx *bolt.Tx, username string, scope APIKeyScope) error {
- bucket, err := getAPIKeysBucket(tx)
- if err != nil {
- return err
- }
- var toRemove []string
- cursor := bucket.Cursor()
- for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
- var apiKey APIKey
- err = json.Unmarshal(v, &apiKey)
- if err != nil {
- return err
- }
- if scope == APIKeyScopeUser {
- if apiKey.User == username {
- toRemove = append(toRemove, apiKey.KeyID)
- }
- } else {
- if apiKey.Admin == username {
- toRemove = append(toRemove, apiKey.KeyID)
- }
- }
- }
- for _, k := range toRemove {
- if err := bucket.Delete([]byte(k)); err != nil {
- return err
- }
- }
- return nil
- }
- func getAPIKeysBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
- var err error
- bucket := tx.Bucket(apiKeysBucket)
- if bucket == nil {
- err = errors.New("unable to find api keys bucket, bolt database structure not correcly defined")
- }
- return bucket, err
- }
- func getAdminsBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
- var err error
- bucket := tx.Bucket(adminsBucket)
- if bucket == nil {
- err = errors.New("unable to find admins bucket, bolt database structure not correcly defined")
- }
- return bucket, err
- }
- func getUsersBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
- var err error
- bucket := tx.Bucket(usersBucket)
- if bucket == nil {
- err = errors.New("unable to find users bucket, bolt database structure not correcly defined")
- }
- return bucket, err
- }
- func getFoldersBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
- var err error
- bucket := tx.Bucket(foldersBucket)
- if bucket == nil {
- err = fmt.Errorf("unable to find folders buckets, bolt database structure not correcly defined")
- }
- return bucket, err
- }
- func getBoltDatabaseVersion(dbHandle *bolt.DB) (schemaVersion, error) {
- var dbVersion schemaVersion
- err := dbHandle.View(func(tx *bolt.Tx) error {
- bucket := tx.Bucket(dbVersionBucket)
- if bucket == nil {
- return fmt.Errorf("unable to find database version bucket")
- }
- v := bucket.Get(dbVersionKey)
- if v == nil {
- dbVersion = schemaVersion{
- Version: 10,
- }
- return nil
- }
- return json.Unmarshal(v, &dbVersion)
- })
- return dbVersion, err
- }
- func updateBoltDatabaseVersion(dbHandle *bolt.DB, version int) error {
- err := dbHandle.Update(func(tx *bolt.Tx) error {
- bucket := tx.Bucket(dbVersionBucket)
- if bucket == nil {
- return fmt.Errorf("unable to find database version bucket")
- }
- newDbVersion := schemaVersion{
- Version: version,
- }
- buf, err := json.Marshal(newDbVersion)
- if err != nil {
- return err
- }
- return bucket.Put(dbVersionKey, buf)
- })
- return err
- }
|