Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ coverage.txt
**/*-packr.go
config.yml
data/
images/
images/
/gotify-server.env.local
7 changes: 1 addition & 6 deletions api/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@ import (
)

func NewOIDC(conf *config.Configuration, db *database.GormDatabase, userChangeNotifier *UserChangeNotifier) *OIDCAPI {
scopes := conf.OIDC.Scopes
if len(scopes) == 0 {
scopes = []string{"openid", "profile", "email"}
}

cookieKey := make([]byte, 32)
if _, err := rand.Read(cookieKey); err != nil {
log.Fatal().Err(err).Msg("failed to generate OIDC cookie key")
Expand All @@ -46,7 +41,7 @@ func NewOIDC(conf *config.Configuration, db *database.GormDatabase, userChangeNo
conf.OIDC.ClientID,
conf.OIDC.ClientSecret,
conf.OIDC.RedirectURL,
scopes,
conf.OIDC.Scopes,
opts...,
)
if err != nil {
Expand Down
4 changes: 0 additions & 4 deletions api/stream/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/gin-gonic/gin"

@jmattheis jmattheis Jun 7, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review.

To be frank I'm not super sold on this .. could you clarify what is the problem we are solving by "standalone and understandable"?

I dislike having two different formats to configure gotify. E.g. the two sections in https://gotify.net/docs/config. Having a unified format with only env vars make the config section more compact. We recommend using env vars for container deployments, so I'd expect most users already use environment variables,

I also dislike the list format for environement variables of configor, there have been a couple of tickets about this, where people didn't use the [a,b] syntax for environment variables.

Edit: configor is unmaintained, with the last commit from 3 years ago.

That said, I'm perfectly fine with dropping the PR, I though right now would be a good time to do breaking changes. So you can see this as POC for a config format.

I don't think the old format is too bad, so if you're against or neutral towards this POC, I'd rather drop the PR and just implement _FILE in configor (though we'd have to fork it against then, we currently use the upstream version).

It looks like the library has a .Marshal function so I would say we should at least try to make an automated config migration utility to decrease the friction to users.

Yeah, we could, but I'm not sure if it's worth the effort, I'd guess most users only have 2-5 settings configured, so just starting fresh with the new example config may be better.

It looks like you basically unrolled the entire config parsing in config.go. Could we have achieved all the benefits you listed by adding special cases to help configor (AND achieved backwards compatibility with YAML syntax) anyways?

I dislike having two config formats, if there should be backwards compatibility then I'd rather discard this PR, as there isn't much benefit to support both formats. With a major version increase this should be the best time to make breaking changes.

The entire config discovery is done relative to the executable in a "python venv" style with only option to add one file to the front of the config list, which IMO strongly bias towards one kind of deployment, and moving the environment means the gotify executable has to move with the config file as well.

True, can be changed back to using the working directory. I thought we had a ticket about this, but this should be already fixed with the GOTIFY_CONFIG_FILE.

The switch to dotenv format from YAML would encourage users to run "lean" configs with only specific items overriden. This can lead to complex problems when they are running multiple configs on the same system.

I'm okay with only reading the first found config file, in this order, and then not reading other files.

Loaded from $GOTIFY_CONFIG_FILE
gotify-server.env (working directory)
$XDG_CONFIG_HOME/gotify/gotify-server.env
/etc/gotify/server.env

"github.com/gorilla/websocket"
"github.com/gotify/server/v2/auth"
"github.com/gotify/server/v2/mode"
"github.com/gotify/server/v2/model"
)

Expand Down Expand Up @@ -214,9 +213,6 @@ func newUpgrader(allowedWebSocketOrigins []string) *websocket.Upgrader {
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
if mode.IsDev() {
return true
}
return isAllowedOrigin(r, compiledAllowedOrigins)
},
}
Expand Down
18 changes: 13 additions & 5 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,21 @@ var (
)

func main() {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339, NoColor: noColor()})

vInfo := &model.VersionInfo{Version: Version, Commit: Commit, BuildDate: BuildDate}
mode.Set(Mode)

conf, futureLogs := config.Get()
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339, NoColor: noColor(conf.NoColor)}).Level(zerolog.Level(conf.LogLevel))
log.Info().Str("version", vInfo.Version).Str("build_date", BuildDate).Msg("Gotify")
conf := config.Get()

exit := false
for _, futureLog := range futureLogs {
log.WithLevel(futureLog.Level).Msg(futureLog.Msg)
exit = exit || futureLog.Level == zerolog.FatalLevel || futureLog.Level == zerolog.PanicLevel
}
if exit {
os.Exit(1)
}

if conf.PluginsDir != "" {
if err := os.MkdirAll(conf.PluginsDir, 0o755); err != nil {
Expand All @@ -59,9 +67,9 @@ func main() {
}
}

func noColor() bool {
func noColor(noColorEnv string) bool {
// https://no-color.org/
if os.Getenv("NO_COLOR") == "1" {
if noColorEnv == "1" {
return true
}

Expand Down
32 changes: 11 additions & 21 deletions auth/cors.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/gin-contrib/cors"
"github.com/gotify/server/v2/config"
"github.com/gotify/server/v2/mode"
)

// CorsConfig generates a config to use in gin cors middleware based on server configuration.
Expand All @@ -16,28 +15,19 @@ func CorsConfig(conf *config.Configuration) cors.Config {
MaxAge: 12 * time.Hour,
AllowBrowserExtensions: true,
}
if mode.IsDev() {
corsConf.AllowAllOrigins = true
corsConf.AllowMethods = []string{"GET", "POST", "DELETE", "OPTIONS", "PUT"}
corsConf.AllowHeaders = []string{
"X-Gotify-Key", "Authorization", "Content-Type", "Upgrade", "Origin",
"Connection", "Accept-Encoding", "Accept-Language", "Host",
}
} else {
compiledOrigins := compileAllowedCORSOrigins(conf.Server.Cors.AllowOrigins)
corsConf.AllowMethods = conf.Server.Cors.AllowMethods
corsConf.AllowHeaders = conf.Server.Cors.AllowHeaders
corsConf.AllowOriginFunc = func(origin string) bool {
for _, compiledOrigin := range compiledOrigins {
if compiledOrigin.MatchString(strings.ToLower(origin)) {
return true
}
compiledOrigins := compileAllowedCORSOrigins(conf.Server.Cors.AllowOrigins)
corsConf.AllowMethods = conf.Server.Cors.AllowMethods
corsConf.AllowHeaders = conf.Server.Cors.AllowHeaders
corsConf.AllowOriginFunc = func(origin string) bool {
for _, compiledOrigin := range compiledOrigins {
if compiledOrigin.MatchString(strings.ToLower(origin)) {
return true
}
return false
}
if allowedOrigin := headerIgnoreCase(conf, "access-control-allow-origin"); allowedOrigin != "" && len(compiledOrigins) == 0 {
corsConf.AllowOrigins = append(corsConf.AllowOrigins, allowedOrigin)
}
return false
}
if allowedOrigin := headerIgnoreCase(conf, "access-control-allow-origin"); allowedOrigin != "" && len(compiledOrigins) == 0 {
corsConf.AllowOrigins = append(corsConf.AllowOrigins, allowedOrigin)
}

return corsConf
Expand Down
21 changes: 0 additions & 21 deletions auth/cors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,24 +50,3 @@ func TestEmptyCorsConfigWithResponseHeaders(t *testing.T) {
AllowBrowserExtensions: true,
}, actual)
}

func TestDevCorsConfig(t *testing.T) {
mode.Set(mode.Dev)
serverConf := config.Configuration{}
serverConf.Server.Cors.AllowOrigins = []string{"http://test.com"}
serverConf.Server.Cors.AllowHeaders = []string{"content-type"}
serverConf.Server.Cors.AllowMethods = []string{"GET"}

actual := CorsConfig(&serverConf)

assert.Equal(t, cors.Config{
AllowHeaders: []string{
"X-Gotify-Key", "Authorization", "Content-Type", "Upgrade", "Origin",
"Connection", "Accept-Encoding", "Accept-Language", "Host",
},
AllowMethods: []string{"GET", "POST", "DELETE", "OPTIONS", "PUT"},
MaxAge: 12 * time.Hour,
AllowAllOrigins: true,
AllowBrowserExtensions: true,
}, actual)
}
68 changes: 0 additions & 68 deletions config.example.yml

This file was deleted.

Loading
Loading