diff --git a/Dockerfile b/Dockerfile index 07cf33f..fa0572a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,16 +4,15 @@ LABEL author="vlbeaudoin" WORKDIR /go/src/app -COPY LICENSE cmd.go config.go db.go entity.go flag.go go.mod go.sum handler.go server.go x509.go ./ +COPY LICENSE cmd.go config.go db.go entity.go flag.go go.mod go.sum handler.go main.go server.go ./ -ADD cmd/ cmd/ ADD queries/ queries/ ADD ui/ ui/ RUN CGO_ENABLED=0 go build \ -a \ -o presences \ - ./cmd/presences/ + ./ # Alpine diff --git a/Makefile b/Makefile index 4553995..b6e4afc 100644 --- a/Makefile +++ b/Makefile @@ -4,40 +4,13 @@ .DEFAULT_GOAL := help -# splits current git annotated tag into 'MAJOR MINOR PATCH EXTRAS'. -# intended to be used as arguments for certain scripts requiring a semver as args -current_semver := $(shell git describe | tr -d 'v' | tr '.' ' ' | tr '-' ' ') - .PHONY: help help: ## Show this help - @grep -E -h '\s##\s' $(MAKEFILE_LIST) | \ + @egrep -h '\s##\s' $(MAKEFILE_LIST) | \ sort | \ awk \ 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' -.PHONY: go-install -go-install: ## Use `go install` to build and link the executable - go install -a ./cmd/presences/ - -.PHONY: docker-build -docker-build: ## Build container image - #docker-compose build \ - #--build-arg bottin_version=`git describe` - docker-compose build - -.PHONY: docker-deploy -docker-deploy: ## Using `docker-compose up`, deploy the database and containers - docker-compose up -d - -.PHONY: docker-tag-from-git -docker-tag-from-git: ## Tag latest image according to annotated tag from `git describe` - ./scripts/docker-tag.sh $(current_semver) - -.PHONY: docker-push-from-git -docker-push-from-git: ## Push images to git.agecem.com according to annotated tag from `git describe` - ./scripts/docker-push.sh $(current_semver) - -## pipelines - -.PHONY: deploy -deploy: docker-build docker-deploy ## Build and deploy container image +.PHONY: build +build: ## Use `docker build` to build the container image + docker build . -f Dockerfile -t git.agecem.com/bottin/presences:latest diff --git a/cmd.go b/cmd.go index 538d035..738a67b 100644 --- a/cmd.go +++ b/cmd.go @@ -1,15 +1,11 @@ -package presences +package main import ( "context" "encoding/json" "fmt" "log" - "net/http" - "codeberg.org/vlbeaudoin/voki/v3" - "git.agecem.com/bottin/bottin/v11" - "github.com/jackc/pgx/v5/pgxpool" "github.com/spf13/cobra" ) @@ -53,47 +49,3 @@ var rootCmd = &cobra.Command{ } }, } - -func run(ctx context.Context, cfg Config) error { - select { - case <-ctx.Done(): - return ctx.Err() - default: - bottinClient := bottin.APIClient{Caller: voki.New( - http.DefaultClient, - cfg.Bottin.Host, - cfg.Bottin.Key, - cfg.Bottin.Port, - func() string { - if cfg.Bottin.TLS.Enabled { - return "https" - } else { - return "http" - } - }(), - )} - - // connect to db - dbPool, err := pgxpool.New(ctx, - fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=%s", - cfg.DB.Username, - cfg.DB.Password, - cfg.DB.Host, - cfg.DB.Port, - cfg.DB.Database, - cfg.DB.SSLMode, - )) - if err != nil { - return err - } - defer dbPool.Close() - - dbClient := DBClient{Pool: dbPool} - - if err := RunUIServer(ctx, cfg, &bottinClient, &dbClient); err != nil && err != http.ErrServerClosed { - return err - } - - return nil - } -} diff --git a/cmd/presences/main.go b/cmd/presences/main.go deleted file mode 100644 index ae112db..0000000 --- a/cmd/presences/main.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "git.agecem.com/bottin/presences" -) - -// Entry -func main() { - // Start commandline parsing then call `run` - presences.Execute() -} diff --git a/compose.yaml b/compose.yaml index b6de464..47ed675 100644 --- a/compose.yaml +++ b/compose.yaml @@ -39,7 +39,7 @@ services: volumes: - 'presences-config:/etc/presences/' restart: 'unless-stopped' - command: ['presences', '--config', '/etc/presences/config.yaml'] + command: ['presences', '--config', '/etc/presences/config.yaml', 'server'] adminer: depends_on: diff --git a/config.go b/config.go index 4ce0ba5..b630b5f 100644 --- a/config.go +++ b/config.go @@ -1,11 +1,11 @@ -package presences +package main import ( "fmt" "os" "strings" - "git.agecem.com/bottin/bottin/v11" + "git.agecem.com/bottin/bottin/v10/pkg/bottin" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -33,12 +33,13 @@ type Config struct { Key string } - UI struct { - //Username string - //Password string + // Credentials holds username-password pairs for basic authentication + // not part of minimum viable product + //Credentials map[string]string - // Credentials holds username-password pairs for basic authentication - Credentials map[string]string + UI struct { + Username string + Password string } // Port holds the port on which to expose the user interface diff --git a/db.go b/db.go index 2d6447e..a24994f 100644 --- a/db.go +++ b/db.go @@ -1,4 +1,4 @@ -package presences +package main import ( "context" diff --git a/entity.go b/entity.go index d7ca315..cb4e53e 100644 --- a/entity.go +++ b/entity.go @@ -1,4 +1,4 @@ -package presences +package main import "time" diff --git a/flag.go b/flag.go index 014b0c6..64e7d0f 100644 --- a/flag.go +++ b/flag.go @@ -1,4 +1,4 @@ -package presences +package main import ( "github.com/spf13/pflag" @@ -6,106 +6,37 @@ import ( ) const ( - flagPortConfig = "Port" - flagPortDefault = 8080 - flagPort = "port" + configPort = "Port" + defaultPort = 8080 + flagPort = "port" - flagTLSCertConfig = "TLS.Cert" - flagTLSCertDefault = "" - flagTLSCert = "tls-cert" + configTLSCert = "TLS.Cert" + defaultTLSCert = "" + flagTLSCert = "tls-cert" - flagTLSKeyConfig = "TLS.Key" - flagTLSKeyDefault = "" - flagTLSKey = "tls-key" - - flagDBDatabaseConfig = "DB.Database" - flagDBDatabaseDefault = "presences" - flagDBDatabase = "db-database" - - flagDBHostConfig = "DB.Host" - flagDBHostDefault = "presences-db" - flagDBHost = "db-host" - - flagDBPasswordConfig = "DB.Password" - flagDBPasswordDefault = "presences" - flagDBPassword = "db-password" - - flagDBPortConfig = "DB.Port" - flagDBPortDefault = 5432 - flagDBPort = "db-port" - - flagDBSSLModeConfig = "DB.SSLMode" - flagDBSSLModeDefault = "prefer" - flagDBSSLMode = "db-sslmode" - - flagDBUsernameConfig = "DB.Username" - flagDBUsernameDefault = "presences" - flagDBUsername = "db-username" - - /* - flagUICredentialsConfig = "UI.Credentials" - //flagUICredentialsDefault = make(map[string]string) - flagUICredentials = "ui-credentials" - */ - - //TODO check if any necessary flags are missing + configTLSKey = "TLS.Key" + defaultTLSKey = "" + flagTLSKey = "tls-key" ) // BindClientFlags declares client-related flags and config options in the specified *pflag.FlagSet func BindFlags(set *pflag.FlagSet) error { // Credentials -> seulement par config - set.Int(flagPort, flagPortDefault, "User interface port") - if err := viper.BindPFlag(flagPortConfig, set.Lookup(flagPort)); err != nil { + set.Int(flagPort, defaultPort, "User interface port") + if err := viper.BindPFlag(configPort, set.Lookup(flagPort)); err != nil { return err } - set.String(flagTLSKey, flagTLSKeyDefault, "User interface TLS private key (or path to file)") - if err := viper.BindPFlag(flagTLSKeyConfig, set.Lookup(flagTLSKey)); err != nil { + set.String(flagTLSKey, defaultTLSKey, "User interface TLS private key (or path to file)") + if err := viper.BindPFlag(configTLSKey, set.Lookup(flagTLSKey)); err != nil { return err } - set.String(flagTLSCert, flagTLSCertDefault, "User interface TLS certificate (or path to file)") - if err := viper.BindPFlag(flagTLSCertConfig, set.Lookup(flagTLSCert)); err != nil { + set.String(flagTLSCert, defaultTLSCert, "User interface TLS certificate (or path to file)") + if err := viper.BindPFlag(configTLSCert, set.Lookup(flagTLSCert)); err != nil { return err } - set.String(flagDBDatabase, flagDBDatabaseDefault, "PostgreSQL database") - if err := viper.BindPFlag(flagDBDatabaseConfig, set.Lookup(flagDBDatabase)); err != nil { - return err - } - - set.String(flagDBHost, flagDBHostDefault, "PostgreSQL host") - if err := viper.BindPFlag(flagDBHostConfig, set.Lookup(flagDBHost)); err != nil { - return err - } - - set.String(flagDBPassword, flagDBPasswordDefault, "PostgreSQL password") - if err := viper.BindPFlag(flagDBPasswordConfig, set.Lookup(flagDBPassword)); err != nil { - return err - } - - set.Int(flagDBPort, flagDBPortDefault, "PostgreSQL port") - if err := viper.BindPFlag(flagDBPortConfig, set.Lookup(flagDBPort)); err != nil { - return err - } - - set.String(flagDBSSLMode, flagDBSSLModeDefault, "PostgreSQL ssl mode") - if err := viper.BindPFlag(flagDBSSLModeConfig, set.Lookup(flagDBSSLMode)); err != nil { - return err - } - - set.String(flagDBUsername, flagDBUsernameDefault, "PostgreSQL username") - if err := viper.BindPFlag(flagDBUsernameConfig, set.Lookup(flagDBUsername)); err != nil { - return err - } - - /* - set.StringToString(flagUICredentials, nil, "Sets of credentials for the UI console") - if err := viper.BindPFlag(flagUICredentialsConfig, set.Lookup(flagUICredentials)); err != nil { - return err - } - */ - return nil } diff --git a/go.mod b/go.mod index 0f81fd1..14144f2 100644 --- a/go.mod +++ b/go.mod @@ -4,39 +4,44 @@ go 1.23.6 require ( codeberg.org/vlbeaudoin/voki/v3 v3.0.1 - git.agecem.com/bottin/bottin/v11 v11.0.2 - github.com/jackc/pgx/v5 v5.7.4 + git.agecem.com/bottin/bottin/v10 v10.6.0 + github.com/jackc/pgx/v5 v5.7.2 github.com/labstack/echo/v4 v4.13.3 github.com/spf13/cobra v1.9.1 github.com/spf13/pflag v1.0.6 - github.com/spf13/viper v1.20.1 + github.com/spf13/viper v1.19.0 ) require ( - github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/labstack/gommon v0.4.2 // indirect + github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect - github.com/sagikazarmark/locafero v0.9.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/sagikazarmark/locafero v0.7.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.14.0 // indirect - github.com/spf13/cast v1.8.0 // indirect + github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/cast v1.7.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.38.0 // indirect - golang.org/x/net v0.40.0 // indirect - golang.org/x/sync v0.14.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.25.0 // indirect - golang.org/x/time v0.11.0 // indirect + golang.org/x/crypto v0.35.0 // indirect + golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect + golang.org/x/time v0.10.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 054eaae..c20a8c0 100644 --- a/go.sum +++ b/go.sum @@ -1,29 +1,30 @@ codeberg.org/vlbeaudoin/voki/v3 v3.0.1 h1:pFjd/ZKsu4eOzRJYViE9F1S3RglSkAuIiqCo9IH9tUI= codeberg.org/vlbeaudoin/voki/v3 v3.0.1/go.mod h1:+6LMXosAu2ijNKV04sMwkeujpH+cghZU1fydqj2y95g= -git.agecem.com/bottin/bottin/v11 v11.0.2 h1:QtbjTDln3jcd4Vkc66uil+YoLisOPaDy2SerZQ95weo= -git.agecem.com/bottin/bottin/v11 v11.0.2/go.mod h1:c0sV8VOTLtnwel3oCo8xyBTW9zdmrVRwiGEF5NyYjjY= +git.agecem.com/bottin/bottin/v10 v10.6.0 h1:I9xQMizlqfWHrJ1ZL2PlX/EeTpRm+B7bsheaBOVChFM= +git.agecem.com/bottin/bottin/v10 v10.6.0/go.mod h1:KTwlqY5XdVi9F7cpwy3hxYN1DQm+74tBv7Wc9rfKXuM= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= -github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 h1:FWNFq4fM1wPfcK40yHE5UO3RUdSNPaBC+j3PokzA6OQ= github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg= -github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= +github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= +github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -34,31 +35,38 @@ github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaa github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= +github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= -github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= -github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= -github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= -github.com/spf13/cast v1.8.0 h1:gEN9K4b8Xws4EX0+a0reLmhq8moKn7ntRlQYgjPeCDk= -github.com/spf13/cast v1.8.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= -github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -72,22 +80,26 @@ github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQ github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= +golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4= +golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= -golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= -golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= +golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/handler.go b/handler.go index 53127e8..369ec02 100644 --- a/handler.go +++ b/handler.go @@ -1,4 +1,4 @@ -package presences +package main import ( "context" @@ -6,7 +6,7 @@ import ( "log" "net/http" - "git.agecem.com/bottin/bottin/v11" + "git.agecem.com/bottin/bottin/v10/pkg/bottin" "github.com/labstack/echo/v4" ) diff --git a/main.go b/main.go new file mode 100644 index 0000000..de0d965 --- /dev/null +++ b/main.go @@ -0,0 +1,61 @@ +package main + +import ( + "context" + "fmt" + "net/http" + + "codeberg.org/vlbeaudoin/voki/v3" + "git.agecem.com/bottin/bottin/v10/pkg/bottin" + "github.com/jackc/pgx/v5/pgxpool" +) + +// Entry +func main() { + // Start commandline parsing then call `run` + Execute() +} + +func run(ctx context.Context, cfg Config) error { + select { + case <-ctx.Done(): + return ctx.Err() + default: + bottinClient := bottin.APIClient{Caller: voki.New( + http.DefaultClient, + cfg.Bottin.Host, + cfg.Bottin.Key, + cfg.Bottin.Port, + func() string { + if cfg.Bottin.TLS.Enabled { + return "https" + } else { + return "http" + } + }(), + )} + + // connect to db + dbPool, err := pgxpool.New(ctx, + fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=%s", + cfg.DB.Username, + cfg.DB.Password, + cfg.DB.Host, + cfg.DB.Port, + cfg.DB.Database, + cfg.DB.SSLMode, + )) + if err != nil { + return err + } + defer dbPool.Close() + + dbClient := DBClient{Pool: dbPool} + + if err := RunUIServer(ctx, cfg, &bottinClient, &dbClient); err != nil && err != http.ErrServerClosed { + return err + } + + return nil + } +} diff --git a/server.go b/server.go index e583d80..3c8a182 100644 --- a/server.go +++ b/server.go @@ -1,14 +1,12 @@ -package presences +package main import ( "context" "crypto/subtle" - "crypto/tls" "fmt" - "log" "net/http" - "git.agecem.com/bottin/bottin/v11" + "git.agecem.com/bottin/bottin/v10/pkg/bottin" "git.agecem.com/bottin/presences/ui" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" @@ -43,19 +41,19 @@ func RunUIServer(ctx context.Context, cfg Config, bottinClient *bottin.APIClient e.Pre(middleware.AddTrailingSlash()) - if len(cfg.UI.Credentials) == 0 { - return fmt.Errorf("UI.Credentials config file option of type map[string]string must contain at least one username-password key-value pair. Note that there is no flag or ENV counterpart, this must be done through a config file.") + // basic auth + if cfg.UI.Username == "" || cfg.UI.Password == "" { + return fmt.Errorf("UI username and password cannot be empty, please set UI.Password and UI.Username (PRESENCES_UI_PASSWORD and PRESENCES_UI_USERNAME") } e.Pre(middleware.BasicAuth( func(username, password string, c echo.Context) (bool, error) { - rightPassword, userExists := cfg.UI.Credentials[username] - if !userExists { - return false, nil + userOK := subtle.ConstantTimeCompare([]byte(username), []byte(cfg.UI.Username)) == 1 + passOK := subtle.ConstantTimeCompare([]byte(password), []byte(cfg.UI.Password)) == 1 + if userOK && passOK { + return true, nil } - - passwordOK := subtle.ConstantTimeCompare([]byte(password), []byte(rightPassword)) == 1 - return passwordOK, nil + return false, nil }), ) @@ -71,30 +69,7 @@ func RunUIServer(ctx context.Context, cfg Config, bottinClient *bottin.APIClient address := fmt.Sprintf(":%d", cfg.Port) - switch { - case cfg.TLS.Cert != "" && cfg.TLS.Key != "": - return e.StartTLS(address, cfg.TLS.Cert, cfg.TLS.Key) - case cfg.TLS.Cert != "" && cfg.TLS.Key == "": - return fmt.Errorf("found TLS certificate but missing associated TLS private key") - case cfg.TLS.Cert == "" && cfg.TLS.Key != "": - return fmt.Errorf("found TLS private key but missing associated TLS certificate") - default: - log.Println("No TLS pair was provided. Generating self-signed pair.") - - tlsPair, err := newTLSPair() - if err != nil { - return err - } - - server := &http.Server{ - Addr: address, - Handler: e, - TLSConfig: &tls.Config{ - Certificates: []tls.Certificate{tlsPair}, - }, - } - - return server.ListenAndServeTLS("", "") - } + return e.StartTLS(address, cfg.TLS.Cert, cfg.TLS.Key) } + } diff --git a/x509.go b/x509.go deleted file mode 100644 index 434c720..0000000 --- a/x509.go +++ /dev/null @@ -1,74 +0,0 @@ -package presences - -import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/tls" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "fmt" - "math/big" - "time" -) - -func newTLSPair() (tls.Certificate, error) { - //TODO revise this code to make sure it is satisfying - - // Generate an ECDSA private key using P256. - priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - return tls.Certificate{}, fmt.Errorf("Failed to generate private key: %v", err) - } - - // Generate a random serial number. - serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) - if err != nil { - return tls.Certificate{}, fmt.Errorf("Failed to generate serial number: %v", err) - } - - // Create a certificate template. - template := x509.Certificate{ - SerialNumber: serialNumber, - Subject: pkix.Name{ - Organization: []string{"AGECEM-bottin-presences"}, - CommonName: "localhost", // common name localhost for local development - }, - NotBefore: time.Now().Add(-time.Hour), // valid from 1 hour ago - NotAfter: time.Now().Add(365 * 24 * time.Hour), // valid for 1 year - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - IsCA: true, // self-signed, so we can mark it as CA (optional) - } - - // Self-sign the certificate. - derCert, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) - if err != nil { - return tls.Certificate{}, fmt.Errorf("Failed to create certificate: %v", err) - } - - // Encode the certificate PEM block. - certPEM := pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: derCert, - }) - // Encode the private key PEM block. - keyBytes, err := x509.MarshalECPrivateKey(priv) - if err != nil { - return tls.Certificate{}, fmt.Errorf("Unable to marshal ECDSA private key: %v", err) - } - keyPEM := pem.EncodeToMemory(&pem.Block{ - Type: "EC PRIVATE KEY", - Bytes: keyBytes, - }) - - // Load the generated certificate into a tls.Certificate. - tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) - if err != nil { - return tls.Certificate{}, fmt.Errorf("failed to load X509 key pair: %v", err) - } - - return tlsCert, nil -}