2023-01-03 09:18:30 +00:00
// Copyright (C) 2019-2023 Nicola Murino
2022-07-17 18:16:00 +00:00
//
// 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
2023-01-03 09:18:30 +00:00
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2022-07-17 18:16:00 +00:00
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"
2023-02-09 08:33:33 +00:00
"net/netip"
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
2022-07-24 14:18:54 +00:00
"github.com/drakkan/sftpgo/v2/internal/logger"
"github.com/drakkan/sftpgo/v2/internal/util"
"github.com/drakkan/sftpgo/v2/internal/vfs"
2019-07-20 10:26:52 +00:00
)
2020-02-08 13:44:25 +00:00
const (
2023-02-09 08:33:33 +00:00
sqlDatabaseVersion = 27
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 {
2022-06-11 09:57:06 +00:00
QueryRowContext ( ctx context . Context , query string , args ... any ) * sql . Row
QueryContext ( ctx context . Context , query string , args ... any ) ( * sql . Rows , error )
ExecContext ( ctx context . Context , query string , args ... any ) ( sql . Result , error )
2022-07-19 20:25:00 +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 , "{{users_folders_mapping}}" , sqlTableUsersFoldersMapping )
sql = strings . ReplaceAll ( sql , "{{users_groups_mapping}}" , sqlTableUsersGroupsMapping )
2022-09-13 16:04:27 +00:00
sql = strings . ReplaceAll ( sql , "{{admins_groups_mapping}}" , sqlTableAdminsGroupsMapping )
2022-04-25 13:49:11 +00:00
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 18:08:49 +00:00
sql = strings . ReplaceAll ( sql , "{{shared_sessions}}" , sqlTableSharedSessions )
2022-07-11 06:17:36 +00:00
sql = strings . ReplaceAll ( sql , "{{events_actions}}" , sqlTableEventsActions )
sql = strings . ReplaceAll ( sql , "{{events_rules}}" , sqlTableEventsRules )
sql = strings . ReplaceAll ( sql , "{{rules_actions_mapping}}" , sqlTableRulesActionsMapping )
sql = strings . ReplaceAll ( sql , "{{tasks}}" , sqlTableTasks )
2022-09-25 17:48:55 +00:00
sql = strings . ReplaceAll ( sql , "{{nodes}}" , sqlTableNodes )
2022-11-16 18:04:50 +00:00
sql = strings . ReplaceAll ( sql , "{{roles}}" , sqlTableRoles )
2023-02-09 08:33:33 +00:00
sql = strings . ReplaceAll ( sql , "{{ip_lists}}" , sqlTableIPLists )
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 ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
filterUser := username != ""
q := getShareByIDQuery ( filterUser )
2022-06-11 09:57:06 +00:00
2021-11-06 13:13:20 +00:00
var row * sql . Row
if filterUser {
2022-06-11 09:57:06 +00:00
row = dbHandle . QueryRowContext ( ctx , q , shareID , username )
2021-11-06 13:13:20 +00:00
} else {
2022-06-11 09:57:06 +00:00
row = dbHandle . QueryRowContext ( ctx , q , shareID )
2021-11-06 13:13:20 +00:00
}
return getShareFromDbRow ( row )
}
func sqlCommonAddShare ( share * Share , dbHandle * sql . DB ) error {
err := share . validate ( )
if err != nil {
return err
}
2022-11-16 18:04:50 +00:00
user , err := provider . userExists ( share . Username , "" )
2021-11-06 13:13:20 +00:00
if err != nil {
2023-01-21 14:41:24 +00:00
return util . NewGenericError ( fmt . Sprintf ( "unable to validate user %#v" , share . Username ) )
2021-11-06 13:13:20 +00:00
}
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 ( )
2022-06-11 09:57:06 +00:00
q := getAddShareQuery ( )
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
}
2022-06-11 09:57:06 +00:00
_ , err = dbHandle . ExecContext ( ctx , q , 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 )
}
}
2022-11-16 18:04:50 +00:00
user , err := provider . userExists ( share . Username , "" )
2021-11-06 13:13:20 +00:00
if err != nil {
2023-01-21 14:41:24 +00:00
return util . NewGenericError ( fmt . Sprintf ( "unable to validate user %#v" , share . Username ) )
2021-11-06 13:13:20 +00:00
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2022-06-11 09:57:06 +00:00
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
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
}
2022-06-11 09:57:06 +00:00
_ , err = dbHandle . ExecContext ( ctx , q , share . Name , share . Description , share . Scope , string ( paths ) ,
2021-11-27 10:12:51 +00:00
share . CreatedAt , share . UpdatedAt , share . LastUseAt , share . ExpiresAt , share . Password , share . MaxTokens ,
share . UsedTokens , allowFrom , user . ID , share . ShareID )
} else {
2022-06-11 09:57:06 +00:00
_ , err = dbHandle . ExecContext ( ctx , q , share . Name , share . Description , share . Scope , string ( paths ) ,
2021-11-27 10:12:51 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
res , err := dbHandle . ExecContext ( ctx , q , share . ShareID )
2022-05-19 17:49:51 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
q := getSharesQuery ( order )
rows , err := dbHandle . QueryContext ( ctx , q , username , limit , offset )
2021-11-06 13:13:20 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
q := getDumpSharesQuery ( )
rows , err := dbHandle . QueryContext ( ctx , q )
2021-11-06 13:13:20 +00:00
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 ) {
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 ( )
2022-06-11 09:57:06 +00:00
row := dbHandle . QueryRowContext ( ctx , q , keyID )
2021-08-17 16:08:32 +00:00
2022-06-11 09:57:06 +00:00
apiKey , err := getAPIKeyFromDbRow ( row )
2021-08-17 16:08:32 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
q := getAddAPIKeyQuery ( )
_ , err = dbHandle . ExecContext ( ctx , q , apiKey . KeyID , apiKey . Name , apiKey . Key , apiKey . Scope ,
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , apiKey . LastUseAt ,
apiKey . ExpiresAt , apiKey . Description , userID , adminID )
2021-08-17 16:08:32 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
q := getUpdateAPIKeyQuery ( )
_ , err = dbHandle . ExecContext ( ctx , q , apiKey . Name , apiKey . Scope , apiKey . ExpiresAt , userID , adminID ,
2021-08-17 16:08:32 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
2021-08-17 16:08:32 +00:00
q := getDeleteAPIKeyQuery ( )
2022-06-11 09:57:06 +00:00
res , err := dbHandle . ExecContext ( ctx , q , apiKey . KeyID )
2022-05-19 17:49:51 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
q := getAPIKeysQuery ( order )
rows , err := dbHandle . QueryContext ( ctx , q , limit , offset )
2021-08-17 16:08:32 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
q := getDumpAPIKeysQuery ( )
rows , err := dbHandle . QueryContext ( ctx , q )
2021-08-17 16:08:32 +00:00
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 ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2022-06-11 09:57:06 +00:00
2021-01-17 21:29:08 +00:00
q := getAdminByUsernameQuery ( )
2022-06-11 09:57:06 +00:00
row := dbHandle . QueryRowContext ( ctx , q , username )
2021-01-17 21:29:08 +00:00
2022-09-13 16:04:27 +00:00
admin , err := getAdminFromDbRow ( row )
if err != nil {
return admin , err
}
return getAdminWithGroups ( ctx , admin , dbHandle )
2021-01-17 21:29:08 +00:00
}
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
}
perms , err := json . Marshal ( admin . Permissions )
if err != nil {
return err
}
filters , err := json . Marshal ( admin . Filters )
if err != nil {
return err
}
2022-09-13 16:04:27 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
2022-11-16 18:04:50 +00:00
q := getAddAdminQuery ( admin . Role )
2022-09-13 16:04:27 +00:00
_ , err = tx . ExecContext ( ctx , q , admin . Username , admin . Password , admin . Status , admin . Email , string ( perms ) ,
string ( filters ) , admin . AdditionalInfo , admin . Description , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
2022-11-16 18:04:50 +00:00
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , admin . Role )
2022-09-13 16:04:27 +00:00
if err != nil {
return err
}
return generateAdminGroupMapping ( ctx , admin , tx )
} )
2021-01-17 21:29:08 +00:00
}
func sqlCommonUpdateAdmin ( admin * Admin , dbHandle * sql . DB ) error {
err := admin . validate ( )
if err != nil {
return err
}
perms , err := json . Marshal ( admin . Permissions )
if err != nil {
return err
}
filters , err := json . Marshal ( admin . Filters )
if err != nil {
return err
}
2022-09-13 16:04:27 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
2022-11-16 18:04:50 +00:00
q := getUpdateAdminQuery ( admin . Role )
2022-09-13 16:04:27 +00:00
_ , err = tx . ExecContext ( ctx , q , admin . Password , admin . Status , admin . Email , string ( perms ) , string ( filters ) ,
2022-11-16 18:04:50 +00:00
admin . AdditionalInfo , admin . Description , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , admin . Role , admin . Username )
2022-09-13 16:04:27 +00:00
if err != nil {
return err
}
return generateAdminGroupMapping ( ctx , admin , tx )
} )
2021-01-17 21:29:08 +00:00
}
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 ( )
2022-06-11 09:57:06 +00:00
2021-01-17 21:29:08 +00:00
q := getDeleteAdminQuery ( )
2022-06-11 09:57:06 +00:00
res , err := dbHandle . ExecContext ( ctx , q , admin . Username )
2022-05-19 17:49:51 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
q := getAdminsQuery ( order )
rows , err := dbHandle . QueryContext ( ctx , q , limit , offset )
2021-01-17 21:29:08 +00:00
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 )
}
2022-09-13 16:04:27 +00:00
err = rows . Err ( )
if err != nil {
return admins , err
}
return getAdminsWithGroups ( ctx , admins , dbHandle )
2021-01-17 21:29:08 +00:00
}
func sqlCommonDumpAdmins ( dbHandle sqlQuerier ) ( [ ] Admin , error ) {
admins := make ( [ ] Admin , 0 , 30 )
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2022-06-11 09:57:06 +00:00
q := getDumpAdminsQuery ( )
rows , err := dbHandle . QueryContext ( ctx , q )
2021-01-17 21:29:08 +00:00
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 )
}
2022-09-13 16:04:27 +00:00
err = rows . Err ( )
if err != nil {
return admins , err
}
return getAdminsWithGroups ( ctx , admins , dbHandle )
2021-01-17 21:29:08 +00:00
}
2023-02-09 08:33:33 +00:00
func sqlCommonGetIPListEntry ( ipOrNet string , listType IPListType , dbHandle sqlQuerier ) ( IPListEntry , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getIPListEntryQuery ( )
row := dbHandle . QueryRowContext ( ctx , q , listType , ipOrNet )
return getIPListEntryFromDbRow ( row )
}
func sqlCommonDumpIPListEntries ( dbHandle * sql . DB ) ( [ ] IPListEntry , error ) {
count , err := sqlCommonCountIPListEntries ( 0 , dbHandle )
if err != nil {
return nil , err
}
if count > ipListMemoryLimit {
providerLog ( logger . LevelInfo , "IP lists excluded from dump, too many entries: %d" , count )
return nil , nil
}
entries := make ( [ ] IPListEntry , 0 , 100 )
ctx , cancel := context . WithTimeout ( context . Background ( ) , longSQLQueryTimeout )
defer cancel ( )
q := getDumpListEntriesQuery ( )
rows , err := dbHandle . QueryContext ( ctx , q )
if err != nil {
return entries , err
}
defer rows . Close ( )
for rows . Next ( ) {
entry , err := getIPListEntryFromDbRow ( rows )
if err != nil {
return entries , err
}
entries = append ( entries , entry )
}
return entries , rows . Err ( )
}
func sqlCommonCountIPListEntries ( listType IPListType , dbHandle * sql . DB ) ( int64 , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
var q string
var args [ ] any
if listType == 0 {
q = getCountAllIPListEntriesQuery ( )
} else {
q = getCountIPListEntriesQuery ( )
args = append ( args , listType )
}
var count int64
err := dbHandle . QueryRowContext ( ctx , q , args ... ) . Scan ( & count )
return count , err
}
func sqlCommonGetIPListEntries ( listType IPListType , filter , from , order string , limit int , dbHandle sqlQuerier ) ( [ ] IPListEntry , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getIPListEntriesQuery ( filter , from , order , limit )
args := [ ] any { listType }
if from != "" {
args = append ( args , from )
}
if filter != "" {
args = append ( args , filter + "%" )
}
if limit > 0 {
args = append ( args , limit )
}
entries := make ( [ ] IPListEntry , 0 , limit )
rows , err := dbHandle . QueryContext ( ctx , q , args ... )
if err != nil {
return entries , err
}
defer rows . Close ( )
for rows . Next ( ) {
entry , err := getIPListEntryFromDbRow ( rows )
if err != nil {
return entries , err
}
entries = append ( entries , entry )
}
return entries , rows . Err ( )
}
func sqlCommonGetRecentlyUpdatedIPListEntries ( after int64 , dbHandle sqlQuerier ) ( [ ] IPListEntry , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , longSQLQueryTimeout )
defer cancel ( )
q := getRecentlyUpdatedIPListQuery ( )
entries := make ( [ ] IPListEntry , 0 , 5 )
rows , err := dbHandle . QueryContext ( ctx , q , after )
if err != nil {
return entries , err
}
defer rows . Close ( )
for rows . Next ( ) {
entry , err := getIPListEntryFromDbRow ( rows )
if err != nil {
return entries , err
}
entries = append ( entries , entry )
}
return entries , rows . Err ( )
}
func sqlCommonGetListEntriesForIP ( ip string , listType IPListType , dbHandle sqlQuerier ) ( [ ] IPListEntry , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
var rows * sql . Rows
var err error
entries := make ( [ ] IPListEntry , 0 , 2 )
if config . Driver == PGSQLDataProviderName || config . Driver == CockroachDataProviderName {
rows , err = dbHandle . QueryContext ( ctx , getIPListEntriesForIPQueryPg ( ) , listType , ip )
if err != nil {
return entries , err
}
} else {
ipAddr , err := netip . ParseAddr ( ip )
if err != nil {
return entries , fmt . Errorf ( "invalid ip address %s" , ip )
}
var netType int
var ipBytes [ ] byte
if ipAddr . Is4 ( ) || ipAddr . Is4In6 ( ) {
netType = ipTypeV4
as4 := ipAddr . As4 ( )
ipBytes = as4 [ : ]
} else {
netType = ipTypeV6
as16 := ipAddr . As16 ( )
ipBytes = as16 [ : ]
}
rows , err = dbHandle . QueryContext ( ctx , getIPListEntriesForIPQueryNoPg ( ) , listType , netType , ipBytes )
if err != nil {
return entries , err
}
}
defer rows . Close ( )
for rows . Next ( ) {
entry , err := getIPListEntryFromDbRow ( rows )
if err != nil {
return entries , err
}
entries = append ( entries , entry )
}
return entries , rows . Err ( )
}
func sqlCommonAddIPListEntry ( entry * IPListEntry , dbHandle * sql . DB ) error {
if err := entry . validate ( ) ; err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
var err error
q := getAddIPListEntryQuery ( )
first := entry . getFirst ( )
last := entry . getLast ( )
var netType int
if first . Is4 ( ) {
netType = ipTypeV4
} else {
netType = ipTypeV6
}
if config . IsShared == 1 {
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
_ , err := tx . ExecContext ( ctx , getRemoveSoftDeletedIPListEntryQuery ( ) , entry . Type , entry . IPOrNet )
if err != nil {
return err
}
if config . Driver == PGSQLDataProviderName || config . Driver == CockroachDataProviderName {
_ , err = tx . ExecContext ( ctx , q , entry . Type , entry . IPOrNet , first . String ( ) , last . String ( ) ,
netType , entry . Protocols , entry . Description , entry . Mode , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) )
} else {
_ , err = tx . ExecContext ( ctx , q , entry . Type , entry . IPOrNet , entry . First , entry . Last ,
netType , entry . Protocols , entry . Description , entry . Mode , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) )
}
return err
} )
}
if config . Driver == PGSQLDataProviderName || config . Driver == CockroachDataProviderName {
_ , err = dbHandle . ExecContext ( ctx , q , entry . Type , entry . IPOrNet , first . String ( ) , last . String ( ) ,
netType , entry . Protocols , entry . Description , entry . Mode , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) )
} else {
_ , err = dbHandle . ExecContext ( ctx , q , entry . Type , entry . IPOrNet , entry . First , entry . Last ,
netType , entry . Protocols , entry . Description , entry . Mode , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) )
}
return err
}
func sqlCommonUpdateIPListEntry ( entry * IPListEntry , dbHandle * sql . DB ) error {
if err := entry . validate ( ) ; err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateIPListEntryQuery ( )
_ , err := dbHandle . ExecContext ( ctx , q , entry . Mode , entry . Protocols , entry . Description ,
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , entry . Type , entry . IPOrNet )
return err
}
func sqlCommonDeleteIPListEntry ( entry IPListEntry , softDelete bool , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDeleteIPListEntryQuery ( softDelete )
var args [ ] any
if softDelete {
ts := util . GetTimeAsMsSinceEpoch ( time . Now ( ) )
args = append ( args , ts , ts )
}
args = append ( args , entry . Type , entry . IPOrNet )
res , err := dbHandle . ExecContext ( ctx , q , args ... )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
}
2022-11-16 18:04:50 +00:00
func sqlCommonGetRoleByName ( name string , dbHandle sqlQuerier ) ( Role , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getRoleByNameQuery ( )
row := dbHandle . QueryRowContext ( ctx , q , name )
role , err := getRoleFromDbRow ( row )
if err != nil {
return role , err
}
role , err = getRoleWithUsers ( ctx , role , dbHandle )
if err != nil {
return role , err
}
return getRoleWithAdmins ( ctx , role , dbHandle )
}
func sqlCommonDumpRoles ( dbHandle sqlQuerier ) ( [ ] Role , error ) {
roles := make ( [ ] Role , 0 , 10 )
ctx , cancel := context . WithTimeout ( context . Background ( ) , longSQLQueryTimeout )
defer cancel ( )
q := getDumpRolesQuery ( )
rows , err := dbHandle . QueryContext ( ctx , q )
if err != nil {
return roles , err
}
defer rows . Close ( )
for rows . Next ( ) {
role , err := getRoleFromDbRow ( rows )
if err != nil {
return roles , err
}
roles = append ( roles , role )
}
return roles , rows . Err ( )
}
func sqlCommonGetRoles ( limit int , offset int , order string , minimal bool , dbHandle sqlQuerier ) ( [ ] Role , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getRolesQuery ( order , minimal )
roles := make ( [ ] Role , 0 , limit )
rows , err := dbHandle . QueryContext ( ctx , q , limit , offset )
if err != nil {
return roles , err
}
defer rows . Close ( )
for rows . Next ( ) {
var role Role
if minimal {
err = rows . Scan ( & role . ID , & role . Name )
} else {
role , err = getRoleFromDbRow ( rows )
}
if err != nil {
return roles , err
}
roles = append ( roles , role )
}
err = rows . Err ( )
if err != nil {
return roles , err
}
if minimal {
return roles , nil
}
roles , err = getRolesWithUsers ( ctx , roles , dbHandle )
if err != nil {
return roles , err
}
return getRolesWithAdmins ( ctx , roles , dbHandle )
}
func sqlCommonAddRole ( role * Role , dbHandle * sql . DB ) error {
if err := role . validate ( ) ; err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getAddRoleQuery ( )
_ , err := dbHandle . ExecContext ( ctx , q , role . Name , role . Description , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) )
return err
}
func sqlCommonUpdateRole ( role * Role , dbHandle * sql . DB ) error {
if err := role . validate ( ) ; err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateRoleQuery ( )
_ , err := dbHandle . ExecContext ( ctx , q , role . Description , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , role . Name )
return err
}
func sqlCommonDeleteRole ( role Role , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDeleteRoleQuery ( )
res , err := dbHandle . ExecContext ( ctx , q , role . Name )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
}
2022-04-25 13:49:11 +00:00
func sqlCommonGetGroupByName ( name string , dbHandle sqlQuerier ) ( Group , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getGroupByNameQuery ( )
2022-06-11 09:57:06 +00:00
row := dbHandle . QueryRowContext ( ctx , q , name )
group , err := getGroupFromDbRow ( row )
2022-04-25 13:49:11 +00:00
if err != nil {
return group , err
}
group , err = getGroupWithVirtualFolders ( ctx , group , dbHandle )
if err != nil {
return group , err
}
2022-09-13 16:04:27 +00:00
group , err = getGroupWithUsers ( ctx , group , dbHandle )
if err != nil {
return group , err
}
return getGroupWithAdmins ( ctx , group , dbHandle )
2022-04-25 13:49:11 +00:00
}
func sqlCommonDumpGroups ( dbHandle sqlQuerier ) ( [ ] Group , error ) {
groups := make ( [ ] Group , 0 , 50 )
ctx , cancel := context . WithTimeout ( context . Background ( ) , longSQLQueryTimeout )
defer cancel ( )
q := getDumpGroupsQuery ( )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q )
2022-04-25 13:49:11 +00:00
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-24 11:16:45 +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 ) )
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 ) )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q , 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 ) )
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 ) )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q , 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 )
2022-06-11 09:57:06 +00:00
groups := make ( [ ] Group , 0 , limit )
rows , err := dbHandle . QueryContext ( ctx , q , limit , offset )
2022-04-25 13:49:11 +00:00
if err != nil {
2022-06-11 09:57:06 +00:00
return groups , err
2022-04-25 13:49:11 +00:00
}
2022-06-11 09:57:06 +00:00
defer rows . Close ( )
2022-04-25 13:49:11 +00:00
2022-06-11 09:57:06 +00:00
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
2022-04-25 13:49:11 +00:00
}
2022-06-11 09:57:06 +00:00
groups = append ( groups , group )
2022-04-25 13:49:11 +00:00
}
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
}
2022-09-13 16:04:27 +00:00
groups , err = getGroupsWithAdmins ( ctx , groups , dbHandle )
if err != nil {
return groups , err
}
2022-04-25 13:49:11 +00:00
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
}
2022-07-11 06:17:36 +00:00
settings , err := json . Marshal ( group . UserSettings )
if err != nil {
return err
}
2022-04-25 13:49:11 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
q := getAddGroupQuery ( )
2022-07-11 06:17:36 +00:00
_ , err := tx . ExecContext ( ctx , q , group . Name , group . Description , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
2022-04-25 13:49:11 +00:00
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
}
2022-07-11 06:17:36 +00:00
settings , err := json . Marshal ( group . UserSettings )
if err != nil {
return err
}
2022-04-25 13:49:11 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
q := getUpdateGroupQuery ( )
2022-07-11 06:17:36 +00:00
_ , err := tx . ExecContext ( ctx , q , group . Description , settings , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , group . Name )
2022-04-25 13:49:11 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
res , err := dbHandle . ExecContext ( ctx , q , group . Name )
2022-05-19 17:49:51 +00:00
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
2022-04-25 13:49:11 +00:00
}
2022-11-16 18:04:50 +00:00
func sqlCommonGetUserByUsername ( username , role string , dbHandle sqlQuerier ) ( User , error ) {
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
2022-11-16 18:04:50 +00:00
q := getUserByUsernameQuery ( role )
args := [ ] any { username }
if role != "" {
args = append ( args , role )
}
row := dbHandle . QueryRowContext ( ctx , q , args ... )
2022-06-11 09:57:06 +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 ) {
2022-11-16 18:04:50 +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" )
}
2022-11-16 18:04:50 +00:00
user , err := sqlCommonGetUserByUsername ( username , "" , dbHandle )
2021-02-28 11:10:40 +00:00
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
}
2022-11-16 18:04:50 +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 ( )
2022-06-11 09:57:06 +00:00
2022-01-30 10:42:36 +00:00
q := getUpdateTransferQuotaQuery ( reset )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , uploadSize , downloadSize , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , username )
2022-01-30 10:42:36 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
2019-07-28 11:24:46 +00:00
q := getUpdateQuotaQuery ( reset )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , 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
2022-06-11 09:57:06 +00:00
q := getQuotaQuery ( )
2019-07-20 10:26:52 +00:00
var usedFiles int
2022-01-30 10:42:36 +00:00
var usedSize , usedUploadSize , usedDownloadSize int64
2022-06-11 09:57:06 +00:00
err := dbHandle . QueryRowContext ( ctx , q , 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 ( )
2022-06-11 09:57:06 +00:00
2021-11-06 13:13:20 +00:00
q := getUpdateShareLastUseQuery ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , numTokens , shareID )
2021-11-06 13:13:20 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
2021-08-17 16:08:32 +00:00
q := getUpdateAPIKeyLastUseQuery ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , keyID )
2021-08-17 16:08:32 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
2021-08-19 13:51:43 +00:00
q := getUpdateAdminLastLoginQuery ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , username )
2021-08-19 13:51:43 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
2021-08-19 13:51:43 +00:00
q := getSetUpdateAtQuery ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , username )
2021-08-19 13:51:43 +00:00
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 )
}
}
2022-08-21 17:01:08 +00:00
func sqlCommonSetFirstDownloadTimestamp ( username string , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getSetFirstDownloadQuery ( )
res , err := dbHandle . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , username )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
}
func sqlCommonSetFirstUploadTimestamp ( username string , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getSetFirstUploadQuery ( )
res , err := dbHandle . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , username )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
}
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 ( )
2022-06-11 09:57:06 +00:00
2020-06-07 21:30:18 +00:00
q := getUpdateLastLoginQuery ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , 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
}
2022-07-11 06:17:36 +00:00
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
}
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 {
2022-11-01 11:53:08 +00:00
if config . IsShared == 1 {
_ , err := tx . ExecContext ( ctx , getRemoveSoftDeletedUserQuery ( ) , user . Username )
if err != nil {
return err
}
}
2022-11-16 18:04:50 +00:00
q := getAddUserQuery ( user . Role )
2022-07-11 06:17:36 +00:00
_ , err := tx . ExecContext ( ctx , q , user . Username , user . Password , string ( publicKeys ) , user . HomeDir , user . UID , user . GID ,
2022-01-30 10:42:36 +00:00
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 ( ) ) ,
2022-12-11 16:15:34 +00:00
user . UploadDataTransfer , user . DownloadDataTransfer , user . TotalDataTransfer , user . Role , user . LastPasswordChange )
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 ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , password , username )
2022-04-02 20:20:21 +00:00
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
}
2022-07-11 06:17:36 +00:00
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
}
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 {
2022-11-16 18:04:50 +00:00
q := getUpdateUserQuery ( user . Role )
2022-07-11 06:17:36 +00:00
_ , err := tx . ExecContext ( ctx , q , user . Password , string ( publicKeys ) , user . HomeDir , user . UID , user . GID , user . MaxSessions ,
2022-01-30 10:42:36 +00:00
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 ,
2022-12-11 16:15:34 +00:00
user . Role , user . LastPasswordChange , 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-07-17 16:48:41 +00:00
func sqlCommonDeleteUser ( user User , softDelete bool , dbHandle * sql . DB ) error {
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2022-06-11 09:57:06 +00:00
2022-07-17 16:48:41 +00:00
q := getDeleteUserQuery ( softDelete )
if softDelete {
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
if err := sqlCommonClearUserFolderMapping ( ctx , & user , tx ) ; err != nil {
return err
}
if err := sqlCommonClearUserGroupMapping ( ctx , & user , tx ) ; err != nil {
return err
}
ts := util . GetTimeAsMsSinceEpoch ( time . Now ( ) )
res , err := tx . ExecContext ( ctx , q , ts , ts , user . Username )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
} )
}
2022-06-11 09:57:06 +00:00
res , err := dbHandle . ExecContext ( ctx , q , user . ID )
2022-05-19 17:49:51 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
2019-12-27 22:12:44 +00:00
q := getDumpUsersQuery ( )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q )
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 ( )
2022-06-11 09:57:06 +00:00
2021-08-20 07:35:06 +00:00
q := getRecentlyUpdatedUsersQuery ( )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q , after )
2021-08-20 07:35:06 +00:00
if err != nil {
2022-06-11 09:57:06 +00:00
return users , err
2021-08-20 07:35:06 +00:00
}
2022-06-11 09:57:06 +00:00
defer rows . Close ( )
2021-08-20 07:35:06 +00:00
2022-06-11 09:57:06 +00:00
for rows . Next ( ) {
u , err := getUserFromDbRow ( rows )
if err != nil {
return users , err
2021-08-20 07:35:06 +00:00
}
2022-06-11 09:57:06 +00:00
users = append ( users , u )
2021-08-20 07:35:06 +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
}
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 ) )
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 ] )
}
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q , queryArgs ... )
2022-01-20 17:19:20 +00:00
if err != nil {
return nil , err
}
defer rows . Close ( )
for rows . Next ( ) {
var user User
2022-11-16 18:04:50 +00:00
var filters [ ] byte
2022-01-30 10:42:36 +00:00
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-11-16 18:04:50 +00:00
var userFilters UserFilters
err = json . Unmarshal ( filters , & userFilters )
if err == nil {
user . Filters = userFilters
2022-01-30 10:42:36 +00:00
}
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 ( )
2022-06-11 09:57:06 +00:00
2022-01-30 10:42:36 +00:00
q := getAddActiveTransferQuery ( )
now := util . GetTimeAsMsSinceEpoch ( time . Now ( ) )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , transfer . ID , transfer . ConnID , transfer . Type , transfer . Username ,
2022-01-30 10:42:36 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
q := getUpdateActiveTransferSizesQuery ( )
_ , err := dbHandle . ExecContext ( ctx , q , ulSize , dlSize , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , connectionID , transferID )
2022-01-30 10:42:36 +00:00
return err
}
func sqlCommonRemoveActiveTransfer ( transferID int64 , connectionID string , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2022-06-11 09:57:06 +00:00
2022-01-30 10:42:36 +00:00
q := getRemoveActiveTransferQuery ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , connectionID , transferID )
2022-01-30 10:42:36 +00:00
return err
}
func sqlCommonCleanupActiveTransfers ( before time . Time , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getCleanupActiveTransfersQuery ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( before ) )
2022-01-30 10:42:36 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( from ) )
2022-01-30 10:42:36 +00:00
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 ( )
}
2022-11-16 18:04:50 +00:00
func sqlCommonGetUsers ( limit int , offset int , order , role 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 ( )
2022-06-11 09:57:06 +00:00
2022-11-16 18:04:50 +00:00
q := getUsersQuery ( order , role )
var args [ ] any
if role == "" {
args = append ( args , limit , offset )
} else {
args = append ( args , role , limit , offset )
}
rows , err := dbHandle . QueryContext ( ctx , q , args ... )
2019-07-20 10:26:52 +00:00
if err != nil {
2022-06-11 09:57:06 +00:00
return users , err
2019-07-20 10:26:52 +00:00
}
2022-06-11 09:57:06 +00:00
defer rows . Close ( )
2021-01-17 21:29:08 +00:00
2022-06-11 09:57:06 +00:00
for rows . Next ( ) {
u , err := getUserFromDbRow ( rows )
if err != nil {
return users , err
2019-07-20 10:26:52 +00:00
}
2022-06-11 09:57:06 +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 ( )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q , from , limit )
2021-12-25 11:08:07 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
row := dbHandle . QueryRowContext ( ctx , q , ip , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) )
err := row . Scan ( & host . ID )
2021-12-25 11:08:07 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
row := dbHandle . QueryRowContext ( ctx , q , ip , from )
2021-12-25 11:08:07 +00:00
var banTime sql . NullInt64
2022-06-11 09:57:06 +00:00
err := row . Scan ( & host . ID , & host . IP , & banTime )
2021-12-25 11:08:07 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
2021-12-25 11:08:07 +00:00
q := getDefenderIncrementBanTimeQuery ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , minutesToAdd * 60000 , ip )
2021-12-25 11:08:07 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
2021-12-25 11:08:07 +00:00
q := getDefenderSetBanTimeQuery ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , banTime , ip )
2021-12-25 11:08:07 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
2021-12-25 11:08:07 +00:00
q := getDeleteDefenderHostQuery ( )
2022-06-11 09:57:06 +00:00
res , err := dbHandle . ExecContext ( ctx , q , 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 ( )
2022-06-11 09:57:06 +00:00
_ , err := tx . ExecContext ( ctx , q , ip , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) )
2021-12-25 11:08:07 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
_ , err := tx . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , score , ip )
2021-12-25 11:08:07 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , from )
2021-12-25 11:08:07 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , from )
2021-12-25 11:08:07 +00:00
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
2022-11-16 18:04:50 +00:00
var description , password sql . NullString
var allowFrom , paths [ ] byte
2021-11-06 13:13:20 +00:00
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
}
2022-11-16 18:04:50 +00:00
var list [ ] string
err = json . Unmarshal ( paths , & list )
if err != nil {
return share , err
2021-11-06 13:13:20 +00:00
}
2022-11-16 18:04:50 +00:00
share . Paths = list
2021-11-06 13:13:20 +00:00
if description . Valid {
share . Description = description . String
}
if password . Valid {
share . Password = password . String
}
2022-11-16 18:04:50 +00:00
list = nil
err = json . Unmarshal ( allowFrom , & list )
if err == nil {
share . AllowFrom = list
2021-11-06 13:13:20 +00:00
}
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
2022-11-16 18:04:50 +00:00
var email , additionalInfo , description , role sql . NullString
var permissions , filters [ ] byte
2021-01-17 21:29:08 +00:00
err := row . Scan ( & admin . ID , & admin . Username , & admin . Password , & admin . Status , & email , & permissions ,
2022-11-16 18:04:50 +00:00
& filters , & additionalInfo , & description , & admin . CreatedAt , & admin . UpdatedAt , & admin . LastLogin , & role )
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
}
2022-11-16 18:04:50 +00:00
var perms [ ] string
err = json . Unmarshal ( permissions , & perms )
if err != nil {
return admin , err
2021-01-17 21:29:08 +00:00
}
2022-11-16 18:04:50 +00:00
admin . Permissions = perms
2021-01-17 21:29:08 +00:00
if email . Valid {
admin . Email = email . String
}
2022-11-16 18:04:50 +00:00
var adminFilters AdminFilters
err = json . Unmarshal ( filters , & adminFilters )
if err == nil {
admin . Filters = adminFilters
2021-01-17 21:29:08 +00:00
}
if additionalInfo . Valid {
admin . AdditionalInfo = additionalInfo . String
}
2021-02-24 18:40:29 +00:00
if description . Valid {
admin . Description = description . String
}
2022-11-16 18:04:50 +00:00
if role . Valid {
admin . Role = role . 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-07-11 06:17:36 +00:00
func getEventActionFromDbRow ( row sqlScanner ) ( BaseEventAction , error ) {
var action BaseEventAction
var description sql . NullString
var options [ ] byte
err := row . Scan ( & action . ID , & action . Name , & description , & action . Type , & options )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
return action , util . NewRecordNotFoundError ( err . Error ( ) )
}
return action , err
}
if description . Valid {
action . Description = description . String
}
2022-11-16 18:04:50 +00:00
var actionOptions BaseEventActionOptions
err = json . Unmarshal ( options , & actionOptions )
if err == nil {
action . Options = actionOptions
2022-07-11 06:17:36 +00:00
}
return action , nil
}
func getEventRuleFromDbRow ( row sqlScanner ) ( EventRule , error ) {
var rule EventRule
var description sql . NullString
var conditions [ ] byte
err := row . Scan ( & rule . ID , & rule . Name , & description , & rule . CreatedAt , & rule . UpdatedAt , & rule . Trigger ,
2023-01-19 17:33:04 +00:00
& conditions , & rule . DeletedAt , & rule . Status )
2022-07-11 06:17:36 +00:00
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
return rule , util . NewRecordNotFoundError ( err . Error ( ) )
}
return rule , err
}
2022-11-16 18:04:50 +00:00
var ruleConditions EventConditions
err = json . Unmarshal ( conditions , & ruleConditions )
if err == nil {
rule . Conditions = ruleConditions
2022-07-11 06:17:36 +00:00
}
2022-11-16 18:04:50 +00:00
2022-07-11 06:17:36 +00:00
if description . Valid {
rule . Description = description . String
}
return rule , nil
}
2023-02-09 08:33:33 +00:00
func getIPListEntryFromDbRow ( row sqlScanner ) ( IPListEntry , error ) {
var entry IPListEntry
var description sql . NullString
err := row . Scan ( & entry . Type , & entry . IPOrNet , & entry . Mode , & entry . Protocols , & description ,
& entry . CreatedAt , & entry . UpdatedAt , & entry . DeletedAt )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
return entry , util . NewRecordNotFoundError ( err . Error ( ) )
}
return entry , err
}
if description . Valid {
entry . Description = description . String
}
return entry , err
}
2022-11-16 18:04:50 +00:00
func getRoleFromDbRow ( row sqlScanner ) ( Role , error ) {
var role Role
var description sql . NullString
err := row . Scan ( & role . ID , & role . Name , & description , & role . CreatedAt , & role . UpdatedAt )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
return role , util . NewRecordNotFoundError ( err . Error ( ) )
}
return role , err
}
if description . Valid {
role . Description = description . String
}
return role , nil
}
2022-04-25 13:49:11 +00:00
func getGroupFromDbRow ( row sqlScanner ) ( Group , error ) {
var group Group
2022-11-16 18:04:50 +00:00
var description sql . NullString
var userSettings [ ] byte
2022-04-25 13:49:11 +00:00
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
}
2022-11-16 18:04:50 +00:00
var settings GroupUserSettings
err = json . Unmarshal ( userSettings , & settings )
if err == nil {
group . UserSettings = settings
2022-04-25 13:49:11 +00:00
}
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 password sql . NullString
2022-11-16 18:04:50 +00:00
var permissions , publicKey , filters , fsConfig [ ] byte
var additionalInfo , description , email , role 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 ,
2022-08-21 17:01:08 +00:00
& user . TotalDataTransfer , & user . UsedUploadDataTransfer , & user . UsedDownloadDataTransfer , & user . DeletedAt , & user . FirstDownload ,
2022-12-11 16:15:34 +00:00
& user . FirstUpload , & role , & user . LastPasswordChange )
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
}
2022-11-16 18:04:50 +00:00
perms := make ( map [ string ] [ ] string )
err = json . Unmarshal ( permissions , & perms )
if err != nil {
providerLog ( logger . LevelError , "unable to deserialize permissions for user %#v: %v" , user . Username , err )
return user , fmt . Errorf ( "unable to deserialize permissions for user %#v: %v" , user . Username , err )
}
user . Permissions = perms
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
2022-11-16 18:04:50 +00:00
var pKeys [ ] string
err = json . Unmarshal ( publicKey , & pKeys )
if err == nil {
user . PublicKeys = pKeys
2019-07-20 10:26:52 +00:00
}
2022-11-16 18:04:50 +00:00
var userFilters UserFilters
err = json . Unmarshal ( filters , & userFilters )
if err == nil {
user . Filters = userFilters
2019-12-30 17:37:50 +00:00
}
2022-11-16 18:04:50 +00:00
var fs vfs . Filesystem
err = json . Unmarshal ( fsConfig , & 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
}
2022-11-16 18:04:50 +00:00
if role . Valid {
user . Role = role . 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 ( )
2022-06-11 09:57:06 +00:00
row := dbHandle . QueryRowContext ( ctx , q , name )
2022-11-16 18:04:50 +00:00
var mappedPath , description sql . NullString
var fsConfig [ ] byte
2022-06-11 09:57:06 +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
}
2022-11-16 18:04:50 +00:00
var fs vfs . Filesystem
err = json . Unmarshal ( fsConfig , & fs )
if err == nil {
folder . FsConfig = fs
2021-03-21 18:15:47 +00:00
}
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 ( )
2022-06-11 09:57:06 +00:00
_ , err = dbHandle . ExecContext ( ctx , q , baseFolder . MappedPath , usedQuotaSize , usedQuotaFiles ,
2022-04-28 12:49:57 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
2020-06-07 21:30:18 +00:00
q := getAddFolderQuery ( )
2022-06-11 09:57:06 +00:00
_ , err = dbHandle . ExecContext ( ctx , q , 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 ( )
2022-06-11 09:57:06 +00:00
2021-02-01 18:04:15 +00:00
q := getUpdateFolderQuery ( )
2022-06-11 09:57:06 +00:00
_ , err = dbHandle . ExecContext ( ctx , q , 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 ( )
2022-06-11 09:57:06 +00:00
2020-06-07 21:30:18 +00:00
q := getDeleteFolderQuery ( )
2022-06-11 09:57:06 +00:00
res , err := dbHandle . ExecContext ( ctx , q , folder . ID )
2022-05-19 17:49:51 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
2020-06-07 21:30:18 +00:00
q := getDumpFoldersQuery ( )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q )
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-11-16 18:04:50 +00:00
var mappedPath , description sql . NullString
var fsConfig [ ] byte
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
}
2022-11-16 18:04:50 +00:00
var fs vfs . Filesystem
err = json . Unmarshal ( fsConfig , & fs )
if err == nil {
folder . FsConfig = fs
2021-03-21 18:15:47 +00:00
}
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 ( )
2021-02-01 18:04:15 +00:00
2022-06-11 09:57:06 +00:00
q := getFoldersQuery ( order , minimal )
rows , err := dbHandle . QueryContext ( ctx , q , 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 {
2022-11-16 18:04:50 +00:00
var mappedPath , description sql . NullString
var fsConfig [ ] byte
2022-04-25 13:49:11 +00:00
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
}
2022-11-16 18:04:50 +00:00
var fs vfs . Filesystem
err = json . Unmarshal ( fsConfig , & 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 ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , 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 ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , group . Name )
2022-04-25 13:49:11 +00:00
return err
}
func sqlCommonClearUserGroupMapping ( ctx context . Context , user * User , dbHandle sqlQuerier ) error {
q := getClearUserGroupMappingQuery ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , user . Username )
2022-04-25 13:49:11 +00:00
return err
}
func sqlCommonAddUserFolderMapping ( ctx context . Context , user * User , folder * vfs . VirtualFolder , dbHandle sqlQuerier ) error {
q := getAddUserFolderMappingQuery ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , folder . VirtualPath , folder . QuotaSize , folder . QuotaFiles , folder . Name , user . Username )
2020-06-07 21:30:18 +00:00
return err
}
2022-09-13 16:04:27 +00:00
func sqlCommonClearAdminGroupMapping ( ctx context . Context , admin * Admin , dbHandle sqlQuerier ) error {
q := getClearAdminGroupMappingQuery ( )
_ , err := dbHandle . ExecContext ( ctx , q , admin . Username )
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 ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , folder . VirtualPath , folder . QuotaSize , folder . QuotaFiles , folder . Name , group . Name )
2022-04-25 13:49:11 +00:00
return err
}
func sqlCommonAddUserGroupMapping ( ctx context . Context , username , groupName string , groupType int , dbHandle sqlQuerier ) error {
q := getAddUserGroupMappingQuery ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , username , groupName , groupType )
2022-04-25 13:49:11 +00:00
return err
}
2022-09-13 16:04:27 +00:00
func sqlCommonAddAdminGroupMapping ( ctx context . Context , username , groupName string , mappingOptions AdminGroupMappingOptions ,
dbHandle sqlQuerier ,
) error {
options , err := json . Marshal ( mappingOptions )
if err != nil {
return err
}
q := getAddAdminGroupMappingQuery ( )
_ , err = dbHandle . ExecContext ( ctx , q , username , groupName , string ( options ) )
return err
}
2022-04-25 13:49:11 +00:00
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-09-13 16:04:27 +00:00
func generateAdminGroupMapping ( ctx context . Context , admin * Admin , dbHandle sqlQuerier ) error {
err := sqlCommonClearAdminGroupMapping ( ctx , admin , dbHandle )
if err != nil {
return err
}
for _ , group := range admin . Groups {
err = sqlCommonAddAdminGroupMapping ( ctx , admin . Username , group . Name , group . Options , dbHandle )
if err != nil {
return err
}
}
return 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 )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q , from )
2021-12-25 11:08:07 +00:00
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-09-13 16:04:27 +00:00
func getAdminWithGroups ( ctx context . Context , admin Admin , dbHandle sqlQuerier ) ( Admin , error ) {
admins , err := getAdminsWithGroups ( ctx , [ ] Admin { admin } , dbHandle )
if err != nil {
return admin , err
}
if len ( admins ) == 0 {
return admin , errSQLGroupsAssociation
}
return admins [ 0 ] , err
}
func getAdminsWithGroups ( ctx context . Context , admins [ ] Admin , dbHandle sqlQuerier ) ( [ ] Admin , error ) {
if len ( admins ) == 0 {
return admins , nil
}
adminsGroups := make ( map [ int64 ] [ ] AdminGroupMapping )
q := getRelatedGroupsForAdminsQuery ( admins )
rows , err := dbHandle . QueryContext ( ctx , q )
if err != nil {
return nil , err
}
defer rows . Close ( )
for rows . Next ( ) {
var group AdminGroupMapping
var adminID int64
var options [ ] byte
err = rows . Scan ( & group . Name , & options , & adminID )
if err != nil {
return admins , err
}
err = json . Unmarshal ( options , & group . Options )
if err != nil {
return admins , err
}
adminsGroups [ adminID ] = append ( adminsGroups [ adminID ] , group )
}
err = rows . Err ( )
if err != nil {
return admins , err
}
if len ( adminsGroups ) == 0 {
return admins , err
}
for idx := range admins {
ref := & admins [ idx ]
ref . Groups = adminsGroups [ ref . ID ]
}
return admins , err
}
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
usersVirtualFolders := make ( map [ int64 ] [ ] vfs . VirtualFolder )
2020-06-07 21:30:18 +00:00
q := getRelatedFoldersForUsersQuery ( users )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q )
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
2022-11-16 18:04:50 +00:00
var mappedPath , description sql . NullString
var fsConfig [ ] byte
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
}
2022-11-16 18:04:50 +00:00
var fs vfs . Filesystem
err = json . Unmarshal ( fsConfig , & fs )
if err == nil {
folder . FsConfig = fs
2021-03-21 18:15:47 +00:00
}
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
}
usersGroups := make ( map [ int64 ] [ ] sdk . GroupMapping )
q := getRelatedGroupsForUsersQuery ( users )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q )
2022-04-25 13:49:11 +00:00
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
}
2022-11-16 18:04:50 +00:00
func getRoleWithUsers ( ctx context . Context , role Role , dbHandle sqlQuerier ) ( Role , error ) {
roles , err := getRolesWithUsers ( ctx , [ ] Role { role } , dbHandle )
if err != nil {
return role , err
}
if len ( roles ) == 0 {
return role , errors . New ( "unable to associate users with role" )
}
return roles [ 0 ] , err
}
func getRoleWithAdmins ( ctx context . Context , role Role , dbHandle sqlQuerier ) ( Role , error ) {
roles , err := getRolesWithAdmins ( ctx , [ ] Role { role } , dbHandle )
if err != nil {
return role , err
}
if len ( roles ) == 0 {
return role , errors . New ( "unable to associate admins with role" )
}
return roles [ 0 ] , err
}
2022-09-13 16:04:27 +00:00
func getGroupWithAdmins ( ctx context . Context , group Group , dbHandle sqlQuerier ) ( Group , error ) {
groups , err := getGroupsWithAdmins ( ctx , [ ] Group { group } , dbHandle )
if err != nil {
return group , err
}
if len ( groups ) == 0 {
return group , errSQLUsersAssociation
}
return groups [ 0 ] , err
}
2022-04-25 13:49:11 +00:00
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
}
q := getRelatedFoldersForGroupsQuery ( groups )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q )
2022-04-25 13:49:11 +00:00
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
2022-11-16 18:04:50 +00:00
var mappedPath , description sql . NullString
var fsConfig [ ] byte
2022-04-25 13:49:11 +00:00
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
}
2022-11-16 18:04:50 +00:00
var fs vfs . Filesystem
err = json . Unmarshal ( fsConfig , & fs )
if err == nil {
folder . FsConfig = fs
2022-04-25 13:49:11 +00:00
}
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
}
q := getRelatedUsersForGroupsQuery ( groups )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q )
2022-04-25 13:49:11 +00:00
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
}
2022-11-16 18:04:50 +00:00
func getRolesWithUsers ( ctx context . Context , roles [ ] Role , dbHandle sqlQuerier ) ( [ ] Role , error ) {
if len ( roles ) == 0 {
return roles , nil
}
rows , err := dbHandle . QueryContext ( ctx , getUsersWithRolesQuery ( roles ) )
if err != nil {
return nil , err
}
defer rows . Close ( )
rolesUsers := make ( map [ int64 ] [ ] string )
for rows . Next ( ) {
var roleID int64
var username string
err = rows . Scan ( & roleID , & username )
if err != nil {
return roles , err
}
rolesUsers [ roleID ] = append ( rolesUsers [ roleID ] , username )
}
err = rows . Err ( )
if err != nil {
return roles , err
}
if len ( rolesUsers ) > 0 {
for idx := range roles {
ref := & roles [ idx ]
ref . Users = rolesUsers [ ref . ID ]
}
}
return roles , nil
}
func getRolesWithAdmins ( ctx context . Context , roles [ ] Role , dbHandle sqlQuerier ) ( [ ] Role , error ) {
if len ( roles ) == 0 {
return roles , nil
}
rows , err := dbHandle . QueryContext ( ctx , getAdminsWithRolesQuery ( roles ) )
if err != nil {
return nil , err
}
defer rows . Close ( )
rolesAdmins := make ( map [ int64 ] [ ] string )
for rows . Next ( ) {
var roleID int64
var username string
err = rows . Scan ( & roleID , & username )
if err != nil {
return roles , err
}
rolesAdmins [ roleID ] = append ( rolesAdmins [ roleID ] , username )
}
if err = rows . Err ( ) ; err != nil {
return roles , err
}
if len ( rolesAdmins ) > 0 {
for idx := range roles {
ref := & roles [ idx ]
ref . Admins = rolesAdmins [ ref . ID ]
}
}
return roles , nil
}
2022-09-13 16:04:27 +00:00
func getGroupsWithAdmins ( ctx context . Context , groups [ ] Group , dbHandle sqlQuerier ) ( [ ] Group , error ) {
if len ( groups ) == 0 {
return groups , nil
}
q := getRelatedAdminsForGroupsQuery ( groups )
rows , err := dbHandle . QueryContext ( ctx , q )
if err != nil {
return nil , err
}
defer rows . Close ( )
groupsAdmins := make ( map [ int64 ] [ ] string )
for rows . Next ( ) {
var groupID int64
var username string
err = rows . Scan ( & groupID , & username )
if err != nil {
return groups , err
}
groupsAdmins [ groupID ] = append ( groupsAdmins [ groupID ] , username )
}
err = rows . Err ( )
if err != nil {
return groups , err
}
if len ( groupsAdmins ) > 0 {
for idx := range groups {
ref := & groups [ idx ]
ref . Admins = groupsAdmins [ ref . ID ]
}
}
return groups , nil
}
2022-04-25 13:49:11 +00:00
func getVirtualFoldersWithGroups ( folders [ ] vfs . BaseVirtualFolder , dbHandle sqlQuerier ) ( [ ] vfs . BaseVirtualFolder , error ) {
if len ( folders ) == 0 {
return folders , nil
}
vFoldersGroups := make ( map [ int64 ] [ ] string )
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2022-06-11 09:57:06 +00:00
2022-04-25 13:49:11 +00:00
q := getRelatedGroupsForFoldersQuery ( folders )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q )
2022-04-25 13:49:11 +00:00
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
}
2020-07-08 16:54:44 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
2022-06-11 09:57:06 +00:00
2020-06-07 21:30:18 +00:00
q := getRelatedUsersForFoldersQuery ( folders )
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q )
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 ( )
2022-06-11 09:57:06 +00:00
2020-06-07 21:30:18 +00:00
q := getUpdateFolderQuotaQuery ( reset )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , 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
2022-06-11 09:57:06 +00:00
q := getQuotaFolderQuery ( )
2020-06-07 21:30:18 +00:00
var usedFiles int
var usedSize int64
2022-06-11 09:57:06 +00:00
err := dbHandle . QueryRowContext ( ctx , q , 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 )
}
2022-06-11 09:57:06 +00:00
rows , err := dbHandle . QueryContext ( ctx , q )
2021-08-17 16:08:32 +00:00
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 != "" {
2022-11-16 18:04:50 +00:00
u , err := provider . userExists ( apiKey . User , "" )
2021-08-17 16:08:32 +00:00
if err != nil {
2023-01-21 14:41:24 +00:00
return userID , adminID , util . NewGenericError ( fmt . Sprintf ( "unable to validate user %v" , apiKey . User ) )
2021-08-17 16:08:32 +00:00
}
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 ( )
2022-06-11 09:57:06 +00:00
_ , err = dbHandle . ExecContext ( ctx , q , session . Key , data , session . Type , session . Timestamp )
2022-05-19 17:49:51 +00:00
return err
}
func sqlCommonGetSession ( key string , dbHandle sqlQuerier ) ( Session , error ) {
var session Session
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getSessionQuery ( )
var data [ ] byte // type hint, some driver will use string instead of []byte if the type is any
2022-06-11 09:57:06 +00:00
err := dbHandle . QueryRowContext ( ctx , q , key ) . Scan ( & session . Key , & data , & session . Type , & session . Timestamp )
2022-05-19 17:49:51 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
res , err := dbHandle . ExecContext ( ctx , q , key )
2022-05-19 17:49:51 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , sessionType , before )
2022-05-19 17:49:51 +00:00
return err
}
2022-07-11 06:17:36 +00:00
func getActionsWithRuleNames ( ctx context . Context , actions [ ] BaseEventAction , dbHandle sqlQuerier ,
) ( [ ] BaseEventAction , error ) {
if len ( actions ) == 0 {
return actions , nil
}
q := getRelatedRulesForActionsQuery ( actions )
rows , err := dbHandle . QueryContext ( ctx , q )
if err != nil {
return nil , err
}
defer rows . Close ( )
actionsRules := make ( map [ int64 ] [ ] string )
for rows . Next ( ) {
var name string
var actionID int64
if err = rows . Scan ( & actionID , & name ) ; err != nil {
return nil , err
}
actionsRules [ actionID ] = append ( actionsRules [ actionID ] , name )
}
err = rows . Err ( )
if err != nil {
return nil , err
}
if len ( actionsRules ) == 0 {
return actions , nil
}
for idx := range actions {
ref := & actions [ idx ]
ref . Rules = actionsRules [ ref . ID ]
}
return actions , nil
}
func getRulesWithActions ( ctx context . Context , rules [ ] EventRule , dbHandle sqlQuerier ) ( [ ] EventRule , error ) {
if len ( rules ) == 0 {
return rules , nil
}
rulesActions := make ( map [ int64 ] [ ] EventAction )
q := getRelatedActionsForRulesQuery ( rules )
rows , err := dbHandle . QueryContext ( ctx , q )
if err != nil {
return nil , err
}
defer rows . Close ( )
for rows . Next ( ) {
var action EventAction
var ruleID int64
var description sql . NullString
var baseOptions , options [ ] byte
err = rows . Scan ( & action . ID , & action . Name , & description , & action . Type , & baseOptions , & options ,
& action . Order , & ruleID )
if err != nil {
return rules , err
}
if len ( baseOptions ) > 0 {
err = json . Unmarshal ( baseOptions , & action . BaseEventAction . Options )
if err != nil {
return rules , err
}
}
if len ( options ) > 0 {
err = json . Unmarshal ( options , & action . Options )
if err != nil {
return rules , err
}
}
action . BaseEventAction . Options . SetEmptySecretsIfNil ( )
rulesActions [ ruleID ] = append ( rulesActions [ ruleID ] , action )
}
err = rows . Err ( )
if err != nil {
return rules , err
}
if len ( rulesActions ) == 0 {
return rules , nil
}
for idx := range rules {
ref := & rules [ idx ]
ref . Actions = rulesActions [ ref . ID ]
}
return rules , nil
}
func generateEventRuleActionsMapping ( ctx context . Context , rule * EventRule , dbHandle sqlQuerier ) error {
q := getClearRuleActionMappingQuery ( )
_ , err := dbHandle . ExecContext ( ctx , q , rule . Name )
if err != nil {
return err
}
for _ , action := range rule . Actions {
options , err := json . Marshal ( action . Options )
if err != nil {
return err
}
q = getAddRuleActionMappingQuery ( )
_ , err = dbHandle . ExecContext ( ctx , q , rule . Name , action . Name , action . Order , string ( options ) )
if err != nil {
return err
}
}
return nil
}
func sqlCommonGetEventActionByName ( name string , dbHandle sqlQuerier ) ( BaseEventAction , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getEventActionByNameQuery ( )
row := dbHandle . QueryRowContext ( ctx , q , name )
action , err := getEventActionFromDbRow ( row )
if err != nil {
return action , err
}
actions , err := getActionsWithRuleNames ( ctx , [ ] BaseEventAction { action } , dbHandle )
if err != nil {
return action , err
}
if len ( actions ) != 1 {
return action , fmt . Errorf ( "unable to associate rules with action %q" , name )
}
return actions [ 0 ] , nil
}
func sqlCommonDumpEventActions ( dbHandle sqlQuerier ) ( [ ] BaseEventAction , error ) {
actions := make ( [ ] BaseEventAction , 0 , 10 )
ctx , cancel := context . WithTimeout ( context . Background ( ) , longSQLQueryTimeout )
defer cancel ( )
q := getDumpEventActionsQuery ( )
rows , err := dbHandle . QueryContext ( ctx , q )
if err != nil {
return actions , err
}
defer rows . Close ( )
for rows . Next ( ) {
action , err := getEventActionFromDbRow ( rows )
if err != nil {
return actions , err
}
actions = append ( actions , action )
}
return actions , rows . Err ( )
}
func sqlCommonGetEventActions ( limit int , offset int , order string , minimal bool ,
dbHandle sqlQuerier ,
) ( [ ] BaseEventAction , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getEventsActionsQuery ( order , minimal )
actions := make ( [ ] BaseEventAction , 0 , limit )
rows , err := dbHandle . QueryContext ( ctx , q , limit , offset )
if err != nil {
return actions , err
}
defer rows . Close ( )
for rows . Next ( ) {
var action BaseEventAction
if minimal {
err = rows . Scan ( & action . ID , & action . Name )
} else {
action , err = getEventActionFromDbRow ( rows )
}
if err != nil {
return actions , err
}
actions = append ( actions , action )
}
err = rows . Err ( )
if err != nil {
return nil , err
}
if minimal {
return actions , nil
}
actions , err = getActionsWithRuleNames ( ctx , actions , dbHandle )
if err != nil {
return nil , err
}
for idx := range actions {
actions [ idx ] . PrepareForRendering ( )
}
return actions , nil
}
func sqlCommonAddEventAction ( action * BaseEventAction , dbHandle * sql . DB ) error {
if err := action . validate ( ) ; err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getAddEventActionQuery ( )
options , err := json . Marshal ( action . Options )
if err != nil {
return err
}
_ , err = dbHandle . ExecContext ( ctx , q , action . Name , action . Description , action . Type , string ( options ) )
return err
}
func sqlCommonUpdateEventAction ( action * BaseEventAction , dbHandle * sql . DB ) error {
if err := action . validate ( ) ; err != nil {
return err
}
options , err := json . Marshal ( action . Options )
if err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
q := getUpdateEventActionQuery ( )
_ , err = tx . ExecContext ( ctx , q , action . Description , action . Type , string ( options ) , action . Name )
if err != nil {
return err
}
q = getUpdateRulesTimestampQuery ( )
_ , err = tx . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , action . ID )
return err
} )
}
func sqlCommonDeleteEventAction ( action BaseEventAction , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDeleteEventActionQuery ( )
res , err := dbHandle . ExecContext ( ctx , q , action . Name )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
}
func sqlCommonGetEventRuleByName ( name string , dbHandle sqlQuerier ) ( EventRule , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getEventRulesByNameQuery ( )
row := dbHandle . QueryRowContext ( ctx , q , name )
rule , err := getEventRuleFromDbRow ( row )
if err != nil {
return rule , err
}
rules , err := getRulesWithActions ( ctx , [ ] EventRule { rule } , dbHandle )
if err != nil {
return rule , err
}
if len ( rules ) != 1 {
return rule , fmt . Errorf ( "unable to associate rule %q with actions" , name )
}
return rules [ 0 ] , nil
}
func sqlCommonDumpEventRules ( dbHandle sqlQuerier ) ( [ ] EventRule , error ) {
rules := make ( [ ] EventRule , 0 , 10 )
ctx , cancel := context . WithTimeout ( context . Background ( ) , longSQLQueryTimeout )
defer cancel ( )
q := getDumpEventRulesQuery ( )
rows , err := dbHandle . QueryContext ( ctx , q )
if err != nil {
return rules , err
}
defer rows . Close ( )
for rows . Next ( ) {
rule , err := getEventRuleFromDbRow ( rows )
if err != nil {
return rules , err
}
rules = append ( rules , rule )
}
err = rows . Err ( )
if err != nil {
return rules , err
}
return getRulesWithActions ( ctx , rules , dbHandle )
}
func sqlCommonGetRecentlyUpdatedRules ( after int64 , dbHandle sqlQuerier ) ( [ ] EventRule , error ) {
rules := make ( [ ] EventRule , 0 , 10 )
ctx , cancel := context . WithTimeout ( context . Background ( ) , longSQLQueryTimeout )
defer cancel ( )
q := getRecentlyUpdatedRulesQuery ( )
rows , err := dbHandle . QueryContext ( ctx , q , after )
if err != nil {
return rules , err
}
defer rows . Close ( )
for rows . Next ( ) {
rule , err := getEventRuleFromDbRow ( rows )
if err != nil {
return rules , err
}
rules = append ( rules , rule )
}
err = rows . Err ( )
if err != nil {
return rules , err
}
return getRulesWithActions ( ctx , rules , dbHandle )
}
func sqlCommonGetEventRules ( limit int , offset int , order string , dbHandle sqlQuerier ) ( [ ] EventRule , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getEventRulesQuery ( order )
rules := make ( [ ] EventRule , 0 , limit )
rows , err := dbHandle . QueryContext ( ctx , q , limit , offset )
if err != nil {
return rules , err
}
defer rows . Close ( )
for rows . Next ( ) {
rule , err := getEventRuleFromDbRow ( rows )
if err != nil {
return rules , err
}
rules = append ( rules , rule )
}
err = rows . Err ( )
if err != nil {
return rules , err
}
rules , err = getRulesWithActions ( ctx , rules , dbHandle )
if err != nil {
return rules , err
}
for idx := range rules {
rules [ idx ] . PrepareForRendering ( )
}
return rules , nil
}
func sqlCommonAddEventRule ( rule * EventRule , dbHandle * sql . DB ) error {
if err := rule . validate ( ) ; err != nil {
return err
}
conditions , err := json . Marshal ( rule . Conditions )
if err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
2022-11-01 16:39:53 +00:00
if config . IsShared == 1 {
_ , err := tx . ExecContext ( ctx , getRemoveSoftDeletedRuleQuery ( ) , rule . Name )
if err != nil {
return err
}
}
2022-07-11 06:17:36 +00:00
q := getAddEventRuleQuery ( )
_ , err := tx . ExecContext ( ctx , q , rule . Name , rule . Description , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
2023-01-19 17:33:04 +00:00
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , rule . Trigger , string ( conditions ) , rule . Status )
2022-07-11 06:17:36 +00:00
if err != nil {
return err
}
return generateEventRuleActionsMapping ( ctx , rule , tx )
} )
}
func sqlCommonUpdateEventRule ( rule * EventRule , dbHandle * sql . DB ) error {
if err := rule . validate ( ) ; err != nil {
return err
}
conditions , err := json . Marshal ( rule . Conditions )
if err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
q := getUpdateEventRuleQuery ( )
_ , err := tx . ExecContext ( ctx , q , rule . Description , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
2023-01-19 17:33:04 +00:00
rule . Trigger , string ( conditions ) , rule . Status , rule . Name )
2022-07-11 06:17:36 +00:00
if err != nil {
return err
}
return generateEventRuleActionsMapping ( ctx , rule , tx )
} )
}
func sqlCommonDeleteEventRule ( rule EventRule , softDelete bool , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
return sqlCommonExecuteTx ( ctx , dbHandle , func ( tx * sql . Tx ) error {
if softDelete {
q := getClearRuleActionMappingQuery ( )
_ , err := tx . ExecContext ( ctx , q , rule . Name )
if err != nil {
return err
}
}
q := getDeleteEventRuleQuery ( softDelete )
if softDelete {
ts := util . GetTimeAsMsSinceEpoch ( time . Now ( ) )
res , err := tx . ExecContext ( ctx , q , ts , ts , rule . Name )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
}
res , err := tx . ExecContext ( ctx , q , rule . Name )
if err != nil {
return err
}
if err = sqlCommonRequireRowAffected ( res ) ; err != nil {
return err
}
return sqlCommonDeleteTask ( rule . Name , tx )
} )
}
func sqlCommonGetTaskByName ( name string , dbHandle sqlQuerier ) ( Task , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
task := Task {
Name : name ,
}
q := getTaskByNameQuery ( )
row := dbHandle . QueryRowContext ( ctx , q , name )
err := row . Scan ( & task . UpdateAt , & task . Version )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
return task , util . NewRecordNotFoundError ( err . Error ( ) )
}
}
return task , err
}
func sqlCommonAddTask ( name string , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getAddTaskQuery ( )
_ , err := dbHandle . ExecContext ( ctx , q , name , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) )
return err
}
func sqlCommonUpdateTask ( name string , version int64 , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateTaskQuery ( )
res , err := dbHandle . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , name , version )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
}
func sqlCommonUpdateTaskTimestamp ( name string , dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateTaskTimestampQuery ( )
res , err := dbHandle . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , name )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
}
func sqlCommonDeleteTask ( name string , dbHandle sqlQuerier ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getDeleteTaskQuery ( )
_ , err := dbHandle . ExecContext ( ctx , q , name )
return err
}
2022-09-25 17:48:55 +00:00
func sqlCommonAddNode ( dbHandle * sql . DB ) error {
if err := currentNode . validate ( ) ; err != nil {
return fmt . Errorf ( "unable to register cluster node: %w" , err )
}
data , err := json . Marshal ( currentNode . Data )
if err != nil {
return err
}
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getAddNodeQuery ( )
_ , err = dbHandle . ExecContext ( ctx , q , currentNode . Name , string ( data ) , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) ,
util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) )
if err != nil {
return fmt . Errorf ( "unable to register cluster node: %w" , err )
}
providerLog ( logger . LevelInfo , "registered as cluster node %q, port: %d, proto: %s" ,
currentNode . Name , currentNode . Data . Port , currentNode . Data . Proto )
return nil
}
func sqlCommonGetNodeByName ( name string , dbHandle * sql . DB ) ( Node , error ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
var data [ ] byte
var node Node
q := getNodeByNameQuery ( )
row := dbHandle . QueryRowContext ( ctx , q , name , util . GetTimeAsMsSinceEpoch ( time . Now ( ) . Add ( activeNodeTimeDiff ) ) )
err := row . Scan ( & node . Name , & data , & node . CreatedAt , & node . UpdatedAt )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
return node , util . NewRecordNotFoundError ( err . Error ( ) )
}
return node , err
}
err = json . Unmarshal ( data , & node . Data )
return node , err
}
func sqlCommonGetNodes ( dbHandle * sql . DB ) ( [ ] Node , error ) {
var nodes [ ] Node
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getNodesQuery ( )
rows , err := dbHandle . QueryContext ( ctx , q , currentNode . Name ,
util . GetTimeAsMsSinceEpoch ( time . Now ( ) . Add ( activeNodeTimeDiff ) ) )
if err != nil {
return nodes , err
}
defer rows . Close ( )
for rows . Next ( ) {
var node Node
var data [ ] byte
err = rows . Scan ( & node . Name , & data , & node . CreatedAt , & node . UpdatedAt )
if err != nil {
return nodes , err
}
err = json . Unmarshal ( data , & node . Data )
if err != nil {
return nodes , err
}
nodes = append ( nodes , node )
}
return nodes , rows . Err ( )
}
func sqlCommonUpdateNodeTimestamp ( dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getUpdateNodeTimestampQuery ( )
res , err := dbHandle . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( time . Now ( ) ) , currentNode . Name )
if err != nil {
return err
}
return sqlCommonRequireRowAffected ( res )
}
func sqlCommonCleanupNodes ( dbHandle * sql . DB ) error {
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
q := getCleanupNodesQuery ( )
_ , err := dbHandle . ExecContext ( ctx , q , util . GetTimeAsMsSinceEpoch ( time . Now ( ) . Add ( 10 * activeNodeTimeDiff ) ) )
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 ( )
2022-07-19 20:25:00 +00:00
stmt , err := dbHandle . PrepareContext ( ctx , q )
if err != nil {
providerLog ( logger . LevelError , "error preparing database query %#v: %v" , q , err )
if showInitWarn && strings . Contains ( err . Error ( ) , sqlTableSchemaVersion ) {
logger . WarnToConsole ( "database query error, did you forgot to run the \"initprovider\" command?" )
}
return result , err
}
defer stmt . Close ( )
row := stmt . QueryRowContext ( ctx )
err = row . Scan ( & result . Version )
2020-02-08 13:44:25 +00:00
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 ( )
2022-06-11 09:57:06 +00:00
_ , err := dbHandle . ExecContext ( ctx , q , 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 :
var lockResult sql . NullInt64
2022-06-11 09:57:06 +00:00
err := dbHandle . QueryRowContext ( ctx , ` SELECT GET_LOCK('sftpgo.migration',30) ` ) . Scan ( & lockResult )
2022-05-15 13:25:12 +00:00
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 {
2022-07-11 06:17:36 +00:00
return fmt . Errorf ( "unable to get lock, result: %d" , lockResult . Int64 )
2022-05-15 13:25:12 +00:00
}
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 ( )
}