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"
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"
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-01-30 10:42:36 +00:00
sqlDatabaseVersion = 16
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 (
errSQLFoldersAssosaction = errors . New ( "unable to associate virtual folders to user" )
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 {
Scan ( dest ... interface { } ) error
}
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
}
func sqlCommonDeleteShare ( share * Share , dbHandle * sql . DB ) error {
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 ( )
_ , err = stmt . ExecContext ( ctx , share . ShareID )
return err
}
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
}
func sqlCommonDeleteAPIKey ( apiKey * APIKey , dbHandle * sql . DB ) error {
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 ( )
_ , err = stmt . ExecContext ( ctx , apiKey . KeyID )
return err
}
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
}
func sqlCommonDeleteAdmin ( admin * Admin , dbHandle * sql . DB ) error {
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 ( )
_ , err = stmt . ExecContext ( ctx , admin . Username )
return err
}
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 ( )
}
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 ( )
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
}
2021-04-19 16:58:53 +00:00
return getUserWithVirtualFolders ( 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
}
2019-09-13 16:45:36 +00:00
func sqlCommonCheckAvailability ( dbHandle * sql . DB ) error {
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 ( )
return dbHandle . PingContext ( ctx )
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
}
return generateVirtualFoldersMapping ( ctx , user , tx )
} )
2019-07-20 10:26:52 +00:00
}
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
}
return generateVirtualFoldersMapping ( ctx , user , tx )
} )
2019-07-20 10:26:52 +00:00
}
2021-01-05 08:50:22 +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 ( )
2020-07-08 16:54:44 +00:00
_ , err = stmt . ExecContext ( ctx , user . ID )
2019-07-20 10:26:52 +00:00
return err
}
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
}
err = addCredentialsToUser ( & u )
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
}
2021-04-19 16:58:53 +00:00
return getUsersWithVirtualFolders ( 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
}
return getUsersWithVirtualFolders ( ctx , users , dbHandle )
}
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 ]
if len ( usersWithFolders ) == 0 {
return users , nil
}
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 ... )
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 ( )
queryArgs := make ( [ ] interface { } , 0 , len ( usernames ) )
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
}
2021-03-22 18:03:25 +00:00
u . PrepareForRendering ( )
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
}
2021-04-19 16:58:53 +00:00
return getUsersWithVirtualFolders ( ctx , users , dbHandle )
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 ( )
_ , err = stmt . ExecContext ( ctx , ip )
if err != nil {
providerLog ( logger . LevelError , "unable to delete defender host %#v: %v" , ip , err )
}
return err
}
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
}
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 sqlCommonCheckFolderExists ( ctx context . Context , name string , dbHandle sqlQuerier ) error {
var folderName string
q := checkFolderNameQuery ( )
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-03-21 18:15:47 +00:00
return err
}
defer stmt . Close ( )
row := stmt . QueryRowContext ( ctx , name )
return row . Scan ( & folderName )
}
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 )
}
return folders [ 0 ] , nil
}
2021-03-21 18:15:47 +00:00
func sqlCommonAddOrUpdateFolder ( ctx context . Context , baseFolder * vfs . BaseVirtualFolder , usedQuotaSize int64 ,
usedQuotaFiles int , lastQuotaUpdate int64 , dbHandle sqlQuerier ) ( vfs . BaseVirtualFolder , error ) {
var folder vfs . BaseVirtualFolder
// FIXME: we could use an UPSERT here, this SELECT could be racy
err := sqlCommonCheckFolderExists ( ctx , baseFolder . Name , dbHandle )
switch err {
case nil :
err = sqlCommonUpdateFolder ( baseFolder , dbHandle )
if err != nil {
return folder , err
2020-01-19 06:41:05 +00:00
}
2021-03-21 18:15:47 +00:00
case sql . ErrNoRows :
baseFolder . UsedQuotaFiles = usedQuotaFiles
baseFolder . UsedQuotaSize = usedQuotaSize
baseFolder . LastQuotaUpdate = lastQuotaUpdate
err = sqlCommonAddFolder ( baseFolder , dbHandle )
2020-06-07 21:30:18 +00:00
if err != nil {
return folder , err
}
2021-03-21 18:15:47 +00:00
default :
return folder , err
2020-01-19 06:41:05 +00:00
}
2021-03-21 18:15:47 +00:00
return sqlCommonGetFolder ( ctx , baseFolder . Name , dbHandle )
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
}
2021-01-05 08:50:22 +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 ( )
2020-07-08 16:54:44 +00:00
_ , err = stmt . ExecContext ( ctx , folder . ID )
2020-06-07 21:30:18 +00:00
return err
}
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 )
}
err = rows . Err ( )
if err != nil {
return folders , err
}
return getVirtualFoldersWithUsers ( folders , dbHandle )
}
2021-02-01 18:04:15 +00:00
func sqlCommonGetFolders ( limit , offset int , order string , 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 ( )
2021-02-01 18:04:15 +00:00
q := getFoldersQuery ( order )
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
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
}
}
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
}
return getVirtualFoldersWithUsers ( folders , dbHandle )
}
2021-01-05 08:50:22 +00:00
func sqlCommonClearFolderMapping ( ctx context . Context , user * User , dbHandle sqlQuerier ) error {
2020-06-07 21:30:18 +00:00
q := getClearFolderMappingQuery ( )
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
}
2021-03-21 18:15:47 +00:00
func sqlCommonAddFolderMapping ( ctx context . Context , user * User , folder * vfs . VirtualFolder , dbHandle sqlQuerier ) error {
2020-06-07 21:30:18 +00:00
q := getAddFolderMappingQuery ( )
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 , folder . VirtualPath , folder . QuotaSize , folder . QuotaFiles , folder . ID , user . Username )
2020-06-07 21:30:18 +00:00
return err
}
2021-01-05 08:50:22 +00:00
func generateVirtualFoldersMapping ( ctx context . Context , user * User , dbHandle sqlQuerier ) error {
2020-07-08 16:54:44 +00:00
err := sqlCommonClearFolderMapping ( 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 ]
f , err := sqlCommonAddOrUpdateFolder ( ctx , & vfolder . BaseVirtualFolder , 0 , 0 , 0 , dbHandle )
2020-06-07 21:30:18 +00:00
if err != nil {
return err
}
vfolder . BaseVirtualFolder = f
2020-07-08 16:54:44 +00:00
err = sqlCommonAddFolderMapping ( ctx , user , vfolder , dbHandle )
2020-06-07 21:30:18 +00:00
if err != nil {
return err
}
}
return err
}
2021-04-19 16:58:53 +00:00
func getUserWithVirtualFolders ( ctx context . Context , user User , dbHandle sqlQuerier ) ( User , error ) {
users , err := getUsersWithVirtualFolders ( ctx , [ ] User { user } , dbHandle )
2020-06-07 21:30:18 +00:00
if err != nil {
return user , err
}
if len ( users ) == 0 {
return user , errSQLFoldersAssosaction
}
return users [ 0 ] , err
}
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
}
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
}
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
vFoldersUsers := make ( map [ int64 ] [ ] string )
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 ( )
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
}
2020-08-30 11:50:43 +00:00
func sqlCommonGetDatabaseVersion ( dbHandle * sql . DB , 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 ( )
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
}
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
2021-03-23 18:14:15 +00:00
func sqlCommonExecSQLAndUpdateDBVersion ( dbHandle * sql . DB , sqlQueries [ ] string , newVersion int ) error {
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
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 )
} )
}
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 ( )
}