From 73367df5d5f66cee2cb12808f96d4cde8f076717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Jochum?= Date: Sun, 25 Sep 2022 02:52:44 +0200 Subject: [PATCH] Initial commit --- .drone.yml | 32 ++++ .env | 4 + .env.sample | 4 + LICENSE | 13 ++ README.md | 38 ++++ Taskfile.yml | 112 +++++++++++ cmd/microgeoipd/config/config.go | 10 + cmd/microgeoipd/main.go | 50 +++++ cmd/microgeoipd/plugins.go | 8 + docker/geoip/Dockerfile | 31 ++++ go.mod | 84 +++++++++ go.sum | 307 +++++++++++++++++++++++++++++++ internal/maxmind/README.md | 3 + internal/maxmind/client.go | 61 ++++++ internal/maxmind/downloader.go | 207 +++++++++++++++++++++ internal/maxmind/editionid.go | 80 ++++++++ internal/maxmind/util.go | 58 ++++++ proto/geoippb/geoippb.proto | 30 +++ 18 files changed, 1132 insertions(+) create mode 100644 .drone.yml create mode 100644 .env create mode 100644 .env.sample create mode 100644 LICENSE create mode 100644 README.md create mode 100644 Taskfile.yml create mode 100644 cmd/microgeoipd/config/config.go create mode 100644 cmd/microgeoipd/main.go create mode 100644 cmd/microgeoipd/plugins.go create mode 100644 docker/geoip/Dockerfile create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/maxmind/README.md create mode 100644 internal/maxmind/client.go create mode 100644 internal/maxmind/downloader.go create mode 100644 internal/maxmind/editionid.go create mode 100644 internal/maxmind/util.go create mode 100644 proto/geoippb/geoippb.proto diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..9303f3b --- /dev/null +++ b/.drone.yml @@ -0,0 +1,32 @@ +--- +kind: pipeline +type: docker +name: default + +platform: + os: linux + arch: amd64 + +trigger: + event: + - cron + - custom + - tag + +steps: +- name: build + image: plugins/docker + settings: + registry: registry.fk.jochum.dev + username: robot$jo-micro+drone + password: + from_secret: registry.fk.jochum.dev-robot + dockerfile: ./docker/geoip/Dockerfile + repo: registry.fk.jochum.dev/jo-micro/geoip + build_args: + - DOCKER_IO=registry.fk.jochum.dev/docker_hub_cache + - DOCKER_ORG_JO_MICRO=registry.fk.jochum.dev/jo-micro + - VERSION=${DRONE_TAG:1} + tags: + - ${DRONE_TAG:1} + - latest diff --git a/.env b/.env new file mode 100644 index 0000000..d1ccadf --- /dev/null +++ b/.env @@ -0,0 +1,4 @@ +DOCKER_IO="registry.fk.jochum.dev/docker_hub_cache" +DOCKER_ORG_JO_MICRO="registry.fk.jochum.dev/jo-micro" + +BUILD_MOUNT_FOLDER="~" \ No newline at end of file diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..86f9bf1 --- /dev/null +++ b/.env.sample @@ -0,0 +1,4 @@ +DOCKER_IO=docker.io +DOCKER_ORG_JO_MICRO=docker.io/jomicro + +BUILD_MOUNT_FOLDER="~" \ 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..d0c0650 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +[![Build Status](https://drone.fk.jochum.dev/api/badges/jo-micro/geoip/status.svg)](https://drone.fk.jochum.dev/jo-micro/geoip) +[![Software License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg?style=flat-square)](LICENSE) +[![Go Reference](https://pkg.go.dev/badge/jochum.dev/jo-micro/geoip.svg)](https://pkg.go.dev/jochum.dev/jo-micro/geoip) + +# geoip +/ +## Developers corner + +### Build podman/docker image + +#### Prerequesits + +- podman +- [Task](https://taskfile.dev/#/installation) + +#### Build + +```bash +cp .env.sample .env +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..14d1e56 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,112 @@ +version: '3' + +dotenv: [".env"] + +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 + PWD: + sh: echo $PWD + +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-geoip_go 1>/dev/null 2>&1 || podman volume create jo_micro-geoip_go + + builder: + desc: Run something in the builder container for example "task builder -- go get -u ./..." + cmds: + - podman run --rm + -v "{{.BUILD_MOUNT_FOLDER_INT}}:{{.BUILD_MOUNT_FOLDER_INT}}" + -v "{{.PWD}}:/code" + -v "{{.VOLUME_PATH}}:/go:rw" + {{.DOCKER_ORG_JO_MICRO}}/builder:latest {{.CLI_ARGS}} + vars: + VOLUME_PATH: + sh: podman volume inspect jo_micro-geoip_go --format "{{"{{"}}.Mountpoint{{"}}"}}" + BUILD_MOUNT_FOLDER_INT: + sh: realpath {{.BUILD_MOUNT_FOLDER}} + preconditions: + - test -n "{{.CLI_ARGS}}" + + protoc: + run: "once" + desc: Generate protobruf go files + sources: + - ./**/*.proto + cmds: + - task: builder + vars: + CLI_ARGS: /scripts/protoc_gen.sh + + build:podman: + sources: + - ./go.sum + - ./go.work.sum + - ./cmd/microgeoipd/**/*.go + - ./internal/**/*.go + - /*.go + deps: + - protoc + cmds: + - podman build + -v "{{.BUILD_MOUNT_FOLDER_INT}}:{{.BUILD_MOUNT_FOLDER_INT}}" + -v "{{.VOLUME_PATH}}:/go:rw" + --build-arg CACHEBUST={{.DATE}} + --build-arg VERSION={{.VERSION}} + --build-arg=DOCKER_IO={{.DOCKER_IO}} + --build-arg=DOCKER_ORG_JO_MICRO={{.DOCKER_ORG_JO_MICRO}} + -t {{.DOCKER_ORG_JO_MICRO}}/geoip:latest + -f ./docker/geoip/Dockerfile + . + vars: + DATE: + sh: date -u -Iseconds + VOLUME_PATH: + sh: podman volume inspect jo_micro-geoip_go --format "{{"{{"}}.Mountpoint{{"}}"}}" + BUILD_MOUNT_FOLDER_INT: + sh: realpath {{.BUILD_MOUNT_FOLDER}} + + podman: + desc: Generate docker container for jo-micro/geoip tagged as {{.DOCKER_ORG_JO_MICRO}}/geoip:latest + cmds: + - task: build:podman + + 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 + + rm: + desc: Remove all persistent data + cmds: + - podman image rm {{.DOCKER_ORG_JO_MICRO}}/geoip:latest || exit 0 + - podman volume rm jo_micro-geoip_go || exit 0 + - rm -rf $PWD/.task \ No newline at end of file diff --git a/cmd/microgeoipd/config/config.go b/cmd/microgeoipd/config/config.go new file mode 100644 index 0000000..8f1c860 --- /dev/null +++ b/cmd/microgeoipd/config/config.go @@ -0,0 +1,10 @@ +package config + +var ( + Version = "0.0.1-dev0" +) + +const ( + Name = "jo.micro.geoip" + PkgPath = "jochum.dev/jo-micro/auth2" +) diff --git a/cmd/microgeoipd/main.go b/cmd/microgeoipd/main.go new file mode 100644 index 0000000..01c1f25 --- /dev/null +++ b/cmd/microgeoipd/main.go @@ -0,0 +1,50 @@ +package main + +import ( + "github.com/urfave/cli/v2" + "go-micro.dev/v4" + "go-micro.dev/v4/logger" + "jochum.dev/jo-micro/auth2" + jwtClient "jochum.dev/jo-micro/auth2/plugins/client/jwt" + "jochum.dev/jo-micro/components" + "jochum.dev/jo-micro/geoip/cmd/microgeoipd/config" + "jochum.dev/jo-micro/geoip/cmd/microgeoipd/geoiphandler" + "jochum.dev/jo-micro/logruscomponent" + "jochum.dev/jo-micro/router" +) + +func main() { + service := micro.NewService() + cReg := components.New(service, "geoip", logruscomponent.New(), auth2.ClientAuthComponent(), geoiphandler.New(), router.New()) + + auth2ClientReg := auth2.ClientAuthMustReg(cReg) + auth2ClientReg.Register(jwtClient.New()) + + service.Init( + micro.Name(config.Name), + micro.Version(config.Version), + micro.Flags(cReg.AppendFlags([]cli.Flag{})...), + micro.WrapHandler(auth2ClientReg.WrapHandler()), + micro.Action(func(c *cli.Context) error { + // Start/Init the components + if err := cReg.Init(c); err != nil { + logger.Fatal(err) + return err + } + + return nil + }), + ) + + // Run the server + if err := service.Run(); err != nil { + logruscomponent.MustReg(cReg).Logger().Fatal(err) + return + } + + // Stop the components + if err := cReg.Stop(); err != nil { + logger.Fatal(err) + return + } +} diff --git a/cmd/microgeoipd/plugins.go b/cmd/microgeoipd/plugins.go new file mode 100644 index 0000000..15fd8a0 --- /dev/null +++ b/cmd/microgeoipd/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/geoip/Dockerfile b/docker/geoip/Dockerfile new file mode 100644 index 0000000..7436221 --- /dev/null +++ b/docker/geoip/Dockerfile @@ -0,0 +1,31 @@ +ARG DOCKER_IO=docker.io +ARG DOCKER_ORG_JO_MICRO=docker.io/jomicro + +# STEP 1 build executable binary +FROM ${DOCKER_ORG_JO_MICRO}/builder:latest AS builder + +# Create appuser (/etc/passwd entry for the runner container) +RUN useradd appuser + +ARG VERSION +COPY . /code/ +WORKDIR /code + +ARG CACHEBUST=1 +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -installsuffix cgo -ldflags="-w -s -X 'jochum.dev/jo-micro/geoip/internal/config.Version=$VERSION'" -o /usr/local/bin/microgeoipd jochum.dev/jo-micro/geoip/cmd/microgeoipd + +# STEP 2 build a small image +# start from busybox +FROM ${DOCKER_IO}/library/busybox:latest + +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/microgeoipd /usr/local/bin/microgeoipd + +# Run as appuser +USER appuser + +CMD [ "/usr/local/bin/microgeoipd" ] \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..3aa94be --- /dev/null +++ b/go.mod @@ -0,0 +1,84 @@ +module jochum.dev/jo-micro/geoip + +go 1.19 + +require ( + github.com/avast/retry-go/v4 v4.1.0 + github.com/docker/go-units v0.5.0 + github.com/go-micro/plugins/v4/broker/nats v1.1.1-0.20220908125827-e0369dde429b + 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/mholt/archiver/v3 v3.5.1 + github.com/oschwald/geoip2-golang v1.8.0 + github.com/pkg/errors v0.9.1 + github.com/sirupsen/logrus v1.9.0 + 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/auth2 v0.5.5 + jochum.dev/jo-micro/components v0.3.2 + jochum.dev/jo-micro/logruscomponent v0.0.5 + jochum.dev/jo-micro/router v0.4.10 +) + +require ( + github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 // indirect + github.com/acomagu/bufpipe v1.0.3 // indirect + github.com/andybalholm/brotli v1.0.4 // indirect + github.com/bitly/go-simplejson v0.5.0 // indirect + github.com/cloudflare/circl v1.2.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/fsnotify/fsnotify v1.5.4 // 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-micro/plugins/v4/logger/logrus v1.1.0 // 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/golang-jwt/jwt/v4 v4.4.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/handlers v1.5.1 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/compress v1.15.11 // indirect + github.com/klauspost/pgzip v1.2.5 // indirect + github.com/miekg/dns v1.1.50 // indirect + github.com/mitchellh/go-homedir v1.1.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/nwaples/rardecode v1.1.3 // indirect + github.com/nxadm/tail v1.4.8 // indirect + github.com/oschwald/maxminddb-golang v1.10.0 // indirect + github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/pierrec/lz4/v4 v4.1.16 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sergi/go-diff v1.2.0 // indirect + github.com/ulikunitz/xz v0.5.10 // indirect + github.com/xanzy/ssh-agent v0.3.2 // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + golang.org/x/crypto v0.0.0-20220924013350-4ba4fb4dd9e7 // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/net v0.0.0-20220923203811-8be639271d50 // indirect + golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect + golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.12 // indirect + google.golang.org/genproto v0.0.0-20220923205249-dd2d53f1fffc // 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 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e849e96 --- /dev/null +++ b/go.sum @@ -0,0 +1,307 @@ +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/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +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/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +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/v4 v4.1.0 h1:CwudD9anYv6JMVnDuTRlK6kLo4dBamiL+F3U8YDiyfg= +github.com/avast/retry-go/v4 v4.1.0/go.mod h1:HqmLvS2VLdStPCGDFjSuZ9pzlTqVRldCI4w2dO4m1Ms= +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/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/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= +github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= +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/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/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/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/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/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/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/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +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/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/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/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.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo= +github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= +github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +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/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/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= +github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= +github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= +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/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/nats-io/jwt v1.2.2 h1:w3GMTO969dFg+UOKTmmyuu7IGdusK+7Ytlt//OYH/uU= +github.com/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI= +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/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= +github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6SLNcKTs= +github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw= +github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg= +github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0= +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/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.16 h1:kQPfno+wyx6C5572ABwV+Uo3pDFzQ7yhyGchSyRda0c= +github.com/pierrec/lz4/v4 v4.1.16/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrre/gotestcover v0.0.0-20160517101806-924dca7d15f0/go.mod h1:4xpMLz7RBWyB+ElzHu8Llua96TRCB3YwX+l5EP1wmHk= +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/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +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/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/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= +github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +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/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/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +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= +github.com/yuin/goldmark v1.4.0/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-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-20220924013350-4ba4fb4dd9e7 h1:WJywXQVIb56P2kAvXeMGTIgQ1ZHQxR60+F9dLsodECc= +golang.org/x/crypto v0.0.0-20220924013350-4ba4fb4dd9e7/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-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220923203811-8be639271d50 h1:vKyz8L3zkd+xrMeIaBsQ/MNVPVFSffdaU3ZyYlBGFnI= +golang.org/x/net v0.0.0-20220923203811-8be639271d50/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-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc= +golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/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-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-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-20210809222454-d867a43fc93e/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-20211107104306-e0b2ad06fe42/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-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= +golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/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.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +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-20220923205249-dd2d53f1fffc h1:saaNe2+SBQxandnzcD/qB1JEBQ2Pqew+KlFLLdA/XcM= +google.golang.org/genproto v0.0.0-20220923205249-dd2d53f1fffc/go.mod h1:yEEpwVWKMZZzo81NwRgyEJnA2fQvpXAYPVisv8EgDVs= +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-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/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.v3 v3.0.0-20200313102051-9f266ea9e77c/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= +jochum.dev/jo-micro/auth2 v0.5.4 h1:gHF84nYpFBUBYiQy/2411QeRRSlskXkK45+NgNypt5s= +jochum.dev/jo-micro/auth2 v0.5.4/go.mod h1:2tJTA5Hy5/A9XBsaKQuFsSM+ukrSRuJ1uTNU77Rir7A= +jochum.dev/jo-micro/auth2 v0.5.5 h1:M3o8gye0TROScFyyubCyMhd7dvOblcILbmX7hn+YC2A= +jochum.dev/jo-micro/auth2 v0.5.5/go.mod h1:SIgJ4EXjhX/H/IsG6ZGP6+WvJGAFmPCHyHe35TixlBU= +jochum.dev/jo-micro/components v0.3.2 h1:Z6Od76Uh2C2+bKhfZvaDLbry8vWGe4Ie/rDfrObE1pg= +jochum.dev/jo-micro/components v0.3.2/go.mod h1:MXpsIY5Gut4/wDNquiCN+e4zYtATVwn+7uiNKj4nlKk= +jochum.dev/jo-micro/logruscomponent v0.0.4 h1:KkJhLIM0mm2tlk+z+gZdpb5vCeuBs6bhG3bncGhCqoQ= +jochum.dev/jo-micro/logruscomponent v0.0.4/go.mod h1:NVy+eN3Xm2SlzdsQGuC/9/+MwU+8BwxFZuaTprmLguU= +jochum.dev/jo-micro/logruscomponent v0.0.5 h1:ddFOhuxZQefn/T8EF/wwVzKpdaitRkfFNrX7Jf4W3b8= +jochum.dev/jo-micro/logruscomponent v0.0.5/go.mod h1:SODU64v/PBvgA041CHVX16ZZUqqNE9n6g55Zh2e9hEs= +jochum.dev/jo-micro/router v0.4.10 h1:iNnD13iMBX1deBPdmm/1ym/6iA1sTywg4e79PhmTL6w= +jochum.dev/jo-micro/router v0.4.10/go.mod h1:zJFOoZm4S0pTkhQcdT+ohve3zmfal2p6o2N+2kLb/7Y= diff --git a/internal/maxmind/README.md b/internal/maxmind/README.md new file mode 100644 index 0000000..31e5380 --- /dev/null +++ b/internal/maxmind/README.md @@ -0,0 +1,3 @@ +# maxmind + +This package has been stolen from [crazy-max/geoip-updater](https://github.com/crazy-max/geoip-updater/tree/master/pkg/maxmind) which is under the MIT License. \ No newline at end of file diff --git a/internal/maxmind/client.go b/internal/maxmind/client.go new file mode 100644 index 0000000..a129ede --- /dev/null +++ b/internal/maxmind/client.go @@ -0,0 +1,61 @@ +package maxmind + +import ( + "net/http" + "net/url" + "os" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// Client represents an active maxmind object +type Client struct { + http *http.Client + logrus *logrus.Logger + workDir string + downloadDir string + licenseKey string + baseURL string +} + +// Config defines the config for maxmind +type Config struct { + Logrus *logrus.Logger + DownloadDirectory string + LicenseKey string + BaseURL string +} + +// New returns a maxmind client +func New(config Config) (*Client, error) { + if config.LicenseKey == "" { + return nil, errors.New("License key required") + } + + if config.BaseURL == "" { + config.BaseURL = "https://download.maxmind.com" + } + _, err := url.ParseRequestURI(config.BaseURL) + if err != nil { + return nil, errors.Wrap(err, "Invalid base URL") + } + + return &Client{ + http: http.DefaultClient, + logrus: config.Logrus, + workDir: os.TempDir(), + downloadDir: config.DownloadDirectory, + licenseKey: config.LicenseKey, + baseURL: config.BaseURL, + }, nil +} + +// NewDownloader returns a new downloader instance +func (c *Client) NewDownloader(eid EditionID) (*Downloader, error) { + return &Downloader{ + Client: c, + eid: eid, + dlDir: c.downloadDir, + }, nil +} diff --git a/internal/maxmind/downloader.go b/internal/maxmind/downloader.go new file mode 100644 index 0000000..a551f23 --- /dev/null +++ b/internal/maxmind/downloader.go @@ -0,0 +1,207 @@ +package maxmind + +import ( + "fmt" + "io" + "net/http" + "os" + "path" + "path/filepath" + "strings" + + "github.com/docker/go-units" + "github.com/mholt/archiver/v3" + "github.com/pkg/errors" +) + +// Downloader represents an active downloader object +type Downloader struct { + *Client + eid EditionID + dlDir string +} + +// Download downloads a database +func (d *Downloader) Download() ([]os.FileInfo, error) { + // Retrieve expected hash + expHash, err := d.expectedHash() + if err != nil { + return nil, errors.Wrap(err, "Cannot get archive checksum") + } + + // Download DB archive + archive := path.Join(d.workDir, d.eid.Filename()) + if err := d.downloadArchive(expHash, archive); err != nil { + return nil, err + } + + // Create checksum file + checksumFile := path.Join(d.workDir, fmt.Sprintf(".%s.%s", d.eid.Filename(), "sha256")) + if err := createFile(checksumFile, expHash); err != nil { + return nil, errors.Errorf("Cannot create checksum file %s", checksumFile) + } + + // Extract DB from archive + dbs, err := d.extractArchive(archive) + if err != nil { + return nil, err + } + + return dbs, nil +} + +func (d *Downloader) expectedHash() (string, error) { + req, err := http.NewRequest("GET", fmt.Sprintf("%s/app/geoip_download", d.baseURL), nil) + if err != nil { + return "", errors.Wrap(err, "Request failed") + } + + q := req.URL.Query() + q.Add("license_key", d.licenseKey) + q.Add("edition_id", d.eid.String()) + q.Add("suffix", fmt.Sprintf("%s.sha256", d.eid.Suffix().String())) + req.URL.RawQuery = q.Encode() + + res, err := d.http.Do(req) + if err != nil { + return "", err + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + return "", errors.Errorf("Received invalid status code %d", res.StatusCode) + } + + checksum, err := io.ReadAll(res.Body) + if err != nil { + return "", errors.Wrap(err, "Cannot download checksum file") + } + + checksumAr := strings.SplitN(strings.TrimSpace(string(checksum)), " ", 2) + if len(checksumAr[0]) != 64 { + return "", errors.Errorf("Invalid checksum: %s", checksum) + } + + return checksumAr[0], nil +} + +func (d *Downloader) downloadArchive(expHash string, archive string) error { + if _, err := os.Stat(archive); err == nil { + curHash, err := checksumFromFile(archive) + if err != nil { + return errors.Wrap(err, "Cannot get archive checksum") + } + if expHash == curHash { + d.logrus. + WithField("edition_id", d.eid.String()). + WithField("hash", expHash). + Debug("Archive already downloaded and valid. Skipping download") + return nil + } + } + + d.logrus. + WithField("edition_id", d.eid.String()). + WithField("archive", filepath.Base(archive)). + Info("Downloading archive...") + + req, err := http.NewRequest("GET", fmt.Sprintf("%s/app/geoip_download", d.baseURL), nil) + if err != nil { + return errors.Wrap(err, "Request failed") + } + + q := req.URL.Query() + q.Add("license_key", d.licenseKey) + q.Add("edition_id", d.eid.String()) + q.Add("suffix", d.eid.Suffix().String()) + req.URL.RawQuery = q.Encode() + + res, err := d.http.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + return errors.Errorf("Received invalid status code %d", res.StatusCode) + } + + out, err := os.Create(archive) + if err != nil { + return errors.Wrap(err, "Cannot create archive file") + } + defer out.Close() + + _, err = io.Copy(out, res.Body) + if err != nil { + return errors.Wrap(err, "Cannot download archive") + } + + curHash, err := checksumFromFile(archive) + if err != nil { + return errors.Wrap(err, "Cannot get archive checksum") + } + + if expHash != curHash { + return errors.Errorf("Checksum of downloaded archive (%s) does not match the expected one (%s)", curHash, expHash) + } + + return nil +} + +func (d *Downloader) extractArchive(archive string) ([]os.FileInfo, error) { + var dbs []os.FileInfo + err := archiver.Walk(archive, func(f archiver.File) error { + if f.IsDir() { + return nil + } + if filepath.Ext(f.Name()) != ".csv" && filepath.Ext(f.Name()) != ".mmdb" { + return nil + } + + expHash, reader, err := checksumFromReader(f) + if err != nil { + return err + } + + sublog := d.logrus. + WithField("edition_id", d.eid.String()). + WithField("db_name", f.Name()). + WithField("db_size", units.HumanSize(float64(f.Size()))). + WithField("db_modtime", f.ModTime()). + WithField("db_hash", expHash) + + dbpath := path.Join(d.dlDir, f.Name()) + if fileExists(dbpath) { + curHash, err := checksumFromFile(dbpath) + if err != nil { + return err + } + if expHash == curHash { + sublog.Debug("Database is already up to date") + return nil + } + } + + sublog.Debug("Extracting database") + dbfile, err := os.Create(dbpath) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("Cannot create database file %s", f.Name())) + } + defer dbfile.Close() + + _, err = io.Copy(dbfile, reader) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("Cannot extract database file %s", f.Name())) + } + + if err = os.Chtimes(dbpath, f.ModTime(), f.ModTime()); err != nil { + sublog.WithField("error", err).Warn("Cannot preserve modtime of database file") + } + + dbs = append(dbs, f) + return nil + }) + + return dbs, err +} diff --git a/internal/maxmind/editionid.go b/internal/maxmind/editionid.go new file mode 100644 index 0000000..5a55a39 --- /dev/null +++ b/internal/maxmind/editionid.go @@ -0,0 +1,80 @@ +package maxmind + +import ( + "fmt" +) + +// Suffix represents the suffix of a database +type Suffix string + +// Suffix enum +const ( + SfxTarGz = Suffix("tar.gz") + SfxZip = Suffix("zip") +) + +// String returns the string representation of a suffix +func (sfx Suffix) String() string { + return string(sfx) +} + +// EditionID represents the edition ID of a database +type EditionID string + +// Edition ID enum +const ( + EIDGeoLite2ASN = EditionID("GeoLite2-ASN") + EIDGeoLite2ASNCSV = EditionID("GeoLite2-ASN-CSV") + EIDGeoLite2City = EditionID("GeoLite2-City") + EIDGeoLite2CityCSV = EditionID("GeoLite2-City-CSV") + EIDGeoLite2Country = EditionID("GeoLite2-Country") + EIDGeoLite2CountryCSV = EditionID("GeoLite2-Country-CSV") +) + +// GetEditionID returns an edition ID from string +func GetEditionID(eidStr string) (EditionID, error) { + eids := []EditionID{ + EIDGeoLite2ASN, + EIDGeoLite2ASNCSV, + EIDGeoLite2City, + EIDGeoLite2CityCSV, + EIDGeoLite2Country, + EIDGeoLite2CountryCSV, + } + for _, eid := range eids { + if EditionID(eidStr) == eid { + return eid, nil + } + } + return "", fmt.Errorf("invalid edition ID: %s", eidStr) +} + +// Suffix returns the suffix linked of an edition ID +func (eid EditionID) Suffix() Suffix { + switch eid { + case EIDGeoLite2ASN: + return SfxTarGz + case EIDGeoLite2ASNCSV: + return SfxZip + case EIDGeoLite2City: + return SfxTarGz + case EIDGeoLite2CityCSV: + return SfxZip + case EIDGeoLite2Country: + return SfxTarGz + case EIDGeoLite2CountryCSV: + return SfxZip + default: + return "" + } +} + +// Filename returns the filename of an edition ID +func (eid EditionID) Filename() string { + return fmt.Sprintf("%s.%s", eid.String(), eid.Suffix().String()) +} + +// String returns the string representation of an edition ID +func (eid EditionID) String() string { + return string(eid) +} diff --git a/internal/maxmind/util.go b/internal/maxmind/util.go new file mode 100644 index 0000000..8a62771 --- /dev/null +++ b/internal/maxmind/util.go @@ -0,0 +1,58 @@ +package maxmind + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "io" + "os" +) + +func checksumFromFile(filename string) (string, error) { + file, err := os.Open(filename) + if err != nil { + return "", err + } + defer file.Close() + + hash := sha256.New() + if _, err := io.Copy(hash, file); err != nil { + return "", err + } + + return hex.EncodeToString(hash.Sum(nil)), nil +} + +func checksumFromReader(reader io.Reader) (string, io.Reader, error) { + var b bytes.Buffer + + hash := sha256.New() + if _, err := io.Copy(&b, io.TeeReader(reader, hash)); err != nil { + return "", nil, err + } + + return hex.EncodeToString(hash.Sum(nil)), &b, nil +} + +func createFile(path string, content string) error { + file, err := os.Create(path) + if err != nil { + return err + } + defer file.Close() + if _, err = file.WriteString(content); err != nil { + return err + } + if err = file.Sync(); err != nil { + return err + } + return nil +} + +func fileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} diff --git a/proto/geoippb/geoippb.proto b/proto/geoippb/geoippb.proto new file mode 100644 index 0000000..b27e572 --- /dev/null +++ b/proto/geoippb/geoippb.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package geoippb; + +option go_package = "jochum.dev/jo-micro/geoip/proto/geoippb;geoippb"; + +service GeoIPService { + rpc Country(IpRequest) returns (CountryResponse) {} + rpc City(IpRequest) returns (CityResponse) {} +} + +message IpRequest { + string ip = 1; + repeated string languages = 2; // Optional + string commaLanguages = 3; // Optional for url requests +} + +message CountryResponse { + string isoCode = 1; + map countryName = 2; +} + +message CityResponse { + string isoCode = 1; + string timeZone = 2; + map cityName = 3; + map countryName = 4; + double latitude = 5; + double longitude = 6; +} \ No newline at end of file