2022-07-18 11:43:25 +00:00
// Copyright (C) 2019-2022 Nicola Murino
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2019-07-20 10:26:52 +00:00
package dataprovider
import (
2019-09-14 14:18:31 +00:00
"context"
2021-02-28 11:10:40 +00:00
"crypto/x509"
2019-07-20 10:26:52 +00:00
"database/sql"
"encoding/json"
"errors"
2021-02-01 18:04:15 +00:00
"fmt"
2022-04-28 10:55:01 +00:00
"runtime/debug"
2020-06-07 21:30:18 +00:00
"strings"
2019-07-20 10:26:52 +00:00
"time"
2021-03-23 18:14:15 +00:00
"github.com/cockroachdb/cockroach-go/v2/crdb"
2022-04-25 13:49:11 +00:00
"github.com/sftpgo/sdk"
2021-03-23 18:14:15 +00:00
2021-06-26 05:31:41 +00:00
"github.com/drakkan/sftpgo/v2/logger"
2021-07-11 13:26:51 +00:00
"github.com/drakkan/sftpgo/v2/util"
2021-06-26 05:31:41 +00:00
"github.com/drakkan/sftpgo/v2/vfs"
2019-07-20 10:26:52 +00:00
)
2020-02-08 13:44:25 +00:00
const (
2022-05-19 17:49:51 +00:00
sqlDatabaseVersion = 19
2020-07-08 16:54:44 +00:00
defaultSQLQueryTimeout = 10 * time . Second
longSQLQueryTimeout = 60 * time . Second
2020-02-08 13:44:25 +00:00
)
2021-11-15 17:40:31 +00:00
var (
2022-04-25 13:49:11 +00:00
errSQLFoldersAssociation = errors . New ( "unable to associate virtual folders to user" )
errSQLGroupsAssociation = errors . New ( "unable to associate groups to user" )
errSQLUsersAssociation = errors . New ( "unable to associate users to group" )
2021-11-15 17:40:31 +00:00
errSchemaVersionEmpty = errors . New ( "we can't determine schema version because the schema_migration table is empty. The SFTPGo database might be corrupted. Consider using the \"resetprovider\" sub-command" )
)
2020-06-07 21:30:18 +00:00
type sqlQuerier interface {
2020-07-08 16:54:44 +00:00
PrepareContext ( ctx context . Context , query string ) ( * sql . Stmt , error )
2020-06-07 21:30:18 +00:00
}
2021-01-17 21:29:08 +00:00
type sqlScanner interface {
2022-05-19 17:49:51 +00:00
Scan ( dest ... any ) error
2021-01-17 21:29:08 +00:00
}
2022-04-25 13:49:11 +00:00
func sqlReplaceAll ( sql string ) string {
sql = strings . ReplaceAll ( sql , "{{schema_version}}" , sqlTableSchemaVersion )
sql = strings . ReplaceAll ( sql , "{{admins}}" , sqlTableAdmins )
sql = strings . ReplaceAll ( sql , "{{folders}}" , sqlTableFolders )
sql = strings . ReplaceAll ( sql , "{{users}}" , sqlTableUsers )
sql = strings . ReplaceAll ( sql , "{{groups}}" , sqlTableGroups )
sql = strings . ReplaceAll ( sql , "{{folders_mapping}}" , sqlTableFoldersMapping )
sql = strings . ReplaceAll ( sql , "{{users_folders_mapping}}" , sqlTableUsersFoldersMapping )
sql = strings . ReplaceAll ( sql , "{{users_groups_mapping}}" , sqlTableUsersGroupsMapping )
sql = strings . ReplaceAll ( sql , "{{groups_folders_mapping}}" , sqlTableGroupsFoldersMapping )
sql = strings . ReplaceAll ( sql , "{{api_keys}}" , sqlTableAPIKeys )
sql = strings . ReplaceAll ( sql , "{{shares}}" , sqlTableShares )
sql = strings . ReplaceAll ( sql , "{{defender_events}}" , sqlTableDefenderEvents )
sql = strings . ReplaceAll ( sql , "{{defender_hosts}}" , sqlTableDefenderHosts )
sql = strings . ReplaceAll ( sql , "{{active_transfers}}" , sqlTableActiveTransfers )
2022-06-13 17:40:24 +00:00
sql = strings . ReplaceAll ( sql , "{{shared_sessions}}" , sqlTableSharedSessions )
2022-04-25 13:49:11 +00:00
sql = strings . ReplaceAll ( sql , "{{prefix}}" , config . SQLTablesPrefix )
return sql
}
2021-11-06 13:13:20 +00:00
func sqlCommonGetShareByID ( shareID , username string , dbHandle sqlQuerier ) ( Share , error ) {
var share Share
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
filterUser := username != ""
q := getShareByIDQuery ( filterUser )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-11-06 13:13:20 +00:00
return share , err
}
defer stmt . Close ( )
var row * sql . Row
if filterUser {
row = stmt . QueryRowContext ( ctx , shareID , username )
} else {
row = stmt . QueryRowContext ( ctx , shareID )
}
return getShareFromDbRow ( row )
}
func sqlCommonAddShare ( share * Share , dbHandle * sql . DB ) error {
err := share . validate ( )
if err != nil {
return err
}
user , err := provider . userExists ( share . Username )
if err != nil {
return util . NewValidationError ( fmt . Sprintf ( "unable to validate user %#v" , share . Username ) )
}
paths , err := json . Marshal ( share . Paths )
if err != nil {
return err
}
allowFrom := ""
if len ( share . AllowFrom ) > 0 {
res , err := json . Marshal ( share . AllowFrom )
if err == nil {
allowFrom = string ( res )
}
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getAddShareQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-11-06 13:13:20 +00:00
return err
}
defer stmt . Close ( )
2021-11-27 10:12:51 +00:00
usedTokens := 0
createdAt := util . GetTimeAsMsSinceEpoch ( time . Now ( ) )
updatedAt := createdAt
lastUseAt := int64 ( 0 )
if share . IsRestore {
usedTokens = share . UsedTokens
if share . CreatedAt > 0 {
createdAt = share . CreatedAt
}
if share . UpdatedAt > 0 {
updatedAt = share . UpdatedAt
}
lastUseAt = share . LastUseAt
}
2021-11-06 13:13:20 +00:00
_ , err = stmt . ExecContext ( ctx , share . ShareID , share . Name , share . Description , share . Scope ,
2021-11-27 10:12:51 +00:00
string ( paths ) , createdAt , updatedAt , lastUseAt , share . ExpiresAt , share . Password ,
share . MaxTokens , usedTokens , allowFrom , user . ID )
2021-11-06 13:13:20 +00:00
return err
}
func sqlCommonUpdateShare ( share * Share , dbHandle * sql . DB ) error {
err := share . validate ( )
if err != nil {
return err
}
paths , err := json . Marshal ( share . Paths )
if err != nil {
return err
}
allowFrom := ""
if len ( share . AllowFrom ) > 0 {
res , err := json . Marshal ( share . AllowFrom )
if err == nil {
allowFrom = string ( res )
}
}
user , err := provider . userExists ( share . Username )
if err != nil {
return util . NewValidationError ( fmt . Sprintf ( "unable to validate user %#v" , share . Username ) )
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2021-11-27 10:12:51 +00:00
var q string
if share . IsRestore {
q = getUpdateShareRestoreQuery ( )
} else {
q = getUpdateShareQuery ( )
}
2021-11-06 13:13:20 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-11-06 13:13:20 +00:00
return err
}
defer stmt . Close ( )
2021-11-27 10:12:51 +00:00
if share . IsRestore {
if share . CreatedAt == 0 {
share . CreatedAt = util . GetTimeAsMsSinceEpoch ( time . Now ( ) )
}
if share . UpdatedAt == 0 {
share . UpdatedAt = share . CreatedAt
}
_ , err = stmt . ExecContext ( ctx , share . Name , share . Description , share . Scope , string ( paths ) ,
share . CreatedAt , share . UpdatedAt , share . LastUseAt , share . ExpiresAt , share . Password , share . MaxTokens ,
share . UsedTokens , allowFrom , user . ID , share . ShareID )
} else {
_ , err = stmt . ExecContext ( ctx , share . Name , share . Description , share . Scope , string ( paths ) ,
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , share . ExpiresAt , share . Password , share . MaxTokens ,
allowFrom , user . ID , share . ShareID )
}
2021-11-06 13:13:20 +00:00
return err
}
2022-04-25 13:49:11 +00:00
func sqlCommonDeleteShare ( share Share , dbHandle * sql . DB ) error {
2021-11-06 13:13:20 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDeleteShareQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-11-06 13:13:20 +00:00
return err
}
defer stmt . Close ( )
2022-05-19 17:49:51 +00:00
res , err := stmt . ExecContext ( ctx , share . ShareID )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
2021-11-06 13:13:20 +00:00
}
func sqlCommonGetShares ( limit , offset int , order , username string , dbHandle sqlQuerier ) ( [ ] Share , error ) {
shares := make ( [ ] Share , 0 , limit )
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getSharesQuery ( order )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-11-06 13:13:20 +00:00
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx , username , limit , offset )
if err != nil {
return shares , err
}
defer rows . Close ( )
for rows . Next ( ) {
s , err := getShareFromDbRow ( rows )
if err != nil {
return shares , err
}
s . HideConfidentialData ( )
shares = append ( shares , s )
}
return shares , rows . Err ( )
}
func sqlCommonDumpShares ( dbHandle sqlQuerier ) ( [ ] Share , error ) {
shares := make ( [ ] Share , 0 , 30 )
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDumpSharesQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-11-06 13:13:20 +00:00
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx )
if err != nil {
return shares , err
}
defer rows . Close ( )
for rows . Next ( ) {
s , err := getShareFromDbRow ( rows )
if err != nil {
return shares , err
}
shares = append ( shares , s )
}
return shares , rows . Err ( )
}
2021-08-17 16:08:32 +00:00
func sqlCommonGetAPIKeyByID ( keyID string , dbHandle sqlQuerier ) ( APIKey , error ) {
var apiKey APIKey
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2021-11-06 13:13:20 +00:00
2021-08-17 16:08:32 +00:00
q := getAPIKeyByIDQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-08-17 16:08:32 +00:00
return apiKey , err
}
defer stmt . Close ( )
row := stmt . QueryRowContext ( ctx , keyID )
apiKey , err = getAPIKeyFromDbRow ( row )
if err != nil {
return apiKey , err
}
return getAPIKeyWithRelatedFields ( ctx , apiKey , dbHandle )
}
func sqlCommonAddAPIKey ( apiKey * APIKey , dbHandle * sql . DB ) error {
err := apiKey . validate ( )
if err != nil {
return err
}
userID , adminID , err := sqlCommonGetAPIKeyRelatedIDs ( apiKey )
if err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getAddAPIKeyQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-08-17 16:08:32 +00:00
return err
}
defer stmt . Close ( )
2021-08-19 13:51:43 +00:00
_ , err = stmt . ExecContext ( ctx , apiKey . KeyID , apiKey . Name , apiKey . Key , apiKey . Scope , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
2021-08-17 16:08:32 +00:00
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , apiKey . LastUseAt , apiKey . ExpiresAt , apiKey . Description ,
userID , adminID )
return err
}
func sqlCommonUpdateAPIKey ( apiKey * APIKey , dbHandle * sql . DB ) error {
err := apiKey . validate ( )
if err != nil {
return err
}
userID , adminID , err := sqlCommonGetAPIKeyRelatedIDs ( apiKey )
if err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateAPIKeyQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-08-17 16:08:32 +00:00
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , apiKey . Name , apiKey . Scope , apiKey . ExpiresAt , userID , adminID ,
apiKey . Description , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , apiKey . KeyID )
return err
}
2022-04-25 13:49:11 +00:00
func sqlCommonDeleteAPIKey ( apiKey APIKey , dbHandle * sql . DB ) error {
2021-08-17 16:08:32 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDeleteAPIKeyQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-08-17 16:08:32 +00:00
return err
}
defer stmt . Close ( )
2022-05-19 17:49:51 +00:00
res , err := stmt . ExecContext ( ctx , apiKey . KeyID )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
2021-08-17 16:08:32 +00:00
}
func sqlCommonGetAPIKeys ( limit , offset int , order string , dbHandle sqlQuerier ) ( [ ] APIKey , error ) {
apiKeys := make ( [ ] APIKey , 0 , limit )
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getAPIKeysQuery ( order )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-08-17 16:08:32 +00:00
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx , limit , offset )
if err != nil {
return apiKeys , err
}
defer rows . Close ( )
for rows . Next ( ) {
k , err := getAPIKeyFromDbRow ( rows )
if err != nil {
return apiKeys , err
}
k . HideConfidentialData ( )
apiKeys = append ( apiKeys , k )
}
err = rows . Err ( )
if err != nil {
return apiKeys , err
}
apiKeys , err = getRelatedValuesForAPIKeys ( ctx , apiKeys , dbHandle , APIKeyScopeAdmin )
if err != nil {
return apiKeys , err
}
return getRelatedValuesForAPIKeys ( ctx , apiKeys , dbHandle , APIKeyScopeUser )
}
func sqlCommonDumpAPIKeys ( dbHandle sqlQuerier ) ( [ ] APIKey , error ) {
apiKeys := make ( [ ] APIKey , 0 , 30 )
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDumpAPIKeysQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-08-17 16:08:32 +00:00
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx )
if err != nil {
return apiKeys , err
}
defer rows . Close ( )
for rows . Next ( ) {
k , err := getAPIKeyFromDbRow ( rows )
if err != nil {
return apiKeys , err
}
apiKeys = append ( apiKeys , k )
}
err = rows . Err ( )
if err != nil {
return apiKeys , err
}
apiKeys , err = getRelatedValuesForAPIKeys ( ctx , apiKeys , dbHandle , APIKeyScopeAdmin )
if err != nil {
return apiKeys , err
}
return getRelatedValuesForAPIKeys ( ctx , apiKeys , dbHandle , APIKeyScopeUser )
}
2021-01-17 21:29:08 +00:00
func sqlCommonGetAdminByUsername ( username string , dbHandle sqlQuerier ) ( Admin , error ) {
var admin Admin
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getAdminByUsernameQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-01-17 21:29:08 +00:00
return admin , err
}
defer stmt . Close ( )
row := stmt . QueryRowContext ( ctx , username )
return getAdminFromDbRow ( row )
}
func sqlCommonValidateAdminAndPass ( username , password , ip string , dbHandle * sql . DB ) ( Admin , error ) {
admin , err := sqlCommonGetAdminByUsername ( username , dbHandle )
if err != nil {
providerLog ( logger . LevelWarn , "error authenticating admin %#v: %v" , username , err )
2021-04-26 17:48:21 +00:00
return admin , ErrInvalidCredentials
2021-01-17 21:29:08 +00:00
}
err = admin . checkUserAndPass ( password , ip )
return admin , err
}
func sqlCommonAddAdmin ( admin * Admin , dbHandle * sql . DB ) error {
err := admin . validate ( )
if err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getAddAdminQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-01-17 21:29:08 +00:00
return err
}
defer stmt . Close ( )
perms , err := json . Marshal ( admin . Permissions )
if err != nil {
return err
}
filters , err := json . Marshal ( admin . Filters )
if err != nil {
return err
}
_ , err = stmt . ExecContext ( ctx , admin . Username , admin . Password , admin . Status , admin . Email , string ( perms ) ,
2021-08-19 13:51:43 +00:00
string ( filters ) , admin . AdditionalInfo , admin . Description , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) )
2021-01-17 21:29:08 +00:00
return err
}
func sqlCommonUpdateAdmin ( admin * Admin , dbHandle * sql . DB ) error {
err := admin . validate ( )
if err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateAdminQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-01-17 21:29:08 +00:00
return err
}
defer stmt . Close ( )
perms , err := json . Marshal ( admin . Permissions )
if err != nil {
return err
}
filters , err := json . Marshal ( admin . Filters )
if err != nil {
return err
}
_ , err = stmt . ExecContext ( ctx , admin . Password , admin . Status , admin . Email , string ( perms ) , string ( filters ) ,
2021-08-19 13:51:43 +00:00
admin . AdditionalInfo , admin . Description , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , admin . Username )
2021-01-17 21:29:08 +00:00
return err
}
2022-04-25 13:49:11 +00:00
func sqlCommonDeleteAdmin ( admin Admin , dbHandle * sql . DB ) error {
2021-01-17 21:29:08 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDeleteAdminQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-01-17 21:29:08 +00:00
return err
}
defer stmt . Close ( )
2022-05-19 17:49:51 +00:00
res , err := stmt . ExecContext ( ctx , admin . Username )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
2021-01-17 21:29:08 +00:00
}
func sqlCommonGetAdmins ( limit , offset int , order string , dbHandle sqlQuerier ) ( [ ] Admin , error ) {
admins := make ( [ ] Admin , 0 , limit )
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getAdminsQuery ( order )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-01-17 21:29:08 +00:00
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx , limit , offset )
if err != nil {
return admins , err
}
defer rows . Close ( )
for rows . Next ( ) {
a , err := getAdminFromDbRow ( rows )
if err != nil {
return admins , err
}
a . HideConfidentialData ( )
admins = append ( admins , a )
}
return admins , rows . Err ( )
}
func sqlCommonDumpAdmins ( dbHandle sqlQuerier ) ( [ ] Admin , error ) {
admins := make ( [ ] Admin , 0 , 30 )
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDumpAdminsQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-01-17 21:29:08 +00:00
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx )
if err != nil {
return admins , err
}
defer rows . Close ( )
for rows . Next ( ) {
a , err := getAdminFromDbRow ( rows )
if err != nil {
return admins , err
}
admins = append ( admins , a )
}
return admins , rows . Err ( )
}
2022-04-25 13:49:11 +00:00
func sqlCommonGetGroupByName ( name string , dbHandle sqlQuerier ) ( Group , error ) {
var group Group
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getGroupByNameQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return group , err
}
defer stmt . Close ( )
row := stmt . QueryRowContext ( ctx , name )
group , err = getGroupFromDbRow ( row )
if err != nil {
return group , err
}
group , err = getGroupWithVirtualFolders ( ctx , group , dbHandle )
if err != nil {
return group , err
}
return getGroupWithUsers ( ctx , group , dbHandle )
}
func sqlCommonDumpGroups ( dbHandle sqlQuerier ) ( [ ] Group , error ) {
groups := make ( [ ] Group , 0 , 50 )
ctx , cancel := context . WithTimeout ( context . Background ( ) , longSQLQueryTimeout )
defer cancel ( )
q := getDumpGroupsQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx )
if err != nil {
return groups , err
}
defer rows . Close ( )
for rows . Next ( ) {
group , err := getGroupFromDbRow ( rows )
if err != nil {
return groups , err
}
groups = append ( groups , group )
}
2022-06-21 12:13:25 +00:00
err = rows . Err ( )
if err != nil {
return groups , err
}
return getGroupsWithVirtualFolders ( ctx , groups , dbHandle )
2022-04-25 13:49:11 +00:00
}
func sqlCommonGetUsersInGroups ( names [ ] string , dbHandle sqlQuerier ) ( [ ] string , error ) {
if len ( names ) == 0 {
return nil , nil
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUsersInGroupsQuery ( len ( names ) )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return nil , err
}
defer stmt . Close ( )
2022-05-19 17:49:51 +00:00
args := make ( [ ] any , 0 , len ( names ) )
2022-04-25 13:49:11 +00:00
for _ , name := range names {
args = append ( args , name )
}
usernames := make ( [ ] string , 0 , len ( names ) )
rows , err := stmt . QueryContext ( ctx , args ... )
2022-05-14 09:54:55 +00:00
if err != nil {
return nil , err
}
defer rows . Close ( )
for rows . Next ( ) {
var username string
err = rows . Scan ( & username )
if err != nil {
return usernames , err
2022-04-25 13:49:11 +00:00
}
2022-05-14 09:54:55 +00:00
usernames = append ( usernames , username )
2022-04-25 13:49:11 +00:00
}
return usernames , rows . Err ( )
}
func sqlCommonGetGroupsWithNames ( names [ ] string , dbHandle sqlQuerier ) ( [ ] Group , error ) {
if len ( names ) == 0 {
return nil , nil
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getGroupsWithNamesQuery ( len ( names ) )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return nil , err
}
defer stmt . Close ( )
2022-05-19 17:49:51 +00:00
args := make ( [ ] any , 0 , len ( names ) )
2022-04-25 13:49:11 +00:00
for _ , name := range names {
args = append ( args , name )
}
groups := make ( [ ] Group , 0 , len ( names ) )
rows , err := stmt . QueryContext ( ctx , args ... )
2022-05-14 09:54:55 +00:00
if err != nil {
return groups , err
}
defer rows . Close ( )
for rows . Next ( ) {
group , err := getGroupFromDbRow ( rows )
if err != nil {
return groups , err
2022-04-25 13:49:11 +00:00
}
2022-05-14 09:54:55 +00:00
groups = append ( groups , group )
2022-04-25 13:49:11 +00:00
}
err = rows . Err ( )
if err != nil {
return groups , err
}
return getGroupsWithVirtualFolders ( ctx , groups , dbHandle )
}
func sqlCommonGetGroups ( limit int , offset int , order string , minimal bool , dbHandle sqlQuerier ) ( [ ] Group , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getGroupsQuery ( order , minimal )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return nil , err
}
defer stmt . Close ( )
groups := make ( [ ] Group , 0 , limit )
rows , err := stmt . QueryContext ( ctx , limit , offset )
if err == nil {
defer rows . Close ( )
for rows . Next ( ) {
var group Group
if minimal {
err = rows . Scan ( & group . ID , & group . Name )
} else {
group , err = getGroupFromDbRow ( rows )
}
if err != nil {
return groups , err
}
groups = append ( groups , group )
}
}
err = rows . Err ( )
if err != nil {
return groups , err
}
if minimal {
return groups , nil
}
groups , err = getGroupsWithVirtualFolders ( ctx , groups , dbHandle )
if err != nil {
return groups , err
}
groups , err = getGroupsWithUsers ( ctx , groups , dbHandle )
if err != nil {
return groups , err
}
for idx := range groups {
groups [ idx ] . PrepareForRendering ( )
}
return groups , nil
}
func sqlCommonAddGroup ( group * Group , dbHandle * sql . DB ) error {
if err := group . validate ( ) ; err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
q := getAddGroupQuery ( )
stmt , err := tx . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
settings , err := json . Marshal ( group . UserSettings )
if err != nil {
return err
}
_ , err = stmt . ExecContext ( ctx , group . Name , group . Description , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , string ( settings ) )
if err != nil {
return err
}
return generateGroupVirtualFoldersMapping ( ctx , group , tx )
} )
}
func sqlCommonUpdateGroup ( group * Group , dbHandle * sql . DB ) error {
if err := group . validate ( ) ; err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
q := getUpdateGroupQuery ( )
stmt , err := tx . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
settings , err := json . Marshal ( group . UserSettings )
if err != nil {
return err
}
_ , err = stmt . ExecContext ( ctx , group . Description , settings , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , group . Name )
if err != nil {
return err
}
return generateGroupVirtualFoldersMapping ( ctx , group , tx )
} )
}
func sqlCommonDeleteGroup ( group Group , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDeleteGroupQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
2022-05-19 17:49:51 +00:00
res , err := stmt . ExecContext ( ctx , group . Name )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
2022-04-25 13:49:11 +00:00
}
2021-01-17 21:29:08 +00:00
func sqlCommonGetUserByUsername ( username string , dbHandle sqlQuerier ) ( User , error ) {
2019-07-20 10:26:52 +00:00
var user User
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2022-04-25 13:49:11 +00:00
2019-07-20 10:26:52 +00:00
q := getUserByUsernameQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2019-07-20 10:26:52 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2019-07-20 10:26:52 +00:00
return user , err
}
defer stmt . Close ( )
2020-07-08 16:54:44 +00:00
row := stmt . QueryRowContext ( ctx , username )
2021-01-17 21:29:08 +00:00
user , err = getUserFromDbRow ( row )
2020-06-07 21:30:18 +00:00
if err != nil {
return user , err
}
2022-04-25 13:49:11 +00:00
user , err = getUserWithVirtualFolders ( ctx , user , dbHandle )
if err != nil {
return user , err
}
return getUserWithGroups ( ctx , user , dbHandle )
2019-07-20 10:26:52 +00:00
}
2020-08-19 17:36:12 +00:00
func sqlCommonValidateUserAndPass ( username , password , ip , protocol string , dbHandle * sql . DB ) ( User , error ) {
2019-07-20 10:26:52 +00:00
var user User
2021-01-05 08:50:22 +00:00
if password == "" {
2021-03-21 18:15:47 +00:00
return user , errors . New ( "credentials cannot be null or empty" )
2019-07-20 10:26:52 +00:00
}
2021-01-17 21:29:08 +00:00
user , err := sqlCommonGetUserByUsername ( username , dbHandle )
2019-07-20 10:26:52 +00:00
if err != nil {
2021-01-04 16:52:14 +00:00
providerLog ( logger . LevelWarn , "error authenticating user %#v: %v" , username , err )
2021-05-06 19:35:43 +00:00
return user , err
2019-07-20 10:26:52 +00:00
}
2021-02-16 18:11:36 +00:00
return checkUserAndPass ( & user , password , ip , protocol )
2019-07-20 10:26:52 +00:00
}
2021-02-28 11:10:40 +00:00
func sqlCommonValidateUserAndTLSCertificate ( username , protocol string , tlsCert * x509 . Certificate , dbHandle * sql . DB ) ( User , error ) {
var user User
if tlsCert == nil {
return user , errors . New ( "TLS certificate cannot be null or empty" )
}
user , err := sqlCommonGetUserByUsername ( username , dbHandle )
if err != nil {
providerLog ( logger . LevelWarn , "error authenticating user %#v: %v" , username , err )
2021-05-06 19:35:43 +00:00
return user , err
2021-02-28 11:10:40 +00:00
}
return checkUserAndTLSCertificate ( & user , protocol , tlsCert )
}
2022-03-31 16:16:50 +00:00
func sqlCommonValidateUserAndPubKey ( username string , pubKey [ ] byte , isSSHCert bool , dbHandle * sql . DB ) ( User , string , error ) {
2019-07-20 10:26:52 +00:00
var user User
if len ( pubKey ) == 0 {
2021-03-21 18:15:47 +00:00
return user , "" , errors . New ( "credentials cannot be null or empty" )
2019-07-20 10:26:52 +00:00
}
2021-01-17 21:29:08 +00:00
user , err := sqlCommonGetUserByUsername ( username , dbHandle )
2019-07-20 10:26:52 +00:00
if err != nil {
2021-01-04 16:52:14 +00:00
providerLog ( logger . LevelWarn , "error authenticating user %#v: %v" , username , err )
2021-05-06 19:35:43 +00:00
return user , "" , err
2019-07-20 19:17:53 +00:00
}
2022-03-31 16:16:50 +00:00
return checkUserAndPubKey ( & user , pubKey , isSSHCert )
2019-07-20 10:26:52 +00:00
}
2022-04-28 10:55:01 +00:00
func sqlCommonCheckAvailability ( dbHandle * sql . DB ) ( err error ) {
defer func ( ) {
if r := recover ( ) ; r != nil {
providerLog ( logger . LevelError , "panic in check provider availability, stack trace: %v" , string ( debug . Stack ( ) ) )
err = errors . New ( "unable to check provider status" )
}
} ( )
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
2019-09-14 14:18:31 +00:00
defer cancel ( )
2022-04-28 10:55:01 +00:00
err = dbHandle . PingContext ( ctx )
return
2019-09-13 16:45:36 +00:00
}
2022-01-30 10:42:36 +00:00
func sqlCommonUpdateTransferQuota ( username string , uploadSize , downloadSize int64 , reset bool , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateTransferQuotaQuery ( reset )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , uploadSize , downloadSize , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , username )
if err == nil {
providerLog ( logger . LevelDebug , "transfer quota updated for user %#v, ul increment: %v dl increment: %v is reset? %v" ,
username , uploadSize , downloadSize , reset )
} else {
providerLog ( logger . LevelError , "error updating quota for user %#v: %v" , username , err )
}
return err
}
2019-08-11 12:53:37 +00:00
func sqlCommonUpdateQuota ( username string , filesAdd int , sizeAdd int64 , reset bool , dbHandle * sql . DB ) error {
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2019-07-28 11:24:46 +00:00
q := getUpdateQuotaQuery ( reset )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2019-07-20 10:26:52 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2019-07-20 10:26:52 +00:00
return err
}
defer stmt . Close ( )
2021-07-11 13:26:51 +00:00
_ , err = stmt . ExecContext ( ctx , sizeAdd , filesAdd , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , username )
2019-07-20 10:26:52 +00:00
if err == nil {
2019-11-13 10:36:21 +00:00
providerLog ( logger . LevelDebug , "quota updated for user %#v, files increment: %v size increment: %v is reset? %v" ,
2019-07-28 11:24:46 +00:00
username , filesAdd , sizeAdd , reset )
2019-07-20 10:26:52 +00:00
} else {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error updating quota for user %#v: %v" , username , err )
2019-11-13 10:36:21 +00:00
}
return err
}
2022-01-30 10:42:36 +00:00
func sqlCommonGetUsedQuota ( username string , dbHandle * sql . DB ) ( int , int64 , int64 , int64 , error ) {
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2019-07-20 10:26:52 +00:00
q := getQuotaQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2019-07-20 10:26:52 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2022-01-30 10:42:36 +00:00
return 0 , 0 , 0 , 0 , err
2019-07-20 10:26:52 +00:00
}
defer stmt . Close ( )
var usedFiles int
2022-01-30 10:42:36 +00:00
var usedSize , usedUploadSize , usedDownloadSize int64
err = stmt . QueryRowContext ( ctx , username ) . Scan ( & usedSize , & usedFiles , & usedUploadSize , & usedDownloadSize )
2019-07-20 10:26:52 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error getting quota for user: %v, error: %v" , username , err )
2022-01-30 10:42:36 +00:00
return 0 , 0 , 0 , 0 , err
2019-07-20 10:26:52 +00:00
}
2022-01-30 10:42:36 +00:00
return usedFiles , usedSize , usedUploadSize , usedDownloadSize , err
2019-07-20 10:26:52 +00:00
}
2021-11-06 13:13:20 +00:00
func sqlCommonUpdateShareLastUse ( shareID string , numTokens int , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateShareLastUseQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-11-06 13:13:20 +00:00
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , numTokens , shareID )
if err == nil {
providerLog ( logger . LevelDebug , "last use updated for shared object %#v" , shareID )
} else {
providerLog ( logger . LevelWarn , "error updating last use for shared object %#v: %v" , shareID , err )
}
return err
}
2021-08-17 16:08:32 +00:00
func sqlCommonUpdateAPIKeyLastUse ( keyID string , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateAPIKeyLastUseQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-08-17 16:08:32 +00:00
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , keyID )
if err == nil {
providerLog ( logger . LevelDebug , "last use updated for key %#v" , keyID )
} else {
providerLog ( logger . LevelWarn , "error updating last use for key %#v: %v" , keyID , err )
}
return err
}
2021-08-19 13:51:43 +00:00
func sqlCommonUpdateAdminLastLogin ( username string , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateAdminLastLoginQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-08-19 13:51:43 +00:00
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , username )
if err == nil {
providerLog ( logger . LevelDebug , "last login updated for admin %#v" , username )
} else {
providerLog ( logger . LevelWarn , "error updating last login for admin %#v: %v" , username , err )
}
return err
}
func sqlCommonSetUpdatedAt ( username string , dbHandle * sql . DB ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getSetUpdateAtQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-08-19 13:51:43 +00:00
return
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , username )
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 )
}
}
2020-06-07 21:30:18 +00:00
func sqlCommonUpdateLastLogin ( username string , dbHandle * sql . DB ) error {
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2020-06-07 21:30:18 +00:00
q := getUpdateLastLoginQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-06-07 21:30:18 +00:00
return err
}
defer stmt . Close ( )
2021-07-11 13:26:51 +00:00
_ , err = stmt . ExecContext ( ctx , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , username )
2020-06-07 21:30:18 +00:00
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
}
2021-01-05 08:50:22 +00:00
func sqlCommonAddUser ( user * User , dbHandle * sql . DB ) error {
2021-01-25 20:31:33 +00:00
err := ValidateUser ( user )
2019-07-20 10:26:52 +00:00
if err != nil {
return err
}
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2021-02-16 18:11:36 +00:00
2021-03-23 18:14:15 +00:00
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
q := getAddUserQuery ( )
stmt , err := tx . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-03-23 18:14:15 +00:00
return err
}
defer stmt . Close ( )
permissions , err := user . GetPermissionsAsJSON ( )
if err != nil {
return err
}
publicKeys , err := user . GetPublicKeysAsJSON ( )
if err != nil {
return err
}
filters , err := user . GetFiltersAsJSON ( )
if err != nil {
return err
}
fsConfig , err := user . GetFsConfigAsJSON ( )
if err != nil {
return err
}
2022-01-30 10:42:36 +00:00
_ , err = stmt . ExecContext ( ctx , user . Username , user . Password , string ( publicKeys ) , user . HomeDir , user . UID , user . GID ,
user . MaxSessions , user . QuotaSize , user . QuotaFiles , string ( permissions ) , user . UploadBandwidth ,
user . DownloadBandwidth , user . Status , user . ExpirationDate , string ( filters ) , string ( fsConfig ) , user . AdditionalInfo ,
user . Description , user . Email , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
user . UploadDataTransfer , user . DownloadDataTransfer , user . TotalDataTransfer )
2021-03-23 18:14:15 +00:00
if err != nil {
return err
}
2022-04-25 13:49:11 +00:00
if err := generateUserVirtualFoldersMapping ( ctx , user , tx ) ; err != nil {
return err
}
return generateUserGroupMapping ( ctx , user , tx )
2021-03-23 18:14:15 +00:00
} )
2019-07-20 10:26:52 +00:00
}
2022-04-02 20:20:21 +00:00
func sqlCommonUpdateUserPassword ( username , password string , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateUserPasswordQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , password , username )
return err
}
2021-01-05 08:50:22 +00:00
func sqlCommonUpdateUser ( user * User , dbHandle * sql . DB ) error {
2021-01-25 20:31:33 +00:00
err := ValidateUser ( user )
2019-07-20 10:26:52 +00:00
if err != nil {
return err
}
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2021-02-16 18:11:36 +00:00
2021-03-23 18:14:15 +00:00
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
q := getUpdateUserQuery ( )
stmt , err := tx . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-03-23 18:14:15 +00:00
return err
}
defer stmt . Close ( )
permissions , err := user . GetPermissionsAsJSON ( )
if err != nil {
return err
}
publicKeys , err := user . GetPublicKeysAsJSON ( )
if err != nil {
return err
}
filters , err := user . GetFiltersAsJSON ( )
if err != nil {
return err
}
fsConfig , err := user . GetFsConfigAsJSON ( )
if err != nil {
return err
}
2022-01-30 10:42:36 +00:00
_ , err = stmt . ExecContext ( ctx , user . Password , string ( publicKeys ) , user . HomeDir , user . UID , user . GID , user . MaxSessions ,
user . QuotaSize , user . QuotaFiles , string ( permissions ) , user . UploadBandwidth , user . DownloadBandwidth , user . Status ,
user . ExpirationDate , string ( filters ) , string ( fsConfig ) , user . AdditionalInfo , user . Description , user . Email ,
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , user . UploadDataTransfer , user . DownloadDataTransfer , user . TotalDataTransfer ,
2021-09-25 17:06:13 +00:00
user . ID )
2021-03-23 18:14:15 +00:00
if err != nil {
return err
}
2022-04-25 13:49:11 +00:00
if err := generateUserVirtualFoldersMapping ( ctx , user , tx ) ; err != nil {
return err
}
return generateUserGroupMapping ( ctx , user , tx )
2021-03-23 18:14:15 +00:00
} )
2019-07-20 10:26:52 +00:00
}
2022-04-25 13:49:11 +00:00
func sqlCommonDeleteUser ( user User , dbHandle * sql . DB ) error {
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2019-07-20 10:26:52 +00:00
q := getDeleteUserQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2019-07-20 10:26:52 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2019-07-20 10:26:52 +00:00
return err
}
defer stmt . Close ( )
2022-05-19 17:49:51 +00:00
res , err := stmt . ExecContext ( ctx , user . ID )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
2019-07-20 10:26:52 +00:00
}
2020-06-07 21:30:18 +00:00
func sqlCommonDumpUsers ( dbHandle sqlQuerier ) ( [ ] User , error ) {
users := make ( [ ] User , 0 , 100 )
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , longSQLQueryTimeout )
defer cancel ( )
2019-12-27 22:12:44 +00:00
q := getDumpUsersQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2019-12-27 22:12:44 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2019-12-27 22:12:44 +00:00
return nil , err
}
defer stmt . Close ( )
2020-07-08 16:54:44 +00:00
rows , err := stmt . QueryContext ( ctx )
2020-06-07 21:30:18 +00:00
if err != nil {
return users , err
2019-12-27 22:12:44 +00:00
}
2020-06-07 21:30:18 +00:00
defer rows . Close ( )
for rows . Next ( ) {
2021-01-17 21:29:08 +00:00
u , err := getUserFromDbRow ( rows )
2020-06-07 21:30:18 +00:00
if err != nil {
return users , err
}
users = append ( users , u )
}
2021-01-17 21:29:08 +00:00
err = rows . Err ( )
if err != nil {
return users , err
}
2022-04-25 13:49:11 +00:00
users , err = getUsersWithVirtualFolders ( ctx , users , dbHandle )
if err != nil {
return users , err
}
return getUsersWithGroups ( ctx , users , dbHandle )
2019-12-27 22:12:44 +00:00
}
2021-08-20 07:35:06 +00:00
func sqlCommonGetRecentlyUpdatedUsers ( after int64 , dbHandle sqlQuerier ) ( [ ] User , error ) {
users := make ( [ ] User , 0 , 10 )
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getRecentlyUpdatedUsersQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-08-20 07:35:06 +00:00
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx , after )
if err == nil {
defer rows . Close ( )
for rows . Next ( ) {
u , err := getUserFromDbRow ( rows )
if err != nil {
return users , err
}
users = append ( users , u )
}
}
err = rows . Err ( )
if err != nil {
return users , err
}
2022-04-25 13:49:11 +00:00
users , err = getUsersWithVirtualFolders ( ctx , users , dbHandle )
if err != nil {
return users , err
}
users , err = getUsersWithGroups ( ctx , users , dbHandle )
if err != nil {
return users , err
}
var groupNames [ ] string
for _ , u := range users {
for _ , g := range u . Groups {
groupNames = append ( groupNames , g . Name )
}
}
2022-05-31 16:22:18 +00:00
groupNames = util . RemoveDuplicates ( groupNames , false )
2022-04-25 13:49:11 +00:00
groups , err := sqlCommonGetGroupsWithNames ( groupNames , dbHandle )
if err != nil {
return users , err
}
2022-04-30 09:59:36 +00:00
if len ( groups ) == 0 {
return users , nil
}
2022-04-25 13:49:11 +00:00
groupsMapping := make ( map [ string ] Group )
2022-04-30 09:59:36 +00:00
for idx := range groups {
groupsMapping [ groups [ idx ] . Name ] = groups [ idx ]
2022-04-25 13:49:11 +00:00
}
for idx := range users {
ref := & users [ idx ]
ref . applyGroupSettings ( groupsMapping )
}
return users , nil
2021-08-20 07:35:06 +00:00
}
2022-01-20 17:19:20 +00:00
func sqlCommonGetUsersForQuotaCheck ( toFetch map [ string ] bool , dbHandle sqlQuerier ) ( [ ] User , error ) {
users := make ( [ ] User , 0 , 30 )
usernames := make ( [ ] string , 0 , len ( toFetch ) )
for k := range toFetch {
usernames = append ( usernames , k )
}
maxUsers := 30
for len ( usernames ) > 0 {
if maxUsers > len ( usernames ) {
maxUsers = len ( usernames )
}
usersRange , err := sqlCommonGetUsersRangeForQuotaCheck ( usernames [ : maxUsers ] , dbHandle )
if err != nil {
return users , err
}
users = append ( users , usersRange ... )
usernames = usernames [ maxUsers : ]
}
var usersWithFolders [ ] User
validIdx := 0
for _ , user := range users {
if toFetch [ user . Username ] {
usersWithFolders = append ( usersWithFolders , user )
} else {
users [ validIdx ] = user
validIdx ++
}
}
users = users [ : validIdx ]
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
usersWithFolders , err := getUsersWithVirtualFolders ( ctx , usersWithFolders , dbHandle )
if err != nil {
return users , err
}
users = append ( users , usersWithFolders ... )
2022-04-25 13:49:11 +00:00
users , err = getUsersWithGroups ( ctx , users , dbHandle )
if err != nil {
return users , err
}
var groupNames [ ] string
for _ , u := range users {
for _ , g := range u . Groups {
groupNames = append ( groupNames , g . Name )
}
}
2022-05-31 16:22:18 +00:00
groupNames = util . RemoveDuplicates ( groupNames , false )
2022-04-30 09:59:36 +00:00
if len ( groupNames ) == 0 {
return users , nil
}
2022-04-25 13:49:11 +00:00
groups , err := sqlCommonGetGroupsWithNames ( groupNames , dbHandle )
if err != nil {
return users , err
}
groupsMapping := make ( map [ string ] Group )
2022-04-30 09:59:36 +00:00
for idx := range groups {
groupsMapping [ groups [ idx ] . Name ] = groups [ idx ]
2022-04-25 13:49:11 +00:00
}
for idx := range users {
ref := & users [ idx ]
ref . applyGroupSettings ( groupsMapping )
}
2022-01-20 17:19:20 +00:00
return users , nil
}
func sqlCommonGetUsersRangeForQuotaCheck ( usernames [ ] string , dbHandle sqlQuerier ) ( [ ] User , error ) {
users := make ( [ ] User , 0 , len ( usernames ) )
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUsersForQuotaCheckQuery ( len ( usernames ) )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return users , err
}
defer stmt . Close ( )
2022-05-19 17:49:51 +00:00
queryArgs := make ( [ ] any , 0 , len ( usernames ) )
2022-01-20 17:19:20 +00:00
for idx := range usernames {
queryArgs = append ( queryArgs , usernames [ idx ] )
}
rows , err := stmt . QueryContext ( ctx , queryArgs ... )
if err != nil {
return nil , err
}
defer rows . Close ( )
for rows . Next ( ) {
var user User
2022-01-30 10:42:36 +00:00
var filters sql . NullString
err = rows . Scan ( & user . ID , & user . Username , & user . QuotaSize , & user . UsedQuotaSize , & user . TotalDataTransfer ,
& user . UploadDataTransfer , & user . DownloadDataTransfer , & user . UsedUploadDataTransfer ,
& user . UsedDownloadDataTransfer , & filters )
2022-01-20 17:19:20 +00:00
if err != nil {
return users , err
}
2022-01-30 10:42:36 +00:00
if filters . Valid {
var userFilters UserFilters
err = json . Unmarshal ( [ ] byte ( filters . String ) , & userFilters )
if err == nil {
user . Filters = userFilters
}
}
2022-01-20 17:19:20 +00:00
users = append ( users , user )
}
return users , rows . Err ( )
}
2022-01-30 10:42:36 +00:00
func sqlCommonAddActiveTransfer ( transfer ActiveTransfer , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getAddActiveTransferQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
now := util . GetTimeAsMsSinceEpoch ( time . Now ( ) )
_ , err = stmt . ExecContext ( ctx , transfer . ID , transfer . ConnID , transfer . Type , transfer . Username ,
transfer . FolderName , transfer . IP , transfer . TruncatedSize , transfer . CurrentULSize , transfer . CurrentDLSize ,
now , now )
return err
}
func sqlCommonUpdateActiveTransferSizes ( ulSize , dlSize , transferID int64 , connectionID string , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateActiveTransferSizesQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , ulSize , dlSize , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , connectionID , transferID )
return err
}
func sqlCommonRemoveActiveTransfer ( transferID int64 , connectionID string , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getRemoveActiveTransferQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , connectionID , transferID )
return err
}
func sqlCommonCleanupActiveTransfers ( before time . Time , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getCleanupActiveTransfersQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , util . GetTimeAsMsSinceEpoch ( before ) )
return err
}
func sqlCommonGetActiveTransfers ( from time . Time , dbHandle sqlQuerier ) ( [ ] ActiveTransfer , error ) {
transfers := make ( [ ] ActiveTransfer , 0 , 30 )
ctx , cancel := context . WithTimeout ( context . Background ( ) , longSQLQueryTimeout )
defer cancel ( )
q := getActiveTransfersQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx , util . GetTimeAsMsSinceEpoch ( from ) )
if err != nil {
return nil , err
}
defer rows . Close ( )
for rows . Next ( ) {
var transfer ActiveTransfer
var folderName sql . NullString
err = rows . Scan ( & transfer . ID , & transfer . ConnID , & transfer . Type , & transfer . Username , & folderName , & transfer . IP ,
& transfer . TruncatedSize , & transfer . CurrentULSize , & transfer . CurrentDLSize , & transfer . CreatedAt ,
& transfer . UpdatedAt )
if err != nil {
return transfers , err
}
if folderName . Valid {
transfer . FolderName = folderName . String
}
transfers = append ( transfers , transfer )
}
return transfers , rows . Err ( )
}
2021-01-17 21:29:08 +00:00
func sqlCommonGetUsers ( limit int , offset int , order string , dbHandle sqlQuerier ) ( [ ] User , error ) {
2020-06-07 21:30:18 +00:00
users := make ( [ ] User , 0 , limit )
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2021-01-17 21:29:08 +00:00
q := getUsersQuery ( order )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2019-07-20 10:26:52 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2019-07-20 10:26:52 +00:00
return nil , err
}
defer stmt . Close ( )
2021-01-17 21:29:08 +00:00
rows , err := stmt . QueryContext ( ctx , limit , offset )
2019-07-20 10:26:52 +00:00
if err == nil {
defer rows . Close ( )
for rows . Next ( ) {
2021-01-17 21:29:08 +00:00
u , err := getUserFromDbRow ( rows )
2020-06-07 21:30:18 +00:00
if err != nil {
return users , err
2019-07-20 10:26:52 +00:00
}
2020-11-22 20:53:04 +00:00
users = append ( users , u )
2019-07-20 10:26:52 +00:00
}
}
2020-06-07 21:30:18 +00:00
err = rows . Err ( )
if err != nil {
return users , err
}
2022-04-25 13:49:11 +00:00
users , err = getUsersWithVirtualFolders ( ctx , users , dbHandle )
if err != nil {
return users , err
}
users , err = getUsersWithGroups ( ctx , users , dbHandle )
if err != nil {
return users , err
}
for idx := range users {
users [ idx ] . PrepareForRendering ( )
}
return users , nil
2019-07-20 10:26:52 +00:00
}
2022-01-16 11:09:17 +00:00
func sqlCommonGetDefenderHosts ( from int64 , limit int , dbHandle sqlQuerier ) ( [ ] DefenderEntry , error ) {
hosts := make ( [ ] DefenderEntry , 0 , 100 )
2021-12-25 11:08:07 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDefenderHostsQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx , from , limit )
if err != nil {
providerLog ( logger . LevelError , "unable to get defender hosts: %v" , err )
return hosts , err
}
defer rows . Close ( )
var idForScores [ ] int64
for rows . Next ( ) {
var banTime sql . NullInt64
host := DefenderEntry { }
err = rows . Scan ( & host . ID , & host . IP , & banTime )
if err != nil {
providerLog ( logger . LevelError , "unable to scan defender host row: %v" , err )
return hosts , err
}
var hostBanTime time . Time
if banTime . Valid && banTime . Int64 > 0 {
hostBanTime = util . GetTimeFromMsecSinceEpoch ( banTime . Int64 )
}
if hostBanTime . IsZero ( ) || hostBanTime . Before ( time . Now ( ) ) {
idForScores = append ( idForScores , host . ID )
} else {
host . BanTime = hostBanTime
}
2022-01-16 11:09:17 +00:00
hosts = append ( hosts , host )
2021-12-25 11:08:07 +00:00
}
err = rows . Err ( )
if err != nil {
providerLog ( logger . LevelError , "unable to iterate over defender host rows: %v" , err )
return hosts , err
}
return getDefenderHostsWithScores ( ctx , hosts , from , idForScores , dbHandle )
}
2022-01-16 11:09:17 +00:00
func sqlCommonIsDefenderHostBanned ( ip string , dbHandle sqlQuerier ) ( DefenderEntry , error ) {
2021-12-25 11:08:07 +00:00
var host DefenderEntry
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDefenderIsHostBannedQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2022-01-16 11:09:17 +00:00
return host , err
2021-12-25 11:08:07 +00:00
}
defer stmt . Close ( )
row := stmt . QueryRowContext ( ctx , ip , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) )
err = row . Scan ( & host . ID )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
2022-01-16 11:09:17 +00:00
return host , util . NewRecordNotFoundError ( "host not found" )
2021-12-25 11:08:07 +00:00
}
providerLog ( logger . LevelError , "unable to check ban status for host %#v: %v" , ip , err )
2022-01-16 11:09:17 +00:00
return host , err
2021-12-25 11:08:07 +00:00
}
2022-01-16 11:09:17 +00:00
return host , nil
2021-12-25 11:08:07 +00:00
}
2022-01-16 11:09:17 +00:00
func sqlCommonGetDefenderHostByIP ( ip string , from int64 , dbHandle sqlQuerier ) ( DefenderEntry , error ) {
2021-12-25 11:08:07 +00:00
var host DefenderEntry
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDefenderHostQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2022-01-16 11:09:17 +00:00
return host , err
2021-12-25 11:08:07 +00:00
}
defer stmt . Close ( )
row := stmt . QueryRowContext ( ctx , ip , from )
var banTime sql . NullInt64
err = row . Scan ( & host . ID , & host . IP , & banTime )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
2022-01-16 11:09:17 +00:00
return host , util . NewRecordNotFoundError ( "host not found" )
2021-12-25 11:08:07 +00:00
}
providerLog ( logger . LevelError , "unable to get host for ip %#v: %v" , ip , err )
2022-01-16 11:09:17 +00:00
return host , err
2021-12-25 11:08:07 +00:00
}
if banTime . Valid && banTime . Int64 > 0 {
hostBanTime := util . GetTimeFromMsecSinceEpoch ( banTime . Int64 )
if ! hostBanTime . IsZero ( ) && hostBanTime . After ( time . Now ( ) ) {
host . BanTime = hostBanTime
2022-01-16 11:09:17 +00:00
return host , nil
2021-12-25 11:08:07 +00:00
}
}
2022-01-16 11:09:17 +00:00
hosts , err := getDefenderHostsWithScores ( ctx , [ ] DefenderEntry { host } , from , [ ] int64 { host . ID } , dbHandle )
2021-12-25 11:08:07 +00:00
if err != nil {
2022-01-16 11:09:17 +00:00
return host , err
2021-12-25 11:08:07 +00:00
}
if len ( hosts ) == 0 {
2022-01-16 11:09:17 +00:00
return host , util . NewRecordNotFoundError ( "host not found" )
2021-12-25 11:08:07 +00:00
}
return hosts [ 0 ] , nil
}
func sqlCommonDefenderIncrementBanTime ( ip string , minutesToAdd int , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDefenderIncrementBanTimeQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , minutesToAdd * 60000 , ip )
if err == nil {
providerLog ( logger . LevelDebug , "ban time updated for ip %#v, increment (minutes): %v" ,
ip , minutesToAdd )
} else {
providerLog ( logger . LevelError , "error updating ban time for ip %#v: %v" , ip , err )
}
return err
}
func sqlCommonSetDefenderBanTime ( ip string , banTime int64 , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDefenderSetBanTimeQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , banTime , ip )
if err == nil {
providerLog ( logger . LevelDebug , "ip %#v banned until %v" , ip , util . GetTimeFromMsecSinceEpoch ( banTime ) )
} else {
providerLog ( logger . LevelError , "error setting ban time for ip %#v: %v" , ip , err )
}
return err
}
func sqlCommonDeleteDefenderHost ( ip string , dbHandle sqlQuerier ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDeleteDefenderHostQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
2022-05-19 17:49:51 +00:00
res , err := stmt . ExecContext ( ctx , ip )
2021-12-25 11:08:07 +00:00
if err != nil {
providerLog ( logger . LevelError , "unable to delete defender host %#v: %v" , ip , err )
2022-05-19 17:49:51 +00:00
return err
2021-12-25 11:08:07 +00:00
}
2022-05-19 17:49:51 +00:00
return sqlCommonRequireRowAffected ( res )
2021-12-25 11:08:07 +00:00
}
func sqlCommonAddDefenderHostAndEvent ( ip string , score int , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
if err := sqlCommonAddDefenderHost ( ctx , ip , tx ) ; err != nil {
return err
}
return sqlCommonAddDefenderEvent ( ctx , ip , score , tx )
} )
}
func sqlCommonDefenderCleanup ( from int64 , dbHandler * sql . DB ) error {
if err := sqlCommonCleanupDefenderEvents ( from , dbHandler ) ; err != nil {
return err
}
return sqlCommonCleanupDefenderHosts ( from , dbHandler )
}
func sqlCommonAddDefenderHost ( ctx context . Context , ip string , tx * sql . Tx ) error {
q := getAddDefenderHostQuery ( )
stmt , err := tx . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , ip , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) )
if err != nil {
providerLog ( logger . LevelError , "unable to add defender host %#v: %v" , ip , err )
}
return err
}
func sqlCommonAddDefenderEvent ( ctx context . Context , ip string , score int , tx * sql . Tx ) error {
q := getAddDefenderEventQuery ( )
stmt , err := tx . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , score , ip )
if err != nil {
providerLog ( logger . LevelError , "unable to add defender event for %#v: %v" , ip , err )
}
return err
}
func sqlCommonCleanupDefenderHosts ( from int64 , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDefenderHostsCleanupQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , from )
if err != nil {
providerLog ( logger . LevelError , "unable to cleanup defender hosts: %v" , err )
}
return err
}
func sqlCommonCleanupDefenderEvents ( from int64 , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDefenderEventsCleanupQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , from )
if err != nil {
providerLog ( logger . LevelError , "unable to cleanup defender events: %v" , err )
}
return err
}
2021-11-06 13:13:20 +00:00
func getShareFromDbRow ( row sqlScanner ) ( Share , error ) {
var share Share
var description , password , allowFrom , paths sql . NullString
err := row . Scan ( & share . ShareID , & share . Name , & description , & share . Scope ,
& paths , & share . Username , & share . CreatedAt , & share . UpdatedAt ,
& share . LastUseAt , & share . ExpiresAt , & password , & share . MaxTokens ,
& share . UsedTokens , & allowFrom )
if err != nil {
2021-11-15 17:40:31 +00:00
if errors . Is ( err , sql . ErrNoRows ) {
2021-11-06 13:13:20 +00:00
return share , util . NewRecordNotFoundError ( err . Error ( ) )
}
return share , err
}
if paths . Valid {
var list [ ] string
err = json . Unmarshal ( [ ] byte ( paths . String ) , & list )
if err != nil {
return share , err
}
share . Paths = list
} else {
return share , errors . New ( "unable to decode shared paths" )
}
if description . Valid {
share . Description = description . String
}
if password . Valid {
share . Password = password . String
}
if allowFrom . Valid {
var list [ ] string
err = json . Unmarshal ( [ ] byte ( allowFrom . String ) , & list )
if err == nil {
share . AllowFrom = list
}
}
return share , nil
}
2021-08-17 16:08:32 +00:00
func getAPIKeyFromDbRow ( row sqlScanner ) ( APIKey , error ) {
var apiKey APIKey
var userID , adminID sql . NullInt64
var description sql . NullString
err := row . Scan ( & apiKey . KeyID , & apiKey . Name , & apiKey . Key , & apiKey . Scope , & apiKey . CreatedAt , & apiKey . UpdatedAt ,
& apiKey . LastUseAt , & apiKey . ExpiresAt , & description , & userID , & adminID )
if err != nil {
2021-11-15 17:40:31 +00:00
if errors . Is ( err , sql . ErrNoRows ) {
2021-08-17 16:08:32 +00:00
return apiKey , util . NewRecordNotFoundError ( err . Error ( ) )
}
return apiKey , err
}
if userID . Valid {
apiKey . userID = userID . Int64
}
if adminID . Valid {
apiKey . adminID = adminID . Int64
}
if description . Valid {
apiKey . Description = description . String
}
return apiKey , nil
}
2021-01-17 21:29:08 +00:00
func getAdminFromDbRow ( row sqlScanner ) ( Admin , error ) {
var admin Admin
2021-02-24 18:40:29 +00:00
var email , filters , additionalInfo , permissions , description sql . NullString
2021-01-17 21:29:08 +00:00
err := row . Scan ( & admin . ID , & admin . Username , & admin . Password , & admin . Status , & email , & permissions ,
2021-08-19 13:51:43 +00:00
& filters , & additionalInfo , & description , & admin . CreatedAt , & admin . UpdatedAt , & admin . LastLogin )
2021-01-17 21:29:08 +00:00
if err != nil {
2021-11-15 17:40:31 +00:00
if errors . Is ( err , sql . ErrNoRows ) {
2021-07-11 13:26:51 +00:00
return admin , util . NewRecordNotFoundError ( err . Error ( ) )
2021-01-17 21:29:08 +00:00
}
return admin , err
}
if permissions . Valid {
var perms [ ] string
err = json . Unmarshal ( [ ] byte ( permissions . String ) , & perms )
if err != nil {
return admin , err
}
admin . Permissions = perms
}
if email . Valid {
admin . Email = email . String
}
if filters . Valid {
var adminFilters AdminFilters
err = json . Unmarshal ( [ ] byte ( filters . String ) , & adminFilters )
if err == nil {
admin . Filters = adminFilters
}
}
if additionalInfo . Valid {
admin . AdditionalInfo = additionalInfo . String
}
2021-02-24 18:40:29 +00:00
if description . Valid {
admin . Description = description . String
}
2021-01-17 21:29:08 +00:00
2021-09-04 10:11:04 +00:00
admin . SetEmptySecretsIfNil ( )
2021-08-17 16:08:32 +00:00
return admin , nil
2021-01-17 21:29:08 +00:00
}
2022-04-25 13:49:11 +00:00
func getGroupFromDbRow ( row sqlScanner ) ( Group , error ) {
var group Group
var userSettings , description sql . NullString
err := row . Scan ( & group . ID , & group . Name , & description , & group . CreatedAt , & group . UpdatedAt , & userSettings )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
return group , util . NewRecordNotFoundError ( err . Error ( ) )
}
return group , err
}
if description . Valid {
group . Description = description . String
}
if userSettings . Valid {
var settings GroupUserSettings
err = json . Unmarshal ( [ ] byte ( userSettings . String ) , & settings )
if err == nil {
group . UserSettings = settings
}
}
return group , nil
}
2021-01-17 21:29:08 +00:00
func getUserFromDbRow ( row sqlScanner ) ( User , error ) {
2019-07-20 10:26:52 +00:00
var user User
var permissions sql . NullString
var password sql . NullString
var publicKey sql . NullString
2019-12-30 17:37:50 +00:00
var filters sql . NullString
2020-01-19 06:41:05 +00:00
var fsConfig sql . NullString
2021-09-25 17:06:13 +00:00
var additionalInfo , description , email sql . NullString
2021-01-17 21:29:08 +00:00
err := row . Scan ( & user . ID , & user . Username , & password , & publicKey , & user . HomeDir , & user . UID , & user . GID , & user . MaxSessions ,
& user . QuotaSize , & user . QuotaFiles , & permissions , & user . UsedQuotaSize , & user . UsedQuotaFiles , & user . LastQuotaUpdate ,
& user . UploadBandwidth , & user . DownloadBandwidth , & user . ExpirationDate , & user . LastLogin , & user . Status , & filters , & fsConfig ,
2022-01-30 10:42:36 +00:00
& additionalInfo , & description , & email , & user . CreatedAt , & user . UpdatedAt , & user . UploadDataTransfer , & user . DownloadDataTransfer ,
& user . TotalDataTransfer , & user . UsedUploadDataTransfer , & user . UsedDownloadDataTransfer )
2019-07-20 10:26:52 +00:00
if err != nil {
2021-11-15 17:40:31 +00:00
if errors . Is ( err , sql . ErrNoRows ) {
2021-07-11 13:26:51 +00:00
return user , util . NewRecordNotFoundError ( err . Error ( ) )
2019-08-12 16:31:31 +00:00
}
2019-07-20 10:26:52 +00:00
return user , err
}
if password . Valid {
user . Password = password . String
}
2020-02-23 10:30:26 +00:00
// we can have a empty string or an invalid json in null string
// so we do a relaxed test if the field is optional, for example we
// populate public keys only if unmarshal does not return an error
2019-07-20 10:26:52 +00:00
if publicKey . Valid {
2019-08-01 20:42:46 +00:00
var list [ ] string
err = json . Unmarshal ( [ ] byte ( publicKey . String ) , & list )
if err == nil {
2019-08-07 21:41:10 +00:00
user . PublicKeys = list
2019-08-01 20:42:46 +00:00
}
2019-07-20 10:26:52 +00:00
}
if permissions . Valid {
2021-02-22 07:37:50 +00:00
perms := make ( map [ string ] [ ] string )
err = json . Unmarshal ( [ ] byte ( permissions . String ) , & perms )
2020-02-23 10:30:26 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "unable to deserialize permissions for user %#v: %v" , user . Username , err )
2021-02-22 07:37:50 +00:00
return user , fmt . Errorf ( "unable to deserialize permissions for user %#v: %v" , user . Username , err )
2019-07-20 10:26:52 +00:00
}
2021-02-22 07:37:50 +00:00
user . Permissions = perms
2019-07-20 10:26:52 +00:00
}
2019-12-30 17:37:50 +00:00
if filters . Valid {
2022-01-06 09:11:47 +00:00
var userFilters UserFilters
2019-12-30 17:37:50 +00:00
err = json . Unmarshal ( [ ] byte ( filters . String ) , & userFilters )
if err == nil {
user . Filters = userFilters
}
}
2020-01-19 06:41:05 +00:00
if fsConfig . Valid {
2021-03-21 18:15:47 +00:00
var fs vfs . Filesystem
2020-01-19 06:41:05 +00:00
err = json . Unmarshal ( [ ] byte ( fsConfig . String ) , & fs )
if err == nil {
user . FsConfig = fs
}
2020-02-23 10:30:26 +00:00
}
2020-11-25 21:26:34 +00:00
if additionalInfo . Valid {
user . AdditionalInfo = additionalInfo . String
}
2021-02-24 18:40:29 +00:00
if description . Valid {
user . Description = description . String
}
2021-09-25 17:06:13 +00:00
if email . Valid {
user . Email = email . String
}
2020-11-30 20:46:34 +00:00
user . SetEmptySecretsIfNil ( )
2021-08-17 16:08:32 +00:00
return user , nil
2020-06-07 21:30:18 +00:00
}
2021-03-21 18:15:47 +00:00
func sqlCommonGetFolder ( ctx context . Context , name string , dbHandle sqlQuerier ) ( vfs . BaseVirtualFolder , error ) {
2020-06-07 21:30:18 +00:00
var folder vfs . BaseVirtualFolder
2021-02-01 18:04:15 +00:00
q := getFolderByNameQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-06-07 21:30:18 +00:00
return folder , err
}
defer stmt . Close ( )
2020-07-08 16:54:44 +00:00
row := stmt . QueryRowContext ( ctx , name )
2021-03-21 18:15:47 +00:00
var mappedPath , description , fsConfig sql . NullString
2021-02-01 18:04:15 +00:00
err = row . Scan ( & folder . ID , & mappedPath , & folder . UsedQuotaSize , & folder . UsedQuotaFiles , & folder . LastQuotaUpdate ,
2021-03-21 18:15:47 +00:00
& folder . Name , & description , & fsConfig )
2021-11-15 17:40:31 +00:00
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
return folder , util . NewRecordNotFoundError ( err . Error ( ) )
}
return folder , err
2020-06-07 21:30:18 +00:00
}
2021-02-01 18:04:15 +00:00
if mappedPath . Valid {
folder . MappedPath = mappedPath . String
}
2021-02-24 18:40:29 +00:00
if description . Valid {
folder . Description = description . String
}
2021-03-21 18:15:47 +00:00
if fsConfig . Valid {
var fs vfs . Filesystem
err = json . Unmarshal ( [ ] byte ( fsConfig . String ) , & fs )
if err == nil {
folder . FsConfig = fs
}
}
2020-06-07 21:30:18 +00:00
return folder , err
}
2021-02-01 18:04:15 +00:00
func sqlCommonGetFolderByName ( ctx context . Context , name string , dbHandle sqlQuerier ) ( vfs . BaseVirtualFolder , error ) {
2021-03-21 18:15:47 +00:00
folder , err := sqlCommonGetFolder ( ctx , name , dbHandle )
2021-02-01 18:04:15 +00:00
if err != nil {
return folder , err
}
folders , err := getVirtualFoldersWithUsers ( [ ] vfs . BaseVirtualFolder { folder } , dbHandle )
if err != nil {
return folder , err
}
if len ( folders ) != 1 {
return folder , fmt . Errorf ( "unable to associate users with folder %#v" , name )
}
2022-04-25 13:49:11 +00:00
folders , err = getVirtualFoldersWithGroups ( [ ] vfs . BaseVirtualFolder { folders [ 0 ] } , dbHandle )
if err != nil {
return folder , err
}
if len ( folders ) != 1 {
return folder , fmt . Errorf ( "unable to associate groups with folder %#v" , name )
}
2021-02-01 18:04:15 +00:00
return folders [ 0 ] , nil
}
2021-03-21 18:15:47 +00:00
func sqlCommonAddOrUpdateFolder ( ctx context . Context , baseFolder * vfs . BaseVirtualFolder , usedQuotaSize int64 ,
2022-04-28 12:49:57 +00:00
usedQuotaFiles int , lastQuotaUpdate int64 , dbHandle sqlQuerier ,
) error {
fsConfig , err := json . Marshal ( baseFolder . FsConfig )
if err != nil {
return err
}
q := getUpsertFolderQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
2020-01-19 06:41:05 +00:00
}
2022-04-28 12:49:57 +00:00
defer stmt . Close ( )
2021-03-21 18:15:47 +00:00
2022-04-28 12:49:57 +00:00
_ , err = stmt . ExecContext ( ctx , baseFolder . MappedPath , usedQuotaSize , usedQuotaFiles ,
lastQuotaUpdate , baseFolder . Name , baseFolder . Description , string ( fsConfig ) )
return err
2020-06-07 21:30:18 +00:00
}
2021-01-05 08:50:22 +00:00
func sqlCommonAddFolder ( folder * vfs . BaseVirtualFolder , dbHandle sqlQuerier ) error {
2021-02-04 18:09:43 +00:00
err := ValidateFolder ( folder )
2020-06-07 21:30:18 +00:00
if err != nil {
return err
}
2021-03-21 18:15:47 +00:00
fsConfig , err := json . Marshal ( folder . FsConfig )
if err != nil {
return err
}
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2020-06-07 21:30:18 +00:00
q := getAddFolderQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-06-07 21:30:18 +00:00
return err
}
defer stmt . Close ( )
2021-02-01 18:04:15 +00:00
_ , err = stmt . ExecContext ( ctx , folder . MappedPath , folder . UsedQuotaSize , folder . UsedQuotaFiles ,
2021-03-21 18:15:47 +00:00
folder . LastQuotaUpdate , folder . Name , folder . Description , string ( fsConfig ) )
2021-02-01 18:04:15 +00:00
return err
}
2021-03-21 18:15:47 +00:00
func sqlCommonUpdateFolder ( folder * vfs . BaseVirtualFolder , dbHandle sqlQuerier ) error {
2021-02-04 18:09:43 +00:00
err := ValidateFolder ( folder )
2021-02-01 18:04:15 +00:00
if err != nil {
return err
}
2021-03-21 18:15:47 +00:00
fsConfig , err := json . Marshal ( folder . FsConfig )
if err != nil {
return err
}
2021-02-01 18:04:15 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateFolderQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-02-01 18:04:15 +00:00
return err
}
defer stmt . Close ( )
2021-03-21 18:15:47 +00:00
_ , err = stmt . ExecContext ( ctx , folder . MappedPath , folder . Description , string ( fsConfig ) , folder . Name )
2020-06-07 21:30:18 +00:00
return err
}
2022-04-25 13:49:11 +00:00
func sqlCommonDeleteFolder ( folder vfs . BaseVirtualFolder , dbHandle sqlQuerier ) error {
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2020-06-07 21:30:18 +00:00
q := getDeleteFolderQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-06-07 21:30:18 +00:00
return err
}
defer stmt . Close ( )
2022-05-19 17:49:51 +00:00
res , err := stmt . ExecContext ( ctx , folder . ID )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
2020-06-07 21:30:18 +00:00
}
func sqlCommonDumpFolders ( dbHandle sqlQuerier ) ( [ ] vfs . BaseVirtualFolder , error ) {
folders := make ( [ ] vfs . BaseVirtualFolder , 0 , 50 )
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , longSQLQueryTimeout )
defer cancel ( )
2020-06-07 21:30:18 +00:00
q := getDumpFoldersQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-06-07 21:30:18 +00:00
return nil , err
}
defer stmt . Close ( )
2020-07-08 16:54:44 +00:00
rows , err := stmt . QueryContext ( ctx )
2020-06-07 21:30:18 +00:00
if err != nil {
return folders , err
}
defer rows . Close ( )
for rows . Next ( ) {
var folder vfs . BaseVirtualFolder
2021-03-21 18:15:47 +00:00
var mappedPath , description , fsConfig sql . NullString
2021-02-01 18:04:15 +00:00
err = rows . Scan ( & folder . ID , & mappedPath , & folder . UsedQuotaSize , & folder . UsedQuotaFiles ,
2021-03-21 18:15:47 +00:00
& folder . LastQuotaUpdate , & folder . Name , & description , & fsConfig )
2020-06-07 21:30:18 +00:00
if err != nil {
return folders , err
}
2021-02-01 18:04:15 +00:00
if mappedPath . Valid {
folder . MappedPath = mappedPath . String
}
2021-02-24 18:40:29 +00:00
if description . Valid {
folder . Description = description . String
}
2021-03-21 18:15:47 +00:00
if fsConfig . Valid {
var fs vfs . Filesystem
err = json . Unmarshal ( [ ] byte ( fsConfig . String ) , & fs )
if err == nil {
folder . FsConfig = fs
}
}
2020-06-07 21:30:18 +00:00
folders = append ( folders , folder )
}
2022-05-14 09:54:55 +00:00
return folders , rows . Err ( )
2020-06-07 21:30:18 +00:00
}
2022-04-25 13:49:11 +00:00
func sqlCommonGetFolders ( limit , offset int , order string , minimal bool , dbHandle sqlQuerier ) ( [ ] vfs . BaseVirtualFolder , error ) {
2020-06-07 21:30:18 +00:00
folders := make ( [ ] vfs . BaseVirtualFolder , 0 , limit )
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2022-04-25 13:49:11 +00:00
q := getFoldersQuery ( order , minimal )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-06-07 21:30:18 +00:00
return nil , err
}
defer stmt . Close ( )
2021-02-01 18:04:15 +00:00
rows , err := stmt . QueryContext ( ctx , limit , offset )
2020-06-07 21:30:18 +00:00
if err != nil {
return folders , err
}
defer rows . Close ( )
for rows . Next ( ) {
var folder vfs . BaseVirtualFolder
2022-04-25 13:49:11 +00:00
if minimal {
err = rows . Scan ( & folder . ID , & folder . Name )
if err != nil {
return folders , err
}
} else {
var mappedPath , description , fsConfig sql . NullString
err = rows . Scan ( & folder . ID , & mappedPath , & folder . UsedQuotaSize , & folder . UsedQuotaFiles ,
& folder . LastQuotaUpdate , & folder . Name , & description , & fsConfig )
if err != nil {
return folders , err
}
if mappedPath . Valid {
folder . MappedPath = mappedPath . String
}
if description . Valid {
folder . Description = description . String
}
if fsConfig . Valid {
var fs vfs . Filesystem
err = json . Unmarshal ( [ ] byte ( fsConfig . String ) , & fs )
if err == nil {
folder . FsConfig = fs
}
2021-03-21 18:15:47 +00:00
}
}
2021-03-22 18:03:25 +00:00
folder . PrepareForRendering ( )
2020-06-07 21:30:18 +00:00
folders = append ( folders , folder )
}
err = rows . Err ( )
if err != nil {
return folders , err
}
2022-04-25 13:49:11 +00:00
if minimal {
return folders , nil
}
folders , err = getVirtualFoldersWithUsers ( folders , dbHandle )
if err != nil {
return folders , err
}
return getVirtualFoldersWithGroups ( folders , dbHandle )
2020-06-07 21:30:18 +00:00
}
2022-04-25 13:49:11 +00:00
func sqlCommonClearUserFolderMapping ( ctx context . Context , user * User , dbHandle sqlQuerier ) error {
q := getClearUserFolderMappingQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-06-07 21:30:18 +00:00
return err
}
defer stmt . Close ( )
2020-07-08 16:54:44 +00:00
_ , err = stmt . ExecContext ( ctx , user . Username )
2020-06-07 21:30:18 +00:00
return err
}
2022-04-25 13:49:11 +00:00
func sqlCommonClearGroupFolderMapping ( ctx context . Context , group * Group , dbHandle sqlQuerier ) error {
q := getClearGroupFolderMappingQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , group . Name )
return err
}
func sqlCommonClearUserGroupMapping ( ctx context . Context , user * User , dbHandle sqlQuerier ) error {
q := getClearUserGroupMappingQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , user . Username )
return err
}
func sqlCommonAddUserFolderMapping ( ctx context . Context , user * User , folder * vfs . VirtualFolder , dbHandle sqlQuerier ) error {
q := getAddUserFolderMappingQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-06-07 21:30:18 +00:00
return err
}
defer stmt . Close ( )
2022-04-28 12:49:57 +00:00
_ , err = stmt . ExecContext ( ctx , folder . VirtualPath , folder . QuotaSize , folder . QuotaFiles , folder . Name , user . Username )
2020-06-07 21:30:18 +00:00
return err
}
2022-04-25 13:49:11 +00:00
func sqlCommonAddGroupFolderMapping ( ctx context . Context , group * Group , folder * vfs . VirtualFolder , dbHandle sqlQuerier ) error {
q := getAddGroupFolderMappingQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , folder . VirtualPath , folder . QuotaSize , folder . QuotaFiles , folder . Name , group . Name )
return err
}
func sqlCommonAddUserGroupMapping ( ctx context . Context , username , groupName string , groupType int , dbHandle sqlQuerier ) error {
q := getAddUserGroupMappingQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , username , groupName , groupType )
return err
}
func generateGroupVirtualFoldersMapping ( ctx context . Context , group * Group , dbHandle sqlQuerier ) error {
err := sqlCommonClearGroupFolderMapping ( ctx , group , dbHandle )
if err != nil {
return err
}
for idx := range group . VirtualFolders {
vfolder := & group . VirtualFolders [ idx ]
2022-04-28 12:49:57 +00:00
err = sqlCommonAddOrUpdateFolder ( ctx , & vfolder . BaseVirtualFolder , 0 , 0 , 0 , dbHandle )
2022-04-25 13:49:11 +00:00
if err != nil {
return err
}
err = sqlCommonAddGroupFolderMapping ( ctx , group , vfolder , dbHandle )
if err != nil {
return err
}
}
return err
}
func generateUserVirtualFoldersMapping ( ctx context . Context , user * User , dbHandle sqlQuerier ) error {
err := sqlCommonClearUserFolderMapping ( ctx , user , dbHandle )
2020-06-07 21:30:18 +00:00
if err != nil {
return err
}
2021-03-21 18:15:47 +00:00
for idx := range user . VirtualFolders {
vfolder := & user . VirtualFolders [ idx ]
2022-04-28 12:49:57 +00:00
err := sqlCommonAddOrUpdateFolder ( ctx , & vfolder . BaseVirtualFolder , 0 , 0 , 0 , dbHandle )
2020-06-07 21:30:18 +00:00
if err != nil {
return err
}
2022-04-25 13:49:11 +00:00
err = sqlCommonAddUserFolderMapping ( ctx , user , vfolder , dbHandle )
2020-06-07 21:30:18 +00:00
if err != nil {
return err
}
}
return err
}
2022-04-25 13:49:11 +00:00
func generateUserGroupMapping ( ctx context . Context , user * User , dbHandle sqlQuerier ) error {
err := sqlCommonClearUserGroupMapping ( ctx , user , dbHandle )
2020-06-07 21:30:18 +00:00
if err != nil {
2022-04-25 13:49:11 +00:00
return err
2020-06-07 21:30:18 +00:00
}
2022-04-25 13:49:11 +00:00
for _ , group := range user . Groups {
err = sqlCommonAddUserGroupMapping ( ctx , user . Username , group . Name , group . Type , dbHandle )
if err != nil {
return err
}
2020-06-07 21:30:18 +00:00
}
2022-04-25 13:49:11 +00:00
return err
2020-06-07 21:30:18 +00:00
}
2022-01-16 11:09:17 +00:00
func getDefenderHostsWithScores ( ctx context . Context , hosts [ ] DefenderEntry , from int64 , idForScores [ ] int64 ,
2021-12-25 11:08:07 +00:00
dbHandle sqlQuerier ) (
2022-01-16 11:09:17 +00:00
[ ] DefenderEntry ,
2021-12-25 11:08:07 +00:00
error ,
) {
if len ( idForScores ) == 0 {
return hosts , nil
}
hostsWithScores := make ( map [ int64 ] int )
q := getDefenderEventsQuery ( idForScores )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx , from )
if err != nil {
providerLog ( logger . LevelError , "unable to get score for hosts with id %+v: %v" , idForScores , err )
return nil , err
}
defer rows . Close ( )
for rows . Next ( ) {
var hostID int64
var score int
err = rows . Scan ( & hostID , & score )
if err != nil {
providerLog ( logger . LevelError , "error scanning host score row: %v" , err )
return hosts , err
}
if score > 0 {
hostsWithScores [ hostID ] = score
}
}
err = rows . Err ( )
if err != nil {
return hosts , err
}
2022-01-16 11:09:17 +00:00
result := make ( [ ] DefenderEntry , 0 , len ( hosts ) )
2021-12-25 11:08:07 +00:00
for idx := range hosts {
hosts [ idx ] . Score = hostsWithScores [ hosts [ idx ] . ID ]
if hosts [ idx ] . Score > 0 || ! hosts [ idx ] . BanTime . IsZero ( ) {
result = append ( result , hosts [ idx ] )
}
}
return result , nil
}
2022-04-25 13:49:11 +00:00
func getUserWithVirtualFolders ( ctx context . Context , user User , dbHandle sqlQuerier ) ( User , error ) {
users , err := getUsersWithVirtualFolders ( ctx , [ ] User { user } , dbHandle )
if err != nil {
return user , err
}
if len ( users ) == 0 {
return user , errSQLFoldersAssociation
}
return users [ 0 ] , err
}
2021-04-19 16:58:53 +00:00
func getUsersWithVirtualFolders ( ctx context . Context , users [ ] User , dbHandle sqlQuerier ) ( [ ] User , error ) {
2020-06-07 21:30:18 +00:00
if len ( users ) == 0 {
2021-08-17 16:08:32 +00:00
return users , nil
2020-06-07 21:30:18 +00:00
}
2021-08-17 16:08:32 +00:00
var err error
usersVirtualFolders := make ( map [ int64 ] [ ] vfs . VirtualFolder )
2020-06-07 21:30:18 +00:00
q := getRelatedFoldersForUsersQuery ( users )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-06-07 21:30:18 +00:00
return nil , err
}
defer stmt . Close ( )
2020-07-08 16:54:44 +00:00
rows , err := stmt . QueryContext ( ctx )
2020-06-07 21:30:18 +00:00
if err != nil {
return nil , err
}
defer rows . Close ( )
for rows . Next ( ) {
var folder vfs . VirtualFolder
var userID int64
2021-03-21 18:15:47 +00:00
var mappedPath , fsConfig , description sql . NullString
2021-02-01 18:04:15 +00:00
err = rows . Scan ( & folder . ID , & folder . Name , & mappedPath , & folder . UsedQuotaSize , & folder . UsedQuotaFiles ,
2021-03-21 18:15:47 +00:00
& folder . LastQuotaUpdate , & folder . VirtualPath , & folder . QuotaSize , & folder . QuotaFiles , & userID , & fsConfig ,
& description )
2020-06-07 21:30:18 +00:00
if err != nil {
return users , err
}
2021-02-01 18:04:15 +00:00
if mappedPath . Valid {
folder . MappedPath = mappedPath . String
}
2021-03-21 18:15:47 +00:00
if description . Valid {
folder . Description = description . String
}
if fsConfig . Valid {
var fs vfs . Filesystem
err = json . Unmarshal ( [ ] byte ( fsConfig . String ) , & fs )
if err == nil {
folder . FsConfig = fs
}
}
2020-06-07 21:30:18 +00:00
usersVirtualFolders [ userID ] = append ( usersVirtualFolders [ userID ] , folder )
}
err = rows . Err ( )
if err != nil {
return users , err
}
if len ( usersVirtualFolders ) == 0 {
return users , err
}
for idx := range users {
ref := & users [ idx ]
ref . VirtualFolders = usersVirtualFolders [ ref . ID ]
}
return users , err
}
2022-04-25 13:49:11 +00:00
func getUserWithGroups ( ctx context . Context , user User , dbHandle sqlQuerier ) ( User , error ) {
users , err := getUsersWithGroups ( ctx , [ ] User { user } , dbHandle )
if err != nil {
return user , err
}
if len ( users ) == 0 {
return user , errSQLGroupsAssociation
}
return users [ 0 ] , err
}
func getUsersWithGroups ( ctx context . Context , users [ ] User , dbHandle sqlQuerier ) ( [ ] User , error ) {
if len ( users ) == 0 {
return users , nil
}
var err error
usersGroups := make ( map [ int64 ] [ ] sdk . GroupMapping )
q := getRelatedGroupsForUsersQuery ( users )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx )
if err != nil {
return nil , err
}
defer rows . Close ( )
for rows . Next ( ) {
var group sdk . GroupMapping
var userID int64
err = rows . Scan ( & group . Name , & group . Type , & userID )
if err != nil {
return users , err
}
usersGroups [ userID ] = append ( usersGroups [ userID ] , group )
}
err = rows . Err ( )
if err != nil {
return users , err
}
if len ( usersGroups ) == 0 {
return users , err
}
for idx := range users {
ref := & users [ idx ]
ref . Groups = usersGroups [ ref . ID ]
}
return users , err
}
func getGroupWithUsers ( ctx context . Context , group Group , dbHandle sqlQuerier ) ( Group , error ) {
groups , err := getGroupsWithUsers ( ctx , [ ] Group { group } , dbHandle )
if err != nil {
return group , err
}
if len ( groups ) == 0 {
return group , errSQLUsersAssociation
}
return groups [ 0 ] , err
}
func getGroupWithVirtualFolders ( ctx context . Context , group Group , dbHandle sqlQuerier ) ( Group , error ) {
groups , err := getGroupsWithVirtualFolders ( ctx , [ ] Group { group } , dbHandle )
if err != nil {
return group , err
}
if len ( groups ) == 0 {
return group , errSQLFoldersAssociation
}
return groups [ 0 ] , err
}
func getGroupsWithVirtualFolders ( ctx context . Context , groups [ ] Group , dbHandle sqlQuerier ) ( [ ] Group , error ) {
if len ( groups ) == 0 {
return groups , nil
}
var err error
q := getRelatedFoldersForGroupsQuery ( groups )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx )
if err != nil {
return nil , err
}
defer rows . Close ( )
groupsVirtualFolders := make ( map [ int64 ] [ ] vfs . VirtualFolder )
for rows . Next ( ) {
var groupID int64
var folder vfs . VirtualFolder
var mappedPath , fsConfig , description sql . NullString
err = rows . Scan ( & folder . ID , & folder . Name , & mappedPath , & folder . UsedQuotaSize , & folder . UsedQuotaFiles ,
& folder . LastQuotaUpdate , & folder . VirtualPath , & folder . QuotaSize , & folder . QuotaFiles , & groupID , & fsConfig ,
& description )
if err != nil {
return groups , err
}
if mappedPath . Valid {
folder . MappedPath = mappedPath . String
}
if description . Valid {
folder . Description = description . String
}
if fsConfig . Valid {
var fs vfs . Filesystem
err = json . Unmarshal ( [ ] byte ( fsConfig . String ) , & fs )
if err == nil {
folder . FsConfig = fs
}
}
groupsVirtualFolders [ groupID ] = append ( groupsVirtualFolders [ groupID ] , folder )
}
err = rows . Err ( )
if err != nil {
return groups , err
}
if len ( groupsVirtualFolders ) == 0 {
return groups , err
}
for idx := range groups {
ref := & groups [ idx ]
ref . VirtualFolders = groupsVirtualFolders [ ref . ID ]
}
return groups , err
}
func getGroupsWithUsers ( ctx context . Context , groups [ ] Group , dbHandle sqlQuerier ) ( [ ] Group , error ) {
if len ( groups ) == 0 {
return groups , nil
}
var err error
q := getRelatedUsersForGroupsQuery ( groups )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx )
if err != nil {
return nil , err
}
defer rows . Close ( )
groupsUsers := make ( map [ int64 ] [ ] string )
for rows . Next ( ) {
var username string
var groupID int64
err = rows . Scan ( & groupID , & username )
if err != nil {
return groups , err
}
groupsUsers [ groupID ] = append ( groupsUsers [ groupID ] , username )
}
err = rows . Err ( )
if err != nil {
return groups , err
}
if len ( groupsUsers ) == 0 {
return groups , err
}
for idx := range groups {
ref := & groups [ idx ]
ref . Users = groupsUsers [ ref . ID ]
}
return groups , err
}
func getVirtualFoldersWithGroups ( folders [ ] vfs . BaseVirtualFolder , dbHandle sqlQuerier ) ( [ ] vfs . BaseVirtualFolder , error ) {
if len ( folders ) == 0 {
return folders , nil
}
var err error
vFoldersGroups := make ( map [ int64 ] [ ] string )
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getRelatedGroupsForFoldersQuery ( folders )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx )
if err != nil {
return nil , err
}
defer rows . Close ( )
for rows . Next ( ) {
var name string
var folderID int64
err = rows . Scan ( & folderID , & name )
if err != nil {
return folders , err
}
vFoldersGroups [ folderID ] = append ( vFoldersGroups [ folderID ] , name )
}
err = rows . Err ( )
if err != nil {
return folders , err
}
if len ( vFoldersGroups ) == 0 {
return folders , err
}
for idx := range folders {
ref := & folders [ idx ]
ref . Groups = vFoldersGroups [ ref . ID ]
}
return folders , err
}
2020-06-07 21:30:18 +00:00
func getVirtualFoldersWithUsers ( folders [ ] vfs . BaseVirtualFolder , dbHandle sqlQuerier ) ( [ ] vfs . BaseVirtualFolder , error ) {
if len ( folders ) == 0 {
2021-08-17 16:08:32 +00:00
return folders , nil
2020-06-07 21:30:18 +00:00
}
2021-08-17 16:08:32 +00:00
var err error
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2020-06-07 21:30:18 +00:00
q := getRelatedUsersForFoldersQuery ( folders )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-06-07 21:30:18 +00:00
return nil , err
}
defer stmt . Close ( )
2020-07-08 16:54:44 +00:00
rows , err := stmt . QueryContext ( ctx )
2020-06-07 21:30:18 +00:00
if err != nil {
return nil , err
}
defer rows . Close ( )
2022-04-25 13:49:11 +00:00
vFoldersUsers := make ( map [ int64 ] [ ] string )
2020-06-07 21:30:18 +00:00
for rows . Next ( ) {
var username string
var folderID int64
err = rows . Scan ( & folderID , & username )
if err != nil {
return folders , err
}
vFoldersUsers [ folderID ] = append ( vFoldersUsers [ folderID ] , username )
}
err = rows . Err ( )
if err != nil {
return folders , err
}
if len ( vFoldersUsers ) == 0 {
return folders , err
}
for idx := range folders {
ref := & folders [ idx ]
ref . Users = vFoldersUsers [ ref . ID ]
}
return folders , err
}
2021-02-01 18:04:15 +00:00
func sqlCommonUpdateFolderQuota ( name string , filesAdd int , sizeAdd int64 , reset bool , dbHandle * sql . DB ) error {
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2020-06-07 21:30:18 +00:00
q := getUpdateFolderQuotaQuery ( reset )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-06-07 21:30:18 +00:00
return err
}
defer stmt . Close ( )
2021-07-11 13:26:51 +00:00
_ , err = stmt . ExecContext ( ctx , sizeAdd , filesAdd , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , name )
2020-06-07 21:30:18 +00:00
if err == nil {
providerLog ( logger . LevelDebug , "quota updated for folder %#v, files increment: %v size increment: %v is reset? %v" ,
2021-02-01 18:04:15 +00:00
name , filesAdd , sizeAdd , reset )
2020-06-07 21:30:18 +00:00
} else {
2021-02-01 18:04:15 +00:00
providerLog ( logger . LevelWarn , "error updating quota for folder %#v: %v" , name , err )
2020-06-07 21:30:18 +00:00
}
return err
}
func sqlCommonGetFolderUsedQuota ( mappedPath string , dbHandle * sql . DB ) ( int , int64 , error ) {
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2020-06-07 21:30:18 +00:00
q := getQuotaFolderQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-06-07 21:30:18 +00:00
return 0 , 0 , err
}
defer stmt . Close ( )
var usedFiles int
var usedSize int64
2020-07-08 16:54:44 +00:00
err = stmt . QueryRowContext ( ctx , mappedPath ) . Scan ( & usedSize , & usedFiles )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error getting quota for folder: %v, error: %v" , mappedPath , err )
2020-06-07 21:30:18 +00:00
return 0 , 0 , err
}
return usedFiles , usedSize , err
2019-07-20 10:26:52 +00:00
}
2020-02-08 13:44:25 +00:00
2021-08-17 16:08:32 +00:00
func getAPIKeyWithRelatedFields ( ctx context . Context , apiKey APIKey , dbHandle sqlQuerier ) ( APIKey , error ) {
var apiKeys [ ] APIKey
var err error
scope := APIKeyScopeAdmin
if apiKey . userID > 0 {
scope = APIKeyScopeUser
}
apiKeys , err = getRelatedValuesForAPIKeys ( ctx , [ ] APIKey { apiKey } , dbHandle , scope )
if err != nil {
return apiKey , err
}
if len ( apiKeys ) > 0 {
apiKey = apiKeys [ 0 ]
}
return apiKey , nil
}
func getRelatedValuesForAPIKeys ( ctx context . Context , apiKeys [ ] APIKey , dbHandle sqlQuerier , scope APIKeyScope ) ( [ ] APIKey , error ) {
if len ( apiKeys ) == 0 {
return apiKeys , nil
}
values := make ( map [ int64 ] string )
var q string
if scope == APIKeyScopeUser {
q = getRelatedUsersForAPIKeysQuery ( apiKeys )
} else {
q = getRelatedAdminsForAPIKeysQuery ( apiKeys )
}
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2021-08-17 16:08:32 +00:00
return nil , err
}
defer stmt . Close ( )
rows , err := stmt . QueryContext ( ctx )
if err != nil {
return nil , err
}
defer rows . Close ( )
for rows . Next ( ) {
var valueID int64
var valueName string
err = rows . Scan ( & valueID , & valueName )
if err != nil {
return apiKeys , err
}
values [ valueID ] = valueName
}
err = rows . Err ( )
if err != nil {
return apiKeys , err
}
if len ( values ) == 0 {
return apiKeys , nil
}
for idx := range apiKeys {
ref := & apiKeys [ idx ]
if scope == APIKeyScopeUser {
ref . User = values [ ref . userID ]
} else {
ref . Admin = values [ ref . adminID ]
}
}
return apiKeys , nil
}
func sqlCommonGetAPIKeyRelatedIDs ( apiKey * APIKey ) ( sql . NullInt64 , sql . NullInt64 , error ) {
var userID , adminID sql . NullInt64
if apiKey . User != "" {
u , err := provider . userExists ( apiKey . User )
if err != nil {
return userID , adminID , util . NewValidationError ( fmt . Sprintf ( "unable to validate user %v" , apiKey . User ) )
}
userID . Valid = true
userID . Int64 = u . ID
}
if apiKey . Admin != "" {
a , err := provider . adminExists ( apiKey . Admin )
if err != nil {
return userID , adminID , util . NewValidationError ( fmt . Sprintf ( "unable to validate admin %v" , apiKey . Admin ) )
}
adminID . Valid = true
adminID . Int64 = a . ID
}
return userID , adminID , nil
}
2022-05-19 17:49:51 +00:00
func sqlCommonAddSession ( session Session , dbHandle * sql . DB ) error {
if err := session . validate ( ) ; err != nil {
return err
}
data , err := json . Marshal ( session . Data )
if err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getAddSessionQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , session . Key , data , session . Type , session . Timestamp )
return err
}
func sqlCommonGetSession ( key string , dbHandle sqlQuerier ) ( Session , error ) {
var session Session
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getSessionQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return session , err
}
defer stmt . Close ( )
var data [ ] byte // type hint, some driver will use string instead of []byte if the type is any
err = stmt . QueryRowContext ( ctx , key ) . Scan ( & session . Key , & data , & session . Type , & session . Timestamp )
if err != nil {
return session , err
}
session . Data = data
return session , nil
}
func sqlCommonDeleteSession ( key string , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDeleteSessionQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
res , err := stmt . ExecContext ( ctx , key )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
}
func sqlCommonCleanupSessions ( sessionType SessionType , before int64 , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getCleanupSessionsQuery ( )
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
return err
}
defer stmt . Close ( )
_ , err = stmt . ExecContext ( ctx , sessionType , before )
return err
}
2022-05-15 13:25:12 +00:00
func sqlCommonGetDatabaseVersion ( dbHandle sqlQuerier , showInitWarn bool ) ( schemaVersion , error ) {
2020-02-08 13:44:25 +00:00
var result schemaVersion
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2022-05-15 13:25:12 +00:00
2020-02-08 13:44:25 +00:00
q := getDatabaseVersionQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-02-08 13:44:25 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-08-30 11:50:43 +00:00
if showInitWarn && strings . Contains ( err . Error ( ) , sqlTableSchemaVersion ) {
2020-07-09 18:01:37 +00:00
logger . WarnToConsole ( "database query error, did you forgot to run the \"initprovider\" command?" )
}
2020-02-08 13:44:25 +00:00
return result , err
}
defer stmt . Close ( )
2020-07-08 16:54:44 +00:00
row := stmt . QueryRowContext ( ctx )
2020-02-08 13:44:25 +00:00
err = row . Scan ( & result . Version )
return result , err
}
2022-05-19 17:49:51 +00:00
func sqlCommonRequireRowAffected ( res sql . Result ) error {
// MariaDB/MySQL returns 0 rows affected for updates that don't change anything
// so we don't check rows affected for updates
affected , err := res . RowsAffected ( )
if err == nil && affected == 0 {
return util . NewRecordNotFoundError ( sql . ErrNoRows . Error ( ) )
}
return nil
}
2020-07-08 16:54:44 +00:00
func sqlCommonUpdateDatabaseVersion ( ctx context . Context , dbHandle sqlQuerier , version int ) error {
2020-02-08 13:44:25 +00:00
q := getUpdateDBVersionQuery ( )
2020-07-08 16:54:44 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
2020-02-08 13:44:25 +00:00
if err != nil {
2021-12-16 18:53:00 +00:00
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
2020-02-08 13:44:25 +00:00
return err
}
defer stmt . Close ( )
2020-07-08 16:54:44 +00:00
_ , err = stmt . ExecContext ( ctx , version )
2020-02-08 13:44:25 +00:00
return err
2020-02-23 10:30:26 +00:00
}
2020-02-08 13:44:25 +00:00
2022-05-19 17:49:51 +00:00
func sqlCommonExecSQLAndUpdateDBVersion ( dbHandle * sql . DB , sqlQueries [ ] string , newVersion int , isUp bool ) error {
if err := sqlAcquireLock ( dbHandle ) ; err != nil {
2022-05-15 13:25:12 +00:00
return err
}
defer sqlReleaseLock ( dbHandle )
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , longSQLQueryTimeout )
defer cancel ( )
2021-03-23 18:14:15 +00:00
2022-05-15 13:25:12 +00:00
if newVersion > 0 {
currentVersion , err := sqlCommonGetDatabaseVersion ( dbHandle , false )
2022-05-19 17:49:51 +00:00
if err == nil {
if ( isUp && currentVersion . Version >= newVersion ) || ( ! isUp && currentVersion . Version <= newVersion ) {
providerLog ( logger . LevelInfo , "current schema version: %v, requested: %v, did you execute simultaneous migrations?" ,
currentVersion . Version , newVersion )
return nil
}
2022-05-15 13:25:12 +00:00
}
}
2021-03-23 18:14:15 +00:00
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
for _ , q := range sqlQueries {
if strings . TrimSpace ( q ) == "" {
continue
}
_ , err := tx . ExecContext ( ctx , q )
if err != nil {
return err
}
}
2021-11-15 17:40:31 +00:00
if newVersion == 0 {
return nil
}
2021-03-23 18:14:15 +00:00
return sqlCommonUpdateDatabaseVersion ( ctx , tx , newVersion )
} )
}
2022-05-19 17:49:51 +00:00
func sqlAcquireLock ( dbHandle * sql . DB ) error {
2022-05-15 13:25:12 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , longSQLQueryTimeout )
defer cancel ( )
switch config . Driver {
case PGSQLDataProviderName :
_ , err := dbHandle . ExecContext ( ctx , ` SELECT pg_advisory_lock(101,1) ` )
if err != nil {
return fmt . Errorf ( "unable to get advisory lock: %w" , err )
}
providerLog ( logger . LevelInfo , "acquired database lock" )
case MySQLDataProviderName :
stmt , err := dbHandle . PrepareContext ( ctx , ` SELECT GET_LOCK('sftpgo.migration',30) ` )
if err != nil {
return fmt . Errorf ( "unable to get lock: %w" , err )
}
defer stmt . Close ( )
var lockResult sql . NullInt64
err = stmt . QueryRowContext ( ctx ) . Scan ( & lockResult )
if err != nil {
return fmt . Errorf ( "unable to get lock: %w" , err )
}
if ! lockResult . Valid {
return errors . New ( "unable to get lock: null value returned" )
}
if lockResult . Int64 != 1 {
return fmt . Errorf ( "unable to get lock, result: %v" , lockResult . Int64 )
}
providerLog ( logger . LevelInfo , "acquired database lock" )
}
return nil
}
func sqlReleaseLock ( dbHandle * sql . DB ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
switch config . Driver {
case PGSQLDataProviderName :
_ , err := dbHandle . ExecContext ( ctx , ` SELECT pg_advisory_unlock(101,1) ` )
if err != nil {
providerLog ( logger . LevelWarn , "unable to release lock: %v" , err )
} else {
providerLog ( logger . LevelInfo , "released database lock" )
}
case MySQLDataProviderName :
_ , err := dbHandle . ExecContext ( ctx , ` SELECT RELEASE_LOCK('sftpgo.migration') ` )
if err != nil {
providerLog ( logger . LevelWarn , "unable to release lock: %v" , err )
} else {
providerLog ( logger . LevelInfo , "released database lock" )
}
}
}
2021-03-23 18:14:15 +00:00
func sqlCommonExecuteTx ( ctx context . Context , dbHandle * sql . DB , txFn func ( * sql . Tx ) error ) error {
2021-03-25 08:07:56 +00:00
if config . Driver == CockroachDataProviderName {
return crdb . ExecuteTx ( ctx , dbHandle , nil , txFn )
}
2020-07-08 16:54:44 +00:00
tx , err := dbHandle . BeginTx ( ctx , nil )
2020-02-23 10:30:26 +00:00
if err != nil {
return err
}
2021-03-23 18:14:15 +00:00
err = txFn ( tx )
2020-06-07 21:30:18 +00:00
if err != nil {
2021-03-23 18:14:15 +00:00
// we don't change the returned error
tx . Rollback ( ) //nolint:errcheck
2020-06-07 21:30:18 +00:00
return err
}
return tx . Commit ( )
}