Skip to content
Merged
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
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"
Comment thread
jmattheis marked this conversation as resolved.
"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
91 changes: 83 additions & 8 deletions app.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package main

import (
"errors"
"flag"
"fmt"
"io"
"os"
"runtime/debug"
"time"

"github.com/gotify/server/v2/config"
"github.com/gotify/server/v2/config/migrate"
"github.com/gotify/server/v2/database"
"github.com/gotify/server/v2/mode"
"github.com/gotify/server/v2/model"
Expand All @@ -27,26 +33,83 @@ var (
)

func main() {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339, NoColor: noColor()})
os.Exit(run(os.Args[1:], os.Stdout, os.Stderr))
}

func run(args []string, stdout, stderr io.Writer) int {
vInfo := &model.VersionInfo{Version: Version, Commit: Commit, BuildDate: BuildDate}
fs := flag.NewFlagSet("gotify", flag.ContinueOnError)
fs.SetOutput(stderr)
fs.Usage = func() { printUsage(stderr) }
if err := fs.Parse(args); err != nil {
if errors.Is(err, flag.ErrHelp) {
return 0
}
return 2
}

command := fs.Arg(0)
switch command {
case "serve", "":
return serve(vInfo)
case "version":
fmt.Fprintln(stdout, "Version:", vInfo.Version)
fmt.Fprintln(stdout, "Commit:", vInfo.Commit)
fmt.Fprintln(stdout, "Build Date:", vInfo.BuildDate)
fmt.Fprintln(stdout, "Go Build Info:")
b, ok := debug.ReadBuildInfo()
if ok {
fmt.Fprintln(stdout, b)
}
return 0
case "migrate-config":
content, err := migrate.Config(fs.Arg(1))
if err != nil {
fmt.Fprintln(stderr, err)
return 1
}
fmt.Fprintln(stdout, content)
return 0
default:
if command != "" {
fmt.Fprintf(stderr, "gotify: unknown command %q\n\n", command)
}
printUsage(stderr)
return 2
}
}

func serve(vInfo *model.VersionInfo) int {
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 {
return 1
}

if conf.PluginsDir != "" {
if err := os.MkdirAll(conf.PluginsDir, 0o755); err != nil {
panic(err)
log.Error().Err(err).Str("dir", conf.PluginsDir).Msg("Cannot create plugins directory")
return 1
}
}
if err := os.MkdirAll(conf.UploadedImagesDir, 0o755); err != nil {
panic(err)
log.Error().Err(err).Str("dir", conf.UploadedImagesDir).Msg("Cannot create uploaded images directory")
return 1
}

db, err := database.New(conf.Database.Dialect, conf.Database.Connection, conf.DefaultUser.Name, conf.DefaultUser.Pass, conf.PassStrength, true, time.Now)
if err != nil {
panic(err)
log.Error().Err(err).Msg("Cannot initialize database")
return 1
}
defer db.Close()

Expand All @@ -55,13 +118,25 @@ func main() {

if err := runner.Run(engine, conf); err != nil {
log.Error().Err(err).Msg("Server error")
os.Exit(1)
return 1
}
return 0
}

func printUsage(w io.Writer) {
fmt.Fprint(w, `Usage: gotify [flags] <command> [arguments]

Commands:
serve Start the Gotify server.
migrate-config <file.yml> Convert an old YAML config file to the new env
format and print it to stdout.
version Show version information
`)
}

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
31 changes: 31 additions & 0 deletions app_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"
)

func TestRun(t *testing.T) {
cases := []struct {
name string
args []string
wantCode int
stdout string // substring expected on stdout
stderr string // substring expected on stderr
}{
{"version", []string{"version"}, 0, "Version: ", ""},
{"unknown command", []string{"bogus"}, 2, "", "unknown command"},
{"unknown flag", []string{"--nope"}, 2, "", "not defined"},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
var stdout, stderr bytes.Buffer
code := run(c.args, &stdout, &stderr)
assert.Equal(t, c.wantCode, code)
assert.Contains(t, stdout.String(), c.stdout)
assert.Contains(t, stderr.String(), c.stderr)
})
}
}
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