2024-01-01 10:31:45 +00:00
// Copyright (C) 2019 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
2021-08-19 13:51:43 +00:00
//go:build !nomysql
2020-05-23 09:58:05 +00:00
// +build !nomysql
2019-07-20 10:26:52 +00:00
package dataprovider
import (
2020-07-08 16:54:44 +00:00
"context"
2022-01-30 17:04:03 +00:00
"crypto/tls"
2021-02-28 11:10:40 +00:00
"crypto/x509"
2019-07-20 10:26:52 +00:00
"database/sql"
2021-02-22 07:37:50 +00:00
"errors"
2019-07-20 10:26:52 +00:00
"fmt"
2022-01-30 17:04:03 +00:00
"os"
2022-09-07 12:31:50 +00:00
"path/filepath"
2020-02-08 13:44:25 +00:00
"strings"
2019-07-20 10:26:52 +00:00
"time"
2019-09-06 13:19:01 +00:00
2022-01-30 17:04:03 +00:00
"github.com/go-sql-driver/mysql"
2020-05-23 09:58:05 +00:00
2022-07-24 14:18:54 +00:00
"github.com/drakkan/sftpgo/v2/internal/logger"
2024-01-17 16:36:35 +00:00
"github.com/drakkan/sftpgo/v2/internal/util"
2022-07-24 14:18:54 +00:00
"github.com/drakkan/sftpgo/v2/internal/version"
"github.com/drakkan/sftpgo/v2/internal/vfs"
2019-07-20 10:26:52 +00:00
)
2020-02-08 13:44:25 +00:00
const (
2021-11-15 17:40:31 +00:00
mysqlResetSQL = "DROP TABLE IF EXISTS `{{api_keys}}` CASCADE;" +
"DROP TABLE IF EXISTS `{{folders_mapping}}` CASCADE;" +
2022-04-25 13:49:11 +00:00
"DROP TABLE IF EXISTS `{{users_folders_mapping}}` CASCADE;" +
"DROP TABLE IF EXISTS `{{users_groups_mapping}}` CASCADE;" +
2022-09-13 16:04:27 +00:00
"DROP TABLE IF EXISTS `{{admins_groups_mapping}}` CASCADE;" +
2022-04-25 13:49:11 +00:00
"DROP TABLE IF EXISTS `{{groups_folders_mapping}}` CASCADE;" +
2021-11-15 17:40:31 +00:00
"DROP TABLE IF EXISTS `{{admins}}` CASCADE;" +
"DROP TABLE IF EXISTS `{{folders}}` CASCADE;" +
"DROP TABLE IF EXISTS `{{shares}}` CASCADE;" +
"DROP TABLE IF EXISTS `{{users}}` CASCADE;" +
2022-04-25 13:49:11 +00:00
"DROP TABLE IF EXISTS `{{groups}}` CASCADE;" +
2021-12-25 11:08:07 +00:00
"DROP TABLE IF EXISTS `{{defender_events}}` CASCADE;" +
"DROP TABLE IF EXISTS `{{defender_hosts}}` CASCADE;" +
2022-01-30 10:42:36 +00:00
"DROP TABLE IF EXISTS `{{active_transfers}}` CASCADE;" +
2022-05-19 17:49:51 +00:00
"DROP TABLE IF EXISTS `{{shared_sessions}}` CASCADE;" +
2022-07-11 06:17:36 +00:00
"DROP TABLE IF EXISTS `{{rules_actions_mapping}}` CASCADE;" +
"DROP TABLE IF EXISTS `{{events_actions}}` CASCADE;" +
"DROP TABLE IF EXISTS `{{events_rules}}` CASCADE;" +
"DROP TABLE IF EXISTS `{{tasks}}` CASCADE;" +
2022-09-25 17:48:55 +00:00
"DROP TABLE IF EXISTS `{{nodes}}` CASCADE;" +
2022-11-16 18:04:50 +00:00
"DROP TABLE IF EXISTS `{{roles}}` CASCADE;" +
2023-02-09 08:33:33 +00:00
"DROP TABLE IF EXISTS `{{ip_lists}}` CASCADE;" +
2023-02-19 18:03:45 +00:00
"DROP TABLE IF EXISTS `{{configs}}` CASCADE;" +
2021-11-15 17:40:31 +00:00
"DROP TABLE IF EXISTS `{{schema_version}}` CASCADE;"
2021-02-22 07:37:50 +00:00
mysqlInitialSQL = "CREATE TABLE `{{schema_version}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `version` integer NOT NULL);" +
"CREATE TABLE `{{admins}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `username` varchar(255) NOT NULL UNIQUE, " +
2021-06-19 07:03:20 +00:00
"`description` varchar(512) NULL, `password` varchar(255) NOT NULL, `email` varchar(255) NULL, `status` integer NOT NULL, " +
2022-01-09 11:25:53 +00:00
"`permissions` longtext NOT NULL, `filters` longtext NULL, `additional_info` longtext NULL, `last_login` bigint NOT NULL, " +
2023-06-10 11:06:24 +00:00
"`role_id` integer NULL, `created_at` bigint NOT NULL, `updated_at` bigint NOT NULL);" +
2022-06-13 18:08:49 +00:00
"CREATE TABLE `{{active_transfers}}` (`id` bigint AUTO_INCREMENT NOT NULL PRIMARY KEY, " +
"`connection_id` varchar(100) NOT NULL, `transfer_id` bigint NOT NULL, `transfer_type` integer NOT NULL, " +
"`username` varchar(255) NOT NULL, `folder_name` varchar(255) NULL, `ip` varchar(50) NOT NULL, " +
"`truncated_size` bigint NOT NULL, `current_ul_size` bigint NOT NULL, `current_dl_size` bigint NOT NULL, " +
"`created_at` bigint NOT NULL, `updated_at` bigint NOT NULL);" +
2022-01-09 11:25:53 +00:00
"CREATE TABLE `{{defender_hosts}}` (`id` bigint AUTO_INCREMENT NOT NULL PRIMARY KEY, " +
"`ip` varchar(50) NOT NULL UNIQUE, `ban_time` bigint NOT NULL, `updated_at` bigint NOT NULL);" +
"CREATE TABLE `{{defender_events}}` (`id` bigint AUTO_INCREMENT NOT NULL PRIMARY KEY, " +
"`date_time` bigint NOT NULL, `score` integer NOT NULL, `host_id` bigint NOT NULL);" +
"ALTER TABLE `{{defender_events}}` ADD CONSTRAINT `{{prefix}}defender_events_host_id_fk_defender_hosts_id` " +
"FOREIGN KEY (`host_id`) REFERENCES `{{defender_hosts}}` (`id`) ON DELETE CASCADE;" +
2021-02-22 07:37:50 +00:00
"CREATE TABLE `{{folders}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(255) NOT NULL UNIQUE, " +
2022-01-09 11:25:53 +00:00
"`description` varchar(512) NULL, `path` longtext NULL, `used_quota_size` bigint NOT NULL, " +
2021-06-19 07:03:20 +00:00
"`used_quota_files` integer NOT NULL, `last_quota_update` bigint NOT NULL, `filesystem` longtext NULL);" +
2022-06-13 18:08:49 +00:00
"CREATE TABLE `{{groups}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, " +
"`name` varchar(255) NOT NULL UNIQUE, `description` varchar(512) NULL, `created_at` bigint NOT NULL, " +
"`updated_at` bigint NOT NULL, `user_settings` longtext NULL);" +
"CREATE TABLE `{{shared_sessions}}` (`key` varchar(128) NOT NULL PRIMARY KEY, " +
"`data` longtext NOT NULL, `type` integer NOT NULL, `timestamp` bigint NOT NULL);" +
2021-06-19 07:03:20 +00:00
"CREATE TABLE `{{users}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `username` varchar(255) NOT NULL UNIQUE, " +
"`status` integer NOT NULL, `expiration_date` bigint NOT NULL, `description` varchar(512) NULL, `password` longtext NULL, " +
2022-01-16 08:50:23 +00:00
"`public_keys` longtext NULL, `home_dir` longtext NOT NULL, `uid` bigint NOT NULL, `gid` bigint NOT NULL, " +
2021-02-22 07:37:50 +00:00
"`max_sessions` integer NOT NULL, `quota_size` bigint NOT NULL, `quota_files` integer NOT NULL, " +
"`permissions` longtext NOT NULL, `used_quota_size` bigint NOT NULL, `used_quota_files` integer NOT NULL, " +
"`last_quota_update` bigint NOT NULL, `upload_bandwidth` integer NOT NULL, `download_bandwidth` integer NOT NULL, " +
2022-01-09 11:25:53 +00:00
"`last_login` bigint NOT NULL, `filters` longtext NULL, `filesystem` longtext NULL, `additional_info` longtext NULL, " +
2022-06-13 18:08:49 +00:00
"`created_at` bigint NOT NULL, `updated_at` bigint NOT NULL, `email` varchar(255) NULL, " +
"`upload_data_transfer` integer NOT NULL, `download_data_transfer` integer NOT NULL, " +
2024-06-15 14:02:09 +00:00
"`total_data_transfer` integer NOT NULL, `used_upload_data_transfer` bigint NOT NULL, " +
"`used_download_data_transfer` bigint NOT NULL, `deleted_at` bigint NOT NULL, `first_download` bigint NOT NULL, " +
2023-06-10 11:06:24 +00:00
"`first_upload` bigint NOT NULL, `last_password_change` bigint NOT NULL, `role_id` integer NULL);" +
2022-04-25 13:49:11 +00:00
"CREATE TABLE `{{groups_folders_mapping}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, " +
"`group_id` integer NOT NULL, `folder_id` integer NOT NULL, " +
"`virtual_path` longtext NOT NULL, `quota_size` bigint NOT NULL, `quota_files` integer NOT NULL);" +
"CREATE TABLE `{{users_groups_mapping}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, " +
"`user_id` integer NOT NULL, `group_id` integer NOT NULL, `group_type` integer NOT NULL);" +
2022-06-13 18:08:49 +00:00
"CREATE TABLE `{{users_folders_mapping}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `virtual_path` longtext NOT NULL, " +
"`quota_size` bigint NOT NULL, `quota_files` integer NOT NULL, `folder_id` integer NOT NULL, `user_id` integer NOT NULL);" +
2022-04-25 13:49:11 +00:00
"ALTER TABLE `{{users_folders_mapping}}` ADD CONSTRAINT `{{prefix}}unique_user_folder_mapping` " +
"UNIQUE (`user_id`, `folder_id`);" +
"ALTER TABLE `{{users_folders_mapping}}` ADD CONSTRAINT `{{prefix}}users_folders_mapping_user_id_fk_users_id` " +
"FOREIGN KEY (`user_id`) REFERENCES `{{users}}` (`id`) ON DELETE CASCADE;" +
"ALTER TABLE `{{users_folders_mapping}}` ADD CONSTRAINT `{{prefix}}users_folders_mapping_folder_id_fk_folders_id` " +
"FOREIGN KEY (`folder_id`) REFERENCES `{{folders}}` (`id`) ON DELETE CASCADE;" +
"ALTER TABLE `{{users_groups_mapping}}` ADD CONSTRAINT `{{prefix}}unique_user_group_mapping` UNIQUE (`user_id`, `group_id`);" +
"ALTER TABLE `{{groups_folders_mapping}}` ADD CONSTRAINT `{{prefix}}unique_group_folder_mapping` UNIQUE (`group_id`, `folder_id`);" +
"ALTER TABLE `{{users_groups_mapping}}` ADD CONSTRAINT `{{prefix}}users_groups_mapping_group_id_fk_groups_id` " +
"FOREIGN KEY (`group_id`) REFERENCES `{{groups}}` (`id`) ON DELETE NO ACTION;" +
"ALTER TABLE `{{users_groups_mapping}}` ADD CONSTRAINT `{{prefix}}users_groups_mapping_user_id_fk_users_id` " +
2023-10-20 18:31:17 +00:00
"FOREIGN KEY (`user_id`) REFERENCES `{{users}}` (`id`) ON DELETE CASCADE; " +
2022-04-25 13:49:11 +00:00
"ALTER TABLE `{{groups_folders_mapping}}` ADD CONSTRAINT `{{prefix}}groups_folders_mapping_folder_id_fk_folders_id` " +
"FOREIGN KEY (`folder_id`) REFERENCES `{{folders}}` (`id`) ON DELETE CASCADE;" +
"ALTER TABLE `{{groups_folders_mapping}}` ADD CONSTRAINT `{{prefix}}groups_folders_mapping_group_id_fk_groups_id` " +
"FOREIGN KEY (`group_id`) REFERENCES `{{groups}}` (`id`) ON DELETE CASCADE;" +
2022-06-13 18:08:49 +00:00
"CREATE TABLE `{{shares}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, " +
"`share_id` varchar(60) NOT NULL UNIQUE, `name` varchar(255) NOT NULL, `description` varchar(512) NULL, " +
"`scope` integer NOT NULL, `paths` longtext NOT NULL, `created_at` bigint NOT NULL, " +
"`updated_at` bigint NOT NULL, `last_use_at` bigint NOT NULL, `expires_at` bigint NOT NULL, " +
"`password` longtext NULL, `max_tokens` integer NOT NULL, `used_tokens` integer NOT NULL, " +
"`allow_from` longtext NULL, `user_id` integer NOT NULL);" +
"ALTER TABLE `{{shares}}` ADD CONSTRAINT `{{prefix}}shares_user_id_fk_users_id` " +
2022-04-25 13:49:11 +00:00
"FOREIGN KEY (`user_id`) REFERENCES `{{users}}` (`id`) ON DELETE CASCADE;" +
2022-06-13 18:08:49 +00:00
"CREATE TABLE `{{api_keys}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(255) NOT NULL, `key_id` varchar(50) NOT NULL UNIQUE," +
"`api_key` varchar(255) NOT NULL UNIQUE, `scope` integer NOT NULL, `created_at` bigint NOT NULL, `updated_at` bigint NOT NULL, `last_use_at` bigint NOT NULL, " +
"`expires_at` bigint NOT NULL, `description` longtext NULL, `admin_id` integer NULL, `user_id` integer NULL);" +
"ALTER TABLE `{{api_keys}}` ADD CONSTRAINT `{{prefix}}api_keys_admin_id_fk_admins_id` FOREIGN KEY (`admin_id`) REFERENCES `{{admins}}` (`id`) ON DELETE CASCADE;" +
"ALTER TABLE `{{api_keys}}` ADD CONSTRAINT `{{prefix}}api_keys_user_id_fk_users_id` FOREIGN KEY (`user_id`) REFERENCES `{{users}}` (`id`) ON DELETE CASCADE;" +
2022-10-28 12:28:37 +00:00
"CREATE TABLE `{{events_rules}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, " +
2023-06-10 11:06:24 +00:00
"`name` varchar(255) NOT NULL UNIQUE, `status` integer NOT NULL, `description` varchar(512) NULL, `created_at` bigint NOT NULL, " +
2022-07-11 06:17:36 +00:00
"`updated_at` bigint NOT NULL, `trigger` integer NOT NULL, `conditions` longtext NOT NULL, `deleted_at` bigint NOT NULL);" +
"CREATE TABLE `{{events_actions}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, " +
"`name` varchar(255) NOT NULL UNIQUE, `description` varchar(512) NULL, `type` integer NOT NULL, " +
"`options` longtext NOT NULL);" +
"CREATE TABLE `{{rules_actions_mapping}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, " +
"`rule_id` integer NOT NULL, `action_id` integer NOT NULL, `order` integer NOT NULL, `options` longtext NOT NULL);" +
"CREATE TABLE `{{tasks}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(255) NOT NULL UNIQUE, " +
"`updated_at` bigint NOT NULL, `version` bigint NOT NULL);" +
"ALTER TABLE `{{rules_actions_mapping}}` ADD CONSTRAINT `{{prefix}}unique_rule_action_mapping` UNIQUE (`rule_id`, `action_id`);" +
"ALTER TABLE `{{rules_actions_mapping}}` ADD CONSTRAINT `{{prefix}}rules_actions_mapping_rule_id_fk_events_rules_id` " +
"FOREIGN KEY (`rule_id`) REFERENCES `{{events_rules}}` (`id`) ON DELETE CASCADE;" +
"ALTER TABLE `{{rules_actions_mapping}}` ADD CONSTRAINT `{{prefix}}rules_actions_mapping_action_id_fk_events_targets_id` " +
"FOREIGN KEY (`action_id`) REFERENCES `{{events_actions}}` (`id`) ON DELETE NO ACTION;" +
2022-10-28 12:28:37 +00:00
"CREATE TABLE `{{admins_groups_mapping}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, " +
2022-09-13 16:04:27 +00:00
" `admin_id` integer NOT NULL, `group_id` integer NOT NULL, `options` longtext NOT NULL);" +
"ALTER TABLE `{{admins_groups_mapping}}` ADD CONSTRAINT `{{prefix}}unique_admin_group_mapping` " +
"UNIQUE (`admin_id`, `group_id`);" +
"ALTER TABLE `{{admins_groups_mapping}}` ADD CONSTRAINT `{{prefix}}admins_groups_mapping_admin_id_fk_admins_id` " +
"FOREIGN KEY (`admin_id`) REFERENCES `{{admins}}` (`id`) ON DELETE CASCADE;" +
"ALTER TABLE `{{admins_groups_mapping}}` ADD CONSTRAINT `{{prefix}}admins_groups_mapping_group_id_fk_groups_id` " +
2022-10-28 12:28:37 +00:00
"FOREIGN KEY (`group_id`) REFERENCES `{{groups}}` (`id`) ON DELETE CASCADE;" +
"CREATE TABLE `{{nodes}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, " +
2022-09-25 17:48:55 +00:00
"`name` varchar(255) NOT NULL UNIQUE, `data` longtext NOT NULL, `created_at` bigint NOT NULL, " +
2022-10-28 12:28:37 +00:00
"`updated_at` bigint NOT NULL);" +
2023-06-10 11:06:24 +00:00
"CREATE TABLE `{{roles}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(255) NOT NULL UNIQUE, " +
"`description` varchar(512) NULL, `created_at` bigint NOT NULL, `updated_at` bigint NOT NULL);" +
"ALTER TABLE `{{admins}}` ADD CONSTRAINT `{{prefix}}admins_role_id_fk_roles_id` FOREIGN KEY (`role_id`) " +
"REFERENCES `{{roles}}`(`id`) ON DELETE NO ACTION;" +
"ALTER TABLE `{{users}}` ADD CONSTRAINT `{{prefix}}users_role_id_fk_roles_id` FOREIGN KEY (`role_id`) " +
"REFERENCES `{{roles}}`(`id`) ON DELETE SET NULL;" +
"CREATE TABLE `{{ip_lists}}` (`id` bigint AUTO_INCREMENT NOT NULL PRIMARY KEY, `type` integer NOT NULL, " +
"`ipornet` varchar(50) NOT NULL, `mode` integer NOT NULL, `description` varchar(512) NULL, " +
"`first` VARBINARY(16) NOT NULL, `last` VARBINARY(16) NOT NULL, `ip_type` integer NOT NULL, `protocols` integer NOT NULL, " +
"`created_at` bigint NOT NULL, `updated_at` bigint NOT NULL, `deleted_at` bigint NOT NULL);" +
"ALTER TABLE `{{ip_lists}}` ADD CONSTRAINT `{{prefix}}unique_ipornet_type_mapping` UNIQUE (`type`, `ipornet`);" +
"CREATE TABLE `{{configs}}` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `configs` longtext NOT NULL);" +
"INSERT INTO {{configs}} (configs) VALUES ('{}');" +
2022-10-28 12:28:37 +00:00
"CREATE INDEX `{{prefix}}users_updated_at_idx` ON `{{users}}` (`updated_at`);" +
"CREATE INDEX `{{prefix}}users_deleted_at_idx` ON `{{users}}` (`deleted_at`);" +
"CREATE INDEX `{{prefix}}defender_hosts_updated_at_idx` ON `{{defender_hosts}}` (`updated_at`);" +
"CREATE INDEX `{{prefix}}defender_hosts_ban_time_idx` ON `{{defender_hosts}}` (`ban_time`);" +
"CREATE INDEX `{{prefix}}defender_events_date_time_idx` ON `{{defender_events}}` (`date_time`);" +
"CREATE INDEX `{{prefix}}active_transfers_connection_id_idx` ON `{{active_transfers}}` (`connection_id`);" +
"CREATE INDEX `{{prefix}}active_transfers_transfer_id_idx` ON `{{active_transfers}}` (`transfer_id`);" +
"CREATE INDEX `{{prefix}}active_transfers_updated_at_idx` ON `{{active_transfers}}` (`updated_at`);" +
"CREATE INDEX `{{prefix}}shared_sessions_type_idx` ON `{{shared_sessions}}` (`type`);" +
"CREATE INDEX `{{prefix}}shared_sessions_timestamp_idx` ON `{{shared_sessions}}` (`timestamp`);" +
"CREATE INDEX `{{prefix}}events_rules_updated_at_idx` ON `{{events_rules}}` (`updated_at`);" +
"CREATE INDEX `{{prefix}}events_rules_deleted_at_idx` ON `{{events_rules}}` (`deleted_at`);" +
"CREATE INDEX `{{prefix}}events_rules_trigger_idx` ON `{{events_rules}}` (`trigger`);" +
"CREATE INDEX `{{prefix}}rules_actions_mapping_order_idx` ON `{{rules_actions_mapping}}` (`order`);" +
2023-02-09 08:33:33 +00:00
"CREATE INDEX `{{prefix}}ip_lists_type_idx` ON `{{ip_lists}}` (`type`);" +
"CREATE INDEX `{{prefix}}ip_lists_ipornet_idx` ON `{{ip_lists}}` (`ipornet`);" +
"CREATE INDEX `{{prefix}}ip_lists_ip_type_idx` ON `{{ip_lists}}` (`ip_type`);" +
"CREATE INDEX `{{prefix}}ip_lists_updated_at_idx` ON `{{ip_lists}}` (`updated_at`);" +
"CREATE INDEX `{{prefix}}ip_lists_deleted_at_idx` ON `{{ip_lists}}` (`deleted_at`);" +
2023-06-10 11:06:24 +00:00
"CREATE INDEX `{{prefix}}ip_lists_first_last_idx` ON `{{ip_lists}}` (`first`, `last`);" +
2024-06-15 14:02:09 +00:00
"INSERT INTO {{schema_version}} (version) VALUES (29);"
2020-02-08 13:44:25 +00:00
)
2022-01-09 11:25:53 +00:00
// MySQLProvider defines the auth provider for MySQL/MariaDB database
2019-07-20 10:26:52 +00:00
type MySQLProvider struct {
2019-08-11 12:53:37 +00:00
dbHandle * sql . DB
2019-07-20 10:26:52 +00:00
}
2020-05-23 09:58:05 +00:00
func init ( ) {
2020-06-19 15:08:51 +00:00
version . AddFeature ( "+mysql" )
2020-05-23 09:58:05 +00:00
}
2019-07-20 10:26:52 +00:00
func initializeMySQLProvider ( ) error {
2022-01-30 17:04:03 +00:00
connString , err := getMySQLConnectionString ( false )
if err != nil {
return err
}
redactedConnString , err := getMySQLConnectionString ( true )
if err != nil {
return err
}
dbHandle , err := sql . Open ( "mysql" , connString )
2023-03-25 08:29:13 +00:00
if err != nil {
2023-02-20 17:14:02 +00:00
providerLog ( logger . LevelError , "error creating mysql database handler, connection string: %q, error: %v" ,
2022-01-30 17:04:03 +00:00
redactedConnString , err )
2023-03-25 08:29:13 +00:00
return err
}
providerLog ( logger . LevelDebug , "mysql database handle created, connection string: %q, pool size: %v" ,
redactedConnString , config . PoolSize )
dbHandle . SetMaxOpenConns ( config . PoolSize )
if config . PoolSize > 0 {
dbHandle . SetMaxIdleConns ( config . PoolSize )
} else {
dbHandle . SetMaxIdleConns ( 2 )
2019-07-20 10:26:52 +00:00
}
2023-03-25 08:29:13 +00:00
dbHandle . SetConnMaxLifetime ( 240 * time . Second )
dbHandle . SetConnMaxIdleTime ( 120 * time . Second )
provider = & MySQLProvider { dbHandle : dbHandle }
2023-05-23 10:59:27 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , defaultSQLQueryTimeout )
defer cancel ( )
return dbHandle . PingContext ( ctx )
2019-07-20 10:26:52 +00:00
}
2022-01-30 17:04:03 +00:00
func getMySQLConnectionString ( redactedPwd bool ) ( string , error ) {
2019-09-13 19:57:52 +00:00
var connectionString string
2021-01-05 08:50:22 +00:00
if config . ConnectionString == "" {
2019-09-13 19:57:52 +00:00
password := config . Password
2022-02-27 12:08:47 +00:00
if redactedPwd && password != "" {
2019-09-13 19:57:52 +00:00
password = "[redacted]"
}
2022-01-30 17:04:03 +00:00
sslMode := getSSLMode ( )
if sslMode == "custom" && ! redactedPwd {
2022-09-07 12:31:50 +00:00
if err := registerMySQLCustomTLSConfig ( ) ; err != nil {
return "" , err
2022-01-30 17:04:03 +00:00
}
}
2023-02-20 17:14:02 +00:00
connectionString = fmt . Sprintf ( "%s:%s@tcp([%s]:%d)/%s?collation=utf8mb4_unicode_ci&interpolateParams=true&timeout=10s&parseTime=true&clientFoundRows=true&tls=%s&writeTimeout=60s&readTimeout=60s" ,
2022-01-30 17:04:03 +00:00
config . Username , password , config . Host , config . Port , config . Name , sslMode )
2019-09-13 19:57:52 +00:00
} else {
connectionString = config . ConnectionString
}
2022-01-30 17:04:03 +00:00
return connectionString , nil
2019-09-13 19:57:52 +00:00
}
2019-07-20 10:26:52 +00:00
2022-09-07 12:31:50 +00:00
func registerMySQLCustomTLSConfig ( ) error {
tlsConfig := & tls . Config { }
if config . RootCert != "" {
rootCAs , err := x509 . SystemCertPool ( )
if err != nil {
rootCAs = x509 . NewCertPool ( )
}
rootCrt , err := os . ReadFile ( config . RootCert )
if err != nil {
2023-02-27 18:02:43 +00:00
return fmt . Errorf ( "unable to load root certificate %q: %v" , config . RootCert , err )
2022-09-07 12:31:50 +00:00
}
if ! rootCAs . AppendCertsFromPEM ( rootCrt ) {
2023-02-27 18:02:43 +00:00
return fmt . Errorf ( "unable to parse root certificate %q" , config . RootCert )
2022-09-07 12:31:50 +00:00
}
tlsConfig . RootCAs = rootCAs
}
if config . ClientCert != "" && config . ClientKey != "" {
clientCert := make ( [ ] tls . Certificate , 0 , 1 )
tlsCert , err := tls . LoadX509KeyPair ( config . ClientCert , config . ClientKey )
if err != nil {
2023-02-27 18:02:43 +00:00
return fmt . Errorf ( "unable to load key pair %q, %q: %v" , config . ClientCert , config . ClientKey , err )
2022-09-07 12:31:50 +00:00
}
clientCert = append ( clientCert , tlsCert )
tlsConfig . Certificates = clientCert
}
if config . SSLMode == 2 || config . SSLMode == 3 {
tlsConfig . InsecureSkipVerify = true
}
if ! filepath . IsAbs ( config . Host ) && ! config . DisableSNI {
tlsConfig . ServerName = config . Host
}
2023-02-27 18:02:43 +00:00
providerLog ( logger . LevelInfo , "registering custom TLS config, root cert %q, client cert %q, client key %q, disable SNI? %v" ,
2022-09-07 12:31:50 +00:00
config . RootCert , config . ClientCert , config . ClientKey , config . DisableSNI )
if err := mysql . RegisterTLSConfig ( "custom" , tlsConfig ) ; err != nil {
return fmt . Errorf ( "unable to register tls config: %v" , err )
}
return nil
}
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) checkAvailability ( ) error {
2019-09-13 16:45:36 +00:00
return sqlCommonCheckAvailability ( p . dbHandle )
}
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) validateUserAndPass ( username , password , ip , protocol string ) ( User , error ) {
2020-08-19 17:36:12 +00:00
return sqlCommonValidateUserAndPass ( username , password , ip , protocol , p . dbHandle )
2019-07-20 10:26:52 +00:00
}
2021-02-28 11:10:40 +00:00
func ( p * MySQLProvider ) validateUserAndTLSCert ( username , protocol string , tlsCert * x509 . Certificate ) ( User , error ) {
return sqlCommonValidateUserAndTLSCertificate ( username , protocol , tlsCert , p . dbHandle )
}
2022-03-31 16:16:50 +00:00
func ( p * MySQLProvider ) validateUserAndPubKey ( username string , publicKey [ ] byte , isSSHCert bool ) ( User , string , error ) {
return sqlCommonValidateUserAndPubKey ( username , publicKey , isSSHCert , p . dbHandle )
2019-07-20 10:26:52 +00:00
}
2022-01-30 10:42:36 +00:00
func ( p * MySQLProvider ) updateTransferQuota ( username string , uploadSize , downloadSize int64 , reset bool ) error {
return sqlCommonUpdateTransferQuota ( username , uploadSize , downloadSize , reset , p . dbHandle )
}
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) updateQuota ( username string , filesAdd int , sizeAdd int64 , reset bool ) error {
2019-09-13 06:14:07 +00:00
return sqlCommonUpdateQuota ( username , filesAdd , sizeAdd , reset , p . dbHandle )
2019-07-20 10:26:52 +00:00
}
2022-01-30 10:42:36 +00:00
func ( p * MySQLProvider ) getUsedQuota ( username string ) ( int , int64 , int64 , int64 , error ) {
2019-08-11 12:53:37 +00:00
return sqlCommonGetUsedQuota ( username , p . dbHandle )
2019-07-20 10:26:52 +00:00
}
2024-09-21 12:06:25 +00:00
func ( p * MySQLProvider ) getAdminSignature ( username string ) ( string , error ) {
return sqlCommonGetAdminSignature ( username , p . dbHandle )
}
func ( p * MySQLProvider ) getUserSignature ( username string ) ( string , error ) {
return sqlCommonGetUserSignature ( username , p . dbHandle )
}
2021-08-19 13:51:43 +00:00
func ( p * MySQLProvider ) setUpdatedAt ( username string ) {
sqlCommonSetUpdatedAt ( username , p . dbHandle )
}
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) updateLastLogin ( username string ) error {
2020-06-07 21:30:18 +00:00
return sqlCommonUpdateLastLogin ( username , p . dbHandle )
}
2021-08-19 13:51:43 +00:00
func ( p * MySQLProvider ) updateAdminLastLogin ( username string ) error {
return sqlCommonUpdateAdminLastLogin ( username , p . dbHandle )
}
2022-11-16 18:04:50 +00:00
func ( p * MySQLProvider ) userExists ( username , role string ) ( User , error ) {
return sqlCommonGetUserByUsername ( username , role , p . dbHandle )
2019-07-20 10:26:52 +00:00
}
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) addUser ( user * User ) error {
2024-01-17 16:36:35 +00:00
return p . normalizeError ( sqlCommonAddUser ( user , p . dbHandle ) , fieldUsername )
2019-07-20 10:26:52 +00:00
}
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) updateUser ( user * User ) error {
2024-02-03 13:24:50 +00:00
return p . normalizeError ( sqlCommonUpdateUser ( user , p . dbHandle ) , - 1 )
2019-07-20 10:26:52 +00:00
}
2022-07-17 16:48:41 +00:00
func ( p * MySQLProvider ) deleteUser ( user User , softDelete bool ) error {
return sqlCommonDeleteUser ( user , softDelete , p . dbHandle )
2019-07-20 10:26:52 +00:00
}
2022-04-02 20:20:21 +00:00
func ( p * MySQLProvider ) updateUserPassword ( username , password string ) error {
return sqlCommonUpdateUserPassword ( username , password , p . dbHandle )
}
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) dumpUsers ( ) ( [ ] User , error ) {
2019-12-27 22:12:44 +00:00
return sqlCommonDumpUsers ( p . dbHandle )
}
2021-08-20 07:35:06 +00:00
func ( p * MySQLProvider ) getRecentlyUpdatedUsers ( after int64 ) ( [ ] User , error ) {
return sqlCommonGetRecentlyUpdatedUsers ( after , p . dbHandle )
}
2022-11-16 18:04:50 +00:00
func ( p * MySQLProvider ) getUsers ( limit int , offset int , order , role string ) ( [ ] User , error ) {
return sqlCommonGetUsers ( limit , offset , order , role , p . dbHandle )
2019-07-20 10:26:52 +00:00
}
2019-09-28 20:48:52 +00:00
2022-01-20 17:19:20 +00:00
func ( p * MySQLProvider ) getUsersForQuotaCheck ( toFetch map [ string ] bool ) ( [ ] User , error ) {
return sqlCommonGetUsersForQuotaCheck ( toFetch , p . dbHandle )
}
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) dumpFolders ( ) ( [ ] vfs . BaseVirtualFolder , error ) {
2020-06-07 21:30:18 +00:00
return sqlCommonDumpFolders ( p . dbHandle )
}
2022-04-25 13:49:11 +00:00
func ( p * MySQLProvider ) getFolders ( limit , offset int , order string , minimal bool ) ( [ ] vfs . BaseVirtualFolder , error ) {
return sqlCommonGetFolders ( limit , offset , order , minimal , p . dbHandle )
2020-06-07 21:30:18 +00:00
}
2021-02-01 18:04:15 +00:00
func ( p * MySQLProvider ) getFolderByName ( name string ) ( vfs . BaseVirtualFolder , error ) {
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
return sqlCommonGetFolderByName ( ctx , name , p . dbHandle )
2020-06-07 21:30:18 +00:00
}
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) addFolder ( folder * vfs . BaseVirtualFolder ) error {
2024-01-17 16:36:35 +00:00
return p . normalizeError ( sqlCommonAddFolder ( folder , p . dbHandle ) , fieldName )
2020-06-07 21:30:18 +00:00
}
2021-02-01 18:04:15 +00:00
func ( p * MySQLProvider ) updateFolder ( folder * vfs . BaseVirtualFolder ) error {
return sqlCommonUpdateFolder ( folder , p . dbHandle )
}
2022-04-25 13:49:11 +00:00
func ( p * MySQLProvider ) deleteFolder ( folder vfs . BaseVirtualFolder ) error {
2020-06-07 21:30:18 +00:00
return sqlCommonDeleteFolder ( folder , p . dbHandle )
}
2021-02-01 18:04:15 +00:00
func ( p * MySQLProvider ) updateFolderQuota ( name string , filesAdd int , sizeAdd int64 , reset bool ) error {
return sqlCommonUpdateFolderQuota ( name , filesAdd , sizeAdd , reset , p . dbHandle )
2020-06-07 21:30:18 +00:00
}
2021-02-01 18:04:15 +00:00
func ( p * MySQLProvider ) getUsedFolderQuota ( name string ) ( int , int64 , error ) {
return sqlCommonGetFolderUsedQuota ( name , p . dbHandle )
2020-06-07 21:30:18 +00:00
}
2022-04-25 13:49:11 +00:00
func ( p * MySQLProvider ) getGroups ( limit , offset int , order string , minimal bool ) ( [ ] Group , error ) {
return sqlCommonGetGroups ( limit , offset , order , minimal , p . dbHandle )
}
func ( p * MySQLProvider ) getGroupsWithNames ( names [ ] string ) ( [ ] Group , error ) {
return sqlCommonGetGroupsWithNames ( names , p . dbHandle )
}
func ( p * MySQLProvider ) getUsersInGroups ( names [ ] string ) ( [ ] string , error ) {
return sqlCommonGetUsersInGroups ( names , p . dbHandle )
}
func ( p * MySQLProvider ) groupExists ( name string ) ( Group , error ) {
return sqlCommonGetGroupByName ( name , p . dbHandle )
}
func ( p * MySQLProvider ) addGroup ( group * Group ) error {
2024-01-17 16:36:35 +00:00
return p . normalizeError ( sqlCommonAddGroup ( group , p . dbHandle ) , fieldName )
2022-04-25 13:49:11 +00:00
}
func ( p * MySQLProvider ) updateGroup ( group * Group ) error {
return sqlCommonUpdateGroup ( group , p . dbHandle )
}
func ( p * MySQLProvider ) deleteGroup ( group Group ) error {
return sqlCommonDeleteGroup ( group , p . dbHandle )
}
func ( p * MySQLProvider ) dumpGroups ( ) ( [ ] Group , error ) {
return sqlCommonDumpGroups ( p . dbHandle )
}
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) adminExists ( username string ) ( Admin , error ) {
return sqlCommonGetAdminByUsername ( username , p . dbHandle )
}
func ( p * MySQLProvider ) addAdmin ( admin * Admin ) error {
2024-01-17 16:36:35 +00:00
return p . normalizeError ( sqlCommonAddAdmin ( admin , p . dbHandle ) , fieldUsername )
2021-01-17 21:29:08 +00:00
}
func ( p * MySQLProvider ) updateAdmin ( admin * Admin ) error {
2024-02-03 13:24:50 +00:00
return p . normalizeError ( sqlCommonUpdateAdmin ( admin , p . dbHandle ) , - 1 )
2021-01-17 21:29:08 +00:00
}
2022-04-25 13:49:11 +00:00
func ( p * MySQLProvider ) deleteAdmin ( admin Admin ) error {
2021-01-17 21:29:08 +00:00
return sqlCommonDeleteAdmin ( admin , p . dbHandle )
}
func ( p * MySQLProvider ) getAdmins ( limit int , offset int , order string ) ( [ ] Admin , error ) {
return sqlCommonGetAdmins ( limit , offset , order , p . dbHandle )
}
func ( p * MySQLProvider ) dumpAdmins ( ) ( [ ] Admin , error ) {
return sqlCommonDumpAdmins ( p . dbHandle )
}
func ( p * MySQLProvider ) validateAdminAndPass ( username , password , ip string ) ( Admin , error ) {
return sqlCommonValidateAdminAndPass ( username , password , ip , p . dbHandle )
}
2021-08-17 16:08:32 +00:00
func ( p * MySQLProvider ) apiKeyExists ( keyID string ) ( APIKey , error ) {
return sqlCommonGetAPIKeyByID ( keyID , p . dbHandle )
}
func ( p * MySQLProvider ) addAPIKey ( apiKey * APIKey ) error {
2024-02-03 13:24:50 +00:00
return p . normalizeError ( sqlCommonAddAPIKey ( apiKey , p . dbHandle ) , - 1 )
2021-08-17 16:08:32 +00:00
}
func ( p * MySQLProvider ) updateAPIKey ( apiKey * APIKey ) error {
2024-02-03 13:24:50 +00:00
return p . normalizeError ( sqlCommonUpdateAPIKey ( apiKey , p . dbHandle ) , - 1 )
2021-08-17 16:08:32 +00:00
}
2022-04-25 13:49:11 +00:00
func ( p * MySQLProvider ) deleteAPIKey ( apiKey APIKey ) error {
2021-08-17 16:08:32 +00:00
return sqlCommonDeleteAPIKey ( apiKey , p . dbHandle )
}
func ( p * MySQLProvider ) getAPIKeys ( limit int , offset int , order string ) ( [ ] APIKey , error ) {
return sqlCommonGetAPIKeys ( limit , offset , order , p . dbHandle )
}
func ( p * MySQLProvider ) dumpAPIKeys ( ) ( [ ] APIKey , error ) {
return sqlCommonDumpAPIKeys ( p . dbHandle )
}
func ( p * MySQLProvider ) updateAPIKeyLastUse ( keyID string ) error {
return sqlCommonUpdateAPIKeyLastUse ( keyID , p . dbHandle )
}
2021-11-06 13:13:20 +00:00
func ( p * MySQLProvider ) shareExists ( shareID , username string ) ( Share , error ) {
return sqlCommonGetShareByID ( shareID , username , p . dbHandle )
}
func ( p * MySQLProvider ) addShare ( share * Share ) error {
2024-02-03 13:24:50 +00:00
return p . normalizeError ( sqlCommonAddShare ( share , p . dbHandle ) , fieldName )
2021-11-06 13:13:20 +00:00
}
func ( p * MySQLProvider ) updateShare ( share * Share ) error {
2024-02-03 13:24:50 +00:00
return p . normalizeError ( sqlCommonUpdateShare ( share , p . dbHandle ) , - 1 )
2021-11-06 13:13:20 +00:00
}
2022-04-25 13:49:11 +00:00
func ( p * MySQLProvider ) deleteShare ( share Share ) error {
2021-11-06 13:13:20 +00:00
return sqlCommonDeleteShare ( share , p . dbHandle )
}
func ( p * MySQLProvider ) getShares ( limit int , offset int , order , username string ) ( [ ] Share , error ) {
return sqlCommonGetShares ( limit , offset , order , username , p . dbHandle )
}
func ( p * MySQLProvider ) dumpShares ( ) ( [ ] Share , error ) {
return sqlCommonDumpShares ( p . dbHandle )
}
func ( p * MySQLProvider ) updateShareLastUse ( shareID string , numTokens int ) error {
return sqlCommonUpdateShareLastUse ( shareID , numTokens , p . dbHandle )
}
2022-01-16 11:09:17 +00:00
func ( p * MySQLProvider ) getDefenderHosts ( from int64 , limit int ) ( [ ] DefenderEntry , error ) {
2021-12-25 11:08:07 +00:00
return sqlCommonGetDefenderHosts ( from , limit , p . dbHandle )
}
2022-01-16 11:09:17 +00:00
func ( p * MySQLProvider ) getDefenderHostByIP ( ip string , from int64 ) ( DefenderEntry , error ) {
2021-12-25 11:08:07 +00:00
return sqlCommonGetDefenderHostByIP ( ip , from , p . dbHandle )
}
2022-01-16 11:09:17 +00:00
func ( p * MySQLProvider ) isDefenderHostBanned ( ip string ) ( DefenderEntry , error ) {
2021-12-25 11:08:07 +00:00
return sqlCommonIsDefenderHostBanned ( ip , p . dbHandle )
}
func ( p * MySQLProvider ) updateDefenderBanTime ( ip string , minutes int ) error {
return sqlCommonDefenderIncrementBanTime ( ip , minutes , p . dbHandle )
}
func ( p * MySQLProvider ) deleteDefenderHost ( ip string ) error {
return sqlCommonDeleteDefenderHost ( ip , p . dbHandle )
}
func ( p * MySQLProvider ) addDefenderEvent ( ip string , score int ) error {
return sqlCommonAddDefenderHostAndEvent ( ip , score , p . dbHandle )
}
func ( p * MySQLProvider ) setDefenderBanTime ( ip string , banTime int64 ) error {
return sqlCommonSetDefenderBanTime ( ip , banTime , p . dbHandle )
}
func ( p * MySQLProvider ) cleanupDefender ( from int64 ) error {
return sqlCommonDefenderCleanup ( from , p . dbHandle )
}
2022-01-30 10:42:36 +00:00
func ( p * MySQLProvider ) addActiveTransfer ( transfer ActiveTransfer ) error {
return sqlCommonAddActiveTransfer ( transfer , p . dbHandle )
}
func ( p * MySQLProvider ) updateActiveTransferSizes ( ulSize , dlSize , transferID int64 , connectionID string ) error {
return sqlCommonUpdateActiveTransferSizes ( ulSize , dlSize , transferID , connectionID , p . dbHandle )
}
func ( p * MySQLProvider ) removeActiveTransfer ( transferID int64 , connectionID string ) error {
return sqlCommonRemoveActiveTransfer ( transferID , connectionID , p . dbHandle )
}
func ( p * MySQLProvider ) cleanupActiveTransfers ( before time . Time ) error {
return sqlCommonCleanupActiveTransfers ( before , p . dbHandle )
}
func ( p * MySQLProvider ) getActiveTransfers ( from time . Time ) ( [ ] ActiveTransfer , error ) {
return sqlCommonGetActiveTransfers ( from , p . dbHandle )
}
2022-05-19 17:49:51 +00:00
func ( p * MySQLProvider ) addSharedSession ( session Session ) error {
return sqlCommonAddSession ( session , p . dbHandle )
}
func ( p * MySQLProvider ) deleteSharedSession ( key string ) error {
return sqlCommonDeleteSession ( key , p . dbHandle )
}
func ( p * MySQLProvider ) getSharedSession ( key string ) ( Session , error ) {
return sqlCommonGetSession ( key , p . dbHandle )
}
func ( p * MySQLProvider ) cleanupSharedSessions ( sessionType SessionType , before int64 ) error {
return sqlCommonCleanupSessions ( sessionType , before , p . dbHandle )
}
2022-07-11 06:17:36 +00:00
func ( p * MySQLProvider ) getEventActions ( limit , offset int , order string , minimal bool ) ( [ ] BaseEventAction , error ) {
return sqlCommonGetEventActions ( limit , offset , order , minimal , p . dbHandle )
}
func ( p * MySQLProvider ) dumpEventActions ( ) ( [ ] BaseEventAction , error ) {
return sqlCommonDumpEventActions ( p . dbHandle )
}
func ( p * MySQLProvider ) eventActionExists ( name string ) ( BaseEventAction , error ) {
return sqlCommonGetEventActionByName ( name , p . dbHandle )
}
func ( p * MySQLProvider ) addEventAction ( action * BaseEventAction ) error {
2024-01-17 16:36:35 +00:00
return p . normalizeError ( sqlCommonAddEventAction ( action , p . dbHandle ) , fieldName )
2022-07-11 06:17:36 +00:00
}
func ( p * MySQLProvider ) updateEventAction ( action * BaseEventAction ) error {
return sqlCommonUpdateEventAction ( action , p . dbHandle )
}
func ( p * MySQLProvider ) deleteEventAction ( action BaseEventAction ) error {
return sqlCommonDeleteEventAction ( action , p . dbHandle )
}
func ( p * MySQLProvider ) getEventRules ( limit , offset int , order string ) ( [ ] EventRule , error ) {
return sqlCommonGetEventRules ( limit , offset , order , p . dbHandle )
}
func ( p * MySQLProvider ) dumpEventRules ( ) ( [ ] EventRule , error ) {
return sqlCommonDumpEventRules ( p . dbHandle )
}
func ( p * MySQLProvider ) getRecentlyUpdatedRules ( after int64 ) ( [ ] EventRule , error ) {
return sqlCommonGetRecentlyUpdatedRules ( after , p . dbHandle )
}
func ( p * MySQLProvider ) eventRuleExists ( name string ) ( EventRule , error ) {
return sqlCommonGetEventRuleByName ( name , p . dbHandle )
}
func ( p * MySQLProvider ) addEventRule ( rule * EventRule ) error {
2024-01-17 16:36:35 +00:00
return p . normalizeError ( sqlCommonAddEventRule ( rule , p . dbHandle ) , fieldName )
2022-07-11 06:17:36 +00:00
}
func ( p * MySQLProvider ) updateEventRule ( rule * EventRule ) error {
return sqlCommonUpdateEventRule ( rule , p . dbHandle )
}
func ( p * MySQLProvider ) deleteEventRule ( rule EventRule , softDelete bool ) error {
return sqlCommonDeleteEventRule ( rule , softDelete , p . dbHandle )
}
func ( p * MySQLProvider ) getTaskByName ( name string ) ( Task , error ) {
return sqlCommonGetTaskByName ( name , p . dbHandle )
}
func ( p * MySQLProvider ) addTask ( name string ) error {
return sqlCommonAddTask ( name , p . dbHandle )
}
func ( p * MySQLProvider ) updateTask ( name string , version int64 ) error {
return sqlCommonUpdateTask ( name , version , p . dbHandle )
}
func ( p * MySQLProvider ) updateTaskTimestamp ( name string ) error {
return sqlCommonUpdateTaskTimestamp ( name , p . dbHandle )
}
2022-09-25 17:48:55 +00:00
func ( p * MySQLProvider ) addNode ( ) error {
return sqlCommonAddNode ( p . dbHandle )
}
func ( p * MySQLProvider ) getNodeByName ( name string ) ( Node , error ) {
return sqlCommonGetNodeByName ( name , p . dbHandle )
}
func ( p * MySQLProvider ) getNodes ( ) ( [ ] Node , error ) {
return sqlCommonGetNodes ( p . dbHandle )
}
func ( p * MySQLProvider ) updateNodeTimestamp ( ) error {
return sqlCommonUpdateNodeTimestamp ( p . dbHandle )
}
func ( p * MySQLProvider ) cleanupNodes ( ) error {
return sqlCommonCleanupNodes ( p . dbHandle )
}
2022-11-16 18:04:50 +00:00
func ( p * MySQLProvider ) roleExists ( name string ) ( Role , error ) {
return sqlCommonGetRoleByName ( name , p . dbHandle )
}
func ( p * MySQLProvider ) addRole ( role * Role ) error {
2024-01-17 16:36:35 +00:00
return p . normalizeError ( sqlCommonAddRole ( role , p . dbHandle ) , fieldName )
2022-11-16 18:04:50 +00:00
}
func ( p * MySQLProvider ) updateRole ( role * Role ) error {
return sqlCommonUpdateRole ( role , p . dbHandle )
}
func ( p * MySQLProvider ) deleteRole ( role Role ) error {
return sqlCommonDeleteRole ( role , p . dbHandle )
}
func ( p * MySQLProvider ) getRoles ( limit int , offset int , order string , minimal bool ) ( [ ] Role , error ) {
return sqlCommonGetRoles ( limit , offset , order , minimal , p . dbHandle )
}
func ( p * MySQLProvider ) dumpRoles ( ) ( [ ] Role , error ) {
return sqlCommonDumpRoles ( p . dbHandle )
}
2023-02-09 08:33:33 +00:00
func ( p * MySQLProvider ) ipListEntryExists ( ipOrNet string , listType IPListType ) ( IPListEntry , error ) {
return sqlCommonGetIPListEntry ( ipOrNet , listType , p . dbHandle )
}
func ( p * MySQLProvider ) addIPListEntry ( entry * IPListEntry ) error {
2024-01-24 18:23:15 +00:00
return p . normalizeError ( sqlCommonAddIPListEntry ( entry , p . dbHandle ) , fieldIPNet )
2023-02-09 08:33:33 +00:00
}
func ( p * MySQLProvider ) updateIPListEntry ( entry * IPListEntry ) error {
return sqlCommonUpdateIPListEntry ( entry , p . dbHandle )
}
func ( p * MySQLProvider ) deleteIPListEntry ( entry IPListEntry , softDelete bool ) error {
return sqlCommonDeleteIPListEntry ( entry , softDelete , p . dbHandle )
}
func ( p * MySQLProvider ) getIPListEntries ( listType IPListType , filter , from , order string , limit int ) ( [ ] IPListEntry , error ) {
return sqlCommonGetIPListEntries ( listType , filter , from , order , limit , p . dbHandle )
}
func ( p * MySQLProvider ) getRecentlyUpdatedIPListEntries ( after int64 ) ( [ ] IPListEntry , error ) {
return sqlCommonGetRecentlyUpdatedIPListEntries ( after , p . dbHandle )
}
func ( p * MySQLProvider ) dumpIPListEntries ( ) ( [ ] IPListEntry , error ) {
return sqlCommonDumpIPListEntries ( p . dbHandle )
}
func ( p * MySQLProvider ) countIPListEntries ( listType IPListType ) ( int64 , error ) {
return sqlCommonCountIPListEntries ( listType , p . dbHandle )
}
func ( p * MySQLProvider ) getListEntriesForIP ( ip string , listType IPListType ) ( [ ] IPListEntry , error ) {
return sqlCommonGetListEntriesForIP ( ip , listType , p . dbHandle )
}
2023-02-19 18:03:45 +00:00
func ( p * MySQLProvider ) getConfigs ( ) ( Configs , error ) {
return sqlCommonGetConfigs ( p . dbHandle )
}
func ( p * MySQLProvider ) setConfigs ( configs * Configs ) error {
return sqlCommonSetConfigs ( configs , p . dbHandle )
}
2022-08-21 17:01:08 +00:00
func ( p * MySQLProvider ) setFirstDownloadTimestamp ( username string ) error {
return sqlCommonSetFirstDownloadTimestamp ( username , p . dbHandle )
}
func ( p * MySQLProvider ) setFirstUploadTimestamp ( username string ) error {
return sqlCommonSetFirstUploadTimestamp ( username , p . dbHandle )
}
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) close ( ) error {
2019-09-28 20:48:52 +00:00
return p . dbHandle . Close ( )
}
2020-02-02 21:20:39 +00:00
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) reloadConfig ( ) error {
2020-02-02 21:20:39 +00:00
return nil
}
2020-02-08 13:44:25 +00:00
// initializeDatabase creates the initial database structure
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) initializeDatabase ( ) error {
2020-08-30 12:00:45 +00:00
dbVersion , err := sqlCommonGetDatabaseVersion ( p . dbHandle , false )
if err == nil && dbVersion . Version > 0 {
return ErrNoInitRequired
}
2021-11-15 17:40:31 +00:00
if errors . Is ( err , sql . ErrNoRows ) {
return errSchemaVersionEmpty
}
2024-06-15 14:02:09 +00:00
logger . InfoToConsole ( "creating initial database schema, version 29" )
providerLog ( logger . LevelInfo , "creating initial database schema, version 29" )
2022-06-13 18:08:49 +00:00
initialSQL := sqlReplaceAll ( mysqlInitialSQL )
2024-06-15 14:02:09 +00:00
return sqlCommonExecSQLAndUpdateDBVersion ( p . dbHandle , strings . Split ( initialSQL , ";" ) , 29 , true )
2020-02-08 13:44:25 +00:00
}
2023-06-10 11:06:24 +00:00
func ( p * MySQLProvider ) migrateDatabase ( ) error {
2020-08-30 11:50:43 +00:00
dbVersion , err := sqlCommonGetDatabaseVersion ( p . dbHandle , true )
2020-02-23 10:30:26 +00:00
if err != nil {
return err
}
2021-02-22 07:37:50 +00:00
switch version := dbVersion . Version ; {
case version == sqlDatabaseVersion :
2022-10-28 12:28:37 +00:00
providerLog ( logger . LevelDebug , "sql database is up to date, current version: %d" , version )
2020-10-05 17:42:33 +00:00
return ErrNoInitRequired
2024-06-15 14:02:09 +00:00
case version < 29 :
2022-10-28 12:28:37 +00:00
err = fmt . Errorf ( "database schema version %d is too old, please see the upgrading docs" , version )
2021-02-22 07:37:50 +00:00
providerLog ( logger . LevelError , "%v" , err )
logger . ErrorToConsole ( "%v" , err )
return err
2020-11-26 21:08:33 +00:00
default :
2021-02-22 07:37:50 +00:00
if version > sqlDatabaseVersion {
2022-10-28 12:28:37 +00:00
providerLog ( logger . LevelError , "database schema version %d is newer than the supported one: %d" , version ,
2020-11-26 21:08:33 +00:00
sqlDatabaseVersion )
2022-10-28 12:28:37 +00:00
logger . WarnToConsole ( "database schema version %d is newer than the supported one: %d" , version ,
2020-11-26 21:08:33 +00:00
sqlDatabaseVersion )
return nil
}
2022-10-28 12:28:37 +00:00
return fmt . Errorf ( "database schema version not handled: %d" , version )
2020-11-26 21:08:33 +00:00
}
}
2021-01-17 21:29:08 +00:00
func ( p * MySQLProvider ) revertDatabase ( targetVersion int ) error {
2020-11-26 21:08:33 +00:00
dbVersion , err := sqlCommonGetDatabaseVersion ( p . dbHandle , true )
if err != nil {
return err
}
if dbVersion . Version == targetVersion {
2021-02-22 07:37:50 +00:00
return errors . New ( "current version match target version, nothing to do" )
2021-02-01 18:04:15 +00:00
}
2021-02-24 18:40:29 +00:00
2021-08-17 16:08:32 +00:00
switch dbVersion . Version {
default :
2022-10-28 12:28:37 +00:00
return fmt . Errorf ( "database schema version not handled: %d" , dbVersion . Version )
2021-08-17 16:08:32 +00:00
}
}
2021-11-15 17:40:31 +00:00
func ( p * MySQLProvider ) resetDatabase ( ) error {
2022-04-25 13:49:11 +00:00
sql := sqlReplaceAll ( mysqlResetSQL )
2022-05-19 17:49:51 +00:00
return sqlCommonExecSQLAndUpdateDBVersion ( p . dbHandle , strings . Split ( sql , ";" ) , 0 , false )
2021-11-15 17:40:31 +00:00
}
2024-01-17 16:36:35 +00:00
func ( p * MySQLProvider ) normalizeError ( err error , fieldType int ) error {
if err == nil {
return nil
}
var mysqlErr * mysql . MySQLError
if errors . As ( err , & mysqlErr ) {
switch mysqlErr . Number {
case 1062 :
2024-01-24 18:23:15 +00:00
var message string
switch fieldType {
case fieldUsername :
2024-01-17 16:36:35 +00:00
message = util . I18nErrorDuplicatedUsername
2024-01-24 18:23:15 +00:00
case fieldIPNet :
message = util . I18nErrorDuplicatedIPNet
default :
message = util . I18nErrorDuplicatedName
2024-01-17 16:36:35 +00:00
}
return util . NewI18nError (
fmt . Errorf ( "%w: %s" , ErrDuplicatedKey , err . Error ( ) ) ,
message ,
)
case 1452 :
return fmt . Errorf ( "%w: %s" , ErrForeignKeyViolated , err . Error ( ) )
}
}
return err
}