mirror of https://github.com/cloudreve/Cloudreve
[Feature](database): Add Support for SSL Connections and Database URL Configuration (#2540)
* feat(database): add support for SSL connections and database URL configuration * feat(config): update Redis configuration to use TLS in configurre name instead of SSL * fix(database): remove default values for DatabaseURL and SSLMode in DatabaseConfig * chore(.gitignore): add cloudreve built binary to ignore listpull/2499/merge
parent
fec549f5ec
commit
1bd62e8feb
|
@ -32,3 +32,5 @@ conf/conf.ini
|
||||||
dist/
|
dist/
|
||||||
data/
|
data/
|
||||||
tmp/
|
tmp/
|
||||||
|
.devcontainer/
|
||||||
|
cloudreve
|
||||||
|
|
|
@ -329,11 +329,7 @@ func (d *dependency) KV() cache.Driver {
|
||||||
d.kv = cache.NewRedisStore(
|
d.kv = cache.NewRedisStore(
|
||||||
d.Logger(),
|
d.Logger(),
|
||||||
10,
|
10,
|
||||||
config.Network,
|
config,
|
||||||
config.Server,
|
|
||||||
config.User,
|
|
||||||
config.Password,
|
|
||||||
config.DB,
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
d.kv = cache.NewMemoStore(util.DataPath(cache.DefaultCacheFile), d.Logger())
|
d.kv = cache.NewMemoStore(util.DataPath(cache.DefaultCacheFile), d.Logger())
|
||||||
|
|
|
@ -58,45 +58,56 @@ func NewRawEntClient(l logging.Logger, config conf.ConfigProvider) (*ent.Client,
|
||||||
client *sql.Driver
|
client *sql.Driver
|
||||||
)
|
)
|
||||||
|
|
||||||
switch confDBType {
|
// Check if the database type is supported.
|
||||||
case conf.SQLiteDB:
|
if confDBType != conf.SQLiteDB && confDBType != conf.MySqlDB && confDBType != conf.PostgresDB {
|
||||||
dbFile := util.RelativePath(dbConfig.DBFile)
|
return nil, fmt.Errorf("unsupported database type: %s", confDBType)
|
||||||
l.Info("Connect to SQLite database %q.", dbFile)
|
}
|
||||||
client, err = sql.Open("sqlite3", util.RelativePath(dbConfig.DBFile))
|
// If Database connection string provided, use it directly.
|
||||||
case conf.PostgresDB:
|
if dbConfig.DatabaseURL != "" {
|
||||||
l.Info("Connect to Postgres database %q.", dbConfig.Host)
|
l.Info("Connect to database with connection string %q.", dbConfig.DatabaseURL)
|
||||||
client, err = sql.Open("postgres", fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=disable",
|
client, err = sql.Open(string(confDBType), dbConfig.DatabaseURL)
|
||||||
dbConfig.Host,
|
} else {
|
||||||
dbConfig.User,
|
|
||||||
dbConfig.Password,
|
switch confDBType {
|
||||||
dbConfig.Name,
|
case conf.SQLiteDB:
|
||||||
dbConfig.Port))
|
dbFile := util.RelativePath(dbConfig.DBFile)
|
||||||
case conf.MySqlDB, conf.MsSqlDB:
|
l.Info("Connect to SQLite database %q.", dbFile)
|
||||||
l.Info("Connect to MySQL/SQLServer database %q.", dbConfig.Host)
|
client, err = sql.Open("sqlite3", util.RelativePath(dbConfig.DBFile))
|
||||||
var host string
|
case conf.PostgresDB:
|
||||||
if dbConfig.UnixSocket {
|
l.Info("Connect to Postgres database %q.", dbConfig.Host)
|
||||||
host = fmt.Sprintf("unix(%s)",
|
client, err = sql.Open("postgres", fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=allow",
|
||||||
dbConfig.Host)
|
|
||||||
} else {
|
|
||||||
host = fmt.Sprintf("(%s:%d)",
|
|
||||||
dbConfig.Host,
|
dbConfig.Host,
|
||||||
dbConfig.Port)
|
dbConfig.User,
|
||||||
|
dbConfig.Password,
|
||||||
|
dbConfig.Name,
|
||||||
|
dbConfig.Port))
|
||||||
|
case conf.MySqlDB, conf.MsSqlDB:
|
||||||
|
l.Info("Connect to MySQL/SQLServer database %q.", dbConfig.Host)
|
||||||
|
var host string
|
||||||
|
if dbConfig.UnixSocket {
|
||||||
|
host = fmt.Sprintf("unix(%s)",
|
||||||
|
dbConfig.Host)
|
||||||
|
} else {
|
||||||
|
host = fmt.Sprintf("(%s:%d)",
|
||||||
|
dbConfig.Host,
|
||||||
|
dbConfig.Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err = sql.Open(string(confDBType), fmt.Sprintf("%s:%s@%s/%s?charset=%s&parseTime=True&loc=Local",
|
||||||
|
dbConfig.User,
|
||||||
|
dbConfig.Password,
|
||||||
|
host,
|
||||||
|
dbConfig.Name,
|
||||||
|
dbConfig.Charset))
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported database type %q", confDBType)
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err = sql.Open(string(confDBType), fmt.Sprintf("%s:%s@%s/%s?charset=%s&parseTime=True&loc=Local",
|
if err != nil {
|
||||||
dbConfig.User,
|
return nil, fmt.Errorf("failed to open database: %w", err)
|
||||||
dbConfig.Password,
|
}
|
||||||
host,
|
|
||||||
dbConfig.Name,
|
|
||||||
dbConfig.Charset))
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported database type %q", confDBType)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to open database: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set connection pool
|
// Set connection pool
|
||||||
db := client.DB()
|
db := client.DB()
|
||||||
db.SetMaxIdleConns(50)
|
db.SetMaxIdleConns(50)
|
||||||
|
|
|
@ -3,10 +3,12 @@ package cache
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"github.com/cloudreve/Cloudreve/v4/pkg/logging"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cloudreve/Cloudreve/v4/pkg/conf"
|
||||||
|
"github.com/cloudreve/Cloudreve/v4/pkg/logging"
|
||||||
|
|
||||||
"github.com/gomodule/redigo/redis"
|
"github.com/gomodule/redigo/redis"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,7 +46,7 @@ func deserializer(value []byte) (any, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRedisStore 创建新的redis存储
|
// NewRedisStore 创建新的redis存储
|
||||||
func NewRedisStore(l logging.Logger, size int, network, address, user, password, database string) *RedisStore {
|
func NewRedisStore(l logging.Logger, size int, redisConfig *conf.Redis) *RedisStore {
|
||||||
return &RedisStore{
|
return &RedisStore{
|
||||||
pool: &redis.Pool{
|
pool: &redis.Pool{
|
||||||
MaxIdle: size,
|
MaxIdle: size,
|
||||||
|
@ -54,17 +56,19 @@ func NewRedisStore(l logging.Logger, size int, network, address, user, password,
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
Dial: func() (redis.Conn, error) {
|
Dial: func() (redis.Conn, error) {
|
||||||
db, err := strconv.Atoi(database)
|
db, err := strconv.Atoi(redisConfig.DB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := redis.Dial(
|
c, err := redis.Dial(
|
||||||
network,
|
redisConfig.Network,
|
||||||
address,
|
redisConfig.Server,
|
||||||
redis.DialDatabase(db),
|
redis.DialDatabase(db),
|
||||||
redis.DialPassword(password),
|
redis.DialPassword(redisConfig.Password),
|
||||||
redis.DialUsername(user),
|
redis.DialUsername(redisConfig.User),
|
||||||
|
redis.DialUseTLS(redisConfig.UseTLS),
|
||||||
|
redis.DialTLSSkipVerify(redisConfig.TLSSkipVerify),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Panic("Failed to create Redis connection: %s", err)
|
l.Panic("Failed to create Redis connection: %s", err)
|
||||||
|
|
|
@ -2,12 +2,13 @@ package conf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/cloudreve/Cloudreve/v4/pkg/logging"
|
"github.com/cloudreve/Cloudreve/v4/pkg/logging"
|
||||||
"github.com/cloudreve/Cloudreve/v4/pkg/util"
|
"github.com/cloudreve/Cloudreve/v4/pkg/util"
|
||||||
"github.com/go-ini/ini"
|
"github.com/go-ini/ini"
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -24,6 +24,10 @@ type Database struct {
|
||||||
Port int
|
Port int
|
||||||
Charset string
|
Charset string
|
||||||
UnixSocket bool
|
UnixSocket bool
|
||||||
|
// 允许直接使用DATABASE_URL来配置数据库连接
|
||||||
|
DatabaseURL string
|
||||||
|
// SSLMode 允许使用SSL连接数据库, 用户可以在sslmode string中添加证书等配置
|
||||||
|
SSLMode string
|
||||||
}
|
}
|
||||||
|
|
||||||
type SysMode string
|
type SysMode string
|
||||||
|
@ -65,11 +69,13 @@ type Slave struct {
|
||||||
|
|
||||||
// Redis 配置
|
// Redis 配置
|
||||||
type Redis struct {
|
type Redis struct {
|
||||||
Network string
|
Network string
|
||||||
Server string
|
Server string
|
||||||
User string
|
User string
|
||||||
Password string
|
Password string
|
||||||
DB string
|
DB string
|
||||||
|
UseTLS bool
|
||||||
|
TLSSkipVerify bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// 跨域配置
|
// 跨域配置
|
||||||
|
@ -85,18 +91,21 @@ type Cors struct {
|
||||||
|
|
||||||
// RedisConfig Redis服务器配置
|
// RedisConfig Redis服务器配置
|
||||||
var RedisConfig = &Redis{
|
var RedisConfig = &Redis{
|
||||||
Network: "tcp",
|
Network: "tcp",
|
||||||
Server: "",
|
Server: "",
|
||||||
Password: "",
|
Password: "",
|
||||||
DB: "0",
|
DB: "0",
|
||||||
|
UseTLS: false,
|
||||||
|
TLSSkipVerify: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// DatabaseConfig 数据库配置
|
// DatabaseConfig 数据库配置
|
||||||
var DatabaseConfig = &Database{
|
var DatabaseConfig = &Database{
|
||||||
Charset: "utf8mb4",
|
Charset: "utf8mb4",
|
||||||
DBFile: util.DataPath("cloudreve.db"),
|
DBFile: util.DataPath("cloudreve.db"),
|
||||||
Port: 3306,
|
Port: 3306,
|
||||||
UnixSocket: false,
|
UnixSocket: false,
|
||||||
|
DatabaseURL: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
// SystemConfig 系统公用配置
|
// SystemConfig 系统公用配置
|
||||||
|
|
Loading…
Reference in New Issue