2020-09-29 19:55:07 +03:00
package config
2019-05-05 23:36:49 +03:00
2020-05-24 18:32:26 +03:00
import (
"encoding/json"
2020-11-01 22:14:10 +03:00
"fmt"
2021-04-11 13:42:43 +03:00
"net/http"
2023-04-03 15:40:57 +03:00
"os"
2022-07-09 06:58:16 +03:00
"regexp"
2022-11-20 00:21:51 +03:00
"strconv"
2021-04-11 13:42:43 +03:00
"strings"
2021-04-30 15:07:14 +03:00
"time"
2021-04-11 13:42:43 +03:00
2021-01-30 13:17:37 +03:00
"github.com/emvi/logbuch"
2020-05-24 18:32:26 +03:00
"github.com/gorilla/securecookie"
2020-10-04 11:37:38 +03:00
"github.com/jinzhu/configor"
2021-04-11 13:42:43 +03:00
"github.com/muety/wakapi/data"
2022-12-29 19:12:34 +03:00
"github.com/muety/wakapi/utils"
2023-04-03 15:40:57 +03:00
"github.com/robfig/cron/v3"
2022-07-09 06:58:16 +03:00
uuid "github.com/satori/go.uuid"
2020-05-24 18:32:26 +03:00
)
2020-10-04 12:14:44 +03:00
const (
2023-04-03 15:40:57 +03:00
DefaultConfigPath = "config.yml"
2020-11-06 19:20:26 +03:00
SQLDialectMysql = "mysql"
SQLDialectPostgres = "postgres"
SQLDialectSqlite = "sqlite3"
2021-01-17 11:24:09 +03:00
2022-12-29 19:12:34 +03:00
KeyLatestTotalTime = "latest_total_time"
KeyLatestTotalUsers = "latest_total_users"
KeyLastImportImport = "last_import"
KeyFirstHeartbeat = "first_heartbeat"
KeySubscriptionNotificationSent = "sub_reminder"
KeyNewsbox = "newsbox"
2021-02-12 21:25:59 +03:00
2023-01-02 20:05:28 +03:00
SessionKeyDefault = "default"
2021-02-12 21:25:59 +03:00
SimpleDateFormat = "2006-01-02"
SimpleDateTimeFormat = "2006-01-02 15:04:05"
2021-02-13 13:23:58 +03:00
ErrUnauthorized = "401 unauthorized"
2021-08-07 11:16:50 +03:00
ErrBadRequest = "400 bad request"
2021-02-13 01:06:48 +03:00
ErrInternalServerError = "500 internal server error"
2020-10-04 12:14:44 +03:00
)
2021-01-30 12:54:54 +03:00
const (
2021-02-05 20:47:28 +03:00
WakatimeApiUrl = "https://wakatime.com/api/v1"
WakatimeApiUserUrl = "/users/current"
WakatimeApiAllTimeUrl = "/users/current/all_time_since_today"
WakatimeApiHeartbeatsUrl = "/users/current/heartbeats"
WakatimeApiHeartbeatsBulkUrl = "/users/current/heartbeats.bulk"
WakatimeApiUserAgentsUrl = "/users/current/user_agents"
2021-02-11 00:08:00 +03:00
WakatimeApiMachineNamesUrl = "/users/current/machine_names"
2021-01-30 12:54:54 +03:00
)
2021-04-05 23:57:57 +03:00
const (
2021-04-10 01:07:13 +03:00
MailProviderSmtp = "smtp"
2021-04-05 23:57:57 +03:00
MailProviderMailWhale = "mailwhale"
)
var emailProviders = [ ] string {
2021-04-10 01:07:13 +03:00
MailProviderSmtp ,
2021-04-05 23:57:57 +03:00
MailProviderMailWhale ,
}
2021-04-05 17:25:13 +03:00
2020-11-08 12:12:49 +03:00
var cfg * Config
2021-04-16 13:24:19 +03:00
var env string
2020-05-24 14:41:19 +03:00
2020-10-04 12:14:44 +03:00
type appConfig struct {
2022-12-01 22:26:03 +03:00
AggregationTime string ` yaml:"aggregation_time" default:"0 15 2 * * *" env:"WAKAPI_AGGREGATION_TIME" `
LeaderboardGenerationTime string ` yaml:"leaderboard_generation_time" default:"0 0 6 * * *,0 0 18 * * *" env:"WAKAPI_LEADERBOARD_GENERATION_TIME" `
ReportTimeWeekly string ` yaml:"report_time_weekly" default:"0 0 18 * * 5" env:"WAKAPI_REPORT_TIME_WEEKLY" `
2023-01-18 03:26:22 +03:00
DataCleanupTime string ` yaml:"data_cleanup_time" default:"0 0 6 * * 0" env:"WAKAPI_DATA_CLEANUP_TIME" `
2022-10-02 01:01:39 +03:00
ImportBackoffMin int ` yaml:"import_backoff_min" default:"5" env:"WAKAPI_IMPORT_BACKOFF_MIN" `
ImportBatchSize int ` yaml:"import_batch_size" default:"50" env:"WAKAPI_IMPORT_BATCH_SIZE" `
InactiveDays int ` yaml:"inactive_days" default:"7" env:"WAKAPI_INACTIVE_DAYS" `
HeartbeatMaxAge string ` yaml:"heartbeat_max_age" default:"4320h" env:"WAKAPI_HEARTBEAT_MAX_AGE" `
CountCacheTTLMin int ` yaml:"count_cache_ttl_min" default:"30" env:"WAKAPI_COUNT_CACHE_TTL_MIN" `
2022-12-01 22:26:03 +03:00
DataRetentionMonths int ` yaml:"data_retention_months" default:"-1" env:"WAKAPI_DATA_RETENTION_MONTHS" `
2023-01-18 11:26:01 +03:00
DataCleanupDryRun bool ` yaml:"data_cleanup_dry_run" default:"false" env:"WAKAPI_DATA_CLEANUP_DRY_RUN" ` // for debugging only
2022-10-02 01:01:39 +03:00
AvatarURLTemplate string ` yaml:"avatar_url_template" default:"api/avatar/ { username_hash}.svg" env:"WAKAPI_AVATAR_URL_TEMPLATE" `
2022-12-23 12:54:56 +03:00
SupportContact string ` yaml:"support_contact" default:"hostmaster@wakapi.dev" env:"WAKAPI_SUPPORT_CONTACT" `
2022-10-02 01:01:39 +03:00
CustomLanguages map [ string ] string ` yaml:"custom_languages" `
Colors map [ string ] map [ string ] string ` yaml:"-" `
2020-10-04 12:14:44 +03:00
}
type securityConfig struct {
2023-03-04 11:33:36 +03:00
AllowSignup bool ` yaml:"allow_signup" default:"true" env:"WAKAPI_ALLOW_SIGNUP" `
ExposeMetrics bool ` yaml:"expose_metrics" default:"false" env:"WAKAPI_EXPOSE_METRICS" `
EnableProxy bool ` yaml:"enable_proxy" default:"false" env:"WAKAPI_ENABLE_PROXY" ` // only intended for production instance at wakapi.dev
DisableFrontpage bool ` yaml:"disable_frontpage" default:"false" env:"WAKAPI_DISABLE_FRONTPAGE" `
2020-10-04 12:14:44 +03:00
// this is actually a pepper (https://en.wikipedia.org/wiki/Pepper_(cryptography))
PasswordSalt string ` yaml:"password_salt" default:"" env:"WAKAPI_PASSWORD_SALT" `
InsecureCookies bool ` yaml:"insecure_cookies" default:"false" env:"WAKAPI_INSECURE_COOKIES" `
2020-11-22 00:30:56 +03:00
CookieMaxAgeSec int ` yaml:"cookie_max_age" default:"172800" env:"WAKAPI_COOKIE_MAX_AGE" `
2020-10-04 12:14:44 +03:00
SecureCookie * securecookie . SecureCookie ` yaml:"-" `
2023-01-02 20:05:28 +03:00
SessionKey [ ] byte ` yaml:"-" `
2020-10-04 12:14:44 +03:00
}
type dbConfig struct {
2021-04-18 12:03:54 +03:00
Host string ` env:"WAKAPI_DB_HOST" `
2022-12-06 15:10:18 +03:00
Socket string ` env:"WAKAPI_DB_SOCKET" `
2021-04-18 12:03:54 +03:00
Port uint ` env:"WAKAPI_DB_PORT" `
User string ` env:"WAKAPI_DB_USER" `
Password string ` env:"WAKAPI_DB_PASSWORD" `
Name string ` default:"wakapi_db.db" env:"WAKAPI_DB_NAME" `
Dialect string ` yaml:"-" `
Charset string ` default:"utf8mb4" env:"WAKAPI_DB_CHARSET" `
Type string ` yaml:"dialect" default:"sqlite3" env:"WAKAPI_DB_TYPE" `
2022-10-31 20:07:16 +03:00
DSN string ` yaml:"DSN" default:"" env:"WAKAPI_DB_DSN" `
2021-04-18 12:03:54 +03:00
MaxConn uint ` yaml:"max_conn" default:"2" env:"WAKAPI_DB_MAX_CONNECTIONS" `
Ssl bool ` default:"false" env:"WAKAPI_DB_SSL" `
AutoMigrateFailSilently bool ` yaml:"automigrate_fail_silently" default:"false" env:"WAKAPI_DB_AUTOMIGRATE_FAIL_SILENTLY" `
2020-10-04 12:14:44 +03:00
}
type serverConfig struct {
2023-01-08 19:14:43 +03:00
Port int ` default:"3000" env:"WAKAPI_PORT" `
ListenIpV4 string ` yaml:"listen_ipv4" default:"127.0.0.1" env:"WAKAPI_LISTEN_IPV4" `
ListenIpV6 string ` yaml:"listen_ipv6" default:"::1" env:"WAKAPI_LISTEN_IPV6" `
ListenSocket string ` yaml:"listen_socket" default:"" env:"WAKAPI_LISTEN_SOCKET" `
ListenSocketMode uint32 ` yaml:"listen_socket_mode" default:"0666" env:"WAKAPI_LISTEN_SOCKET_MODE" `
TimeoutSec int ` yaml:"timeout_sec" default:"30" env:"WAKAPI_TIMEOUT_SEC" `
BasePath string ` yaml:"base_path" default:"/" env:"WAKAPI_BASE_PATH" `
PublicUrl string ` yaml:"public_url" default:"http://localhost:3000" env:"WAKAPI_PUBLIC_URL" `
TlsCertPath string ` yaml:"tls_cert_path" default:"" env:"WAKAPI_TLS_CERT_PATH" `
TlsKeyPath string ` yaml:"tls_key_path" default:"" env:"WAKAPI_TLS_KEY_PATH" `
2020-10-04 12:14:44 +03:00
}
2022-12-03 02:14:37 +03:00
type subscriptionsConfig struct {
2022-12-21 01:08:59 +03:00
Enabled bool ` yaml:"enabled" default:"false" env:"WAKAPI_SUBSCRIPTIONS_ENABLED" `
2022-12-29 19:12:34 +03:00
ExpiryNotifications bool ` yaml:"expiry_notifications" default:"true" env:"WAKAPI_SUBSCRIPTIONS_EXPIRY_NOTIFICATIONS" `
2022-12-21 01:08:59 +03:00
StripeApiKey string ` yaml:"stripe_api_key" env:"WAKAPI_SUBSCRIPTIONS_STRIPE_API_KEY" `
StripeSecretKey string ` yaml:"stripe_secret_key" env:"WAKAPI_SUBSCRIPTIONS_STRIPE_SECRET_KEY" `
StripeEndpointSecret string ` yaml:"stripe_endpoint_secret" env:"WAKAPI_SUBSCRIPTIONS_STRIPE_ENDPOINT_SECRET" `
StandardPriceId string ` yaml:"standard_price_id" env:"WAKAPI_SUBSCRIPTIONS_STANDARD_PRICE_ID" `
StandardPrice string ` yaml:"-" `
2022-12-03 02:14:37 +03:00
}
2021-03-24 00:12:15 +03:00
type sentryConfig struct {
Dsn string ` env:"WAKAPI_SENTRY_DSN" `
EnableTracing bool ` yaml:"enable_tracing" env:"WAKAPI_SENTRY_TRACING" `
SampleRate float32 ` yaml:"sample_rate" default:"0.75" env:"WAKAPI_SENTRY_SAMPLE_RATE" `
SampleRateHeartbeats float32 ` yaml:"sample_rate_heartbeats" default:"0.1" env:"WAKAPI_SENTRY_SAMPLE_RATE_HEARTBEATS" `
}
2021-04-05 17:25:13 +03:00
type mailConfig struct {
2021-04-12 23:57:52 +03:00
Enabled bool ` env:"WAKAPI_MAIL_ENABLED" default:"true" `
Provider string ` env:"WAKAPI_MAIL_PROVIDER" default:"smtp" `
MailWhale MailwhaleMailConfig ` yaml:"mailwhale" `
Smtp SMTPMailConfig ` yaml:"smtp" `
2021-04-30 16:14:29 +03:00
Sender string ` env:"WAKAPI_MAIL_SENDER" yaml:"sender" `
2021-04-05 17:25:13 +03:00
}
type MailwhaleMailConfig struct {
Url string ` env:"WAKAPI_MAIL_MAILWHALE_URL" `
ClientId string ` yaml:"client_id" env:"WAKAPI_MAIL_MAILWHALE_CLIENT_ID" `
ClientSecret string ` yaml:"client_secret" env:"WAKAPI_MAIL_MAILWHALE_CLIENT_SECRET" `
}
2021-04-10 01:07:13 +03:00
type SMTPMailConfig struct {
Host string ` env:"WAKAPI_MAIL_SMTP_HOST" `
Port uint ` env:"WAKAPI_MAIL_SMTP_PORT" `
Username string ` env:"WAKAPI_MAIL_SMTP_USER" `
Password string ` env:"WAKAPI_MAIL_SMTP_PASS" `
TLS bool ` env:"WAKAPI_MAIL_SMTP_TLS" `
}
2019-05-05 23:36:49 +03:00
type Config struct {
2022-04-18 16:18:01 +03:00
Env string ` default:"dev" env:"ENVIRONMENT" `
Version string ` yaml:"-" `
QuickStart bool ` yaml:"quick_start" env:"WAKAPI_QUICK_START" `
SkipMigrations bool ` yaml:"skip_migrations" env:"WAKAPI_SKIP_MIGRATIONS" `
InstanceId string ` yaml:"-" ` // only temporary, changes between runs
App appConfig
Security securityConfig
Db dbConfig
Server serverConfig
2022-12-03 02:14:37 +03:00
Subscriptions subscriptionsConfig
2022-04-18 16:18:01 +03:00
Sentry sentryConfig
Mail mailConfig
2019-05-05 23:36:49 +03:00
}
2020-02-20 17:39:56 +03:00
2022-01-17 10:25:29 +03:00
func ( c * Config ) CreateCookie ( name , value string ) * http . Cookie {
return c . createCookie ( name , value , c . Server . BasePath , c . Security . CookieMaxAgeSec )
2020-11-22 00:30:56 +03:00
}
2022-01-17 10:25:29 +03:00
func ( c * Config ) GetClearCookie ( name string ) * http . Cookie {
return c . createCookie ( name , "" , c . Server . BasePath , - 1 )
2020-11-22 00:30:56 +03:00
}
func ( c * Config ) createCookie ( name , value , path string , maxAge int ) * http . Cookie {
return & http . Cookie {
Name : name ,
Value : value ,
Path : path ,
MaxAge : maxAge ,
Secure : ! c . Security . InsecureCookies ,
HttpOnly : true ,
2022-12-21 01:08:59 +03:00
SameSite : http . SameSiteLaxMode ,
2020-11-22 00:30:56 +03:00
}
}
2020-02-20 17:39:56 +03:00
func ( c * Config ) IsDev ( ) bool {
2020-05-30 13:11:21 +03:00
return IsDev ( c . Env )
}
2020-12-13 00:07:00 +03:00
func ( c * Config ) UseTLS ( ) bool {
return c . Server . TlsCertPath != "" && c . Server . TlsKeyPath != ""
}
2021-01-07 12:52:49 +03:00
func ( c * appConfig ) GetCustomLanguages ( ) map [ string ] string {
2022-12-01 12:57:07 +03:00
return utils . CloneStringMap ( c . CustomLanguages , false )
2021-01-07 12:52:49 +03:00
}
func ( c * appConfig ) GetLanguageColors ( ) map [ string ] string {
2022-12-01 12:57:07 +03:00
return utils . CloneStringMap ( c . Colors [ "languages" ] , true )
2021-01-30 11:51:36 +03:00
}
func ( c * appConfig ) GetEditorColors ( ) map [ string ] string {
2022-12-01 12:57:07 +03:00
return utils . CloneStringMap ( c . Colors [ "editors" ] , true )
2021-01-30 11:51:36 +03:00
}
func ( c * appConfig ) GetOSColors ( ) map [ string ] string {
2022-12-01 12:57:07 +03:00
return utils . CloneStringMap ( c . Colors [ "operating_systems" ] , true )
2021-01-07 12:52:49 +03:00
}
2022-11-20 00:21:51 +03:00
func ( c * appConfig ) GetAggregationTimeCron ( ) string {
if strings . Contains ( c . AggregationTime , ":" ) {
2022-11-20 12:11:23 +03:00
// old gocron format, e.g. "15:04"
2022-11-20 00:21:51 +03:00
timeParts := strings . Split ( c . AggregationTime , ":" )
h , err := strconv . Atoi ( timeParts [ 0 ] )
if err != nil {
logbuch . Fatal ( err . Error ( ) )
}
m , err := strconv . Atoi ( timeParts [ 1 ] )
if err != nil {
logbuch . Fatal ( err . Error ( ) )
}
return fmt . Sprintf ( "0 %d %d * * *" , m , h )
}
2022-12-01 12:57:07 +03:00
return utils . CronPadToSecondly ( c . AggregationTime )
2021-04-30 15:07:14 +03:00
}
2022-11-20 00:21:51 +03:00
func ( c * appConfig ) GetWeeklyReportCron ( ) string {
if strings . Contains ( c . ReportTimeWeekly , "," ) {
2022-11-20 12:11:23 +03:00
// old gocron format, e.g. "fri,18:00"
2022-11-20 00:21:51 +03:00
split := strings . Split ( c . ReportTimeWeekly , "," )
2022-12-01 12:57:07 +03:00
weekday := utils . ParseWeekday ( split [ 0 ] )
2022-11-20 00:21:51 +03:00
timeParts := strings . Split ( split [ 1 ] , ":" )
h , err := strconv . Atoi ( timeParts [ 0 ] )
if err != nil {
logbuch . Fatal ( err . Error ( ) )
}
m , err := strconv . Atoi ( timeParts [ 1 ] )
if err != nil {
logbuch . Fatal ( err . Error ( ) )
}
return fmt . Sprintf ( "0 %d %d * * %d" , m , h , weekday )
}
2022-12-01 12:57:07 +03:00
return utils . CronPadToSecondly ( c . ReportTimeWeekly )
2022-11-20 00:21:51 +03:00
}
func ( c * appConfig ) GetLeaderboardGenerationTimeCron ( ) [ ] string {
crons := [ ] string { }
var parse func ( string ) string
if strings . Contains ( c . LeaderboardGenerationTime , ":" ) {
2022-11-20 12:11:23 +03:00
// old gocron format, e.g. "15:04"
2022-11-20 00:21:51 +03:00
parse = func ( s string ) string {
timeParts := strings . Split ( s , ":" )
h , err := strconv . Atoi ( timeParts [ 0 ] )
if err != nil {
logbuch . Fatal ( err . Error ( ) )
}
m , err := strconv . Atoi ( timeParts [ 1 ] )
if err != nil {
logbuch . Fatal ( err . Error ( ) )
}
return fmt . Sprintf ( "0 %d %d * * *" , m , h )
}
} else {
parse = func ( s string ) string {
2022-12-01 12:57:07 +03:00
return utils . CronPadToSecondly ( s )
2022-11-20 00:21:51 +03:00
}
}
2022-12-01 12:57:07 +03:00
for _ , s := range utils . SplitMulti ( c . LeaderboardGenerationTime , "," , ";" ) {
2022-11-20 00:21:51 +03:00
crons = append ( crons , parse ( strings . TrimSpace ( s ) ) )
}
return crons
2021-04-30 15:07:14 +03:00
}
2022-03-17 13:35:20 +03:00
func ( c * appConfig ) HeartbeatsMaxAge ( ) time . Duration {
d , _ := time . ParseDuration ( c . HeartbeatMaxAge )
return d
}
2021-12-14 04:17:59 +03:00
func ( c * dbConfig ) IsSQLite ( ) bool {
return c . Dialect == "sqlite3"
}
2021-12-15 12:50:16 +03:00
func ( c * dbConfig ) IsMySQL ( ) bool {
return c . Dialect == "mysql"
}
func ( c * dbConfig ) IsPostgres ( ) bool {
return c . Dialect == "postgres"
}
2021-04-05 17:25:13 +03:00
func ( c * serverConfig ) GetPublicUrl ( ) string {
return strings . TrimSuffix ( c . PublicUrl , "/" )
}
2021-04-10 01:07:13 +03:00
func ( c * SMTPMailConfig ) ConnStr ( ) string {
return fmt . Sprintf ( "%s:%d" , c . Host , c . Port )
}
2020-05-30 13:11:21 +03:00
func IsDev ( env string ) bool {
return env == "dev" || env == "development"
2020-02-20 17:39:56 +03:00
}
2020-05-24 18:32:26 +03:00
2021-01-30 11:51:36 +03:00
func readColors ( ) map [ string ] map [ string ] string {
2020-05-24 18:32:26 +03:00
// Read language colors
2021-01-30 11:51:36 +03:00
// Source:
2022-02-17 14:20:22 +03:00
// - https://raw.githubusercontent.com/ozh/github-colors/master/colors.json
// - https://wakatime.com/colors/operating_systems
2021-01-30 11:51:36 +03:00
// - https://wakatime.com/colors/editors
// Extracted from Wakatime website with XPath (see below) and did a bit of regex magic after.
2022-02-17 14:20:22 +03:00
// - $x('//span[@class="editor-icon tip"]/@data-original-title').map(e => e.nodeValue)
// - $x('//span[@class="editor-icon tip"]/div[1]/text()').map(e => e.nodeValue)
2021-04-16 13:24:19 +03:00
raw := data . ColorsFile
if IsDev ( env ) {
2023-04-03 15:40:57 +03:00
raw , _ = os . ReadFile ( "data/colors.json" )
2021-04-16 13:24:19 +03:00
}
2021-01-30 11:51:36 +03:00
var colors = make ( map [ string ] map [ string ] string )
2021-04-16 13:24:19 +03:00
if err := json . Unmarshal ( raw , & colors ) ; err != nil {
2021-01-30 13:17:37 +03:00
logbuch . Fatal ( err . Error ( ) )
2020-05-24 18:32:26 +03:00
}
2020-10-04 11:37:38 +03:00
return colors
}
2021-01-18 23:34:08 +03:00
func resolveDbDialect ( dbType string ) string {
if dbType == "cockroach" {
return "postgres"
}
2021-12-15 12:50:16 +03:00
if dbType == "sqlite" {
return "sqlite3"
}
if dbType == "mariadb" {
return "mysql"
}
2021-01-18 23:34:08 +03:00
return dbType
}
2020-10-04 11:37:38 +03:00
func Set ( config * Config ) {
cfg = config
}
func Get ( ) * Config {
return cfg
}
2023-04-03 15:40:57 +03:00
func Load ( configFlag string , version string ) * Config {
2020-10-04 11:37:38 +03:00
config := & Config { }
2023-04-03 15:40:57 +03:00
if err := configor . New ( & configor . Config { } ) . Load ( config , configFlag ) ; err != nil {
2021-01-30 13:17:37 +03:00
logbuch . Fatal ( "failed to read config: %v" , err )
2020-10-04 11:37:38 +03:00
}
2021-04-16 13:24:19 +03:00
env = config . Env
2022-07-09 06:58:16 +03:00
2021-04-11 13:42:43 +03:00
config . Version = strings . TrimSpace ( version )
2022-07-09 06:58:16 +03:00
tagVersionMatch , _ := regexp . MatchString ( ` \d+\.\d+\.\d+ ` , version )
if tagVersionMatch {
config . Version = "v" + config . Version
}
2022-01-21 14:35:05 +03:00
config . InstanceId = uuid . NewV4 ( ) . String ( )
2021-01-30 11:51:36 +03:00
config . App . Colors = readColors ( )
2021-01-18 23:34:08 +03:00
config . Db . Dialect = resolveDbDialect ( config . Db . Type )
2023-03-03 23:44:13 +03:00
2023-03-04 00:05:36 +03:00
hashKey := securecookie . GenerateRandomKey ( 64 )
blockKey := securecookie . GenerateRandomKey ( 32 )
sessionKey := securecookie . GenerateRandomKey ( 32 )
2023-03-03 23:44:13 +03:00
if IsDev ( env ) {
logbuch . Warn ( "using temporary keys to sign and encrypt cookies in dev mode, make sure to set env to production for real-world use" )
hashKey , blockKey = getTemporarySecureKeys ( )
2023-03-04 00:05:36 +03:00
blockKey = hashKey
2023-03-03 23:44:13 +03:00
}
config . Security . SecureCookie = securecookie . New ( hashKey , blockKey )
2023-03-04 00:05:36 +03:00
config . Security . SessionKey = sessionKey
2020-05-24 18:32:26 +03:00
2023-04-03 15:40:57 +03:00
config . Server . BasePath = strings . TrimSuffix ( config . Server . BasePath , "/" )
2020-10-04 11:37:38 +03:00
for k , v := range config . App . CustomLanguages {
if v == "" {
config . App . CustomLanguages [ k ] = "unknown"
}
}
2020-09-29 19:55:07 +03:00
2021-05-04 22:04:11 +03:00
if config . Sentry . Dsn != "" {
logbuch . Info ( "enabling sentry integration" )
initSentry ( config . Sentry , config . IsDev ( ) )
}
2022-12-01 22:26:03 +03:00
if config . App . DataRetentionMonths <= 0 {
logbuch . Info ( "disabling data retention policy, keeping data forever" )
} else {
2022-12-29 19:12:34 +03:00
dataRetentionWarning := fmt . Sprintf ( "⚠️ data retention policy will cause user data older than %d months to be deleted" , config . App . DataRetentionMonths )
if config . Subscriptions . Enabled {
dataRetentionWarning += " (except for users with active subscriptions)"
}
logbuch . Warn ( dataRetentionWarning )
2022-12-01 22:26:03 +03:00
}
2021-05-04 22:04:11 +03:00
// some validation checks
2022-12-06 14:55:33 +03:00
if config . Server . ListenIpV4 == "-" && config . Server . ListenIpV6 == "-" && config . Server . ListenSocket == "" {
2021-06-23 18:22:51 +03:00
logbuch . Fatal ( "either of listen_ipv4 or listen_ipv6 or listen_socket must be set" )
2020-12-13 00:07:00 +03:00
}
2021-02-03 00:52:13 +03:00
if config . Db . MaxConn <= 0 {
logbuch . Fatal ( "you must allow at least one database connection" )
}
2021-12-14 04:17:59 +03:00
if config . Db . MaxConn > 1 && config . Db . IsSQLite ( ) {
logbuch . Warn ( "with sqlite, only a single connection is supported" ) // otherwise 'PRAGMA foreign_keys=ON' would somehow have to be set for every connection in the pool
config . Db . MaxConn = 1
}
2022-12-01 12:57:07 +03:00
if config . Mail . Provider != "" && utils . FindString ( config . Mail . Provider , emailProviders , "" ) == "" {
2021-04-05 17:25:13 +03:00
logbuch . Fatal ( "unknown mail provider '%s'" , config . Mail . Provider )
}
2022-03-17 13:35:20 +03:00
if _ , err := time . ParseDuration ( config . App . HeartbeatMaxAge ) ; err != nil {
logbuch . Fatal ( "invalid duration set for heartbeat_max_age" )
}
2021-04-05 17:25:13 +03:00
2022-11-20 00:21:51 +03:00
cronParser := cron . NewParser ( cron . Second | cron . Minute | cron . Hour | cron . Dom | cron . Month | cron . Dow | cron . Descriptor )
if _ , err := cronParser . Parse ( config . App . GetWeeklyReportCron ( ) ) ; err != nil {
logbuch . Fatal ( "invalid cron expression for report_time_weekly" )
}
if _ , err := cronParser . Parse ( config . App . GetAggregationTimeCron ( ) ) ; err != nil {
logbuch . Fatal ( "invalid cron expression for aggregation_time" )
}
for _ , c := range config . App . GetLeaderboardGenerationTimeCron ( ) {
if _ , err := cronParser . Parse ( c ) ; err != nil {
logbuch . Fatal ( "invalid cron expression for leaderboard_generation_time" )
}
}
// deprecation notices
if strings . Contains ( config . App . AggregationTime , ":" ) {
logbuch . Warn ( "you're using deprecated syntax for 'aggregation_time', please change it to a valid cron expression" )
}
if strings . Contains ( config . App . ReportTimeWeekly , ":" ) {
logbuch . Warn ( "you're using deprecated syntax for 'report_time_weekly', please change it to a valid cron expression" )
}
if strings . Contains ( config . App . LeaderboardGenerationTime , ":" ) {
logbuch . Warn ( "you're using deprecated syntax for 'leaderboard_generation_time', please change it to a semicolon-separated list if valid cron expressions" )
}
2020-10-04 11:37:38 +03:00
Set ( config )
2020-09-29 19:55:07 +03:00
return Get ( )
2020-05-24 18:32:26 +03:00
}