commit 9710b3d5709320a96e365e65589f9e16d81c6eaf Author: René Jochum Date: Wed Sep 21 01:26:55 2022 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd6cb06 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.DS_STORE + +.task/ + +!.gitkeep + +go.work +go.work.sum \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b3d2997 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2022 René Jochum + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f8965cd --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +[![Build Status](https://drone.fk.jochum.dev/api/badges/jo-micro/auth2/status.svg)](https://drone.fk.jochum.dev/jo-micro/auth2) [![Go Reference](https://pkg.go.dev/badge/jochum.dev/jo-micro/auth2.svg)](https://pkg.go.dev/jochum.dev/jo-micro/auth2) + +# auth2 + +An auth provider for go-micro, it get's users from a postgres database, in the future maybe from other SQL Databases supported by [bun](https://bun.uptrace.dev/) as well. + +It registers itself with [router](https://jochum.dev/jo-micro/router), if you use it in your stack. + +## JWT Token Auth + +### Generate keys + +```bash +task keys +``` + +## Developers corner + +### Build podman/docker image + +#### Prerequesits + +- podman +- [Task](https://taskfile.dev/#/installation) + +#### Build + +```bash +task +``` + +#### Remove everything + +```bash +task rm +``` + +## Authors + +- René Jochum - rene@jochum.dev + +## License + +Its dual licensed: + +- Apache-2.0 +- GPL-2.0-or-later diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..2bdab66 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,98 @@ +version: '3' + +vars: + GIT_TAG: + sh: git tag --points-at HEAD + GIT_COMMIT: + sh: git rev-parse --short HEAD + GIT_DIRTY: + sh: git status -s + VERSION: + sh: if test "{{.GIT_DIRTY}}" != ""; then echo "{{.GIT_COMMIT}}-dirty"; elif test "{{.GIT_TAG}}" != ""; then echo "{{.GIT_TAG}}"; else echo "{{.GIT_COMMIT}}"; fi + +tasks: + default: + cmds: + - task: version + - task: volume + - task: podman + + version: + desc: Print the version optained from git + cmds: + - echo "{{.VERSION}}" + + volume: + run: "once" + cmds: + - podman volume inspect jo-micro_auth_go 1>/dev/null 2>&1 || podman volume create jo-micro_auth_go + + builder: + desc: Run something in the builder container for example "task builder -- go get -u ./..." + cmds: + - podman run --rm -v "{{.VOLUME_PATH}}:/go:rw" -v "$PWD:/code" registry.fk.jochum.dev/jo-micro/builder:latest {{.CLI_ARGS}} + vars: + VOLUME_PATH: + sh: podman volume inspect jo-micro_auth_go --format "{{"{{"}}.Mountpoint{{"}}"}}" + + protoc: + run: "once" + desc: Generate protobruf go files + sources: + - ./proto/**/*.proto + cmds: + - task: builder + vars: + CLI_ARGS: /scripts/protoc_gen.sh + + build:authsql: + deps: + - protoc + sources: + - ./go.sum + - ./*.go + - ./service/microauthsqld/**/*.go + - ./internal/**/*.go + cmds: + - podman build -v "{{.VOLUME_PATH}}:/go:rw" --build-arg VERSION={{.VERSION}} -t registry.fk.jochum.dev/jo-micro/auth2-sql:latest -f ./docker/microauthsqld/Dockerfile . + vars: + VOLUME_PATH: + sh: podman volume inspect jo-micro_auth_go --format "{{"{{"}}.Mountpoint{{"}}"}}" + + podman: + desc: Generate docker container for jo-micro/auth-sql tagged as registry.fk.jochum.dev/jo-micro/auth2-sql:latest + cmds: + - task: build:authsql + + tidy: + desc: Run "go mod tidy" in a container + cmds: + - task: builder + vars: + CLI_ARGS: go mod tidy + + update: + desc: Run "go get -u ./..." in a container + cmds: + - task: builder + vars: + CLI_ARGS: /scripts/upgrade_deps.sh + + fmt: + desc: Run "go fmt ./..." in a container + cmds: + - task: builder + vars: + CLI_ARGS: go fmt ./... + + keys: + desc: Generate keys + cmds: + - podman run registry.fk.jochum.dev/jo-micro/auth2-sql:latest microauthsqld --generate-keys + + rm: + desc: Remove all persistent data + cmds: + - podman volume rm jo-micro_auth_go || exit 0 + - podman image rm registry.fk.jochum.dev/jo-micro/auth2-sql:latest || exit 0 + - rm -rf $PWD/.task \ No newline at end of file diff --git a/cmd/microauthsqld/config/config.go b/cmd/microauthsqld/config/config.go new file mode 100644 index 0000000..3198f56 --- /dev/null +++ b/cmd/microauthsqld/config/config.go @@ -0,0 +1,71 @@ +package config + +var ( + Version = "0.0.1-dev0" +) + +const ( + Name = "go.micro.auth" + PkgPath = "jochum.dev/jo-micro/auth2" +) + +const ( + EnvDev = "dev" + EnvProd = "prod" +) + +type Config struct { + Auth AuthConfig +} + +type ServerConfig struct { + Env string + RouterURI string +} + +type TokenKeys struct { + PrivKey string + PubKey string +} + +type AuthConfig struct { + Server ServerConfig + + RefreshTokenExpiry int + AccessTokenExpiry int + AccessToken TokenKeys + RefreshToken TokenKeys +} + +func GetConfig() *Config { + return &_cfg +} + +func GetServerConfig() ServerConfig { + return _cfg.Auth.Server +} + +func GetAuthConfig() AuthConfig { + return _cfg.Auth +} + +// internal instance of Config with defaults +var _cfg = Config{ + Auth: AuthConfig{ + Server: ServerConfig{ + Env: EnvProd, + RouterURI: "auth", + }, + + RefreshTokenExpiry: 86400 * 14, // 14 days + AccessTokenExpiry: 900, // 15 minutes + AccessToken: TokenKeys{ + PrivKey: "", + PubKey: "", + }, + RefreshToken: TokenKeys{ + PrivKey: "", + PubKey: "", + }, + }, +} diff --git a/cmd/microauthsqld/main.go b/cmd/microauthsqld/main.go new file mode 100644 index 0000000..3fc5d56 --- /dev/null +++ b/cmd/microauthsqld/main.go @@ -0,0 +1,129 @@ +package main + +import ( + "crypto/ed25519" + "encoding/base64" + "errors" + "fmt" + "log" + "os" + "os/exec" + "strings" + + "github.com/urfave/cli/v2" + "go-micro.dev/v4" + "go-micro.dev/v4/logger" + + "jochum.dev/jo-micro/auth2/cmd/microauthsqld/config" + iconfig "jochum.dev/jo-micro/auth2/internal/config" + iLogger "jochum.dev/jo-micro/auth2/internal/logger" + "jochum.dev/jo-micro/router" + + "jochum.dev/jo-micro/auth2/internal/bun" +) + +var ( + ErrorNoKeys = errors.New("config AUTH_ACCESS_TOKEN_*_KEY or AUTH_REFRESH_TOKEN_*_KEY not given") +) + +func main() { + if err := iconfig.Load(config.GetConfig()); err != nil { + logger.Fatal(err) + } + + srv := micro.NewService() + + flags := []cli.Flag{ + &cli.BoolFlag{ + Name: "generate-keys", + Usage: "Generate keys for the config and/or the environment", + Value: false, + }, + } + flags = append(flags, bun.Flags()...) + flags = append(flags, iLogger.Flags()...) + + opts := []micro.Option{ + micro.Name(config.Name), + micro.Version(config.Version), + micro.Flags(flags...), + micro.Action(func(c *cli.Context) error { + if c.Bool("generate-keys") { + // Just generate keys and print them to the commandline + aPubKeyB, aPrivKeyB, err := ed25519.GenerateKey(nil) + if err != nil { + log.Fatal(err) + return err + } + rPubKeyB, rPrivKeyB, err := ed25519.GenerateKey(nil) + if err != nil { + log.Fatal(err) + return err + } + + absPath, err := exec.LookPath(os.Args[0]) + if err != nil { + // Don't fail here + absPath = os.Args[0] + } + + fmt.Printf("# go.micro.auth ed25519 JWT keys - generated using '%s %s'\n", absPath, strings.Join(os.Args[1:len(os.Args)], " ")) + fmt.Printf("AUTH_ACCESSTOKEN_PRIVKEY=\"%s\"\n", base64.StdEncoding.EncodeToString(aPrivKeyB)) + fmt.Printf("AUTH_ACCESSTOKEN_PUBKEY=\"%s\"\n", base64.StdEncoding.EncodeToString(aPubKeyB)) + fmt.Printf("AUTH_REFRESHTOKEN_PRIVKEY=\"%s\"\n", base64.StdEncoding.EncodeToString(rPrivKeyB)) + fmt.Printf("AUTH_REFRESHTOKEN_PUBKEY=\"%s\"\n", base64.StdEncoding.EncodeToString(rPubKeyB)) + + os.Exit(0) + } + + // Start the logger + if err := iLogger.Start(c); err != nil { + log.Fatal(err) + return err + } + + // Connect to the database + if err := bun.Start(c); err != nil { + log.Fatal(err) + return err + } + + // Check if we got keys + authConfig := config.GetAuthConfig() + if authConfig.AccessToken.PrivKey == "" || authConfig.AccessToken.PubKey == "" || authConfig.RefreshToken.PrivKey == "" || authConfig.RefreshToken.PubKey == "" { + log.Fatal(ErrorNoKeys) + return ErrorNoKeys + } + + // Register with https://jochum.dev/jo-micro/router + r := router.NewHandler( + config.GetServerConfig().RouterURI, + router.NewRoute( + router.Method(router.MethodGet), + router.Path("/routes"), + router.Endpoint("routes"), + ), + ) + r.RegisterWithServer(srv.Server()) + + return nil + }), + } + + srv.Init(opts...) + + // Run server + if err := srv.Run(); err != nil { + logger.Fatal(err) + } + + // Disconnect from the database + if err := bun.Stop(); err != nil { + logger.Fatal(err) + } + + // Stop the logger + if err := iLogger.Stop(); err != nil { + logger.Fatal(err) + } +} diff --git a/cmd/microauthsqld/migrations/postgres/.gitkeep b/cmd/microauthsqld/migrations/postgres/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/cmd/microauthsqld/plugins.go b/cmd/microauthsqld/plugins.go new file mode 100644 index 0000000..15fd8a0 --- /dev/null +++ b/cmd/microauthsqld/plugins.go @@ -0,0 +1,8 @@ +package main + +import ( + _ "github.com/go-micro/plugins/v4/broker/nats" + _ "github.com/go-micro/plugins/v4/registry/nats" + _ "github.com/go-micro/plugins/v4/transport/grpc" + _ "github.com/go-micro/plugins/v4/transport/nats" +) diff --git a/docker/microauthsqld/Dockerfile b/docker/microauthsqld/Dockerfile new file mode 100644 index 0000000..fae756f --- /dev/null +++ b/docker/microauthsqld/Dockerfile @@ -0,0 +1,29 @@ +# STEP 1 build executable binary +FROM registry.fk.jochum.dev/jo-micro/builder:latest AS builder + +# Create appuser (/etc/passwd entry for the runner container) +RUN useradd appuser + +ARG VERSION +COPY . /code/ +WORKDIR /code +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -installsuffix cgo -ldflags="-w -s -X 'jochum.dev/jo-micro/auth2/cmd/microauthsqld/config.Version=$VERSION'" -o /usr/local/bin/microauthsqld jochum.dev/jo-micro/auth2/cmd/microauthsqld + +# STEP 2 build a small image +# start from busybox +FROM busybox + +LABEL maintainer="René Jochum " + +# Copy certs, passwd and binary from builder +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +COPY --from=builder /etc/passwd /etc/passwd +COPY --from=builder /usr/local/bin/microauthsqld /usr/local/bin/microauthsqld +RUN chmod +x /usr/local/bin/microauthsqld + +COPY ./cmd/microauthsqld/migrations /migrations + +# Run as appuser +USER appuser + +CMD [ "/usr/local/bin/microauthsqld" ] \ No newline at end of file diff --git a/docs/implementation.drawio b/docs/implementation.drawio new file mode 100644 index 0000000..f767d5d --- /dev/null +++ b/docs/implementation.drawio @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/implementation.png b/docs/implementation.png new file mode 100644 index 0000000..1620567 Binary files /dev/null and b/docs/implementation.png differ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1f4014b --- /dev/null +++ b/go.mod @@ -0,0 +1,106 @@ +module jochum.dev/jo-micro/auth2 + +go 1.19 + +require ( + github.com/avast/retry-go v3.0.0+incompatible + github.com/go-micro/plugins/v4/broker/nats v1.1.1-0.20220908125827-e0369dde429b + github.com/go-micro/plugins/v4/config/encoder/toml v1.1.0 + github.com/go-micro/plugins/v4/config/encoder/yaml v1.1.0 + github.com/go-micro/plugins/v4/logger/logrus v1.1.0 + github.com/go-micro/plugins/v4/registry/nats v1.1.1-0.20220908125827-e0369dde429b + github.com/go-micro/plugins/v4/transport/grpc v1.1.0 + github.com/go-micro/plugins/v4/transport/nats v1.1.1-0.20220908125827-e0369dde429b + github.com/golang-jwt/jwt/v4 v4.4.2 + github.com/golang-migrate/migrate v3.5.4+incompatible + github.com/google/uuid v1.3.0 + github.com/jackc/pgx v3.6.2+incompatible + github.com/pkg/errors v0.9.1 + github.com/sirupsen/logrus v1.9.0 + github.com/uptrace/bun v1.1.8 + github.com/uptrace/bun/dialect/pgdialect v1.1.8 + github.com/uptrace/bun/extra/bundebug v1.1.8 + github.com/urfave/cli/v2 v2.16.3 + go-micro.dev/v4 v4.8.1 + google.golang.org/protobuf v1.28.1 + jochum.dev/jo-micro/router v0.2.3 +) + +require ( + github.com/BurntSushi/toml v1.2.0 // indirect + github.com/Microsoft/go-winio v0.5.2 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 // indirect + github.com/acomagu/bufpipe v1.0.3 // indirect + github.com/bitly/go-simplejson v0.5.0 // indirect + github.com/cloudflare/circl v1.2.0 // indirect + github.com/cockroachdb/apd v1.1.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.8.1 // indirect + github.com/go-acme/lego/v4 v4.8.0 // indirect + github.com/go-git/gcfg v1.5.0 // indirect + github.com/go-git/go-billy/v5 v5.3.1 // indirect + github.com/go-git/go-git/v5 v5.4.2 // indirect + github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/validator/v10 v10.11.1 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect + github.com/gobwas/ws v1.1.0 // indirect + github.com/goccy/go-json v0.9.11 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-cmp v0.5.8 // indirect + github.com/gorilla/handlers v1.5.1 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/compress v1.15.10 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + github.com/lib/pq v1.10.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/miekg/dns v1.1.50 // indirect + github.com/minio/highwayhash v1.0.2 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/nats-io/jwt/v2 v2.3.0 // indirect + github.com/nats-io/nats.go v1.17.0 // indirect + github.com/nats-io/nkeys v0.3.0 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + github.com/nxadm/tail v1.4.8 // indirect + github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/pelletier/go-toml/v2 v2.0.5 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sergi/go-diff v1.2.0 // indirect + github.com/shopspring/decimal v1.3.1 // indirect + github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect + github.com/ugorji/go/codec v1.2.7 // indirect + github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/xanzy/ssh-agent v0.3.2 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/net v0.0.0-20220909164309-bea034e7d591 // indirect + golang.org/x/sync v0.0.0-20220907140024-f12130a52804 // indirect + golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.12 // indirect + google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa // indirect + google.golang.org/grpc v1.49.0 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..9275fd0 --- /dev/null +++ b/go.sum @@ -0,0 +1,356 @@ +github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= +github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 h1:NsReiLpErIPzRrnogAXYwSoU7txA977LjDGrbkewJbg= +github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8= +github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= +github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= +github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bwesterb/go-ristretto v1.2.1/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= +github.com/cloudflare/circl v1.2.0 h1:NheeISPSUcYftKlfrLuOo4T62FkmD4t4jviLfFFYaec= +github.com/cloudflare/circl v1.2.0/go.mod h1:Ch2UgYr6ti2KTtlejELlROl0YIYj7SLjAC8M+INXlMk= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/containerd/containerd v1.4.3 h1:ijQT13JedHSHrQGWFcGEwzcNKrAGIiZ+jSD5QQG07SY= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +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/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-acme/lego/v4 v4.8.0 h1:XienkuT6ZKHe0DE/LXeGP4ZY+ft+7ZMlqtiJ7XJs2pI= +github.com/go-acme/lego/v4 v4.8.0/go.mod h1:MXCdgHuQh25bfi/tPpyOV/9k2p1JVu6oxXcylAwkouI= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8= +github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= +github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= +github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +github.com/go-log/log v0.2.0 h1:z8i91GBudxD5L3RmF0KVpetCbcGWAV7q1Tw1eRwQM9Q= +github.com/go-micro/plugins/v4/broker/nats v1.1.1-0.20220908125827-e0369dde429b h1:hzQUmqhw+g+qEcMXfZFCR28ASgjnFTbI24KJFSk7+4Y= +github.com/go-micro/plugins/v4/broker/nats v1.1.1-0.20220908125827-e0369dde429b/go.mod h1:dJ5fMD5/7rK1/DNtyWzI/5kGtjYzB1DwMlANr7b2ar4= +github.com/go-micro/plugins/v4/config/encoder/toml v1.1.0 h1:2inKk4YPjzUKvQEzmFT1ecQ4N7aAKQzF6tnOsR+rA9c= +github.com/go-micro/plugins/v4/config/encoder/toml v1.1.0/go.mod h1:QVbmOF267EAet8mWqbxHr7vGd6h9I9Aw6dZ7+/6v2a8= +github.com/go-micro/plugins/v4/config/encoder/yaml v1.1.0 h1:8G9f9WfdN8zzoEznAv5dOtMCh9R9RMdC3isUhDwe6Ro= +github.com/go-micro/plugins/v4/config/encoder/yaml v1.1.0/go.mod h1:NB58gTmSYwibr+jZQOPDj/WoeGXSCcHTvQi+UcdDNxw= +github.com/go-micro/plugins/v4/logger/logrus v1.1.0 h1:qCWt1eW2GiQnwivrBBcPRZbCwQ51A5SGUXptpxmGcuQ= +github.com/go-micro/plugins/v4/logger/logrus v1.1.0/go.mod h1:aNJaayU7YKqlxwM91B3NixYpGgtCk1HiSgwuvCb7co0= +github.com/go-micro/plugins/v4/registry/nats v1.1.1-0.20220908125827-e0369dde429b h1:9XdSUFJq2pR3QQquzpjiyHRBzHahvmQrwATzBtIyM2w= +github.com/go-micro/plugins/v4/registry/nats v1.1.1-0.20220908125827-e0369dde429b/go.mod h1:WdofRVBX8dt+b7J01JpryfAZ3HDD3JDs5t0NXWmBVmI= +github.com/go-micro/plugins/v4/transport/grpc v1.1.0 h1:mXfDYfFQLnVDzjGY3o84oe4prfux9h8txsnA19dKsj8= +github.com/go-micro/plugins/v4/transport/grpc v1.1.0/go.mod h1:J5xMp70xXZzm8yafICrDrWaUDd8Gwy8vt0xif7NcOPg= +github.com/go-micro/plugins/v4/transport/nats v1.1.1-0.20220908125827-e0369dde429b h1:JhY/Le8oAnNpV9k19zkAziU7c2JRbvcGL3c4oT1Qu2o= +github.com/go-micro/plugins/v4/transport/nats v1.1.1-0.20220908125827-e0369dde429b/go.mod h1:V241pJ//Xf5x9kyfQbEK7pf5ivH7vPEZRGRAcVCRVG0= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA= +github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= +github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= +github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-migrate/migrate v3.5.4+incompatible h1:R7OzwvCJTCgwapPCiX6DyBiu2czIUMDCB118gFTKTUA= +github.com/golang-migrate/migrate v3.5.4+incompatible/go.mod h1:IsVUlFN5puWOmXrqjgGUfIRIbU7mr8oNBE2tyERd9Wk= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= +github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o= +github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo= +github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= +github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= +github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI= +github.com/nats-io/jwt/v2 v2.3.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= +github.com/nats-io/nats-server/v2 v2.3.1 h1:tR8rp+ohGbqPGHROuzlvNzvw4G5TTeA5jUkxnSTEYPE= +github.com/nats-io/nats.go v1.17.0 h1:1jp5BThsdGlN91hW0k3YEfJbfACjiOYtUiLXG0RL4IE= +github.com/nats-io/nats.go v1.17.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/uptrace/bun v1.1.8 h1:slxuaP4LYWFbPRUmTtQhfJN+6eX/6ar2HDKYTcI50SA= +github.com/uptrace/bun v1.1.8/go.mod h1:iT89ESdV3uMupD9ixt6Khidht+BK0STabK/LeZE+B84= +github.com/uptrace/bun/dialect/pgdialect v1.1.8 h1:wayJhjYDPGv8tgOBLolbBtSFQ0TihFoo8E1T129UdA8= +github.com/uptrace/bun/dialect/pgdialect v1.1.8/go.mod h1:nNbU8PHTjTUM+CRtGmqyBb9zcuRAB8I680/qoFSmBUk= +github.com/uptrace/bun/extra/bundebug v1.1.8 h1:RrZNOYYFb690k14nCN0t/hokfpsgoppT55/Xk/ijvBA= +github.com/uptrace/bun/extra/bundebug v1.1.8/go.mod h1:AXl9cPt1j3Yyu+a681xTlDyWoIBL1iSjTjr2SAU5oUY= +github.com/urfave/cli/v2 v2.16.3 h1:gHoFIwpPjoyIMbJp/VFd+/vuD0dAgFK4B6DpEMFJfQk= +github.com/urfave/cli/v2 v2.16.3/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xanzy/ssh-agent v0.3.2 h1:eKj4SX2Fe7mui28ZgnFW5fmTz1EIr7ugo5s6wDxdHBM= +github.com/xanzy/ssh-agent v0.3.2/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go-micro.dev/v4 v4.8.1 h1:6/3YtUQ+ofkMJh98lC8TkpuMGoFS8kVcj0cnkQhzwDY= +go-micro.dev/v4 v4.8.1/go.mod h1:Ju8HrZ5hQSF+QguZ2QUs9Kbe42MHP1tJa/fpP5g07Cs= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220907140024-f12130a52804 h1:0SH2R3f1b1VmIMG7BXbEZCBUu2dKmHschSmjqGUrW8A= +golang.org/x/sync v0.0.0-20220907140024-f12130a52804/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/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-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc= +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +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= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa h1:VWkrxnAx2C2hirAP+W5ADU7e/+93Yhk//ioKd2XFyDI= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +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 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/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= +jochum.dev/jo-micro/router v0.2.3 h1:3wLpYQu2COW4GKaWQqzc6pBMaYUhpC/io+vIiNRajFY= +jochum.dev/jo-micro/router v0.2.3/go.mod h1:2uTL8+2ud2cLzCyKG7T+ymK4MPyfWk8C/aJAJksHCoQ= diff --git a/internal/bun/bun.go b/internal/bun/bun.go new file mode 100644 index 0000000..fd099be --- /dev/null +++ b/internal/bun/bun.go @@ -0,0 +1,118 @@ +package bun + +import ( + "database/sql" + "errors" + "fmt" + "strings" + + "github.com/golang-migrate/migrate" + migratePostgres "github.com/golang-migrate/migrate/database/postgres" + "github.com/jackc/pgx" + "github.com/jackc/pgx/log/logrusadapter" + "github.com/jackc/pgx/stdlib" + "github.com/uptrace/bun" + "github.com/uptrace/bun/dialect/pgdialect" + "github.com/uptrace/bun/extra/bundebug" + + iLogger "jochum.dev/jo-micro/auth2/internal/logger" + + "github.com/urfave/cli/v2" +) + +var initialized = false +var SQLDB *sql.DB +var Bun *bun.DB + +func Flags() []cli.Flag { + return []cli.Flag{ + &cli.StringFlag{ + Name: "database-url", + Usage: "bun Database URL", + EnvVars: []string{"DATABASE_URL"}, + }, + &cli.BoolFlag{ + Name: "database-debug", + Usage: "Set it to the debug the database queries", + EnvVars: []string{"DATABASE_DEBUG"}, + DefaultText: "false", + Value: false, + }, + &cli.StringFlag{ + Name: "migrations-table", + Value: "schema_migrations", + Usage: "Table to store migrations info", + EnvVars: []string{"MIGRATIONS_TABLE"}, + }, + &cli.StringFlag{ + Name: "migrations-dir", + Value: "/migrations", + Usage: "Folder which contains migrations", + EnvVars: []string{"MIGRATIONS_DIR"}, + }, + } +} + +func Intialized() bool { + return initialized +} + +func Start(cli *cli.Context) error { + if initialized { + return nil + } + + if strings.HasPrefix(cli.String("database-uri"), "postgres://") { + config, err := pgx.ParseURI(cli.String("database-url")) + if err != nil { + return err + } + + config.PreferSimpleProtocol = true + + if iLogger.Intialized() { + config.Logger = logrusadapter.NewLogger(iLogger.Logrus()) + } + + SQLDB = stdlib.OpenDB(config) + driver, err := migratePostgres.WithInstance(SQLDB, &migratePostgres.Config{MigrationsTable: cli.String("migrations-table")}) + if err != nil { + return err + } + + m, err := migrate.NewWithDatabaseInstance( + fmt.Sprintf("file://%s/postgres", cli.String("migrations-dir")), + "postgres", driver) + if err != nil { + return err + } + if err := m.Up(); err != migrate.ErrNoChange && err != nil { + return err + } + + Bun = bun.NewDB(SQLDB, pgdialect.New()) + if Bun == nil { + return errors.New("failed to create bun") + } + + if cli.Bool("database-debug") { + // Print all queries to stdout. + Bun.AddQueryHook(bundebug.NewQueryHook(bundebug.WithVerbose(true))) + } + } + + initialized = true + return nil +} + +func Stop() error { + if err := SQLDB.Close(); err != nil { + return err + } + + if err := Bun.Close(); err != nil { + return err + } + + return nil +} diff --git a/internal/config/load.go b/internal/config/load.go new file mode 100644 index 0000000..ea2dd64 --- /dev/null +++ b/internal/config/load.go @@ -0,0 +1,75 @@ +package config + +import ( + "os" + "strings" + + "github.com/go-micro/plugins/v4/config/encoder/toml" + "github.com/go-micro/plugins/v4/config/encoder/yaml" + "github.com/pkg/errors" + "go-micro.dev/v4/config" + "go-micro.dev/v4/config/reader" + "go-micro.dev/v4/config/reader/json" + "go-micro.dev/v4/config/source/env" + "go-micro.dev/v4/config/source/file" + "go-micro.dev/v4/logger" + "jochum.dev/jo-micro/auth2/internal/util" +) + +// Load will load configurations and update it when changed +func Load(cfg interface{}) error { + var configor config.Config + var err error + switch strings.ToLower(os.Getenv("CONFIG_TYPE")) { + case "toml": + filename := "config.toml" + if name := os.Getenv("CONFIG_FILE"); len(name) > 0 { + filename = name + } + configor, err = config.NewConfig( + config.WithSource(file.NewSource(file.WithPath(filename))), + config.WithReader(json.NewReader(reader.WithEncoder(toml.NewEncoder()))), + ) + case "yaml": + filename := "config.yaml" + if name := os.Getenv("CONFIG_FILE"); len(name) > 0 { + filename = name + } + configor, err = config.NewConfig( + config.WithSource(file.NewSource(file.WithPath(filename))), + config.WithReader(json.NewReader(reader.WithEncoder(yaml.NewEncoder()))), + ) + default: + configor, err = config.NewConfig( + config.WithSource(env.NewSource()), + ) + } + if err != nil { + return errors.Wrap(err, "configor.New") + } + if err := configor.Load(); err != nil { + return errors.Wrap(err, "configor.Load") + } + if err := configor.Scan(cfg); err != nil { + return errors.Wrap(err, "configor.Scan") + } + + w, err := configor.Watch() + if err != nil { + return errors.Wrap(err, "configor.Watch") + } + util.GoSafe(func() { + for { + v, err := w.Next() + if err != nil { + logger.Error(err) + return + } + if err := v.Scan(cfg); err != nil { + logger.Error(err) + return + } + } + }) + return nil +} diff --git a/internal/logger/logger.go b/internal/logger/logger.go new file mode 100644 index 0000000..62c3fd1 --- /dev/null +++ b/internal/logger/logger.go @@ -0,0 +1,79 @@ +package logger + +import ( + "fmt" + "os" + "runtime" + + microLogrus "github.com/go-micro/plugins/v4/logger/logrus" + microLogger "go-micro.dev/v4/logger" + + "github.com/sirupsen/logrus" + "github.com/urfave/cli/v2" +) + +var myLogger *logrus.Logger = nil +var initialized = false + +func Flags() []cli.Flag { + return []cli.Flag{ + &cli.StringFlag{ + Name: "loglevel", + Value: "info", + Usage: "Logrus log level default 'info', {panic,fatal,error,warn,info,debug,trace} available", + EnvVars: []string{"LOG_LEVEL"}, + }, + } +} + +func Intialized() bool { + return initialized +} + +// caller returns string presentation of log caller which is formatted as +// `/path/to/file.go:line_number`. e.g. `/internal/app/api.go:25` +func caller() func(*runtime.Frame) (function string, file string) { + return func(f *runtime.Frame) (function string, file string) { + return "", fmt.Sprintf("%s:%d", f.File, f.Line) + } +} + +func Start(cli *cli.Context) error { + if initialized { + return nil + } + + lvl, err := logrus.ParseLevel(cli.String("loglevel")) + if err != nil { + return err + } + + myLogger = logrus.New() + myLogger.Out = os.Stdout + myLogger.Level = lvl + + myLogger.SetReportCaller(true) + + myLogger.SetFormatter(&logrus.JSONFormatter{ + CallerPrettyfier: caller(), + FieldMap: logrus.FieldMap{ + logrus.FieldKeyFile: "caller", + }, + }) + + microLogger.DefaultLogger = microLogrus.NewLogger(microLogrus.WithLogger(myLogger)) + + initialized = true + return nil +} + +func Stop() error { + initialized = false + myLogger = nil + + return nil +} + +func Logrus() *logrus.Logger { + return myLogger +} diff --git a/internal/proto/authpb/authpb.pb.go b/internal/proto/authpb/authpb.pb.go new file mode 100644 index 0000000..5e0d8ac --- /dev/null +++ b/internal/proto/authpb/authpb.pb.go @@ -0,0 +1,996 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.21.5 +// source: authpb.proto + +package authpb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type KeysReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Alg string `protobuf:"bytes,1,opt,name=alg,proto3" json:"alg,omitempty"` + AccessPubKey []byte `protobuf:"bytes,2,opt,name=accessPubKey,proto3" json:"accessPubKey,omitempty"` + RefreshPubKey []byte `protobuf:"bytes,3,opt,name=refreshPubKey,proto3" json:"refreshPubKey,omitempty"` +} + +func (x *KeysReply) Reset() { + *x = KeysReply{} + if protoimpl.UnsafeEnabled { + mi := &file_authpb_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *KeysReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*KeysReply) ProtoMessage() {} + +func (x *KeysReply) ProtoReflect() protoreflect.Message { + mi := &file_authpb_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use KeysReply.ProtoReflect.Descriptor instead. +func (*KeysReply) Descriptor() ([]byte, []int) { + return file_authpb_proto_rawDescGZIP(), []int{0} +} + +func (x *KeysReply) GetAlg() string { + if x != nil { + return x.Alg + } + return "" +} + +func (x *KeysReply) GetAccessPubKey() []byte { + if x != nil { + return x.AccessPubKey + } + return nil +} + +func (x *KeysReply) GetRefreshPubKey() []byte { + if x != nil { + return x.RefreshPubKey + } + return nil +} + +type TokenRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AccessToken string `protobuf:"bytes,1,opt,name=accessToken,proto3" json:"accessToken,omitempty"` +} + +func (x *TokenRequest) Reset() { + *x = TokenRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_authpb_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TokenRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TokenRequest) ProtoMessage() {} + +func (x *TokenRequest) ProtoReflect() protoreflect.Message { + mi := &file_authpb_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TokenRequest.ProtoReflect.Descriptor instead. +func (*TokenRequest) Descriptor() ([]byte, []int) { + return file_authpb_proto_rawDescGZIP(), []int{1} +} + +func (x *TokenRequest) GetAccessToken() string { + if x != nil { + return x.AccessToken + } + return "" +} + +type ListRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Limit uint64 `protobuf:"varint,1,opt,name=limit,proto3" json:"limit,omitempty"` + Offset uint64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"` +} + +func (x *ListRequest) Reset() { + *x = ListRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_authpb_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListRequest) ProtoMessage() {} + +func (x *ListRequest) ProtoReflect() protoreflect.Message { + mi := &file_authpb_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListRequest.ProtoReflect.Descriptor instead. +func (*ListRequest) Descriptor() ([]byte, []int) { + return file_authpb_proto_rawDescGZIP(), []int{2} +} + +func (x *ListRequest) GetLimit() uint64 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *ListRequest) GetOffset() uint64 { + if x != nil { + return x.Offset + } + return 0 +} + +type User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + Issuer string `protobuf:"bytes,3,opt,name=issuer,proto3" json:"issuer,omitempty"` + Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Scopes []string `protobuf:"bytes,5,rep,name=scopes,proto3" json:"scopes,omitempty"` +} + +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_authpb_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_authpb_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { + return file_authpb_proto_rawDescGZIP(), []int{3} +} + +func (x *User) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *User) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *User) GetIssuer() string { + if x != nil { + return x.Issuer + } + return "" +} + +func (x *User) GetMetadata() map[string]string { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *User) GetScopes() []string { + if x != nil { + return x.Scopes + } + return nil +} + +type UserListReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Data []*User `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + Count uint64 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"` + Limit uint64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` + Offset uint64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"` +} + +func (x *UserListReply) Reset() { + *x = UserListReply{} + if protoimpl.UnsafeEnabled { + mi := &file_authpb_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserListReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserListReply) ProtoMessage() {} + +func (x *UserListReply) ProtoReflect() protoreflect.Message { + mi := &file_authpb_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserListReply.ProtoReflect.Descriptor instead. +func (*UserListReply) Descriptor() ([]byte, []int) { + return file_authpb_proto_rawDescGZIP(), []int{4} +} + +func (x *UserListReply) GetData() []*User { + if x != nil { + return x.Data + } + return nil +} + +func (x *UserListReply) GetCount() uint64 { + if x != nil { + return x.Count + } + return 0 +} + +func (x *UserListReply) GetLimit() uint64 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *UserListReply) GetOffset() uint64 { + if x != nil { + return x.Offset + } + return 0 +} + +type UserIDRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` +} + +func (x *UserIDRequest) Reset() { + *x = UserIDRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_authpb_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserIDRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserIDRequest) ProtoMessage() {} + +func (x *UserIDRequest) ProtoReflect() protoreflect.Message { + mi := &file_authpb_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserIDRequest.ProtoReflect.Descriptor instead. +func (*UserIDRequest) Descriptor() ([]byte, []int) { + return file_authpb_proto_rawDescGZIP(), []int{5} +} + +func (x *UserIDRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +type UpdateRolesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` + Roles []string `protobuf:"bytes,2,rep,name=roles,proto3" json:"roles,omitempty"` +} + +func (x *UpdateRolesRequest) Reset() { + *x = UpdateRolesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_authpb_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateRolesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateRolesRequest) ProtoMessage() {} + +func (x *UpdateRolesRequest) ProtoReflect() protoreflect.Message { + mi := &file_authpb_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateRolesRequest.ProtoReflect.Descriptor instead. +func (*UpdateRolesRequest) Descriptor() ([]byte, []int) { + return file_authpb_proto_rawDescGZIP(), []int{6} +} + +func (x *UpdateRolesRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *UpdateRolesRequest) GetRoles() []string { + if x != nil { + return x.Roles + } + return nil +} + +type TokenReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AccessToken string `protobuf:"bytes,1,opt,name=accessToken,proto3" json:"accessToken,omitempty"` + AccessTokenExpiresAt int64 `protobuf:"varint,2,opt,name=accessTokenExpiresAt,proto3" json:"accessTokenExpiresAt,omitempty"` + RefreshToken string `protobuf:"bytes,3,opt,name=refreshToken,proto3" json:"refreshToken,omitempty"` + RefreshTokenExpiresAt int64 `protobuf:"varint,4,opt,name=refreshTokenExpiresAt,proto3" json:"refreshTokenExpiresAt,omitempty"` +} + +func (x *TokenReply) Reset() { + *x = TokenReply{} + if protoimpl.UnsafeEnabled { + mi := &file_authpb_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TokenReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TokenReply) ProtoMessage() {} + +func (x *TokenReply) ProtoReflect() protoreflect.Message { + mi := &file_authpb_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TokenReply.ProtoReflect.Descriptor instead. +func (*TokenReply) Descriptor() ([]byte, []int) { + return file_authpb_proto_rawDescGZIP(), []int{7} +} + +func (x *TokenReply) GetAccessToken() string { + if x != nil { + return x.AccessToken + } + return "" +} + +func (x *TokenReply) GetAccessTokenExpiresAt() int64 { + if x != nil { + return x.AccessTokenExpiresAt + } + return 0 +} + +func (x *TokenReply) GetRefreshToken() string { + if x != nil { + return x.RefreshToken + } + return "" +} + +func (x *TokenReply) GetRefreshTokenExpiresAt() int64 { + if x != nil { + return x.RefreshTokenExpiresAt + } + return 0 +} + +type RegisterRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` +} + +func (x *RegisterRequest) Reset() { + *x = RegisterRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_authpb_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterRequest) ProtoMessage() {} + +func (x *RegisterRequest) ProtoReflect() protoreflect.Message { + mi := &file_authpb_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterRequest.ProtoReflect.Descriptor instead. +func (*RegisterRequest) Descriptor() ([]byte, []int) { + return file_authpb_proto_rawDescGZIP(), []int{8} +} + +func (x *RegisterRequest) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *RegisterRequest) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *RegisterRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +type LoginRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` +} + +func (x *LoginRequest) Reset() { + *x = LoginRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_authpb_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LoginRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoginRequest) ProtoMessage() {} + +func (x *LoginRequest) ProtoReflect() protoreflect.Message { + mi := &file_authpb_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead. +func (*LoginRequest) Descriptor() ([]byte, []int) { + return file_authpb_proto_rawDescGZIP(), []int{9} +} + +func (x *LoginRequest) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *LoginRequest) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +type RefreshTokenRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RefreshToken string `protobuf:"bytes,1,opt,name=refreshToken,proto3" json:"refreshToken,omitempty"` +} + +func (x *RefreshTokenRequest) Reset() { + *x = RefreshTokenRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_authpb_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RefreshTokenRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RefreshTokenRequest) ProtoMessage() {} + +func (x *RefreshTokenRequest) ProtoReflect() protoreflect.Message { + mi := &file_authpb_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RefreshTokenRequest.ProtoReflect.Descriptor instead. +func (*RefreshTokenRequest) Descriptor() ([]byte, []int) { + return file_authpb_proto_rawDescGZIP(), []int{10} +} + +func (x *RefreshTokenRequest) GetRefreshToken() string { + if x != nil { + return x.RefreshToken + } + return "" +} + +var File_authpb_proto protoreflect.FileDescriptor + +var file_authpb_proto_rawDesc = []byte{ + 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, + 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x22, 0x67, 0x0a, 0x09, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x61, 0x6c, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, + 0x6c, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x75, 0x62, 0x4b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, + 0x68, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x72, + 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x30, 0x0a, 0x0c, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x3b, + 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, + 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0xcf, 0x01, 0x0a, 0x04, + 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x12, 0x36, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x6f, 0x70, + 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, + 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x75, 0x0a, + 0x0d, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x20, + 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, + 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x22, 0x27, 0x0a, 0x0d, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x42, 0x0a, + 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x72, + 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, + 0x73, 0x22, 0xbc, 0x01, 0x0a, 0x0a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x78, 0x70, + 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, + 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, + 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x34, 0x0a, 0x15, 0x72, 0x65, + 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, + 0x73, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x72, 0x65, 0x66, 0x72, 0x65, + 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, + 0x22, 0x5f, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x22, 0x46, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x39, 0x0a, 0x13, 0x52, 0x65, 0x66, + 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0xc3, 0x03, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x13, 0x2e, 0x61, + 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x15, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x06, 0x44, 0x65, + 0x74, 0x61, 0x69, 0x6c, 0x12, 0x15, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x06, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, + 0x00, 0x12, 0x33, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x17, 0x2e, + 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, + 0x14, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x07, 0x52, + 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x1b, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, + 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x07, 0x49, 0x6e, 0x73, + 0x70, 0x65, 0x63, 0x74, 0x12, 0x14, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x2e, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, 0x74, + 0x68, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x00, 0x42, 0x37, 0x5a, 0x35, 0x6a, 0x6f, + 0x63, 0x68, 0x75, 0x6d, 0x2e, 0x64, 0x65, 0x76, 0x2f, 0x6a, 0x6f, 0x2d, 0x6d, 0x69, 0x63, 0x72, + 0x6f, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x70, 0x62, 0x3b, 0x61, 0x75, 0x74, + 0x68, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_authpb_proto_rawDescOnce sync.Once + file_authpb_proto_rawDescData = file_authpb_proto_rawDesc +) + +func file_authpb_proto_rawDescGZIP() []byte { + file_authpb_proto_rawDescOnce.Do(func() { + file_authpb_proto_rawDescData = protoimpl.X.CompressGZIP(file_authpb_proto_rawDescData) + }) + return file_authpb_proto_rawDescData +} + +var file_authpb_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_authpb_proto_goTypes = []interface{}{ + (*KeysReply)(nil), // 0: authpb.KeysReply + (*TokenRequest)(nil), // 1: authpb.TokenRequest + (*ListRequest)(nil), // 2: authpb.ListRequest + (*User)(nil), // 3: authpb.User + (*UserListReply)(nil), // 4: authpb.UserListReply + (*UserIDRequest)(nil), // 5: authpb.UserIDRequest + (*UpdateRolesRequest)(nil), // 6: authpb.UpdateRolesRequest + (*TokenReply)(nil), // 7: authpb.TokenReply + (*RegisterRequest)(nil), // 8: authpb.RegisterRequest + (*LoginRequest)(nil), // 9: authpb.LoginRequest + (*RefreshTokenRequest)(nil), // 10: authpb.RefreshTokenRequest + nil, // 11: authpb.User.MetadataEntry + (*emptypb.Empty)(nil), // 12: google.protobuf.Empty +} +var file_authpb_proto_depIdxs = []int32{ + 11, // 0: authpb.User.metadata:type_name -> authpb.User.MetadataEntry + 3, // 1: authpb.UserListReply.data:type_name -> authpb.User + 2, // 2: authpb.AuthService.List:input_type -> authpb.ListRequest + 5, // 3: authpb.AuthService.Detail:input_type -> authpb.UserIDRequest + 5, // 4: authpb.AuthService.Delete:input_type -> authpb.UserIDRequest + 6, // 5: authpb.AuthService.UpdateRoles:input_type -> authpb.UpdateRolesRequest + 8, // 6: authpb.AuthService.Register:input_type -> authpb.RegisterRequest + 9, // 7: authpb.AuthService.Login:input_type -> authpb.LoginRequest + 10, // 8: authpb.AuthService.Refresh:input_type -> authpb.RefreshTokenRequest + 1, // 9: authpb.AuthService.Inspect:input_type -> authpb.TokenRequest + 4, // 10: authpb.AuthService.List:output_type -> authpb.UserListReply + 3, // 11: authpb.AuthService.Detail:output_type -> authpb.User + 12, // 12: authpb.AuthService.Delete:output_type -> google.protobuf.Empty + 3, // 13: authpb.AuthService.UpdateRoles:output_type -> authpb.User + 3, // 14: authpb.AuthService.Register:output_type -> authpb.User + 7, // 15: authpb.AuthService.Login:output_type -> authpb.TokenReply + 7, // 16: authpb.AuthService.Refresh:output_type -> authpb.TokenReply + 3, // 17: authpb.AuthService.Inspect:output_type -> authpb.User + 10, // [10:18] is the sub-list for method output_type + 2, // [2:10] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_authpb_proto_init() } +func file_authpb_proto_init() { + if File_authpb_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_authpb_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*KeysReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_authpb_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TokenRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_authpb_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_authpb_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*User); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_authpb_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserListReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_authpb_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserIDRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_authpb_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateRolesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_authpb_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TokenReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_authpb_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_authpb_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoginRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_authpb_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RefreshTokenRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_authpb_proto_rawDesc, + NumEnums: 0, + NumMessages: 12, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_authpb_proto_goTypes, + DependencyIndexes: file_authpb_proto_depIdxs, + MessageInfos: file_authpb_proto_msgTypes, + }.Build() + File_authpb_proto = out.File + file_authpb_proto_rawDesc = nil + file_authpb_proto_goTypes = nil + file_authpb_proto_depIdxs = nil +} diff --git a/internal/proto/authpb/authpb.pb.micro.go b/internal/proto/authpb/authpb.pb.micro.go new file mode 100644 index 0000000..8c6a2c9 --- /dev/null +++ b/internal/proto/authpb/authpb.pb.micro.go @@ -0,0 +1,215 @@ +// Code generated by protoc-gen-micro. DO NOT EDIT. +// source: authpb.proto + +package authpb + +import ( + fmt "fmt" + proto "google.golang.org/protobuf/proto" + emptypb "google.golang.org/protobuf/types/known/emptypb" + math "math" +) + +import ( + context "context" + api "go-micro.dev/v4/api" + client "go-micro.dev/v4/client" + server "go-micro.dev/v4/server" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// Reference imports to suppress errors if they are not otherwise used. +var _ api.Endpoint +var _ context.Context +var _ client.Option +var _ server.Option + +// Api Endpoints for AuthService service + +func NewAuthServiceEndpoints() []*api.Endpoint { + return []*api.Endpoint{} +} + +// Client API for AuthService service + +type AuthService interface { + // * + // @auth AdminAndService + List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*UserListReply, error) + // * + // @auth AuthenticatedUsers + Detail(ctx context.Context, in *UserIDRequest, opts ...client.CallOption) (*User, error) + Delete(ctx context.Context, in *UserIDRequest, opts ...client.CallOption) (*emptypb.Empty, error) + UpdateRoles(ctx context.Context, in *UpdateRolesRequest, opts ...client.CallOption) (*User, error) + Register(ctx context.Context, in *RegisterRequest, opts ...client.CallOption) (*User, error) + Login(ctx context.Context, in *LoginRequest, opts ...client.CallOption) (*TokenReply, error) + Refresh(ctx context.Context, in *RefreshTokenRequest, opts ...client.CallOption) (*TokenReply, error) + Inspect(ctx context.Context, in *TokenRequest, opts ...client.CallOption) (*User, error) +} + +type authService struct { + c client.Client + name string +} + +func NewAuthService(name string, c client.Client) AuthService { + return &authService{ + c: c, + name: name, + } +} + +func (c *authService) List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*UserListReply, error) { + req := c.c.NewRequest(c.name, "AuthService.List", in) + out := new(UserListReply) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authService) Detail(ctx context.Context, in *UserIDRequest, opts ...client.CallOption) (*User, error) { + req := c.c.NewRequest(c.name, "AuthService.Detail", in) + out := new(User) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authService) Delete(ctx context.Context, in *UserIDRequest, opts ...client.CallOption) (*emptypb.Empty, error) { + req := c.c.NewRequest(c.name, "AuthService.Delete", in) + out := new(emptypb.Empty) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authService) UpdateRoles(ctx context.Context, in *UpdateRolesRequest, opts ...client.CallOption) (*User, error) { + req := c.c.NewRequest(c.name, "AuthService.UpdateRoles", in) + out := new(User) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authService) Register(ctx context.Context, in *RegisterRequest, opts ...client.CallOption) (*User, error) { + req := c.c.NewRequest(c.name, "AuthService.Register", in) + out := new(User) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authService) Login(ctx context.Context, in *LoginRequest, opts ...client.CallOption) (*TokenReply, error) { + req := c.c.NewRequest(c.name, "AuthService.Login", in) + out := new(TokenReply) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authService) Refresh(ctx context.Context, in *RefreshTokenRequest, opts ...client.CallOption) (*TokenReply, error) { + req := c.c.NewRequest(c.name, "AuthService.Refresh", in) + out := new(TokenReply) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authService) Inspect(ctx context.Context, in *TokenRequest, opts ...client.CallOption) (*User, error) { + req := c.c.NewRequest(c.name, "AuthService.Inspect", in) + out := new(User) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for AuthService service + +type AuthServiceHandler interface { + // * + // @auth AdminAndService + List(context.Context, *ListRequest, *UserListReply) error + // * + // @auth AuthenticatedUsers + Detail(context.Context, *UserIDRequest, *User) error + Delete(context.Context, *UserIDRequest, *emptypb.Empty) error + UpdateRoles(context.Context, *UpdateRolesRequest, *User) error + Register(context.Context, *RegisterRequest, *User) error + Login(context.Context, *LoginRequest, *TokenReply) error + Refresh(context.Context, *RefreshTokenRequest, *TokenReply) error + Inspect(context.Context, *TokenRequest, *User) error +} + +func RegisterAuthServiceHandler(s server.Server, hdlr AuthServiceHandler, opts ...server.HandlerOption) error { + type authService interface { + List(ctx context.Context, in *ListRequest, out *UserListReply) error + Detail(ctx context.Context, in *UserIDRequest, out *User) error + Delete(ctx context.Context, in *UserIDRequest, out *emptypb.Empty) error + UpdateRoles(ctx context.Context, in *UpdateRolesRequest, out *User) error + Register(ctx context.Context, in *RegisterRequest, out *User) error + Login(ctx context.Context, in *LoginRequest, out *TokenReply) error + Refresh(ctx context.Context, in *RefreshTokenRequest, out *TokenReply) error + Inspect(ctx context.Context, in *TokenRequest, out *User) error + } + type AuthService struct { + authService + } + h := &authServiceHandler{hdlr} + return s.Handle(s.NewHandler(&AuthService{h}, opts...)) +} + +type authServiceHandler struct { + AuthServiceHandler +} + +func (h *authServiceHandler) List(ctx context.Context, in *ListRequest, out *UserListReply) error { + return h.AuthServiceHandler.List(ctx, in, out) +} + +func (h *authServiceHandler) Detail(ctx context.Context, in *UserIDRequest, out *User) error { + return h.AuthServiceHandler.Detail(ctx, in, out) +} + +func (h *authServiceHandler) Delete(ctx context.Context, in *UserIDRequest, out *emptypb.Empty) error { + return h.AuthServiceHandler.Delete(ctx, in, out) +} + +func (h *authServiceHandler) UpdateRoles(ctx context.Context, in *UpdateRolesRequest, out *User) error { + return h.AuthServiceHandler.UpdateRoles(ctx, in, out) +} + +func (h *authServiceHandler) Register(ctx context.Context, in *RegisterRequest, out *User) error { + return h.AuthServiceHandler.Register(ctx, in, out) +} + +func (h *authServiceHandler) Login(ctx context.Context, in *LoginRequest, out *TokenReply) error { + return h.AuthServiceHandler.Login(ctx, in, out) +} + +func (h *authServiceHandler) Refresh(ctx context.Context, in *RefreshTokenRequest, out *TokenReply) error { + return h.AuthServiceHandler.Refresh(ctx, in, out) +} + +func (h *authServiceHandler) Inspect(ctx context.Context, in *TokenRequest, out *User) error { + return h.AuthServiceHandler.Inspect(ctx, in, out) +} diff --git a/internal/proto/authpb/authpb.proto b/internal/proto/authpb/authpb.proto new file mode 100644 index 0000000..859daa1 --- /dev/null +++ b/internal/proto/authpb/authpb.proto @@ -0,0 +1,88 @@ +syntax = "proto3"; + +package authpb; + +option go_package = "jochum.dev/jo-micro/auth2/internal/proto/authpb;authpb"; + +import "google/protobuf/empty.proto"; + +service AuthService { + /** + * @auth AdminAndService + */ + rpc List(ListRequest) returns (UserListReply) {} + + /** + * @auth AuthenticatedUsers + */ + rpc Detail(UserIDRequest) returns (User) {} + rpc Delete(UserIDRequest) returns (google.protobuf.Empty) {} + rpc UpdateRoles(UpdateRolesRequest) returns (User) {} + + rpc Register(RegisterRequest) returns (User) {} + rpc Login(LoginRequest) returns (TokenReply) {} + rpc Refresh(RefreshTokenRequest) returns (TokenReply) {} + + rpc Inspect (TokenRequest) returns (User) {} +} + +message KeysReply { + string alg = 1; + bytes accessPubKey = 2; + bytes refreshPubKey = 3; +} + +message TokenRequest { + string accessToken = 1; +} + +message ListRequest { + uint64 limit = 1; + uint64 offset = 2; +} + +message User { + string id = 1; + string type = 2; + string issuer = 3; + map metadata = 4; + repeated string scopes = 5; +} + +message UserListReply { + repeated User data = 1; + uint64 count = 2; + uint64 limit = 3; + uint64 offset = 4; +} + +message UserIDRequest { + string userId = 1; +} + +message UpdateRolesRequest { + string userId = 1; + repeated string roles = 2; +} + +message TokenReply { + string accessToken = 1; + int64 accessTokenExpiresAt = 2; + string refreshToken = 3; + int64 refreshTokenExpiresAt = 4; +} + +message RegisterRequest { + string username = 1; + string password = 2; + string email = 3; +} + +message LoginRequest { + string username = 1; + string password = 2; +} + +message RefreshTokenRequest { + string refreshToken = 1; +} diff --git a/internal/util/goroutine.go b/internal/util/goroutine.go new file mode 100644 index 0000000..eba459a --- /dev/null +++ b/internal/util/goroutine.go @@ -0,0 +1,22 @@ +package util + +import ( + "runtime/debug" + + "go-micro.dev/v4/logger" +) + +// GoSafe will run func in goroutine safely, avoid crash from unexpected panic +func GoSafe(fn func()) { + if fn == nil { + return + } + go func() { + defer func() { + if e := recover(); e != nil { + logger.Errorf("[panic]%v\n%s", e, debug.Stack()) + } + }() + fn() + }() +} diff --git a/internal/util/retry.go b/internal/util/retry.go new file mode 100644 index 0000000..752ab7b --- /dev/null +++ b/internal/util/retry.go @@ -0,0 +1,46 @@ +package util + +import ( + "fmt" + + "github.com/avast/retry-go" + "go-micro.dev/v4" +) + +func ServiceRetryGet(service micro.Service, svcName string, attempts uint) (string, error) { + r := service.Options().Registry + + var ( + hostAndPort string + ) + + err := retry.Do( + func() error { + services, err := r.GetService(svcName) + if err == nil { + for _, s := range services { + for _, n := range s.Nodes { + hostAndPort = n.Address + break + } + if hostAndPort != "" { + break + } + } + } + + if hostAndPort == "" { + return fmt.Errorf("Service %v not found", svcName) + } + + return nil + }, + retry.Attempts(attempts), + ) + + if err != nil { + return "", err + } + + return hostAndPort, nil +} diff --git a/internal/util/serviceregistry.go b/internal/util/serviceregistry.go new file mode 100644 index 0000000..98fa45d --- /dev/null +++ b/internal/util/serviceregistry.go @@ -0,0 +1,73 @@ +package util + +import ( + "go-micro.dev/v4" + "go-micro.dev/v4/registry" +) + +type ServiceListResult map[*registry.Service][]*registry.Endpoint + +type WrappedEndpoint struct { + Pre string + Handler string +} + +func Endpoints(service micro.Service, regService *registry.Service) ([]*registry.Endpoint, error) { + if len(regService.Endpoints) > 0 { + eps := append([]*registry.Endpoint{}, regService.Endpoints...) + return eps, nil + } + // lookup the endpoints otherwise + newServices, err := service.Options().Registry.GetService(regService.Name) + if err != nil { + return []*registry.Endpoint{}, err + } + if len(newServices) == 0 { + return []*registry.Endpoint{}, err + } + + eps := []*registry.Endpoint{} + for _, s := range newServices { + eps = append(eps, s.Endpoints...) + } + + return eps, nil +} + +func ListEndpoints(service micro.Service) (ServiceListResult, error) { + services, err := service.Options().Registry.ListServices() + if err != nil { + return nil, err + } + + endpoints := make(ServiceListResult) + for _, srv := range services { + eps, err := Endpoints(service, srv) + if err != nil { + continue + } + + endpoints[srv] = eps + } + + return endpoints, nil +} + +func FindByEndpoint(service micro.Service, endpoint interface{}) ([]*registry.Service, error) { + services, err := ListEndpoints(service) + if err != nil { + return []*registry.Service{}, err + } + + strEndpoint := ReflectFunctionName(endpoint) + result := []*registry.Service{} + for s, eps := range services { + for _, ep := range eps { + if ep.Name == strEndpoint { + result = append(result, s) + } + } + } + + return result, nil +} diff --git a/internal/util/token.go b/internal/util/token.go new file mode 100644 index 0000000..44333b3 --- /dev/null +++ b/internal/util/token.go @@ -0,0 +1,31 @@ +package util + +import ( + "errors" + "strings" +) + +type TokenFormat int32 + +const TokenFormatUnknown TokenFormat = 0 +const TokenFormatBearer TokenFormat = 1 +const TokenFormatToken TokenFormat = 2 + +func ExtractToken(hdr string) (string, TokenFormat, error) { + if hdr == "" { + return "", TokenFormatUnknown, errors.New("no authorization header") + } + + th := strings.Split(hdr, " ") + if len(th) != 2 { + return "", TokenFormatUnknown, errors.New("incomplete authorization header") + } + + if strings.ToLower(th[0]) == "bearer" { + return th[1], TokenFormatBearer, nil + } else if strings.ToLower(th[0]) == "token" { + return th[1], TokenFormatToken, nil + } + + return "", TokenFormatUnknown, errors.New("unknow token format") +} diff --git a/internal/util/util.go b/internal/util/util.go new file mode 100644 index 0000000..9e84436 --- /dev/null +++ b/internal/util/util.go @@ -0,0 +1,22 @@ +package util + +import ( + "reflect" + "runtime" + "strings" +) + +// ReflectFunctionName Guess Struct.Method from the given Function +func ReflectFunctionName(i interface{}) string { + switch v := i.(type) { + case string: + return v + default: + path := runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() + // LTrim until the first / + path = path[strings.LastIndex(path, "/")+1:] + + // Return after the next point + return path[strings.Index(path, ".")+1:] + } +} diff --git a/noop.go b/noop.go new file mode 100644 index 0000000..097fa58 --- /dev/null +++ b/noop.go @@ -0,0 +1,115 @@ +package auth + +import ( + "context" + "net/http" + + "github.com/google/uuid" + "github.com/urfave/cli/v2" + "go-micro.dev/v4" + "go-micro.dev/v4/server" +) + +func init() { + ClientAuthRegistry().Register(newNoopClientPlugin()) + ServiceAuthRegistry().Register(newNoopServicePlugin()) + RouterAuthRegistry().Register(newNoopRouterPlugin()) +} + +func newNoopClientPlugin() ClientPlugin { + return new(noopClientPlugin) +} + +type noopClientPlugin struct{} + +func (p *noopClientPlugin) String() string { + return "noop" +} + +func (p *noopClientPlugin) Flags() []cli.Flag { + return []cli.Flag{} +} + +func (p *noopClientPlugin) Init(cli *cli.Context, service micro.Service) error { + return nil +} + +func (p *noopClientPlugin) Stop() error { + return nil +} + +func (p *noopClientPlugin) Health(ctx context.Context) (string, error) { + return "All fine", nil +} + +func (p *noopClientPlugin) Inspect(ctx context.Context) (*User, error) { + return &User{Id: uuid.New().String(), Issuer: p.String()}, nil +} + +func (p *noopClientPlugin) Wrapper() server.HandlerWrapper { + return func(h server.HandlerFunc) server.HandlerFunc { + return func(ctx context.Context, req server.Request, rsp interface{}) error { + return h(ctx, req, rsp) + } + } +} + +func newNoopServicePlugin() ServerPlugin { + return new(noopServicePlugin) +} + +type noopServicePlugin struct{} + +func (p *noopServicePlugin) String() string { + return "noop" +} + +func (p *noopServicePlugin) Flags() []cli.Flag { + return []cli.Flag{} +} + +func (p *noopServicePlugin) Init(cli *cli.Context, service micro.Service) error { + return nil +} + +func (p *noopServicePlugin) Stop() error { + return nil +} + +func (p *noopServicePlugin) Health(ctx context.Context) (string, error) { + return "All fine", nil +} + +func newNoopRouterPlugin() RouterPlugin { + return new(noopRouterPlugin) +} + +type noopRouterPlugin struct{} + +func (p *noopRouterPlugin) String() string { + return "noop" +} + +func (p *noopRouterPlugin) Flags() []cli.Flag { + return []cli.Flag{} +} + +func (p *noopRouterPlugin) Init(cli *cli.Context, service micro.Service) error { + return nil +} + +func (p *noopRouterPlugin) Stop() error { + return nil +} + +func (p *noopRouterPlugin) Health(ctx context.Context) (string, error) { + return "All fine", nil +} + +func (p *noopRouterPlugin) Inspect(r *http.Request) (*User, error) { + return &User{Id: uuid.New().String(), Issuer: p.String()}, nil +} + +func (p *noopRouterPlugin) ForwardContext(r *http.Request, ctx context.Context) (context.Context, error) { + return ctx, nil +} diff --git a/plugin.go b/plugin.go new file mode 100644 index 0000000..f5e25b8 --- /dev/null +++ b/plugin.go @@ -0,0 +1,63 @@ +package auth + +import ( + "context" + "net/http" + + "github.com/urfave/cli/v2" + "go-micro.dev/v4" + "go-micro.dev/v4/server" +) + +type User struct { + Id string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + Issuer string `json:"issuer,omitempty"` + Metadata map[string]string `json:"metadata,omitempty"` + Scopes []string `json:"scopes,omitempty"` + Roles []string `json:"roles,omitempty"` +} + +type registryFuncs interface { + // String returns the name of the plugin + String() string + + // Flags returns a list of cli.Flag's for micro.Service + Flags() []cli.Flag + + // Init should be executed in micro.Init + Init(cli *cli.Context, service micro.Service) error + + // Stop should be executed after service.Run() + Stop() error + + // Health returns the health of the plugin + Health(ctx context.Context) (string, error) +} + +// ClientPlugin is for services that act as client's behind GinRouter +type ClientPlugin interface { + registryFuncs + + // Inspect a context + Inspect(ctx context.Context) (*User, error) + + // Wrapper returns the Auth Wrapper for your service + Wrapper() server.HandlerWrapper +} + +// ServerPlugin is for authservers +type ServerPlugin interface { + registryFuncs +} + +// RouterPlugin is for routers that forward the token or do other stuff required by ClientPlugin +type RouterPlugin interface { + registryFuncs + + // Inspect a http.Request + Inspect(r *http.Request) (*User, error) + + // ForwardContext should forward all required informations from http.Request to the resulting context. + ForwardContext(r *http.Request, ctx context.Context) (context.Context, error) +} diff --git a/plugins/client/jwt/jwt.go b/plugins/client/jwt/jwt.go new file mode 100644 index 0000000..b7e7d27 --- /dev/null +++ b/plugins/client/jwt/jwt.go @@ -0,0 +1,131 @@ +package jwt + +import ( + "context" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + + "github.com/golang-jwt/jwt/v4" + "github.com/urfave/cli/v2" + "go-micro.dev/v4" + "go-micro.dev/v4/metadata" + "go-micro.dev/v4/server" + "jochum.dev/jo-micro/auth2" + "jochum.dev/jo-micro/auth2/internal/util" +) + +type jWTClaims struct { + *jwt.StandardClaims + Type string `json:"type,omitempty"` + Roles []string `json:"roles,omitempty"` + Scopes []string `json:"scopes,omitempty"` +} + +func init() { + auth.ClientAuthRegistry().Register(newJWTPlugin()) +} + +func newJWTPlugin() auth.ClientPlugin { + return new(jwtPlugin) +} + +type jwtPlugin struct { + pubKey any +} + +func (p *jwtPlugin) String() string { + return "jwt" +} + +func (p *jwtPlugin) Flags() []cli.Flag { + return []cli.Flag{ + &cli.StringFlag{ + Name: "auth2_jwt_pub_key", + Usage: "Public key PEM base64 encoded", + EnvVars: []string{"MICRO_AUTH2_JWT_PUB_KEY"}, + }, + } +} + +func (p *jwtPlugin) Init(cli *cli.Context, service micro.Service) error { + if len(cli.String("auth2_jwt_pub_key")) < 1 { + return errors.New("you must provide micro-auth-jwt-pub-key") + } + aPub, err := base64.StdEncoding.DecodeString(cli.String("micro-auth-jwt-pub-key")) + if err != nil { + return err + } + + block, _ := pem.Decode(aPub) + if block == nil { + return errors.New("failed to parse PEM block containing the key") + } + + pub, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return err + } + + p.pubKey = pub + + return nil +} + +func (p *jwtPlugin) Stop() error { + return nil +} + +func (p *jwtPlugin) Health(ctx context.Context) (string, error) { + return "All fine", nil +} + +func (p *jwtPlugin) Inspect(ctx context.Context) (*auth.User, error) { + md, ok := metadata.FromContext(ctx) + if !ok { + return nil, errors.New("failed to extract metadata from context") + } + + authH, ok := md.Get("Authorization") + if !ok { + return nil, errors.New("failed to get Authorization header from context") + } + + aTokenString, _, err := util.ExtractToken(authH) + if err != nil { + return nil, err + } + + claims := jWTClaims{} + _, err = jwt.ParseWithClaims(aTokenString, &claims, func(token *jwt.Token) (interface{}, error) { + return p.pubKey, nil + }) + if err != nil { + return nil, err + } + + cMD := map[string]string{ + "Audience": claims.Audience, + "ExpiresAt": fmt.Sprintf("%d", claims.ExpiresAt), + "IssuedAt": fmt.Sprintf("%d", claims.IssuedAt), + "NotBefore": fmt.Sprintf("%d", claims.NotBefore), + "Subject": claims.Subject, + } + + return &auth.User{Id: claims.Id, Type: claims.Type, Issuer: claims.Issuer, Metadata: cMD, Scopes: claims.Scopes, Roles: claims.Roles}, nil +} + +func (p *jwtPlugin) Wrapper() server.HandlerWrapper { + return func(h server.HandlerFunc) server.HandlerFunc { + return func(ctx context.Context, req server.Request, rsp interface{}) error { + _, err := p.Inspect(ctx) + if err != nil { + return err + } + + return h(ctx, req, rsp) + } + } +} diff --git a/plugins/router/jwt/jwt.go b/plugins/router/jwt/jwt.go new file mode 100644 index 0000000..dc8fe20 --- /dev/null +++ b/plugins/router/jwt/jwt.go @@ -0,0 +1,129 @@ +package jwt + +import ( + "context" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "net/http" + + "github.com/golang-jwt/jwt/v4" + "github.com/urfave/cli/v2" + "go-micro.dev/v4" + "go-micro.dev/v4/metadata" + "jochum.dev/jo-micro/auth2" + "jochum.dev/jo-micro/auth2/internal/util" +) + +type jWTClaims struct { + *jwt.StandardClaims + Type string `json:"type,omitempty"` + Roles []string `json:"roles,omitempty"` + Scopes []string `json:"scopes,omitempty"` +} + +func init() { + auth.RouterAuthRegistry().Register(newJWTPlugin()) +} + +func newJWTPlugin() auth.RouterPlugin { + return new(jwtPlugin) +} + +type jwtPlugin struct { + pubKey any +} + +func (p *jwtPlugin) String() string { + return "jwt" +} + +func (p *jwtPlugin) Flags() []cli.Flag { + return []cli.Flag{ + &cli.StringFlag{ + Name: "auth2_jwt_pub_key", + Usage: "Public key PEM base64 encoded", + EnvVars: []string{"MICRO_AUTH2_JWT_PUB_KEY"}, + }, + } +} + +func (p *jwtPlugin) Init(cli *cli.Context, service micro.Service) error { + if len(cli.String("auth2_jwt_pub_key")) < 1 { + return errors.New("you must provide micro-auth-jwt-pub-key") + } + aPub, err := base64.StdEncoding.DecodeString(cli.String("micro-auth-jwt-pub-key")) + if err != nil { + return err + } + + block, _ := pem.Decode(aPub) + if block == nil { + return errors.New("failed to parse PEM block containing the key") + } + + pub, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return err + } + + p.pubKey = pub + + return nil +} + +func (p *jwtPlugin) Stop() error { + return nil +} + +func (p *jwtPlugin) Health(ctx context.Context) (string, error) { + return "All fine", nil +} + +func (p *jwtPlugin) Inspect(r *http.Request) (*auth.User, error) { + if h := r.Header.Get("Authorization"); len(h) > 0 { + return nil, errors.New("failed to get Authorization header from context") + } + + aTokenString, _, err := util.ExtractToken(r.Header.Get("Authorization")) + if err != nil { + return nil, err + } + + claims := jWTClaims{} + _, err = jwt.ParseWithClaims(aTokenString, &claims, func(token *jwt.Token) (interface{}, error) { + return p.pubKey, nil + }) + if err != nil { + return nil, err + } + + cMD := map[string]string{ + "Audience": claims.Audience, + "ExpiresAt": fmt.Sprintf("%d", claims.ExpiresAt), + "IssuedAt": fmt.Sprintf("%d", claims.IssuedAt), + "NotBefore": fmt.Sprintf("%d", claims.NotBefore), + "Subject": claims.Subject, + } + + return &auth.User{Id: claims.Id, Type: claims.Type, Issuer: claims.Issuer, Metadata: cMD, Scopes: claims.Scopes, Roles: claims.Roles}, nil +} + +func (p *jwtPlugin) ForwardContext(r *http.Request, ctx context.Context) (context.Context, error) { + _, err := p.Inspect(r) + if err != nil { + return ctx, err + } + + md := metadata.Metadata{ + "Authorization": r.Header.Get("Authorization"), + } + + if v := r.Header.Get("X-Forwarded-For"); len(v) > 0 { + md["X-Fowarded-For"] = v + } + + return metadata.MergeContext(ctx, md, true), nil +} diff --git a/registry.go b/registry.go new file mode 100644 index 0000000..aa74a8a --- /dev/null +++ b/registry.go @@ -0,0 +1,90 @@ +package auth + +import ( + "context" + "fmt" + "strings" + + "github.com/urfave/cli/v2" + "go-micro.dev/v4" +) + +var car = &AuthRegistry[ClientPlugin]{kind: "client", plugins: make(map[string]ClientPlugin)} +var sar = &AuthRegistry[ServerPlugin]{kind: "service", plugins: make(map[string]ServerPlugin)} +var rar = &AuthRegistry[RouterPlugin]{kind: "router", plugins: make(map[string]RouterPlugin)} + +func ClientAuthRegistry() *AuthRegistry[ClientPlugin] { + return car +} + +func ServiceAuthRegistry() *AuthRegistry[ServerPlugin] { + return sar +} + +func RouterAuthRegistry() *AuthRegistry[RouterPlugin] { + return rar +} + +type AuthRegistry[T any] struct { + kind string + plugin T + plugins map[string]T +} + +// Register registers a plugin within AuthRegistry +func (r *AuthRegistry[T]) Register(plugin T) { + if s, ok := any(plugin).(registryFuncs); ok { + r.plugins[s.String()] = plugin + } +} + +// Flags returns a list of cli.Flag's for micro.Service +func (r *AuthRegistry[T]) Flags() []cli.Flag { + flags := []cli.Flag{ + &cli.StringFlag{ + Name: fmt.Sprintf("auth2_%s", r.kind), + Usage: fmt.Sprintf("Auth %s Plugin to use", r.kind), + EnvVars: []string{fmt.Sprintf("MICRO_AUTH2_%s", strings.ToUpper(r.kind))}, + Value: "noop", + }, + } + for _, p := range r.plugins { + if p2, ok := any(p).(registryFuncs); ok { + flags = append(flags, p2.Flags()...) + } + } + + return flags +} + +// Plugin returns the current active Plugin +func (r *AuthRegistry[T]) Plugin() T { + return r.plugin +} + +// Init should be executed in micro.Init +func (r *AuthRegistry[T]) Init(cli *cli.Context, service micro.Service) error { + plugin := cli.String(fmt.Sprintf("auth2_%s", r.kind)) + + m, ok := r.plugins[plugin] + if !ok { + return fmt.Errorf("unknown MICRO_AUTH2_%s plugin '%s'", strings.ToUpper(r.kind), plugin) + } + + r.plugin = m + + m2, _ := any(m).(registryFuncs) + return m2.Init(cli, service) +} + +// Stop should be executed after service.Run() +func (r *AuthRegistry[T]) Stop() error { + m, _ := any(r.plugin).(registryFuncs) + return m.Stop() +} + +// Health returns the health of the plugin +func (r *AuthRegistry[T]) Health(ctx context.Context) (string, error) { + m, _ := any(r.plugin).(registryFuncs) + return m.Health(ctx) +}