From 45ac8041ea403523dfdc08115e5d2eecda2bd281 Mon Sep 17 00:00:00 2001 From: Vincent Boutour Date: Sat, 10 Apr 2021 11:46:21 +0200 Subject: [PATCH] feat: Removing sync.Map in favor of Redis storage Signed-off-by: Vincent Boutour --- README.md | 10 ++++ cmd/ketchup/api.go | 7 ++- go.mod | 1 + go.sum | 47 ++++++++++++++- infra/redis.yaml | 27 +++++++++ infra/web.yaml | 4 +- pkg/ketchup/ketchup.go | 18 ++---- pkg/ketchup/renderer.go | 12 +++- pkg/ketchup/signup.go | 22 +++++-- pkg/ketchup/token.go | 90 ---------------------------- pkg/ketchup/token_test.go | 122 -------------------------------------- pkg/token/token.go | 86 +++++++++++++++++++++++++++ 12 files changed, 207 insertions(+), 239 deletions(-) create mode 100644 infra/redis.yaml delete mode 100644 pkg/ketchup/token.go delete mode 100644 pkg/ketchup/token_test.go create mode 100644 pkg/token/token.go diff --git a/README.md b/README.md index efdfe561..cf3be0de 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,8 @@ Usage of ketchup: [owasp] Content-Security-Policy {KETCHUP_CSP} (default "default-src 'self'; base-uri 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'") -dbHost string [db] Host {KETCHUP_DB_HOST} + -dbMaxConn uint + [db] Max Open Connections {KETCHUP_DB_MAX_CONN} (default 5) -dbName string [db] Name {KETCHUP_DB_NAME} -dbPass string @@ -113,6 +115,8 @@ Usage of ketchup: [mailer] URL (https?:// or amqps?://) {KETCHUP_MAILER_URL} -notifierLoginID uint [notifier] Scheduler user ID {KETCHUP_NOTIFIER_LOGIN_ID} (default 1) + -notifierPushUrl string + [notifier] Pushgateway URL {KETCHUP_NOTIFIER_PUSH_URL} -okStatus int [http] Healthy HTTP Status code {KETCHUP_OK_STATUS} (default 204) -port uint @@ -149,6 +153,12 @@ Usage of ketchup: [server] Shutdown Timeout {KETCHUP_SHUTDOWN_TIMEOUT} (default "10s") -title string Application title {KETCHUP_TITLE} (default "Ketchup") + -tokenRedisAddress string + [token] Redis Address {KETCHUP_TOKEN_REDIS_ADDRESS} (default "localhost:6379") + -tokenRedisDatabase int + [token] Redis Database {KETCHUP_TOKEN_REDIS_DATABASE} + -tokenRedisPassword string + [token] Redis Password, if any {KETCHUP_TOKEN_REDIS_PASSWORD} -url string [alcotest] URL to check {KETCHUP_URL} -userAgent string diff --git a/cmd/ketchup/api.go b/cmd/ketchup/api.go index 914a1409..11932fd5 100644 --- a/cmd/ketchup/api.go +++ b/cmd/ketchup/api.go @@ -35,6 +35,7 @@ import ( ketchupStore "github.com/ViBiOh/ketchup/pkg/store/ketchup" repositoryStore "github.com/ViBiOh/ketchup/pkg/store/repository" userStore "github.com/ViBiOh/ketchup/pkg/store/user" + "github.com/ViBiOh/ketchup/pkg/token" mailer "github.com/ViBiOh/mailer/pkg/client" ) @@ -68,6 +69,7 @@ func main() { rendererConfig := renderer.Flags(fs, "", flags.NewOverride("Title", "Ketchup"), flags.NewOverride("PublicURL", "https://ketchup.vibioh.fr")) dbConfig := db.Flags(fs, "db") + tokenConfig := token.Flags(fs, "token") mailerConfig := mailer.Flags(fs, "mailer") githubConfig := github.Flags(fs, "github") notifierConfig := notifier.Flags(fs, "notifier") @@ -107,9 +109,11 @@ func main() { publicRendererApp, err := renderer.New(rendererConfig, content, ketchup.FuncMap) logger.Fatal(err) + tokenApp := token.New(tokenConfig) + notifierApp := notifier.New(notifierConfig, repositoryServiceApp, ketchupServiceApp, mailerApp) schedulerApp := scheduler.New(schedulerConfig, notifierApp) - ketchupApp := ketchup.New(publicRendererApp, ketchupServiceApp, userServiceApp, repositoryServiceApp) + ketchupApp := ketchup.New(publicRendererApp, ketchupServiceApp, userServiceApp, repositoryServiceApp, tokenApp) publicHandler := publicRendererApp.Handler(ketchupApp.PublicTemplateFunc) signupHandler := http.StripPrefix(signupPath, ketchupApp.Signup()) @@ -129,7 +133,6 @@ func main() { publicHandler.ServeHTTP(w, r) }) - go ketchupApp.Start(healthApp.Done()) go githubApp.Start(prometheusApp.Registerer(), healthApp.Done()) if schedulerApp != nil { go schedulerApp.Start(healthApp.Done()) diff --git a/go.mod b/go.mod index be807957..8d1cf2ba 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/ViBiOh/auth/v2 v2.6.12 github.com/ViBiOh/httputils/v4 v4.5.1 github.com/ViBiOh/mailer v1.16.5 + github.com/go-redis/redis/v8 v8.8.0 github.com/lib/pq v1.10.0 github.com/prometheus/client_golang v1.10.0 gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum index 42f792e7..afa7d29b 100644 --- a/go.sum +++ b/go.sum @@ -49,8 +49,11 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= @@ -64,6 +67,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -72,6 +76,8 @@ github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgO github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-redis/redis/v8 v8.8.0 h1:fDZP58UN/1RD3DjtTXP/fFZ04TFohSYhjZDkcDe2dnw= +github.com/go-redis/redis/v8 v8.8.0/go.mod h1:F7resOH5Kdug49Otu24RjHWwgK7u9AmtqWMnCV1iP5Y= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -100,8 +106,9 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -190,12 +197,21 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4= +github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= +github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -215,6 +231,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -272,6 +289,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tdewolff/minify/v2 v2.9.15 h1:gZzGuFHvmxDjsAM6Eu53xo8A5NiaVu3gzamvHAxDpAI= github.com/tdewolff/minify/v2 v2.9.15/go.mod h1:tK4qPnHUZgANtEGVMwTBxrF1eNIBkigHFYo7F3Y98GQ= github.com/tdewolff/parse/v2 v2.5.14 h1:ftdD54vkOeLZ7VkEZxp+wZrYZyyPi43GGon5GwBTRUI= @@ -282,11 +301,20 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/otel v0.19.0 h1:Lenfy7QHRXPZVsw/12CWpxX6d/JkrX8wrx2vO8G80Ng= +go.opentelemetry.io/otel v0.19.0/go.mod h1:j9bF567N9EfomkSidSfmMwIwIBuP37AMAIzVW85OxSg= +go.opentelemetry.io/otel/metric v0.19.0 h1:dtZ1Ju44gkJkYvo+3qGqVXmf88tc+a42edOywypengg= +go.opentelemetry.io/otel/metric v0.19.0/go.mod h1:8f9fglJPRnXuskQmKpnad31lcLJ2VmNNqIsx/uIwBSc= +go.opentelemetry.io/otel/oteltest v0.19.0 h1:YVfA0ByROYqTwOxqHVZYZExzEpfZor+MU1rU+ip2v9Q= +go.opentelemetry.io/otel/oteltest v0.19.0/go.mod h1:tI4yxwh8U21v7JD6R3BcA/2+RBoTKFexE/PJ/nSO7IA= +go.opentelemetry.io/otel/trace v0.19.0 h1:1ucYlenXIDA1OlHVLDZKX0ObXV5RLaq06DtUKz5e5zc= +go.opentelemetry.io/otel/trace v0.19.0/go.mod h1:4IXiNextNOpPnRlI4ryK69mn5iC84bjBWZQA5DXz/qg= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= @@ -310,6 +338,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -326,7 +355,11 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -335,6 +368,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -350,20 +384,26 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -378,7 +418,9 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -419,6 +461,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -429,6 +472,8 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/infra/redis.yaml b/infra/redis.yaml new file mode 100644 index 00000000..673ac9ca --- /dev/null +++ b/infra/redis.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: helm.toolkit.fluxcd.io/v2beta1 +kind: HelmRelease +metadata: + name: ketchup-redis + namespace: default +spec: + interval: 120m + chart: + spec: + chart: redis + version: "0.0.7" + sourceRef: + kind: HelmRepository + name: vibioh + interval: 120m + install: + skipCRDs: true + maxHistory: 3 + upgrade: + remediation: + retries: 3 + rollback: + cleanupOnFail: true + values: + secrets: + redis.conf: AgCVnuDaxpyIWj5uWNLgoCgEErfurpFGRw8PcA+R7YogmXu7Nb0pzFAr8p3+PeaSY/CK4CImVIU05AWyX0WMQashA3wHsP+6hfSzIvYOWWQOmXHctw0tam4eVtHKWju3JCCJMIsQTllmNDD7obGks2bGBEQaVZk5KPja5A0uj819XphitKiqSIVcTazeu8Fc2WhNR1AVhXjys3SAL3qdxTtEKYQUCHHrdJFXMu4q1zzQTTBOVVurVOBOWT1fhWDSkPIigcq3SaTs0bPpdgzzygCUmcWI6HHCPRi8Kpmp5JJNiFc0eV60wlWC3TCSqcYpX6ziwJa3OB6Nr9wAMP+1y/6epe79sQ4/KtJCAVxP3j6CjOVIBH8+Jkuff/e0iAy6JrF8yHAtY917zmFQHZ28aWqNREgsmCtb+q45wKWprmyZGAsMBMh48dFUp+Ib66isAhZ45V+q+73zS9NLtyc8nhYfPmRG2zGpJGLlrLjhRw/d+0VjI2Xc76O3d5vfVnjxHq90PG+cLOhdRzNXJeuz5V1W94CkrF6VHjiNkQdxNUbHdKS3+IK/Tb8QmnQBnmDRcr/bl0RwJmn/X3Pn3GSkyF2wGWJ630a2fu0uIqxsO1SkIjcGV+GKeV5C3cnqR9QOcgYNcyADkw7LFpic00xbTRb3K4h/yBWFMw21vbVm4c7GURGkUhXmHWx13UO+GKxC4scOVGFbQMpjHQpEGrgRIRxWbRXdQZTb5AlJnWWPNV+KAQiXSoqE2RdRSRtAjTGOg3hHUyaHukZ87joJr+cwgCwR7eedGvBMpN4rr2I= diff --git a/infra/web.yaml b/infra/web.yaml index 4aa8e8c4..a6088719 100644 --- a/infra/web.yaml +++ b/infra/web.yaml @@ -33,13 +33,15 @@ spec: KETCHUP_DB_NAME: ketchup KETCHUP_DB_USER: ketchup KETCHUP_SCHEDULER_ENABLED: "false" + KETCHUP_TOKEN_REDIS_ADDRESS: ketchup-redis:80 secrets: KETCHUP_DB_PASS: AgDOK5Ph8WD8SbBi+Mn/ywPirM59KRfhAjkAqaOqDePJJDd3uIQhoJCKN5HCwYsUoux173go8RrPtyhc5CxKm+/sc6JiqeajZVv/mc/EVPa0MyNpCN376jXIvo0P+joasjBGys/rtqEauhdn7hWGr87PnJbL5A2k+XD3kMauzcKJtMXSYkz2QSTx7TW1kW+5zJs/Cgp3FS9qHZ8buvktggnKeffhd0paYJJrLmtyKxKzmkXcyL8Q3i3QnAbXC3u4vSPxP5PMFMEqDZNrmmYiEJVOmNcW+R0jO7u6q3gwWkATL7E0bbtWuanp6/FXgUhlgpmD+i9BSwTEzrglFHEGPESlg+uYDqXDXOKGBzmQPcq7aAU+/jcEyh5ozkF8aVod7fVxFo+g1nGCbwAhXK5E+iT+KZ1Q50mFkhRIOYSQ9aesHONBPpiaLp8y00OJ6oEmbCSmuDNOBTYXo/JIjUnJ5LFIIskcT5MWKPkYV3hlSzshQBR9JPXLqdaiIEiRicjnfU/qWrwel0PlEaU2L1FL1qsikxPkfGu1HHwj0CusGpGduD3DKC1mTEc1U4zAVvmqSMpoSguyfOYf/2C/m+jcd5YTkiS9JpTGUx4OVFvBD6Ug9uT7igLI8nNFZeTHMCnCerG7GES0wapWehYX/wYFaqw9K1ym0Jz2fHByCVNEt8XH0GxFszdTw2iF6Q4AIH4D8lLB9umdTPP91L5hYVSIOpv9qQPUa9pxB5aNwEG9Q+BQt31mM/zNEglv033PqYOAM12KsGqwew9HJBAUFQU= + KETCHUP_TOKEN_REDIS_PASSWORD: AgDFj9oiAU2G4sqvbTzjqaGYCdsJpOxvRJ+V6jo6tmj1wjFOO1G3HIUGl4/K/rjxClTiXyQAG8jTQS5xOyOUMlRtGEWM1ccHxPzkBJ9k1hSSpaPG0cOJokVbSBAeO7GRBOfOv+hDtOBkPMrFOuo/n79ie6bIk8TEMqHjd2UbLkip31i7zp9kNG+k2JJ+EC/vdN4y5eliFV/0vBAgtC7H2yu6/7oaKt+EuM8tqaJ8E3Jp68vlBo0YqurvjueQCa1HEUt0bcexLW+KGwqfPUoG5SVIwDP2Z572UKsA4hdCYjsuCvfV+KWOoMtLMAqIM+e/H+twsV7pU5TI206dywlniQQUpcTJNk+MbNwWepJizBiHIxSeXxzDcNgRR/5ezRoOzFzTLGOHn7Xr4ya6S9yFoaFR+/GQXluvVoyJ7IsEgqOzcz551SVGB7AsgncAPFKs9r2xRlFgSCvserQm+AbOL/JbobzZtinjzPMXKW+gD9LqLrEddcMu1XeGSpzoYo6WUbPNvh1+ETQsVA8KjzMYVBHuVAMMfoxCY+xprsNxkD9HxYKvJkznit59y+G/MZo/hQcx8ow1T8TbsKRWmYsDP8h2PaejAlk7AOYAbKeqh1an7kBcIh2U/YyAuEaXsLxWOzSajXR1zUuVca73ncthejIP8YUj9bDL3M3o6ug0WkWJ3pEhDhks6ZkNs0FP9MqS+t+BySOx+pX07Bsna5Vb+XagAxqfUeOPZJ63ncRShKyD+Uu6EJ+F72LuFcEe75wEcMb23GRwbd5szZY50qjwo3g= KETCHUP_GITHUB_TOKEN: AgBsMBks+FDLh1scbW9OCRA2Y5NfFRfXk6OQws/5L2+wilH7DrDB6l80jWbFz9eEc+Lqq4GBw0024m6sWg6pZdkSZjhyYkgxW+amWTJDzjexg5Kwn7hv8566TAJ/KwpHyQTOoIcyPHBilqovd80Iy/LhVXKHRne79lCxEHA0HeWbS63YsV63eu6BgwF+N5Vp6VvAFfCA7+0Yj9bnhEiYNY6PrSRR/DxLhkY204JZvEoO+n+cnrMe2cir3LauofyZ+HoeLTMsF/0zYgGYiax+uk16tcSgq9sb7oWRyhlM429qOQ5YFeZMmbT9pvJeYEAz3fQH8sbepmB23KFAxzblN2LGImAGHRvn2kEKfPhHZgj/uhFGyeHAdk/Rzm/eoG49r8aBxeYfKbe5e5aL/Xp012I5VKuVu4z7vUiUlZMiHlgka1U5i/KicBj1a2z4XTRJLmIqacDl5L9RvBW1KQoH+eqJhlr+A8t5/GyyI0EjWVdQf+qs6AWrRvJRv1cvd/wL+i1zWKsZZ99B8e0JvA89aHGKBQHCNM4OCGXpv5dSizLClqCFF5W61cRmdZQ7QWnIpJoS/yBbY+xuldTtcHC7hWmQq+L2iHNLALlPnXncehVNhbztWnMoAJUNuhWBRL8coGbbI98OxxXSJlZEnkPscQYltTMI/q2laUcwx7NGX3oCOeGfl3Nz8TE62dW7gNIqCOfCDVVUAG/j/AuRjc1HbdAlx6JctW6k8QKQoXds8ULZbamFGcPnfIXC ingress: enabled: true hosts: - - ketchup.vibioh.fr + - ketchup.vibioh.fr canary: enabled: true url: https://ketchup.vibioh.fr diff --git a/pkg/ketchup/ketchup.go b/pkg/ketchup/ketchup.go index d6cd18fd..ee36ee14 100644 --- a/pkg/ketchup/ketchup.go +++ b/pkg/ketchup/ketchup.go @@ -4,14 +4,12 @@ import ( "html/template" "net/http" "strings" - "time" - "github.com/ViBiOh/httputils/v4/pkg/cron" - "github.com/ViBiOh/httputils/v4/pkg/logger" "github.com/ViBiOh/httputils/v4/pkg/renderer" "github.com/ViBiOh/ketchup/pkg/service/ketchup" "github.com/ViBiOh/ketchup/pkg/service/repository" "github.com/ViBiOh/ketchup/pkg/service/user" + "github.com/ViBiOh/ketchup/pkg/token" ) const ( @@ -26,7 +24,6 @@ var ( // App of package type App interface { - Start(<-chan struct{}) Handler() http.Handler Signup() http.Handler PublicTemplateFunc(*http.Request) (string, int, map[string]interface{}, error) @@ -38,27 +35,20 @@ type app struct { ketchupService ketchup.App userService user.App repositoryService repository.App - tokenStore TokenStore + tokenApp token.App } // New creates new App from Config -func New(rendererApp renderer.App, ketchupService ketchup.App, userService user.App, repositoryService repository.App) App { +func New(rendererApp renderer.App, ketchupService ketchup.App, userService user.App, repositoryService repository.App, tokenApp token.App) App { return app{ - tokenStore: NewTokenStore(), - rendererApp: rendererApp, ketchupService: ketchupService, userService: userService, repositoryService: repositoryService, + tokenApp: tokenApp, } } -func (a app) Start(done <-chan struct{}) { - cron.New().Each(time.Hour).OnError(func(err error) { - logger.Error("error while running token store cleanup: %s", err) - }).Start(a.tokenStore.Clean, done) -} - // Handler for request. Should be use with net/http func (a app) Handler() http.Handler { rendererHandler := a.rendererApp.Handler(a.AppTemplateFunc) diff --git a/pkg/ketchup/renderer.go b/pkg/ketchup/renderer.go index 3cf75a43..7433270e 100644 --- a/pkg/ketchup/renderer.go +++ b/pkg/ketchup/renderer.go @@ -1,6 +1,7 @@ package ketchup import ( + "context" "crypto/rand" "fmt" "math/big" @@ -15,7 +16,7 @@ const ( suggestCount = uint64(5) ) -func (a app) generateToken() (string, int64, error) { +func (a app) generateToken(ctx context.Context) (string, int64, error) { questionID, err := rand.Int(rand.Reader, big.NewInt(int64(len(colors)))) if err != nil { return "", 0, fmt.Errorf("unable to generate random int: %w", err) @@ -23,11 +24,16 @@ func (a app) generateToken() (string, int64, error) { id := questionID.Int64() - return a.tokenStore.Store(id, time.Minute*5), id, nil + token, err := a.tokenApp.Store(ctx, fmt.Sprintf("%d", id), time.Minute*5) + if err != nil { + return token, id, fmt.Errorf("unable to store token: %s", err) + } + + return token, id, nil } func (a app) PublicTemplateFunc(r *http.Request) (string, int, map[string]interface{}, error) { - token, questionID, err := a.generateToken() + token, questionID, err := a.generateToken(r.Context()) if err != nil { return "", http.StatusInternalServerError, nil, err } diff --git a/pkg/ketchup/signup.go b/pkg/ketchup/signup.go index 5b189db1..06a84e8d 100644 --- a/pkg/ketchup/signup.go +++ b/pkg/ketchup/signup.go @@ -4,9 +4,11 @@ import ( "errors" "fmt" "net/http" + "strconv" "strings" authModel "github.com/ViBiOh/auth/v2/pkg/model" + "github.com/ViBiOh/httputils/v4/pkg/logger" httpModel "github.com/ViBiOh/httputils/v4/pkg/model" "github.com/ViBiOh/httputils/v4/pkg/renderer" "github.com/ViBiOh/ketchup/pkg/model" @@ -25,14 +27,20 @@ func (a app) Signup() http.Handler { } token := r.FormValue("token") - questionID, ok := a.tokenStore.Load(token) - if !ok { - a.rendererApp.Error(w, errors.New("token has expired")) + questionIDString, err := a.tokenApp.Load(r.Context(), token) + if err != nil { + a.rendererApp.Error(w, httpModel.WrapInvalid(fmt.Errorf("unable to retrieve captcha token: %s", err))) return } - if colors[questionID.(int64)].Answer != strings.TrimSpace(r.FormValue("answer")) { - a.rendererApp.Error(w, errors.New("invalid question answer")) + questionID, err := strconv.ParseInt(questionIDString, 10, 64) + if err != nil { + a.rendererApp.Error(w, fmt.Errorf("question id is not numerical: %s", err)) + return + } + + if colors[questionID].Answer != strings.TrimSpace(r.FormValue("answer")) { + a.rendererApp.Error(w, httpModel.WrapInvalid(errors.New("invalid question answer"))) return } @@ -46,7 +54,9 @@ func (a app) Signup() http.Handler { return } - a.tokenStore.Delete(token) + if err := a.tokenApp.Delete(r.Context(), token); err != nil { + logger.Warn("unable to delete token: %s", err) + } renderer.Redirect(w, r, fmt.Sprintf("%s/", appPath), renderer.NewSuccessMessage("Welcome to ketchup!")) }) diff --git a/pkg/ketchup/token.go b/pkg/ketchup/token.go deleted file mode 100644 index 5ec27400..00000000 --- a/pkg/ketchup/token.go +++ /dev/null @@ -1,90 +0,0 @@ -package ketchup - -import ( - "crypto/rand" - "fmt" - "sync" - "time" - - "github.com/ViBiOh/httputils/v4/pkg/logger" -) - -// TokenStore stores single usage token -type TokenStore interface { - Store(value interface{}, duration time.Duration) string - Load(key string) (interface{}, bool) - Delete(key string) - Clean(currentTime time.Time) error -} - -type tokenStore struct { - store sync.Map -} - -// NewTokenStore creates a new token store -func NewTokenStore() TokenStore { - return &tokenStore{} -} - -type mapValue struct { - content interface{} - expiration time.Time -} - -func (t *mapValue) isValid() bool { - return t.expiration.After(time.Now()) -} - -func (t *tokenStore) Store(value interface{}, duration time.Duration) string { - token := t.uuid() - - t.store.Store(token, mapValue{ - content: value, - expiration: time.Now().Add(duration), - }) - - return token -} - -func (t *tokenStore) Load(key string) (interface{}, bool) { - if value, ok := t.store.Load(key); ok { - timeValue := value.(mapValue) - if timeValue.isValid() { - return timeValue.content, true - } - - t.Delete(key) - } - - return nil, false -} - -func (t *tokenStore) Delete(key string) { - t.store.Delete(key) -} - -func (t *tokenStore) Clean(_ time.Time) error { - t.store.Range(func(key, value interface{}) bool { - timeValue := value.(mapValue) - if !timeValue.isValid() { - t.Delete(key.(string)) - } - - return true - }) - - return nil -} - -func (t *tokenStore) uuid() string { - raw := make([]byte, 16) - if _, err := rand.Read(raw); err != nil { - logger.Fatal(err) - return "" - } - - raw[8] = raw[8]&^0xc0 | 0x80 - raw[6] = raw[6]&^0xf0 | 0x40 - - return fmt.Sprintf("%x-%x-%x-%x-%x", raw[0:4], raw[4:6], raw[6:8], raw[8:10], raw[10:]) -} diff --git a/pkg/ketchup/token_test.go b/pkg/ketchup/token_test.go deleted file mode 100644 index 95af5f9c..00000000 --- a/pkg/ketchup/token_test.go +++ /dev/null @@ -1,122 +0,0 @@ -package ketchup - -import ( - "testing" - "time" -) - -func TestStore(t *testing.T) { - type args struct { - value interface{} - duration time.Duration - } - - var cases = []struct { - intention string - args args - want int - }{ - { - "nil", - args{ - value: nil, - duration: 0, - }, - 36, - }, - { - "value", - args{ - value: "valid", - duration: 0, - }, - 36, - }, - } - - for _, tc := range cases { - t.Run(tc.intention, func(t *testing.T) { - if got := NewTokenStore().Store(tc.args.value, tc.args.duration); len(got) != tc.want { - t.Errorf("Store() = %s, want %d", got, tc.want) - } - }) - } -} - -func TestLoad(t *testing.T) { - tokenStore := NewTokenStore() - presentToken := tokenStore.Store("ok", time.Minute) - invalidToken := tokenStore.Store("ko", time.Minute*-1) - - type args struct { - key string - } - - var cases = []struct { - intention string - args args - want interface{} - wantFound bool - }{ - { - "absent", - args{ - key: "unknown", - }, - nil, - false, - }, - { - "present", - args{ - key: presentToken, - }, - "ok", - true, - }, - { - "invalid", - args{ - key: invalidToken, - }, - nil, - false, - }, - } - - for _, tc := range cases { - t.Run(tc.intention, func(t *testing.T) { - if got, gotFound := tokenStore.Load(tc.args.key); got != tc.want || gotFound != tc.wantFound { - t.Errorf("Load() = (%s, %t), want (%s, %t)", got, gotFound, tc.want, tc.wantFound) - } - }) - } -} - -func TestClean(t *testing.T) { - tokenStore := NewTokenStore() - presentToken := tokenStore.Store("ok", time.Minute) - invalidToken := tokenStore.Store("ko", time.Minute*-1) - - var cases = []struct { - intention string - }{ - { - "simple", - }, - } - - for _, tc := range cases { - t.Run(tc.intention, func(t *testing.T) { - _ = tokenStore.Clean(time.Now()) - - if _, ok := tokenStore.Load(presentToken); !ok { - t.Errorf("Clean() deleted `%s`, want kept", presentToken) - } - - if _, ok := tokenStore.Load(invalidToken); ok { - t.Errorf("Clean() deleted `%s`, want deleted", invalidToken) - } - }) - } -} diff --git a/pkg/token/token.go b/pkg/token/token.go new file mode 100644 index 00000000..96136440 --- /dev/null +++ b/pkg/token/token.go @@ -0,0 +1,86 @@ +package token + +import ( + "context" + "crypto/rand" + "flag" + "fmt" + "strings" + "time" + + "github.com/ViBiOh/httputils/v4/pkg/flags" + "github.com/ViBiOh/httputils/v4/pkg/logger" + "github.com/go-redis/redis/v8" +) + +// App of package +type App interface { + Store(context.Context, string, time.Duration) (string, error) + Load(context.Context, string) (string, error) + Delete(context.Context, string) error +} + +// Config of package +type Config struct { + redisAddress *string + redisPassword *string + redisDatabase *int +} + +type app struct { + redisClient *redis.Client +} + +// Flags adds flags for configuring package +func Flags(fs *flag.FlagSet, prefix string, overrides ...flags.Override) Config { + return Config{ + redisAddress: flags.New(prefix, "token").Name("RedisAddress").Default(flags.Default("RedisAddress", "localhost:6379", overrides)).Label("Redis Address").ToString(fs), + redisPassword: flags.New(prefix, "token").Name("RedisPassword").Default(flags.Default("RedisPassword", "", overrides)).Label("Redis Password, if any").ToString(fs), + redisDatabase: flags.New(prefix, "token").Name("RedisDatabase").Default(flags.Default("RedisDatabase", 0, overrides)).Label("Redis Database").ToInt(fs), + } +} + +// New creates new App from Config +func New(config Config) App { + address := strings.TrimSpace(*config.redisAddress) + + return app{ + redisClient: redis.NewClient(&redis.Options{ + Addr: address, + Password: strings.TrimSpace(*config.redisPassword), + DB: *config.redisDatabase, + }), + } +} + +func (a app) Store(ctx context.Context, value string, duration time.Duration) (string, error) { + token := uuid() + + return token, a.redisClient.SetNX(ctx, token, value, duration).Err() +} + +func (a app) Load(ctx context.Context, key string) (string, error) { + value, err := a.redisClient.Get(ctx, key).Result() + if err != nil { + return "", err + } + + return value, nil +} + +func (a app) Delete(ctx context.Context, key string) error { + return a.redisClient.Del(ctx, key).Err() +} + +func uuid() string { + raw := make([]byte, 16) + if _, err := rand.Read(raw); err != nil { + logger.Fatal(err) + return "" + } + + raw[8] = raw[8]&^0xc0 | 0x80 + raw[6] = raw[6]&^0xf0 | 0x40 + + return fmt.Sprintf("%x-%x-%x-%x-%x", raw[0:4], raw[4:6], raw[6:8], raw[8:10], raw[10:]) +}