mirror of
https://github.com/MrAle98/sliver
synced 2026-06-08 11:54:46 +00:00
180 lines
4.9 KiB
Go
180 lines
4.9 KiB
Go
package configs
|
|
|
|
/*
|
|
Sliver Implant Framework
|
|
Copyright (C) 2020 Bishop Fox
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
|
|
"github.com/bishopfox/sliver/server/assets"
|
|
"github.com/bishopfox/sliver/server/log"
|
|
)
|
|
|
|
const (
|
|
// Sqlite - SQLite protocol
|
|
Sqlite = "sqlite3"
|
|
// Postgres - Postgresql protocol
|
|
Postgres = "postgresql"
|
|
// MySQL - MySQL protocol
|
|
MySQL = "mysql"
|
|
|
|
databaseConfigFileName = "database.json"
|
|
)
|
|
|
|
var (
|
|
// ErrInvalidDialect - An invalid dialect was specified
|
|
ErrInvalidDialect = errors.New("invalid SQL Dialect")
|
|
|
|
databaseConfigLog = log.NamedLogger("config", "database")
|
|
)
|
|
|
|
// GetDatabaseConfigPath - File path to config.json
|
|
func GetDatabaseConfigPath() string {
|
|
appDir := assets.GetRootAppDir()
|
|
databaseConfigPath := filepath.Join(appDir, "configs", databaseConfigFileName)
|
|
databaseConfigLog.Debugf("Loading config from %s", databaseConfigPath)
|
|
return databaseConfigPath
|
|
}
|
|
|
|
// DatabaseConfig - Server config
|
|
type DatabaseConfig struct {
|
|
Dialect string `json:"dialect"`
|
|
Database string `json:"database"`
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
Host string `json:"host"`
|
|
Port uint16 `json:"port"`
|
|
|
|
Params map[string]string `json:"params"`
|
|
|
|
MaxIdleConns int `json:"max_idle_conns"`
|
|
MaxOpenConns int `json:"max_open_conns"`
|
|
|
|
LogLevel string `json:"log_level"`
|
|
}
|
|
|
|
// DSN - Get the db connections string
|
|
// https://github.com/go-sql-driver/mysql#examples
|
|
func (c *DatabaseConfig) DSN() (string, error) {
|
|
switch c.Dialect {
|
|
case Sqlite:
|
|
filePath := filepath.Join(assets.GetRootAppDir(), "sliver.db")
|
|
params := encodeParams(c.Params)
|
|
return fmt.Sprintf("file:%s?%s", filePath, params), nil
|
|
case MySQL:
|
|
user := url.QueryEscape(c.Username)
|
|
password := url.QueryEscape(c.Password)
|
|
db := url.QueryEscape(c.Database)
|
|
host := fmt.Sprintf("%s:%d", url.QueryEscape(c.Host), c.Port)
|
|
params := encodeParams(c.Params)
|
|
databaseConfigLog.Infof("Connecting to MySQL database %s@%s/%s", user, host, db)
|
|
return fmt.Sprintf("%s:%s@tcp(%s)/%s?%s", user, password, host, db, params), nil
|
|
case Postgres:
|
|
user := url.QueryEscape(c.Username)
|
|
password := url.QueryEscape(c.Password)
|
|
db := url.QueryEscape(c.Database)
|
|
host := url.QueryEscape(c.Host)
|
|
port := c.Port
|
|
params := encodeParams(c.Params)
|
|
databaseConfigLog.Infof("Connecting to Postgres database %s@%s:%d/%s", user, host, port, db)
|
|
return fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s %s", host, port, user, password, db, params), nil
|
|
default:
|
|
return "", ErrInvalidDialect
|
|
}
|
|
}
|
|
|
|
func encodeParams(rawParams map[string]string) string {
|
|
params := url.Values{}
|
|
for key, value := range rawParams {
|
|
params.Add(key, value)
|
|
}
|
|
return params.Encode()
|
|
}
|
|
|
|
// Save - Save config file to disk
|
|
func (c *DatabaseConfig) Save() error {
|
|
configPath := GetDatabaseConfigPath()
|
|
configDir := path.Dir(configPath)
|
|
if _, err := os.Stat(configDir); os.IsNotExist(err) {
|
|
databaseConfigLog.Debugf("Creating config dir %s", configDir)
|
|
err := os.MkdirAll(configDir, 0700)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
data, err := json.MarshalIndent(c, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
databaseConfigLog.Infof("Saving config to %s", configPath)
|
|
err = os.WriteFile(configPath, data, 0600)
|
|
if err != nil {
|
|
databaseConfigLog.Errorf("Failed to write config %s", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetDatabaseConfig - Get config value
|
|
func GetDatabaseConfig() *DatabaseConfig {
|
|
configPath := GetDatabaseConfigPath()
|
|
config := getDefaultDatabaseConfig()
|
|
if _, err := os.Stat(configPath); !os.IsNotExist(err) {
|
|
data, err := os.ReadFile(configPath)
|
|
if err != nil {
|
|
databaseConfigLog.Errorf("Failed to read config file %s", err)
|
|
return config
|
|
}
|
|
err = json.Unmarshal(data, config)
|
|
if err != nil {
|
|
databaseConfigLog.Errorf("Failed to parse config file %s", err)
|
|
return config
|
|
}
|
|
} else {
|
|
databaseConfigLog.Warnf("Config file does not exist, using defaults")
|
|
}
|
|
|
|
if config.MaxIdleConns < 1 {
|
|
config.MaxIdleConns = 1
|
|
}
|
|
if config.MaxOpenConns < 1 {
|
|
config.MaxOpenConns = 1
|
|
}
|
|
|
|
err := config.Save() // This updates the config with any missing fields
|
|
if err != nil {
|
|
databaseConfigLog.Errorf("Failed to save default config %s", err)
|
|
}
|
|
return config
|
|
}
|
|
|
|
func getDefaultDatabaseConfig() *DatabaseConfig {
|
|
return &DatabaseConfig{
|
|
Dialect: Sqlite,
|
|
MaxIdleConns: 10,
|
|
MaxOpenConns: 100,
|
|
|
|
LogLevel: "warn",
|
|
}
|
|
}
|