151 lines
4.6 KiB
Go
151 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/go-redis/redis/v8"
|
|
"github.com/spf13/viper"
|
|
"log"
|
|
"os"
|
|
"time"
|
|
"tytanium/constants"
|
|
"tytanium/global"
|
|
"tytanium/logger"
|
|
)
|
|
|
|
const (
|
|
mebibyte = 1 << 20
|
|
minute = 60000
|
|
characterTagLengthEncoded = 12
|
|
)
|
|
|
|
func init() {
|
|
fmt.Printf("[ ⬢ Tytanium v%s ]\n", constants.Version)
|
|
initConfiguration()
|
|
initLogger()
|
|
checkStorage()
|
|
initRedis()
|
|
log.Println("[init] Initial checks completed")
|
|
}
|
|
|
|
func initConfiguration() {
|
|
viper.SetConfigName("config")
|
|
viper.AddConfigPath("./conf/")
|
|
viper.AutomaticEnv()
|
|
viper.SetConfigType("yml")
|
|
|
|
if err := viper.ReadInConfig(); err != nil {
|
|
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
|
log.Fatalf("No config file set, %v", err)
|
|
} else {
|
|
log.Fatalf("Error reading config file, %v", err)
|
|
}
|
|
}
|
|
|
|
viper.SetDefault("Storage.Directory", "files")
|
|
viper.SetDefault("Storage.MaxSize", 50*mebibyte)
|
|
viper.SetDefault("Storage.IDLength", 5)
|
|
|
|
viper.SetDefault("RateLimit.ResetAfter", minute)
|
|
viper.SetDefault("RateLimit.Path.Upload", 10)
|
|
viper.SetDefault("RateLimit.Path.Global", 60)
|
|
viper.SetDefault("RateLimit.Bandwidth.ResetAfter", 5*minute)
|
|
viper.SetDefault("RateLimit.Bandwidth.Download", 500*mebibyte)
|
|
viper.SetDefault("RateLimit.Bandwidth.Upload", 1000*mebibyte)
|
|
|
|
viper.SetDefault("Server.Port", 3030)
|
|
viper.SetDefault("Server.Concurrency", 128*4)
|
|
viper.SetDefault("Server.ReadTimeout", 5*minute)
|
|
viper.SetDefault("Server.WriteTimeout", 5*minute)
|
|
|
|
viper.SetDefault("StatsCollectionInterval", 30000)
|
|
|
|
viper.SetDefault("Logging.Enabled", true)
|
|
viper.SetDefault("Logging.LogFile", "log.txt")
|
|
|
|
viper.SetDefault("Encryption.EncryptionKeyLength", 12)
|
|
|
|
err := viper.Unmarshal(&global.Configuration)
|
|
if err != nil {
|
|
log.Fatalf("Unable to decode into struct, %v", err)
|
|
}
|
|
|
|
if len(global.Configuration.Domain) == 0 {
|
|
log.Fatalf("Domain must be set in the configuration.")
|
|
}
|
|
|
|
if len(global.Configuration.Encryption.Nonce) == 0 {
|
|
log.Fatalf("You must set a nonce for encryption purposes. (Under Encryption.Nonce, use any string you want. It does not need to be secret.)")
|
|
}
|
|
|
|
if len(global.Configuration.Security.MasterKey) == 0 {
|
|
log.Println("Warning: Master key has not set in your configuration. Anyone on the Internet has permission to upload!")
|
|
if !global.Configuration.Security.DisableEmptyMasterKeyWarning {
|
|
log.Println("Continuing in 5 seconds... (you can set Security.DisableEmptyMasterKeyWarning to true to disable this in the configuration)")
|
|
time.Sleep(time.Second * 5)
|
|
}
|
|
}
|
|
|
|
// Domain length + 1 byte for "/"
|
|
// ID length * 12 (%00%00%00%00)
|
|
// Extension length * 12
|
|
// 9 (?enc_key=) * 12
|
|
// Encryption key length * 12
|
|
constants.PathLengthLimitBytes =
|
|
(len(global.Configuration.Domain) + 1) +
|
|
(global.Configuration.Storage.IDLength * characterTagLengthEncoded) +
|
|
(constants.ExtensionLengthLimit * characterTagLengthEncoded) +
|
|
(9 * characterTagLengthEncoded) +
|
|
(global.Configuration.Encryption.EncryptionKeyLength * characterTagLengthEncoded)
|
|
log.Println("[init] Loaded configuration")
|
|
}
|
|
|
|
func initLogger() {
|
|
if !global.Configuration.Logging.Enabled {
|
|
return
|
|
}
|
|
file, err := os.OpenFile(global.Configuration.Logging.LogFile, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644)
|
|
if err != nil {
|
|
log.Fatalf("Failed to open log file! %v", err)
|
|
}
|
|
|
|
logger.InfoLogger = log.New(file, "info:", log.Ldate|log.Ltime|log.LUTC|log.Lshortfile)
|
|
logger.ErrorLogger = log.New(file, "error:", log.Ldate|log.Ltime|log.LUTC|log.Lshortfile)
|
|
|
|
log.Println("[init] Loggers initialized, output file: " + global.Configuration.Logging.LogFile)
|
|
}
|
|
|
|
func checkStorage() {
|
|
i, err := os.Stat(global.Configuration.Storage.Directory)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
log.Fatalf("The storage directory %s doesn't exist. Did you forget to create it?", global.Configuration.Storage.Directory)
|
|
} else {
|
|
log.Fatalf("Can't stat the files directory, %v", err)
|
|
}
|
|
}
|
|
if i != nil && !i.IsDir() {
|
|
log.Fatalf("Specified storage path (%s) is not a directory or not usable.", global.Configuration.Storage.Directory)
|
|
}
|
|
log.Println("[init] Storage directory is OK")
|
|
}
|
|
|
|
func initRedis() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
global.RedisClient = redis.NewClient(&redis.Options{
|
|
Addr: global.Configuration.Redis.URI,
|
|
Password: global.Configuration.Redis.Password,
|
|
DB: global.Configuration.Redis.DB,
|
|
})
|
|
|
|
status := global.RedisClient.Ping(ctx).Err()
|
|
if status != nil {
|
|
cancel()
|
|
log.Fatalf("Could not ping Redis database, %v", status.Error())
|
|
}
|
|
cancel()
|
|
|
|
log.Println("[init] Redis database connection established")
|
|
}
|