From 1d0bde6644da84e0c7c6473cc6dac6c5024de317 Mon Sep 17 00:00:00 2001 From: Marc Ole Bulling Date: Tue, 21 Nov 2023 20:50:30 +0100 Subject: [PATCH] Changed to sqlite, dropped Windows 32bit support, fixed data dir env not being persistant #115, updated readme --- .github/workflows/test-code.yml | 11 +- README.md | 2 +- build/entrypoint.sh | 2 +- build/go.mod | 49 +- build/go.sum | 32 ++ cmd/databasereader/Main.go | 51 -- cmd/databasereader/Main_test.go | 43 -- cmd/gokapi/Main.go | 2 +- docs/advanced.rst | 4 + docs/index.rst | 2 +- docs/setup.rst | 4 +- go.mod | 49 +- go.sum | 186 +++---- internal/configuration/Configuration.go | 2 +- .../configuration/configupgrade/Upgrade.go | 104 ++-- .../configupgrade/Upgrade_test.go | 13 +- internal/configuration/database/Database.go | 459 ++++-------------- .../configuration/database/Database_test.go | 138 ++++-- internal/configuration/database/apikeys.go | 80 +++ internal/configuration/database/e2econfig.go | 64 +++ internal/configuration/database/hotlinks.go | 47 ++ .../database/legacydb/Database.go | 350 +++++++++++++ .../database/legacydb/Database_test.go | 199 ++++++++ internal/configuration/database/metadata.go | 165 +++++++ internal/configuration/database/sessions.go | 65 +++ .../configuration/database/uploaddefaults.go | 69 +++ .../configuration/database/uploadstatus.go | 63 +++ internal/environment/Environment.go | 24 +- internal/environment/Environment_test.go | 2 +- internal/models/UploadStatus.go | 11 +- internal/storage/FileServing.go | 2 +- .../testconfiguration/TestConfiguration.go | 68 +-- .../TestConfiguration_test.go | 2 +- internal/webserver/api/Api.go | 6 +- .../sessionmanager/SessionManager.go | 2 +- .../sessionmanager/SessionManager_test.go | 2 +- .../web/templates/string_constants.tmpl | 2 +- 37 files changed, 1622 insertions(+), 754 deletions(-) delete mode 100644 cmd/databasereader/Main.go delete mode 100644 cmd/databasereader/Main_test.go create mode 100644 internal/configuration/database/apikeys.go create mode 100644 internal/configuration/database/e2econfig.go create mode 100644 internal/configuration/database/hotlinks.go create mode 100644 internal/configuration/database/legacydb/Database.go create mode 100644 internal/configuration/database/legacydb/Database_test.go create mode 100644 internal/configuration/database/metadata.go create mode 100644 internal/configuration/database/sessions.go create mode 100644 internal/configuration/database/uploaddefaults.go create mode 100644 internal/configuration/database/uploadstatus.go diff --git a/.github/workflows/test-code.yml b/.github/workflows/test-code.yml index 95a81df..62e0639 100644 --- a/.github/workflows/test-code.yml +++ b/.github/workflows/test-code.yml @@ -13,11 +13,8 @@ jobs: with: go-version: '^1.20' - run: go generate ./... - - run: go test ./... -parallel 8 --tags=test,awsmock - - run: go clean -testcache - - run: go test ./... -parallel 8 --tags=test,noaws - - run: go clean -testcache - - run: go test ./... --tags=test,noaws,integration - - run: go clean -testcache - - run: GOKAPI_AWS_BUCKET="gokapi" GOKAPI_AWS_REGION="eu-central-1" GOKAPI_AWS_KEY="keyid" GOKAPI_AWS_KEY_SECRET="secret" go test ./... --tags=test,awstest + - run: go test ./... -parallel 8 -count=1 --tags=test,awsmock + - run: go test ./... -parallel 8 -count=1 --tags=test,noaws + - run: go test ./... --tags=test,noaws,integration -count=1 + - run: GOKAPI_AWS_BUCKET="gokapi" GOKAPI_AWS_REGION="eu-central-1" GOKAPI_AWS_KEY="keyid" GOKAPI_AWS_KEY_SECRET="secret" go test ./... --tags=test,awstest -count=1 diff --git a/README.md b/README.md index ed6f6ed..ef3a041 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Gokapi [![Documentation Status](https://readthedocs.org/projects/gokapi/badge/?version=latest)](https://gokapi.readthedocs.io/en/stable/?badge=stable) [![Go Report Card](https://goreportcard.com/badge/github.com/forceu/gokapi)](https://goreportcard.com/report/github.com/forceu/gokapi) -![gopherbadger-tag-do-not-edit](https://img.shields.io/badge/Go%20Coverage-87%25-brightgreen.svg?longCache=true&style=flat) +![gopherbadger-tag-do-not-edit](https://img.shields.io/badge/Go%20Coverage-83%25-brightgreen.svg?longCache=true&style=flat) [![Docker Pulls](https://img.shields.io/docker/pulls/f0rc3/gokapi.svg)](https://hub.docker.com/r/f0rc3/gokapi/) diff --git a/build/entrypoint.sh b/build/entrypoint.sh index ff03319..545fab3 100755 --- a/build/entrypoint.sh +++ b/build/entrypoint.sh @@ -2,7 +2,7 @@ set -e -targets=${@-"darwin/amd64 darwin/arm64 linux/amd64 linux/386 linux/arm linux/arm64 windows/amd64 windows/386"} +targets=${@-"darwin/amd64 darwin/arm64 linux/amd64 linux/386 linux/arm linux/arm64 windows/amd64"} cd /usr/src/myapp go generate ./... diff --git a/build/go.mod b/build/go.mod index 18aab9b..db51bd8 100644 --- a/build/go.mod +++ b/build/go.mod @@ -5,45 +5,58 @@ go 1.20 require ( git.mills.io/prologic/bitcask v1.0.2 github.com/NYTimes/gziphandler v1.1.1 - github.com/aws/aws-sdk-go v1.45.24 + github.com/aws/aws-sdk-go v1.48.2 github.com/caarlos0/env/v6 v6.10.1 - github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf github.com/jinzhu/copier v0.4.0 - github.com/johannesboyne/gofakes3 v0.0.0-20210415062230-4b6b67a85d38 + github.com/johannesboyne/gofakes3 v0.0.0-20230914150226-f005f5cc03aa github.com/juju/ratelimit v1.0.2 github.com/r3labs/sse/v2 v2.10.0 github.com/secure-io/sio-go v0.3.1 - golang.org/x/crypto v0.14.0 - golang.org/x/oauth2 v0.13.0 - golang.org/x/sync v0.4.0 - golang.org/x/term v0.13.0 + github.com/tdewolff/minify/v2 v2.20.7 + github.com/tdewolff/parse/v2 v2.7.5 + golang.org/x/crypto v0.15.0 + golang.org/x/oauth2 v0.14.0 + golang.org/x/sync v0.5.0 + golang.org/x/term v0.14.0 gopkg.in/yaml.v3 v3.0.1 + modernc.org/sqlite v1.27.0 ) require ( - git.sr.ht/~shabbyrobe/gocovmerge v0.0.0-20180507124511-f6ea450bfb63 // indirect github.com/abcum/lcp v0.0.0-20201209214815-7a3f3840be81 // indirect - github.com/go-jose/go-jose/v3 v3.0.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/go-jose/go-jose/v3 v3.0.1 // indirect github.com/gofrs/flock v0.8.1 // indirect + github.com/google/uuid v1.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/kr/pretty v0.2.1 // indirect - github.com/kr/text v0.1.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-sqlite3 v1.14.18 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/plar/go-adaptive-radix-tree v1.0.5 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/tdewolff/minify/v2 v2.12.5 // indirect - github.com/tdewolff/parse/v2 v2.6.5 // indirect - golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.18.0 // indirect + golang.org/x/tools v0.15.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + lukechampine.com/uint128 v1.3.0 // indirect + modernc.org/cc/v3 v3.41.0 // indirect + modernc.org/ccgo/v3 v3.16.15 // indirect + modernc.org/libc v1.34.9 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.7.2 // indirect + modernc.org/opt v0.1.3 // indirect + modernc.org/strutil v1.2.0 // indirect + modernc.org/token v1.1.0 // indirect ) require ( - github.com/coreos/go-oidc/v3 v3.6.0 - golang.org/x/sys v0.13.0 // indirect + github.com/coreos/go-oidc/v3 v3.7.0 + golang.org/x/sys v0.14.0 // indirect ) diff --git a/build/go.sum b/build/go.sum index 334cdd2..177c246 100644 --- a/build/go.sum +++ b/build/go.sum @@ -54,7 +54,9 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go v1.17.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.44.233/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.256/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go v1.45.24/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.48.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -74,6 +76,7 @@ github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-oidc/v3 v3.5.0/go.mod h1:ecXRtV4romGPeO6ieExAsUK9cb/3fp9hXNz1tlv8PIM= github.com/coreos/go-oidc/v3 v3.6.0/go.mod h1:ZpHUsHBucTUj6WOkrP4E20UPynbLZzhTQ1XKCXkxyPc= +github.com/coreos/go-oidc/v3 v3.7.0/go.mod h1:yQzSCqBnK3e6Fs5l+f5i0F8Kwf0zpH9bPEsbY00KanM= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -102,6 +105,7 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -213,6 +217,7 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/johannesboyne/gofakes3 v0.0.0-20210415062230-4b6b67a85d38/go.mod h1:Zj9d90chLFOXPNj/m+HfCAFx1s8zSue9HiqC/hbHLS0= +github.com/johannesboyne/gofakes3 v0.0.0-20230914150226-f005f5cc03aa/go.mod h1:AxgWC4DDX54O2WDoQO1Ceabtn6IbktjU/7bigor+66g= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -235,6 +240,7 @@ github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -282,6 +288,7 @@ github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5P github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/secure-io/sio-go v0.3.1/go.mod h1:+xbkjDzPjwh4Axd07pRKSNriS9SCiYksWnZqdnfpQxs= github.com/shabbyrobe/gocovmerge v0.0.0-20180507124511-f6ea450bfb63/go.mod h1:n+VKSARF5y/tS9XFSP7vWDfS+GUC5vs/YT7M5XDTUEM= +github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500/go.mod h1:+njLrG5wSeoG4Ds61rFgEzKvenR2UHbjMoDHsczxly0= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= @@ -321,10 +328,13 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tdewolff/minify/v2 v2.12.5 h1:s2KDBt/D/3ayE3gcqQF8VIgTmYgkx+btuLvVAeePzZM= github.com/tdewolff/minify/v2 v2.12.5/go.mod h1:i8QXtVyL7Ddwc4I5gqzvgBqKlTMgMNTbiXaPO4Iqg+A= +github.com/tdewolff/minify/v2 v2.20.7/go.mod h1:bj2NpP3zoUhsPzE4oM4JYwuUyVCU/uMaCYZ6/riEjIo= github.com/tdewolff/parse/v2 v2.6.5 h1:lYvWBk55GkqKl0JJenGpmrgu/cPHQQ6/Mm1hBGswoGQ= github.com/tdewolff/parse/v2 v2.6.5/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs= +github.com/tdewolff/parse/v2 v2.7.5/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= github.com/tdewolff/test v1.0.7 h1:8Vs0142DmPFW/bQeHRP3MV19m1gvndjUb1sn8yy74LM= github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tidwall/btree v0.4.2/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/redcon v1.4.1/go.mod h1:XwNPFbJ4ShWNNSA2Jazhbdje6jegTCcwFR6mfaADvHA= @@ -369,6 +379,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -382,6 +393,7 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk golang.org/x/exp v0.0.0-20200228211341-fcea875c7e85/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -408,6 +420,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -453,8 +467,11 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -470,6 +487,7 @@ golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -482,7 +500,9 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -535,14 +555,20 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -554,6 +580,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -573,6 +601,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190829051458-42f498d34c4d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -612,7 +641,10 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= 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= diff --git a/cmd/databasereader/Main.go b/cmd/databasereader/Main.go deleted file mode 100644 index fd1657d..0000000 --- a/cmd/databasereader/Main.go +++ /dev/null @@ -1,51 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "github.com/forceu/gokapi/internal/configuration/database" - "github.com/forceu/gokapi/internal/helper" - "log" - "os" -) - -func main() { - if !correctArgs() { - showUsageAndExit() - return - } - path := os.Args[1] - database.Init(path) - metadata := database.GetAllMetadata() - for _, file := range metadata { - result, err := json.MarshalIndent(file, "", " ") - if err != nil { - log.Fatal("Error encoding file: ", err) - } - fmt.Println(string(result)) - fmt.Println() - } -} - -func correctArgs() bool { - if len(os.Args) < 2 { - return false - } - path := os.Args[1] - if path == "" { - return false - } - if !helper.FolderExists(path) { - fmt.Println("Error: Folder does not exist: " + path) - return false - } - return true -} - -func showUsageAndExit() { - fmt.Println("Usage: ./databasereader /path/to/database") - osExit(1) - return -} - -var osExit = os.Exit diff --git a/cmd/databasereader/Main_test.go b/cmd/databasereader/Main_test.go deleted file mode 100644 index 8a9f5ad..0000000 --- a/cmd/databasereader/Main_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "github.com/forceu/gokapi/internal/test" - "github.com/forceu/gokapi/internal/test/testconfiguration" - "os" - "testing" -) - -func TestMain(m *testing.M) { - testconfiguration.Create(false) - exitVal := m.Run() - testconfiguration.Delete() - os.Exit(exitVal) -} - -func TestRun(t *testing.T) { - originalArgs := os.Args - hasExited := false - osExit = func(code int) { - hasExited = true - } - os.Args = []string{os.Args[0]} - main() - test.IsEqualBool(t, hasExited, true) - hasExited = false - - os.Args = append(os.Args, "") - main() - test.IsEqualBool(t, hasExited, true) - hasExited = false - - os.Args[1] = "invalidFolder" - main() - test.IsEqualBool(t, hasExited, true) - hasExited = false - - os.Args[1] = "./test/filestorage.db" - main() - test.IsEqualBool(t, hasExited, false) - - os.Args = originalArgs -} diff --git a/cmd/gokapi/Main.go b/cmd/gokapi/Main.go index 6bcbc9b..332b258 100644 --- a/cmd/gokapi/Main.go +++ b/cmd/gokapi/Main.go @@ -31,7 +31,7 @@ import ( // versionGokapi is the current version in readable form. // Other version numbers can be modified in /build/go-generate/updateVersionNumbers.go -const versionGokapi = "1.7.2" +const versionGokapi = "1.8.0beta1" // The following calls update the version numbers, update documentation, minify Js/CSS and build the WASM modules //go:generate go run "../../build/go-generate/updateVersionNumbers.go" diff --git a/docs/advanced.rst b/docs/advanced.rst index 3810c6d..6ee409f 100644 --- a/docs/advanced.rst +++ b/docs/advanced.rst @@ -66,16 +66,20 @@ Available environment variables +--------------------------+------------------------------------------------------------------------------+-------------+-----------------------------+ | GOKAPI_DATA_DIR | Sets the directory for the data | Yes | data | +--------------------------+------------------------------------------------------------------------------+-------------+-----------------------------+ +| GOKAPI_DB_NAME | Sets the name for the database file | No | gokapi.sqlite | ++--------------------------+------------------------------------------------------------------------------+-------------+-----------------------------+ | GOKAPI_LENGTH_ID | Sets the length of the download IDs. Value needs to be 5 or more | Yes | 15 | +--------------------------+------------------------------------------------------------------------------+-------------+-----------------------------+ | GOKAPI_MAX_FILESIZE | Sets the maximum allowed file size in MB | Yes | 102400 (100GB) | +--------------------------+------------------------------------------------------------------------------+-------------+-----------------------------+ | GOKAPI_MAX_MEMORY_UPLOAD | Sets the amount of RAM in MB that can be allocated for an upload. | Yes | 20 | +| | | | | | | Any upload with a size greater than that will be written to a temporary file | | | +--------------------------+------------------------------------------------------------------------------+-------------+-----------------------------+ | GOKAPI_PORT | Sets the webserver port | Yes | 53842 | +--------------------------+------------------------------------------------------------------------------+-------------+-----------------------------+ | TMPDIR | Sets the path which contains temporary files | No | Non-Docker: Default OS path | +| | | | | | | | | Docker: [DATA_DIR] | +--------------------------+------------------------------------------------------------------------------+-------------+-----------------------------+ diff --git a/docs/index.rst b/docs/index.rst index 0d3b425..1180a3c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -7,7 +7,7 @@ Gokapi is a lightweight server to share files, which expire after a set amount o This enables companies or individuals to share their files very easily and having them removed afterwards, therefore saving disk space and having control over who downloads the file from the server. -Identical files will be deduplicated. An API is available to interact with Gokapi. AWS S3 and Backblaze B2 can be used instead of local storage. Customization is very easy with HTML/CSS knowledge. +Identical files will be deduplicated. An API is available to interact with Gokapi. AWS S3 compatible storage can be used instead of local storage. Customization is very easy with HTML/CSS knowledge. Contents diff --git a/docs/setup.rst b/docs/setup.rst index 3785155..e68a03b 100644 --- a/docs/setup.rst +++ b/docs/setup.rst @@ -72,7 +72,7 @@ To start the container, run the following command: :: docker run -v gokapi-data:/app/data -v gokapi-config:/app/config -p 127.0.0.1:53842:53842 f0rc3/gokapi:latest -With the argument ``-p 127.0.0.1:53842:53842`` the service will only be accessible from the machine it is running on. In most usecases you will use a reverse proxy for SSL - if you want to make the service available to other computers in the network without a reverse proxy, replace the argument with ``-p 53842:53842``. Please note, unless you select SSL during the setup, the traffic will not be encrypted that way and data like passwords and transferred files can easily be read by third parties! +With the argument ``-p 127.0.0.1:53842:53842`` the service will only be accessible from the machine it is running on. In most usecases you will use a reverse proxy for SSL - if you want to make the service available to other computers in the network without a reverse proxy, replace the argument with ``-p 53842:53842``. Please note, unless you select SSL during the setup, the traffic will not be encrypted that way and data like passwords or transferred files can easily be read by third parties! Initial Setup @@ -206,7 +206,7 @@ Encryption *Warning: Encryption has not been audited.* -There are three different encryption levels, level 1 encrypts only local files and level 2 encrypts local and files stored on cloud storage (e.g. AWS S3). Decryption of files on remote storage is done client-side, for which a 2MB library needs to be downloaded on first visit. End-to-End encryption (level 3) encrypts the files client-side, therefore even if the Gokapi server has been compromised, no data should leak to the attacker. +There are three different encryption levels, level 1 encrypts only local files and level 2 encrypts local and files stored on cloud storage (e.g. AWS S3). Decryption of files on remote storage is done client-side, for which a 2MB library needs to be downloaded on first visit. End-to-End encryption (level 3) encrypts the files client-side, therefore even if the Gokapi server has been compromised, no data should leak to the attacker. If the decryption is done client-side, the dowload on mobile devices may be significantly slower. There are some drawbacks of using encryption: diff --git a/go.mod b/go.mod index 18aab9b..db51bd8 100644 --- a/go.mod +++ b/go.mod @@ -5,45 +5,58 @@ go 1.20 require ( git.mills.io/prologic/bitcask v1.0.2 github.com/NYTimes/gziphandler v1.1.1 - github.com/aws/aws-sdk-go v1.45.24 + github.com/aws/aws-sdk-go v1.48.2 github.com/caarlos0/env/v6 v6.10.1 - github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf github.com/jinzhu/copier v0.4.0 - github.com/johannesboyne/gofakes3 v0.0.0-20210415062230-4b6b67a85d38 + github.com/johannesboyne/gofakes3 v0.0.0-20230914150226-f005f5cc03aa github.com/juju/ratelimit v1.0.2 github.com/r3labs/sse/v2 v2.10.0 github.com/secure-io/sio-go v0.3.1 - golang.org/x/crypto v0.14.0 - golang.org/x/oauth2 v0.13.0 - golang.org/x/sync v0.4.0 - golang.org/x/term v0.13.0 + github.com/tdewolff/minify/v2 v2.20.7 + github.com/tdewolff/parse/v2 v2.7.5 + golang.org/x/crypto v0.15.0 + golang.org/x/oauth2 v0.14.0 + golang.org/x/sync v0.5.0 + golang.org/x/term v0.14.0 gopkg.in/yaml.v3 v3.0.1 + modernc.org/sqlite v1.27.0 ) require ( - git.sr.ht/~shabbyrobe/gocovmerge v0.0.0-20180507124511-f6ea450bfb63 // indirect github.com/abcum/lcp v0.0.0-20201209214815-7a3f3840be81 // indirect - github.com/go-jose/go-jose/v3 v3.0.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/go-jose/go-jose/v3 v3.0.1 // indirect github.com/gofrs/flock v0.8.1 // indirect + github.com/google/uuid v1.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/kr/pretty v0.2.1 // indirect - github.com/kr/text v0.1.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-sqlite3 v1.14.18 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/plar/go-adaptive-radix-tree v1.0.5 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/tdewolff/minify/v2 v2.12.5 // indirect - github.com/tdewolff/parse/v2 v2.6.5 // indirect - golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.18.0 // indirect + golang.org/x/tools v0.15.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + lukechampine.com/uint128 v1.3.0 // indirect + modernc.org/cc/v3 v3.41.0 // indirect + modernc.org/ccgo/v3 v3.16.15 // indirect + modernc.org/libc v1.34.9 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.7.2 // indirect + modernc.org/opt v0.1.3 // indirect + modernc.org/strutil v1.2.0 // indirect + modernc.org/token v1.1.0 // indirect ) require ( - github.com/coreos/go-oidc/v3 v3.6.0 - golang.org/x/sys v0.13.0 // indirect + github.com/coreos/go-oidc/v3 v3.7.0 + golang.org/x/sys v0.14.0 // indirect ) diff --git a/go.sum b/go.sum index c6b735b..4529f20 100644 --- a/go.sum +++ b/go.sum @@ -24,7 +24,6 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= @@ -40,7 +39,6 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= git.mills.io/prologic/bitcask v1.0.2 h1:Iy9x3mVVd1fB+SWY0LTmsSDPGbzMrd7zCZPKbsb/tDA= git.mills.io/prologic/bitcask v1.0.2/go.mod h1:ppXpR3haeYrijyJDleAkSGH3p90w6sIHxEA/7UHMxH4= -git.sr.ht/~shabbyrobe/gocovmerge v0.0.0-20180507124511-f6ea450bfb63/go.mod h1:7YhY1ru/6vTScuHp4NpcCVCUIyfTdPK7+h4NaJohCCk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= @@ -55,11 +53,11 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.17.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.44.233 h1:KB3p/yL32oG/aF4Ld0Ui9CU0tdezvhX6Xdqpb8vyP3U= -github.com/aws/aws-sdk-go v1.44.233/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/aws-sdk-go v1.45.24 h1:TZx/CizkmCQn8Rtsb11iLYutEQVGK5PK9wAhwouELBo= -github.com/aws/aws-sdk-go v1.45.24/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.256/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.48.0 h1:1SeJ8agckRDQvnSCt1dGZYAwUaoD2Ixj6IaXB4LCv8Q= +github.com/aws/aws-sdk-go v1.48.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go v1.48.2 h1:Lf7+Y4WmHB0AQLRQZA46diSwDa+LWbwY6IGaYoCVtTc= +github.com/aws/aws-sdk-go v1.48.2/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -68,7 +66,6 @@ github.com/caarlos0/env/v6 v6.10.1 h1:t1mPSxNpei6M5yAeu1qtRdPAK29Nbcf/n3G7x+b3/I github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -78,10 +75,8 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-oidc/v3 v3.5.0 h1:VxKtbccHZxs8juq7RdJntSqtXFtde9YpNpGn0yqgEHw= -github.com/coreos/go-oidc/v3 v3.5.0/go.mod h1:ecXRtV4romGPeO6ieExAsUK9cb/3fp9hXNz1tlv8PIM= -github.com/coreos/go-oidc/v3 v3.6.0 h1:AKVxfYw1Gmkn/w96z0DbT/B/xFnzTd3MkZvWLjF4n/o= -github.com/coreos/go-oidc/v3 v3.6.0/go.mod h1:ZpHUsHBucTUj6WOkrP4E20UPynbLZzhTQ1XKCXkxyPc= +github.com/coreos/go-oidc/v3 v3.7.0 h1:FTdj0uexT4diYIPlF4yoFVI5MRO1r5+SEcIpEw9vC0o= +github.com/coreos/go-oidc/v3 v3.7.0/go.mod h1:yQzSCqBnK3e6Fs5l+f5i0F8Kwf0zpH9bPEsbY00KanM= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -93,7 +88,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -105,13 +100,12 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= -github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= +github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -168,8 +162,6 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -186,8 +178,13 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -221,19 +218,14 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s= -github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= -github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= -github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/johannesboyne/gofakes3 v0.0.0-20210415062230-4b6b67a85d38 h1:RzxIE+fiv4JCG5pPjTLWdegsdoDCQHZEE+ByYC49Y0Y= -github.com/johannesboyne/gofakes3 v0.0.0-20210415062230-4b6b67a85d38/go.mod h1:Zj9d90chLFOXPNj/m+HfCAFx1s8zSue9HiqC/hbHLS0= +github.com/johannesboyne/gofakes3 v0.0.0-20230914150226-f005f5cc03aa h1:a6Hc6Hlq6MxPNBW53/S/HnVwVXKc0nbdD/vgnQYuxG0= +github.com/johannesboyne/gofakes3 v0.0.0-20230914150226-f005f5cc03aa/go.mod h1:AxgWC4DDX54O2WDoQO1Ceabtn6IbktjU/7bigor+66g= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -243,13 +235,14 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI= github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -258,9 +251,14 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +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/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI= +github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -303,6 +301,8 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0= github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -313,13 +313,11 @@ github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5P github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/secure-io/sio-go v0.3.1 h1:dNvY9awjabXTYGsTF1PiCySl9Ltofk9GA3VdWlo7rRc= github.com/secure-io/sio-go v0.3.1/go.mod h1:+xbkjDzPjwh4Axd07pRKSNriS9SCiYksWnZqdnfpQxs= -github.com/shabbyrobe/gocovmerge v0.0.0-20180507124511-f6ea450bfb63 h1:J6qvD6rbmOil46orKqJaRPG+zTpoGlBTUdyv8ki63L0= -github.com/shabbyrobe/gocovmerge v0.0.0-20180507124511-f6ea450bfb63/go.mod h1:n+VKSARF5y/tS9XFSP7vWDfS+GUC5vs/YT7M5XDTUEM= +github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500 h1:WnNuhiq+FOY3jNj6JXFT+eLN3CQ/oPIsDPRanvwsmbI= +github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500/go.mod h1:+njLrG5wSeoG4Ds61rFgEzKvenR2UHbjMoDHsczxly0= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.8.1/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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -358,11 +356,11 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tdewolff/minify/v2 v2.12.5 h1:s2KDBt/D/3ayE3gcqQF8VIgTmYgkx+btuLvVAeePzZM= -github.com/tdewolff/minify/v2 v2.12.5/go.mod h1:i8QXtVyL7Ddwc4I5gqzvgBqKlTMgMNTbiXaPO4Iqg+A= -github.com/tdewolff/parse/v2 v2.6.5 h1:lYvWBk55GkqKl0JJenGpmrgu/cPHQQ6/Mm1hBGswoGQ= -github.com/tdewolff/parse/v2 v2.6.5/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs= -github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/tdewolff/minify/v2 v2.20.7 h1:NUkuzJ9dvQUNJjSdmmrfELa/ZpnMdyMR/ZKU2bw7N/E= +github.com/tdewolff/minify/v2 v2.20.7/go.mod h1:bj2NpP3zoUhsPzE4oM4JYwuUyVCU/uMaCYZ6/riEjIo= +github.com/tdewolff/parse/v2 v2.7.5 h1:RdcN3Ja6zAMSvnxxO047xRoWexX3RrXKi3H6EQHzXto= +github.com/tdewolff/parse/v2 v2.7.5/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= +github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tidwall/btree v0.4.2/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/redcon v1.4.1/go.mod h1:XwNPFbJ4ShWNNSA2Jazhbdje6jegTCcwFR6mfaADvHA= @@ -405,10 +403,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -420,10 +416,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200228211341-fcea875c7e85/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -450,6 +444,10 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -458,7 +456,6 @@ golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190310074541-c10a0554eabf/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -493,12 +490,10 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -511,11 +506,8 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= -golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= +golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -527,10 +519,10 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -580,21 +572,20 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -605,9 +596,9 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -615,7 +606,6 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190308174544-00c44ba9c14f/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -627,6 +617,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190829051458-42f498d34c4d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -665,10 +656,10 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= 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= @@ -701,7 +692,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= @@ -779,9 +769,6 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -789,8 +776,6 @@ gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI= 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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= @@ -815,6 +800,41 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= +lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= +modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= +modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= +modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y= +modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= +modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= +modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI= +modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= +modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= +modernc.org/libc v1.29.0 h1:tTFRFq69YKCF2QyGNuRUQxKBm1uZZLubf6Cjh/pVHXs= +modernc.org/libc v1.29.0/go.mod h1:DaG/4Q3LRRdqpiLyP0C2m1B8ZMGkQ+cCgOIjEtQlYhQ= +modernc.org/libc v1.34.9 h1:yhQGs5jsWHJIU7jY6nCe8GJw27j+z6xYi0eorwPpGgI= +modernc.org/libc v1.34.9/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.27.0 h1:MpKAHoyYB7xqcwnUwkuD+npwEa0fojF0B5QRbN+auJ8= +modernc.org/sqlite v1.27.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= +modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= +modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= +modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/internal/configuration/Configuration.go b/internal/configuration/Configuration.go index 40c1676..b28b969 100644 --- a/internal/configuration/Configuration.go +++ b/internal/configuration/Configuration.go @@ -52,7 +52,7 @@ func Load() { err = decoder.Decode(&serverSettings) helper.Check(err) file.Close() - database.Init(Environment.FileDbPath) + database.Init(serverSettings.DataDir, Environment.DatabaseName) if configupgrade.DoUpgrade(&serverSettings, &Environment) { save() } diff --git a/internal/configuration/configupgrade/Upgrade.go b/internal/configuration/configupgrade/Upgrade.go index a22bd07..4510735 100644 --- a/internal/configuration/configupgrade/Upgrade.go +++ b/internal/configuration/configupgrade/Upgrade.go @@ -1,22 +1,16 @@ package configupgrade import ( - "bytes" - "encoding/gob" "fmt" "github.com/forceu/gokapi/internal/configuration/database" + "github.com/forceu/gokapi/internal/configuration/database/legacydb" "github.com/forceu/gokapi/internal/environment" - "github.com/forceu/gokapi/internal/helper" "github.com/forceu/gokapi/internal/models" - "github.com/inhies/go-bytesize" - "github.com/jinzhu/copier" "os" - "strconv" - "strings" ) // CurrentConfigVersion is the version of the configuration structure. Used for upgrading -const CurrentConfigVersion = 14 +const CurrentConfigVersion = 15 // DoUpgrade checks if an old version is present and updates it to the current version if required func DoUpgrade(settings *models.Configuration, env *environment.Environment) bool { @@ -32,76 +26,50 @@ func DoUpgrade(settings *models.Configuration, env *environment.Environment) boo // Upgrades the settings if saved with a previous version func updateConfig(settings *models.Configuration, env *environment.Environment) { - // < v1.5.0 - if settings.ConfigVersion < 11 { - fmt.Println("Please update to version 1.5 before running this version,") + // < v1.7.0 + if settings.ConfigVersion < 13 { + fmt.Println("Please update to version 1.7 before running this version,") osExit(1) return } - // < v1.6.0 - if settings.ConfigVersion < 12 { - keys := database.GetAllMetaDataIds() - for _, key := range keys { - raw, ok := database.GetRawKey("file:id:" + key) - if !ok { - panic("could not read raw key for upgrade") - } - file := legacyFileToCurrentFile(raw) - database.SaveMetaData(file) - } - } - // < v1.6.2 - if settings.ConfigVersion < 13 { - data := database.GetAllMetadata() - for _, file := range data { - b, err := bytesize.Parse(file.Size) - if err == nil { - bytesFormatted := b.Format("%.0f", "b", false) - bytesFormatted = strings.Replace(bytesFormatted, "B", "", 1) - sizeBytes, err := strconv.ParseInt(bytesFormatted, 10, 64) - if err == nil { - file.SizeBytes = sizeBytes - database.SaveMetaData(file) - } - } - } - } // < v1.7.2 if settings.ConfigVersion < 14 { settings.PublicName = "Gokapi" } + // < v1.8.0 + if settings.ConfigVersion < 15 { + fmt.Println("Migrating to SQLite...") + migrateToSqlite(env) + fmt.Println("Migration complete. You will need to login again.") + fmt.Println("It should be safe to delete the folder " + env.LegacyDbPath) + } } -func legacyFileToCurrentFile(input []byte) models.File { - oldFile := legacyFile{} - buf := bytes.NewBuffer(input) - dec := gob.NewDecoder(buf) - err := dec.Decode(&oldFile) - helper.Check(err) - result := models.File{} - err = copier.Copy(&result, oldFile) - helper.Check(err) - result.SHA1 = oldFile.SHA256 - return result -} +// migrateToSqlite copies the content of the old bitcask database to a new sqlite database +// Sessions and Uploadchunks will not be migrated. +func migrateToSqlite(env *environment.Environment) { + legacydb.Init(env.LegacyDbPath) -type legacyFile struct { - Id string `json:"Id"` - Name string `json:"Name"` - Size string `json:"Size"` - SHA256 string `json:"SHA256"` - ExpireAt int64 `json:"ExpireAt"` - ExpireAtString string `json:"ExpireAtString"` - DownloadsRemaining int `json:"DownloadsRemaining"` - DownloadCount int `json:"DownloadCount"` - PasswordHash string `json:"PasswordHash"` - HotlinkId string `json:"HotlinkId"` - ContentType string `json:"ContentType"` - AwsBucket string `json:"AwsBucket"` - Encryption models.EncryptionInfo `json:"Encryption"` - UnlimitedDownloads bool `json:"UnlimitedDownloads"` - UnlimitedTime bool `json:"UnlimitedTime"` - RequiresClientSideDecryption bool `json:"RequiresClientSideDecryption"` + apikeys := legacydb.GetAllApiKeys() + for _, apikey := range apikeys { + database.SaveApiKey(apikey) + } + + e2econfig := legacydb.GetEnd2EndInfo() + database.SaveEnd2EndInfo(e2econfig) + + files := legacydb.GetAllMetadata() + for _, file := range files { + database.SaveMetaData(file) + if file.HotlinkId != "" { + database.SaveHotlink(file) + } + } + + uploadConfig := legacydb.GetUploadDefaults() + database.SaveUploadDefaults(uploadConfig) + + legacydb.Close() } var osExit = os.Exit diff --git a/internal/configuration/configupgrade/Upgrade_test.go b/internal/configuration/configupgrade/Upgrade_test.go index 7ee4ce2..5ddd051 100644 --- a/internal/configuration/configupgrade/Upgrade_test.go +++ b/internal/configuration/configupgrade/Upgrade_test.go @@ -2,6 +2,7 @@ package configupgrade import ( "github.com/forceu/gokapi/internal/configuration/database" + "github.com/forceu/gokapi/internal/environment" "github.com/forceu/gokapi/internal/models" "github.com/forceu/gokapi/internal/test" "github.com/forceu/gokapi/internal/test/testconfiguration" @@ -28,21 +29,23 @@ func TestUpgradeDb(t *testing.T) { osExit = func(code int) { exitCode = code } + env := environment.New() oldConfigFile.ConfigVersion = 10 - upgradeDone := DoUpgrade(&oldConfigFile, nil) + upgradeDone := DoUpgrade(&oldConfigFile, &env) test.IsEqualBool(t, upgradeDone, true) test.IsEqualInt(t, exitCode, 1) + database.Close() - database.Init("./test/filestorage.db") + database.Init("./test", "gokapi.sqlite") exitCode = 0 - oldConfigFile.ConfigVersion = 11 - upgradeDone = DoUpgrade(&oldConfigFile, nil) + oldConfigFile.ConfigVersion = 13 + upgradeDone = DoUpgrade(&oldConfigFile, &env) test.IsEqualBool(t, upgradeDone, true) test.IsEqualInt(t, exitCode, 0) exitCode = 0 oldConfigFile.ConfigVersion = CurrentConfigVersion - upgradeDone = DoUpgrade(&oldConfigFile, nil) + upgradeDone = DoUpgrade(&oldConfigFile, &env) test.IsEqualBool(t, upgradeDone, false) test.IsEqualInt(t, exitCode, 0) diff --git a/internal/configuration/database/Database.go b/internal/configuration/database/Database.go index 20f9f61..8ce6de3 100644 --- a/internal/configuration/database/Database.go +++ b/internal/configuration/database/Database.go @@ -1,399 +1,118 @@ package database import ( - "bytes" - "encoding/binary" - "encoding/gob" + "database/sql" "fmt" - "git.mills.io/prologic/bitcask" "github.com/forceu/gokapi/internal/helper" - "github.com/forceu/gokapi/internal/models" "log" - "strings" - "time" + _ "modernc.org/sqlite" + "os" + "path/filepath" ) -const prefixApiKey = "apikey:id:" -const prefixFile = "file:id:" -const prefixHotlink = "hotlink:id:" -const prefixSessions = "session:id:" -const prefixUploadStatus = "fstatus:id:" -const idLastUploadConfig = "default:lastupload" -const idEnd2EndInfo = "e2e:info" - -const maxKeySize = 96 - -var bitcaskDb *bitcask.Bitcask +var sqliteDb *sql.DB // Init creates the database files and connects to it -func Init(dbPath string) { - if bitcaskDb == nil { - db, err := bitcask.Open(dbPath, bitcask.WithMaxKeySize(maxKeySize)) +func Init(dataDir, dbName string) { + if sqliteDb == nil { + dataDir = filepath.Clean(dataDir) + var err error + if !helper.FolderExists(dataDir) { + err = os.MkdirAll(dataDir, 0700) + helper.Check(err) + } + dbFullPath := dataDir + "/" + dbName + sqliteDb, err = sql.Open("sqlite", dbFullPath+"?_pragma=busy_timeout=10000&_pragma=journal_mode=WAL") if err != nil { log.Fatal(err) } - bitcaskDb = db - } -} + sqliteDb.SetMaxOpenConns(10000) + sqliteDb.SetMaxIdleConns(10000) -// GetLengthAvailable returns the maximum length for a key name -func GetLengthAvailable() int { - maxLength := 0 - for _, key := range []string{prefixApiKey, prefixFile, prefixHotlink, prefixSessions} { - length := len(key) - if length > maxLength { - maxLength = length + if !helper.FileExists(dbFullPath) { + createNewDatabase() } } - return maxKeySize - maxLength } -// Close syncs the database to the filesystem and closes it +// Close the database connection func Close() { - if bitcaskDb != nil { - err := bitcaskDb.Sync() - if err != nil { - fmt.Println(err) - } - err = bitcaskDb.Close() + if sqliteDb != nil { + err := sqliteDb.Close() if err != nil { fmt.Println(err) } } - bitcaskDb = nil -} - -// ## File Metadata ## - -// GetAllMetadata returns a map of all available files -func GetAllMetadata() map[string]models.File { - if bitcaskDb == nil { - panic("Database not loaded!") - } - result := make(map[string]models.File) - keys := GetAllMetaDataIds() - - for _, key := range keys { - file, ok := GetMetaDataById(key) - if ok { - result[file.Id] = file - } - } - - return result -} - -// GetAllMetaDataIds returns all Ids that contain metadata -func GetAllMetaDataIds() []string { - if bitcaskDb == nil { - panic("Database not loaded!") - } - var keys []string - err := bitcaskDb.Scan([]byte(prefixFile), func(key []byte) error { - fileId := strings.Replace(string(key), prefixFile, "", 1) - keys = append(keys, fileId) - return nil - }) - helper.Check(err) - return keys -} - -// GetMetaDataById returns a models.File from the ID passed or false if the id is not valid -func GetMetaDataById(id string) (models.File, bool) { - result := models.File{} - value, ok := getValue(prefixFile + id) - if !ok { - return result, false - } - buf := bytes.NewBuffer(value) - dec := gob.NewDecoder(buf) - err := dec.Decode(&result) - helper.Check(err) - return result, true -} - -// SaveMetaData stores the metadata of a file to the disk -func SaveMetaData(file models.File) { - var buf bytes.Buffer - enc := gob.NewEncoder(&buf) - err := enc.Encode(file) - helper.Check(err) - err = bitcaskDb.Put([]byte(prefixFile+file.Id), buf.Bytes()) - helper.Check(err) - err = bitcaskDb.Sync() - helper.Check(err) -} - -// DeleteMetaData deletes information about a file -func DeleteMetaData(id string) { - deleteKey(prefixFile + id) -} - -// GetUploadStatus returns a models.UploadStatus from the ID passed or false if the id is not valid -func GetUploadStatus(id string) (models.UploadStatus, bool) { - result := models.UploadStatus{} - value, ok := getValue(prefixUploadStatus + id) - if !ok { - return result, false - } - buf := bytes.NewBuffer(value) - dec := gob.NewDecoder(buf) - err := dec.Decode(&result) - helper.Check(err) - return result, true -} - -// SaveUploadStatus stores the upload status of a new file for 24 hours -func SaveUploadStatus(status models.UploadStatus) { - var buf bytes.Buffer - enc := gob.NewEncoder(&buf) - err := enc.Encode(status) - helper.Check(err) - err = bitcaskDb.PutWithTTL([]byte(prefixUploadStatus+status.ChunkId), buf.Bytes(), time.Hour*24) - helper.Check(err) - err = bitcaskDb.Sync() - helper.Check(err) -} - -// ## Hotlinks ## - -// GetHotlink returns the id of the file associated or false if not found -func GetHotlink(id string) (string, bool) { - value, ok := getValue(prefixHotlink + id) - if !ok { - return "", false - } - return string(value), true -} - -// SaveHotlink stores the hotlink associated with the file in the bitcaskDb -func SaveHotlink(file models.File) { - var err error - - if file.UnlimitedTime { - err = bitcaskDb.Put([]byte(prefixHotlink+file.HotlinkId), []byte(file.Id)) - } else { - err = bitcaskDb.PutWithTTL([]byte(prefixHotlink+file.HotlinkId), []byte(file.Id), expiryToDuration(file)) - } - - helper.Check(err) - err = bitcaskDb.Sync() - helper.Check(err) -} - -// DeleteHotlink deletes a hotlink with the given ID -func DeleteHotlink(id string) { - deleteKey(prefixHotlink + id) -} - -// ## API Keys ## - -// GetAllApiKeys returns a map with all API keys -func GetAllApiKeys() map[string]models.ApiKey { - result := make(map[string]models.ApiKey) - var keys []string - err := bitcaskDb.Scan([]byte(prefixApiKey), func(key []byte) error { - apikeyID := strings.Replace(string(key), prefixApiKey, "", 1) - keys = append(keys, apikeyID) - return nil - }) - helper.Check(err) - - for _, key := range keys { - apiKey, ok := GetApiKey(key) - if ok { - result[apiKey.Id] = apiKey - } - } - return result -} - -// GetApiKey returns a models.ApiKey if valid or false if the ID is not valid -func GetApiKey(id string) (models.ApiKey, bool) { - result := models.ApiKey{} - value, ok := getValue(prefixApiKey + id) - if !ok { - return result, false - } - buf := bytes.NewBuffer(value) - dec := gob.NewDecoder(buf) - err := dec.Decode(&result) - helper.Check(err) - return result, true -} - -// SaveApiKey saves the API key to the database. If updateTimeOnly is true, the database might not be synced afterwards -func SaveApiKey(apikey models.ApiKey, updateTimeOnly bool) { - var buf bytes.Buffer - enc := gob.NewEncoder(&buf) - err := enc.Encode(apikey) - helper.Check(err) - err = bitcaskDb.Put([]byte(prefixApiKey+apikey.Id), buf.Bytes()) - helper.Check(err) - if !updateTimeOnly { - err = bitcaskDb.Sync() - helper.Check(err) - } -} - -// DeleteApiKey deletes an API key with the given ID -func DeleteApiKey(id string) { - deleteKey(prefixApiKey + id) -} - -// ## Sessions ## - -// GetSession returns the session with the given ID or false if not a valid ID -func GetSession(id string) (models.Session, bool) { - result := models.Session{} - value, ok := getValue(prefixSessions + id) - if !ok { - return result, false - } - buf := bytes.NewBuffer(value) - dec := gob.NewDecoder(buf) - err := dec.Decode(&result) - helper.Check(err) - return result, true -} - -// DeleteSession deletes a session with the given ID -func DeleteSession(id string) { - deleteKey(prefixSessions + id) -} - -// DeleteAllSessions logs all users out -func DeleteAllSessions() { - err := bitcaskDb.SiftScan([]byte(prefixSessions), func(key []byte) (bool, error) { - return true, nil - }) - helper.Check(err) -} - -// SaveSession stores the given session. After the expiry passed, it will be deleted automatically -func SaveSession(id string, session models.Session, expiry time.Duration) { - var buf bytes.Buffer - enc := gob.NewEncoder(&buf) - err := enc.Encode(session) - helper.Check(err) - err = bitcaskDb.PutWithTTL([]byte(prefixSessions+id), buf.Bytes(), expiry) - helper.Check(err) - err = bitcaskDb.Sync() - helper.Check(err) -} - -// ## Upload Defaults ## - -// GetUploadDefaults returns the last used setting for amount of downloads allowed, last expiry in days and -// a password for the file -func GetUploadDefaults() models.LastUploadValues { - defaultValues := models.LastUploadValues{ - Downloads: 1, - TimeExpiry: 14, - Password: "", - UnlimitedDownload: false, - UnlimitedTime: false, - } - result := models.LastUploadValues{} - if bitcaskDb.Has([]byte(idLastUploadConfig)) { - value, err := bitcaskDb.Get([]byte(idLastUploadConfig)) - helper.Check(err) - buf := bytes.NewBuffer(value) - dec := gob.NewDecoder(buf) - err = dec.Decode(&result) - helper.Check(err) - return result - } - return defaultValues -} - -// SaveUploadDefaults saves the last used setting for an upload -func SaveUploadDefaults(values models.LastUploadValues) { - var buf bytes.Buffer - enc := gob.NewEncoder(&buf) - err := enc.Encode(values) - helper.Check(err) - err = bitcaskDb.Put([]byte(idLastUploadConfig), buf.Bytes()) - helper.Check(err) -} - -// ## End2End Encryption ## - -// SaveEnd2EndInfo stores the encrypted e2e info -func SaveEnd2EndInfo(info models.E2EInfoEncrypted) { - var buf bytes.Buffer - enc := gob.NewEncoder(&buf) - err := enc.Encode(info) - helper.Check(err) - err = bitcaskDb.Put([]byte(idEnd2EndInfo), buf.Bytes()) - helper.Check(err) - err = bitcaskDb.Sync() - helper.Check(err) -} - -// GetEnd2EndInfo retrieves the encrypted e2e info -func GetEnd2EndInfo() models.E2EInfoEncrypted { - result := models.E2EInfoEncrypted{} - value, ok := getValue(idEnd2EndInfo) - if !ok { - return result - } - buf := bytes.NewBuffer(value) - dec := gob.NewDecoder(buf) - err := dec.Decode(&result) - helper.Check(err) - result.AvailableFiles = GetAllMetaDataIds() - return result -} - -// DeleteEnd2EndInfo resets the encrypted e2e info -func DeleteEnd2EndInfo() { - deleteKey(idEnd2EndInfo) + sqliteDb = nil } // RunGarbageCollection runs the databases GC func RunGarbageCollection() { - err := bitcaskDb.RunGC() + cleanExpiredSessions() + cleanUploadStatus() +} + +func createNewDatabase() { + sqlStmt := ` + CREATE TABLE "ApiKeys" ( + "Id" TEXT NOT NULL UNIQUE, + "FriendlyName" TEXT NOT NULL, + "LastUsed" INTEGER NOT NULL, + "LastUsedString" TEXT NOT NULL, + PRIMARY KEY("Id") + ) WITHOUT ROWID; + CREATE TABLE "E2EConfig" ( + "id" INTEGER NOT NULL UNIQUE, + "Config" BLOB NOT NULL, + PRIMARY KEY("id" AUTOINCREMENT) + ); + CREATE TABLE "FileMetaData" ( + "Id" TEXT NOT NULL UNIQUE, + "Name" TEXT NOT NULL, + "Size" TEXT NOT NULL, + "SHA1" TEXT NOT NULL, + "ExpireAt" INTEGER NOT NULL, + "SizeBytes" INTEGER NOT NULL, + "ExpireAtString" TEXT NOT NULL, + "DownloadsRemaining" INTEGER NOT NULL, + "DownloadCount" INTEGER NOT NULL, + "PasswordHash" TEXT NOT NULL, + "HotlinkId" TEXT NOT NULL, + "ContentType" TEXT NOT NULL, + "AwsBucket" TEXT NOT NULL, + "Encryption" BLOB NOT NULL, + "UnlimitedDownloads" INTEGER NOT NULL, + "UnlimitedTime" INTEGER NOT NULL, + PRIMARY KEY("Id") + ); + CREATE TABLE "Hotlinks" ( + "Id" TEXT NOT NULL UNIQUE, + "FileId" TEXT NOT NULL UNIQUE, + PRIMARY KEY("Id") + ) WITHOUT ROWID; + CREATE TABLE "Sessions" ( + "Id" TEXT NOT NULL UNIQUE, + "RenewAt" INTEGER NOT NULL, + "ValidUntil" INTEGER NOT NULL, + PRIMARY KEY("Id") + ) WITHOUT ROWID; + CREATE TABLE "UploadConfig" ( + "id" INTEGER NOT NULL UNIQUE, + "Downloads" INTEGER, + "TimeExpiry" INTEGER, + "Password" TEXT, + "UnlimitedDownloads" INTEGER, + "UnlimitedTime" INTEGER, + PRIMARY KEY("id") + ); + CREATE TABLE "UploadStatus" ( + "ChunkId" TEXT NOT NULL UNIQUE, + "CurrentStatus" INTEGER NOT NULL, + "LastUpdate" INTEGER NOT NULL, + "CreationDate" INTEGER NOT NULL, + PRIMARY KEY("ChunkId") + ) WITHOUT ROWID; +` + _, err := sqliteDb.Exec(sqlStmt) helper.Check(err) } - -func intToByte(integer int) []byte { - buf := make([]byte, binary.MaxVarintLen32) - n := binary.PutVarint(buf, int64(integer)) - return buf[:n] -} - -func byteToInt(intByte []byte) int { - integer, _ := binary.Varint(intByte) - return int(integer) -} - -func deleteKey(id string) { - if !bitcaskDb.Has([]byte(id)) { - return - } - err := bitcaskDb.Delete([]byte(id)) - helper.Check(err) - err = bitcaskDb.Sync() - helper.Check(err) -} - -func getValue(id string) ([]byte, bool) { - value, err := bitcaskDb.Get([]byte(id)) - if err == nil { - return value, true - } - if err == bitcask.ErrEmptyKey || err == bitcask.ErrKeyExpired || err == bitcask.ErrKeyNotFound { - return nil, false - } - panic(err) -} - -// GetRawKey returns the raw value of a database key -func GetRawKey(id string) ([]byte, bool) { - return getValue(id) -} - -func expiryToDuration(file models.File) time.Duration { - return time.Until(time.Unix(file.ExpireAt, 0)) -} diff --git a/internal/configuration/database/Database_test.go b/internal/configuration/database/Database_test.go index 11e5556..d73c7f6 100644 --- a/internal/configuration/database/Database_test.go +++ b/internal/configuration/database/Database_test.go @@ -18,17 +18,17 @@ func TestMain(m *testing.M) { } func TestInit(t *testing.T) { - Init("./test/filestorage.db") - test.IsEqualBool(t, bitcaskDb != nil, true) + Init("./test", "gokapi.sqlite") + test.IsEqualBool(t, sqliteDb != nil, true) // Test that second init doesn't raise an error - Init("./test/filestorage.db") + Init("./test", "gokapi.sqlite") } func TestClose(t *testing.T) { - test.IsEqualBool(t, bitcaskDb != nil, true) + test.IsEqualBool(t, sqliteDb != nil, true) Close() - test.IsEqualBool(t, bitcaskDb == nil, true) - Init("./test/filestorage.db") + test.IsEqualBool(t, sqliteDb == nil, true) + Init("./test", "gokapi.sqlite") } func TestMetaData(t *testing.T) { @@ -81,13 +81,13 @@ func TestApiKey(t *testing.T) { FriendlyName: "New Key", LastUsed: 100, LastUsedString: "LastUsed", - }, false) + }) SaveApiKey(models.ApiKey{ Id: "newkey2", FriendlyName: "New Key2", LastUsed: 200, LastUsedString: "LastUsed2", - }, true) + }) keys := GetAllApiKeys() test.IsEqualInt(t, len(keys), 2) @@ -111,7 +111,7 @@ func TestApiKey(t *testing.T) { FriendlyName: "Old Key", LastUsed: 100, LastUsedString: "LastUsed", - }, false) + }) key, ok = GetApiKey("newkey") test.IsEqualBool(t, ok, true) test.IsEqualString(t, key.FriendlyName, "Old Key") @@ -122,7 +122,7 @@ func TestSession(t *testing.T) { SaveSession("newsession", models.Session{ RenewAt: renewAt, ValidUntil: time.Now().Add(2 * time.Hour).Unix(), - }, 2*time.Hour) + }) session, ok := GetSession("newsession") test.IsEqualBool(t, ok, true) @@ -135,12 +135,12 @@ func TestSession(t *testing.T) { SaveSession("newsession", models.Session{ RenewAt: renewAt, ValidUntil: time.Now().Add(2 * time.Hour).Unix(), - }, 2*time.Hour) + }) SaveSession("anothersession", models.Session{ RenewAt: renewAt, ValidUntil: time.Now().Add(2 * time.Hour).Unix(), - }, 2*time.Hour) + }) _, ok = GetSession("newsession") test.IsEqualBool(t, ok, true) _, ok = GetSession("anothersession") @@ -176,24 +176,106 @@ func TestUploadDefaults(t *testing.T) { test.IsEqualBool(t, defaults.UnlimitedTime, true) } -func TestBinaryConversion(t *testing.T) { - test.IsEqualInt(t, byteToInt(intToByte(0)), 0) - test.IsEqualInt(t, byteToInt(intToByte(-100)), -100) - test.IsEqualInt(t, byteToInt(intToByte(100)), 100) - test.IsEqualInt(t, byteToInt(intToByte(10000)), 10000) - test.IsEqualInt(t, byteToInt(intToByte(2147483647)), 2147483647) - test.IsEqualInt(t, byteToInt(intToByte(-2147483647)), -2147483647) -} +func TestGarbageCollectionUploads(t *testing.T) { + orgiginalFunc := currentTime + currentTime = func() time.Time { + return time.Now().Add(-25 * time.Hour) + } + SaveUploadStatus(models.UploadStatus{ + ChunkId: "ctodelete1", + CurrentStatus: 0, + LastUpdate: time.Now().Add(-24 * time.Hour).Unix(), + }) + SaveUploadStatus(models.UploadStatus{ + ChunkId: "ctodelete2", + CurrentStatus: 1, + LastUpdate: time.Now().Add(-24 * time.Hour).Unix(), + }) + SaveUploadStatus(models.UploadStatus{ + ChunkId: "ctodelete3", + CurrentStatus: 0, + LastUpdate: 0, + }) + SaveUploadStatus(models.UploadStatus{ + ChunkId: "ctodelete4", + CurrentStatus: 0, + LastUpdate: time.Now().Add(-20 * time.Hour).Unix(), + }) + SaveUploadStatus(models.UploadStatus{ + ChunkId: "ctodelete5", + CurrentStatus: 1, + LastUpdate: time.Now().Add(40 * time.Hour).Unix(), + }) + currentTime = orgiginalFunc -func TestRunGc(t *testing.T) { - items := bitcaskDb.Len() - bitcaskDb.PutWithTTL([]byte("test"), []byte("value"), 500*time.Millisecond) - test.IsEqualInt(t, bitcaskDb.Len(), items+1) - time.Sleep(501 * time.Millisecond) + SaveUploadStatus(models.UploadStatus{ + ChunkId: "ctokeep1", + CurrentStatus: 0, + LastUpdate: time.Now().Add(-24 * time.Hour).Unix(), + }) + SaveUploadStatus(models.UploadStatus{ + ChunkId: "ctokeep2", + CurrentStatus: 1, + LastUpdate: time.Now().Add(-24 * time.Hour).Unix(), + }) + SaveUploadStatus(models.UploadStatus{ + ChunkId: "ctokeep3", + CurrentStatus: 0, + LastUpdate: 0, + }) + SaveUploadStatus(models.UploadStatus{ + ChunkId: "ctokeep4", + CurrentStatus: 0, + LastUpdate: time.Now().Add(-20 * time.Hour).Unix(), + }) + SaveUploadStatus(models.UploadStatus{ + ChunkId: "ctokeep5", + CurrentStatus: 1, + LastUpdate: time.Now().Add(40 * time.Hour).Unix(), + }) + for _, item := range []string{"ctodelete1", "ctodelete2", "ctodelete3", "ctodelete4", "ctokeep1", "ctokeep2", "ctokeep3", "ctokeep4"} { + _, result := GetUploadStatus(item) + test.IsEqualBool(t, result, true) + } RunGarbageCollection() - test.IsEqualInt(t, bitcaskDb.Len(), items) + for _, item := range []string{"ctodelete1", "ctodelete2", "ctodelete3", "ctodelete4"} { + _, result := GetUploadStatus(item) + test.IsEqualBool(t, result, false) + } + for _, item := range []string{"ctokeep1", "ctokeep2", "ctokeep3", "ctokeep4"} { + _, result := GetUploadStatus(item) + test.IsEqualBool(t, result, true) + } } -func TestGetLengthAvailable(t *testing.T) { - test.IsEqualInt(t, GetLengthAvailable(), 85) +func TestGarbageCollectionSessions(t *testing.T) { + SaveSession("todelete1", models.Session{ + RenewAt: time.Now().Add(-10 * time.Second).Unix(), + ValidUntil: time.Now().Add(-10 * time.Second).Unix(), + }) + SaveSession("todelete2", models.Session{ + RenewAt: time.Now().Add(10 * time.Second).Unix(), + ValidUntil: time.Now().Add(-10 * time.Second).Unix(), + }) + SaveSession("tokeep1", models.Session{ + RenewAt: time.Now().Add(-10 * time.Second).Unix(), + ValidUntil: time.Now().Add(10 * time.Second).Unix(), + }) + SaveSession("tokeep2", models.Session{ + RenewAt: time.Now().Add(10 * time.Second).Unix(), + ValidUntil: time.Now().Add(10 * time.Second).Unix(), + }) + for _, item := range []string{"todelete1", "todelete2", "tokeep1", "tokeep2"} { + _, result := GetSession(item) + test.IsEqualBool(t, result, true) + } + RunGarbageCollection() + for _, item := range []string{"todelete1", "todelete2"} { + _, result := GetSession(item) + test.IsEqualBool(t, result, false) + } + for _, item := range []string{"tokeep1", "tokeep2"} { + _, result := GetSession(item) + test.IsEqualBool(t, result, true) + } } diff --git a/internal/configuration/database/apikeys.go b/internal/configuration/database/apikeys.go new file mode 100644 index 0000000..4bcf823 --- /dev/null +++ b/internal/configuration/database/apikeys.go @@ -0,0 +1,80 @@ +package database + +import ( + "database/sql" + "errors" + "github.com/forceu/gokapi/internal/helper" + "github.com/forceu/gokapi/internal/models" +) + +type schemaApiKeys struct { + Id string + FriendlyName string + LastUsed int64 + LastUsedString string +} + +// GetAllApiKeys returns a map with all API keys +func GetAllApiKeys() map[string]models.ApiKey { + result := make(map[string]models.ApiKey) + + rows, err := sqliteDb.Query("SELECT * FROM ApiKeys") + helper.Check(err) + defer rows.Close() + for rows.Next() { + rowData := schemaApiKeys{} + err = rows.Scan(&rowData.Id, &rowData.FriendlyName, &rowData.LastUsed, &rowData.LastUsedString) + helper.Check(err) + result[rowData.Id] = models.ApiKey{ + Id: rowData.Id, + FriendlyName: rowData.FriendlyName, + LastUsed: rowData.LastUsed, + LastUsedString: rowData.LastUsedString, + } + } + return result +} + +// GetApiKey returns a models.ApiKey if valid or false if the ID is not valid +func GetApiKey(id string) (models.ApiKey, bool) { + + var rowResult schemaApiKeys + row := sqliteDb.QueryRow("SELECT * FROM ApiKeys WHERE Id = ?", id) + err := row.Scan(&rowResult.Id, &rowResult.FriendlyName, &rowResult.LastUsed, &rowResult.LastUsedString) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return models.ApiKey{}, false + } + helper.Check(err) + return models.ApiKey{}, false + } + + result := models.ApiKey{ + Id: rowResult.Id, + FriendlyName: rowResult.FriendlyName, + LastUsed: rowResult.LastUsed, + LastUsedString: rowResult.LastUsedString, + } + + return result, true +} + +// SaveApiKey saves the API key to the database +func SaveApiKey(apikey models.ApiKey) { + _, err := sqliteDb.Exec("INSERT OR REPLACE INTO ApiKeys (Id, FriendlyName, LastUsed, LastUsedString) VALUES (?, ?, ?, ?)", + apikey.Id, apikey.FriendlyName, apikey.LastUsed, apikey.LastUsedString) + helper.Check(err) +} + +// UpdateTimeApiKey writes the content of LastUsage to the database +func UpdateTimeApiKey(apikey models.ApiKey) { + _, err := sqliteDb.Exec("UPDATE ApiKeys SET LastUsed = ?, LastUsedString = ? WHERE Id = ?", + apikey.LastUsed, apikey.LastUsedString, apikey.Id) + helper.Check(err) +} + +// DeleteApiKey deletes an API key with the given ID +func DeleteApiKey(id string) { + _, err := sqliteDb.Exec("DELETE FROM ApiKeys WHERE Id = ?", id) + helper.Check(err) +} diff --git a/internal/configuration/database/e2econfig.go b/internal/configuration/database/e2econfig.go new file mode 100644 index 0000000..4cabb92 --- /dev/null +++ b/internal/configuration/database/e2econfig.go @@ -0,0 +1,64 @@ +package database + +import ( + "bytes" + "database/sql" + "encoding/gob" + "errors" + "github.com/forceu/gokapi/internal/helper" + "github.com/forceu/gokapi/internal/models" +) + +type schemaE2EConfig struct { + Id int64 + Config []byte +} + +// SaveEnd2EndInfo stores the encrypted e2e info +func SaveEnd2EndInfo(info models.E2EInfoEncrypted) { + + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + err := enc.Encode(info) + helper.Check(err) + + newData := schemaE2EConfig{ + Id: 1, + Config: buf.Bytes(), + } + + _, err = sqliteDb.Exec("INSERT OR REPLACE INTO E2EConfig (id, Config) VALUES (?, ?)", + newData.Id, newData.Config) + helper.Check(err) +} + +// GetEnd2EndInfo retrieves the encrypted e2e info +func GetEnd2EndInfo() models.E2EInfoEncrypted { + result := models.E2EInfoEncrypted{} + rowResult := schemaE2EConfig{} + + row := sqliteDb.QueryRow("SELECT Config FROM E2EConfig WHERE id = 1") + err := row.Scan(&rowResult.Config) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return result + } + helper.Check(err) + return result + } + + buf := bytes.NewBuffer(rowResult.Config) + dec := gob.NewDecoder(buf) + err = dec.Decode(&result) + helper.Check(err) + + result.AvailableFiles = GetAllMetaDataIds() + return result +} + +// DeleteEnd2EndInfo resets the encrypted e2e info +func DeleteEnd2EndInfo() { + //goland:noinspection SqlWithoutWhere + _, err := sqliteDb.Exec("DELETE FROM E2EConfig") + helper.Check(err) +} diff --git a/internal/configuration/database/hotlinks.go b/internal/configuration/database/hotlinks.go new file mode 100644 index 0000000..fa7b774 --- /dev/null +++ b/internal/configuration/database/hotlinks.go @@ -0,0 +1,47 @@ +package database + +import ( + "database/sql" + "errors" + "github.com/forceu/gokapi/internal/helper" + "github.com/forceu/gokapi/internal/models" +) + +type schemaHotlinks struct { + Id string + FileId string +} + +// GetHotlink returns the id of the file associated or false if not found +func GetHotlink(id string) (string, bool) { + var rowResult schemaHotlinks + row := sqliteDb.QueryRow("SELECT FileId FROM Hotlinks WHERE Id = ?", id) + err := row.Scan(&rowResult.FileId) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return "", false + } + helper.Check(err) + return "", false + } + return rowResult.FileId, true +} + +// SaveHotlink stores the hotlink associated with the file in the database +func SaveHotlink(file models.File) { + + newData := schemaHotlinks{ + Id: file.HotlinkId, + FileId: file.Id, + } + + _, err := sqliteDb.Exec("INSERT OR REPLACE INTO Hotlinks (Id, FileId) VALUES (?, ?)", + newData.Id, newData.FileId) + helper.Check(err) +} + +// DeleteHotlink deletes a hotlink with the given ID +func DeleteHotlink(id string) { + _, err := sqliteDb.Exec("DELETE FROM Hotlinks WHERE Id = ?", id) + helper.Check(err) +} diff --git a/internal/configuration/database/legacydb/Database.go b/internal/configuration/database/legacydb/Database.go new file mode 100644 index 0000000..4b24f14 --- /dev/null +++ b/internal/configuration/database/legacydb/Database.go @@ -0,0 +1,350 @@ +package legacydb + +import ( + "bytes" + "encoding/binary" + "encoding/gob" + "fmt" + "git.mills.io/prologic/bitcask" + "github.com/forceu/gokapi/internal/helper" + "github.com/forceu/gokapi/internal/models" + "log" + "strings" + "time" +) + +const prefixApiKey = "apikey:id:" +const prefixFile = "file:id:" +const prefixHotlink = "hotlink:id:" +const prefixSessions = "session:id:" +const prefixUploadStatus = "fstatus:id:" +const idLastUploadConfig = "default:lastupload" +const idEnd2EndInfo = "e2e:info" + +const maxKeySize = 96 + +var bitcaskDb *bitcask.Bitcask + +// Init creates the database files and connects to it +// Deprecated: Package will be removed with 1.9 +func Init(dbPath string) { + if bitcaskDb == nil { + db, err := bitcask.Open(dbPath, bitcask.WithMaxKeySize(maxKeySize)) + if err != nil { + log.Fatal(err) + } + bitcaskDb = db + } +} + +// GetLengthAvailable returns the maximum length for a key name +func GetLengthAvailable() int { + maxLength := 0 + for _, key := range []string{prefixApiKey, prefixFile, prefixHotlink, prefixSessions} { + length := len(key) + if length > maxLength { + maxLength = length + } + } + return maxKeySize - maxLength +} + +// Close syncs the database to the filesystem and closes it +func Close() { + if bitcaskDb != nil { + err := bitcaskDb.Sync() + if err != nil { + fmt.Println(err) + } + err = bitcaskDb.Close() + if err != nil { + fmt.Println(err) + } + } + bitcaskDb = nil +} + +// ## File Metadata ## + +// GetAllMetadata returns a map of all available files +func GetAllMetadata() map[string]models.File { + if bitcaskDb == nil { + panic("Database not loaded!") + } + result := make(map[string]models.File) + keys := GetAllMetaDataIds() + + for _, key := range keys { + file, ok := GetMetaDataById(key) + if ok { + result[file.Id] = file + } + } + + return result +} + +// GetAllMetaDataIds returns all Ids that contain metadata +func GetAllMetaDataIds() []string { + if bitcaskDb == nil { + panic("Database not loaded!") + } + var keys []string + err := bitcaskDb.Scan([]byte(prefixFile), func(key []byte) error { + fileId := strings.Replace(string(key), prefixFile, "", 1) + keys = append(keys, fileId) + return nil + }) + helper.Check(err) + return keys +} + +// GetMetaDataById returns a models.File from the ID passed or false if the id is not valid +func GetMetaDataById(id string) (models.File, bool) { + result := models.File{} + value, ok := getValue(prefixFile + id) + if !ok { + return result, false + } + buf := bytes.NewBuffer(value) + dec := gob.NewDecoder(buf) + err := dec.Decode(&result) + helper.Check(err) + return result, true +} + +// SaveMetaData stores the metadata of a file to the disk +func SaveMetaData(file models.File) { + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + err := enc.Encode(file) + helper.Check(err) + err = bitcaskDb.Put([]byte(prefixFile+file.Id), buf.Bytes()) + helper.Check(err) + err = bitcaskDb.Sync() + helper.Check(err) +} + +// DeleteMetaData deletes information about a file +func DeleteMetaData(id string) { + deleteKey(prefixFile + id) +} + +// ## Hotlinks ## + +// GetHotlink returns the id of the file associated or false if not found +func GetHotlink(id string) (string, bool) { + value, ok := getValue(prefixHotlink + id) + if !ok { + return "", false + } + return string(value), true +} + +// SaveHotlink stores the hotlink associated with the file in the bitcaskDb +func SaveHotlink(file models.File) { + var err error + + if file.UnlimitedTime { + err = bitcaskDb.Put([]byte(prefixHotlink+file.HotlinkId), []byte(file.Id)) + } else { + err = bitcaskDb.PutWithTTL([]byte(prefixHotlink+file.HotlinkId), []byte(file.Id), expiryToDuration(file)) + } + + helper.Check(err) + err = bitcaskDb.Sync() + helper.Check(err) +} + +// DeleteHotlink deletes a hotlink with the given ID +func DeleteHotlink(id string) { + deleteKey(prefixHotlink + id) +} + +// ## API Keys ## + +// GetAllApiKeys returns a map with all API keys +func GetAllApiKeys() map[string]models.ApiKey { + result := make(map[string]models.ApiKey) + var keys []string + err := bitcaskDb.Scan([]byte(prefixApiKey), func(key []byte) error { + apikeyID := strings.Replace(string(key), prefixApiKey, "", 1) + keys = append(keys, apikeyID) + return nil + }) + helper.Check(err) + + for _, key := range keys { + apiKey, ok := GetApiKey(key) + if ok { + result[apiKey.Id] = apiKey + } + } + return result +} + +// GetApiKey returns a models.ApiKey if valid or false if the ID is not valid +func GetApiKey(id string) (models.ApiKey, bool) { + result := models.ApiKey{} + value, ok := getValue(prefixApiKey + id) + if !ok { + return result, false + } + buf := bytes.NewBuffer(value) + dec := gob.NewDecoder(buf) + err := dec.Decode(&result) + helper.Check(err) + return result, true +} + +// SaveApiKey saves the API key to the database. If updateTimeOnly is true, the database might not be synced afterwards +func SaveApiKey(apikey models.ApiKey, updateTimeOnly bool) { + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + err := enc.Encode(apikey) + helper.Check(err) + err = bitcaskDb.Put([]byte(prefixApiKey+apikey.Id), buf.Bytes()) + helper.Check(err) + if !updateTimeOnly { + err = bitcaskDb.Sync() + helper.Check(err) + } +} + +// DeleteApiKey deletes an API key with the given ID +func DeleteApiKey(id string) { + deleteKey(prefixApiKey + id) +} + +// ## Sessions ## + +// GetSession returns the session with the given ID or false if not a valid ID +func GetSession(id string) (models.Session, bool) { + result := models.Session{} + value, ok := getValue(prefixSessions + id) + if !ok { + return result, false + } + buf := bytes.NewBuffer(value) + dec := gob.NewDecoder(buf) + err := dec.Decode(&result) + helper.Check(err) + return result, true +} + +// DeleteSession deletes a session with the given ID +func DeleteSession(id string) { + deleteKey(prefixSessions + id) +} + +// DeleteAllSessions logs all users out +func DeleteAllSessions() { + err := bitcaskDb.SiftScan([]byte(prefixSessions), func(key []byte) (bool, error) { + return true, nil + }) + helper.Check(err) +} + +// SaveSession stores the given session. After the expiry passed, it will be deleted automatically +func SaveSession(id string, session models.Session, expiry time.Duration) { + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + err := enc.Encode(session) + helper.Check(err) + err = bitcaskDb.PutWithTTL([]byte(prefixSessions+id), buf.Bytes(), expiry) + helper.Check(err) + err = bitcaskDb.Sync() + helper.Check(err) +} + +// ## Upload Defaults ## + +// GetUploadDefaults returns the last used setting for amount of downloads allowed, last expiry in days and +// a password for the file +func GetUploadDefaults() models.LastUploadValues { + defaultValues := models.LastUploadValues{ + Downloads: 1, + TimeExpiry: 14, + Password: "", + UnlimitedDownload: false, + UnlimitedTime: false, + } + result := models.LastUploadValues{} + if bitcaskDb.Has([]byte(idLastUploadConfig)) { + value, err := bitcaskDb.Get([]byte(idLastUploadConfig)) + helper.Check(err) + buf := bytes.NewBuffer(value) + dec := gob.NewDecoder(buf) + err = dec.Decode(&result) + helper.Check(err) + return result + } + return defaultValues +} + +// SaveUploadDefaults saves the last used setting for an upload +func SaveUploadDefaults(values models.LastUploadValues) { + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + err := enc.Encode(values) + helper.Check(err) + err = bitcaskDb.Put([]byte(idLastUploadConfig), buf.Bytes()) + helper.Check(err) +} + +// GetEnd2EndInfo retrieves the encrypted e2e info +func GetEnd2EndInfo() models.E2EInfoEncrypted { + result := models.E2EInfoEncrypted{} + value, ok := getValue(idEnd2EndInfo) + if !ok { + return result + } + buf := bytes.NewBuffer(value) + dec := gob.NewDecoder(buf) + err := dec.Decode(&result) + helper.Check(err) + result.AvailableFiles = GetAllMetaDataIds() + return result +} + +// RunGarbageCollection runs the databases GC +func RunGarbageCollection() { + err := bitcaskDb.RunGC() + helper.Check(err) +} + +func intToByte(integer int) []byte { + buf := make([]byte, binary.MaxVarintLen32) + n := binary.PutVarint(buf, int64(integer)) + return buf[:n] +} + +func byteToInt(intByte []byte) int { + integer, _ := binary.Varint(intByte) + return int(integer) +} + +func deleteKey(id string) { + if !bitcaskDb.Has([]byte(id)) { + return + } + err := bitcaskDb.Delete([]byte(id)) + helper.Check(err) + err = bitcaskDb.Sync() + helper.Check(err) +} + +func getValue(id string) ([]byte, bool) { + value, err := bitcaskDb.Get([]byte(id)) + if err == nil { + return value, true + } + if err == bitcask.ErrEmptyKey || err == bitcask.ErrKeyExpired || err == bitcask.ErrKeyNotFound { + return nil, false + } + panic(err) +} + +func expiryToDuration(file models.File) time.Duration { + return time.Until(time.Unix(file.ExpireAt, 0)) +} diff --git a/internal/configuration/database/legacydb/Database_test.go b/internal/configuration/database/legacydb/Database_test.go new file mode 100644 index 0000000..cf25803 --- /dev/null +++ b/internal/configuration/database/legacydb/Database_test.go @@ -0,0 +1,199 @@ +package legacydb + +import ( + "github.com/forceu/gokapi/internal/models" + "github.com/forceu/gokapi/internal/test" + "os" + "testing" + "time" +) + +func TestMain(m *testing.M) { + os.Setenv("GOKAPI_CONFIG_DIR", "test") + os.Setenv("GOKAPI_DATA_DIR", "test") + os.Mkdir("test", 0777) + exitVal := m.Run() + os.RemoveAll("test") + os.Exit(exitVal) +} + +func TestInit(t *testing.T) { + Init("./test/filestorage.db") + test.IsEqualBool(t, bitcaskDb != nil, true) + // Test that second init doesn't raise an error + Init("./test/filestorage.db") +} + +func TestClose(t *testing.T) { + test.IsEqualBool(t, bitcaskDb != nil, true) + Close() + test.IsEqualBool(t, bitcaskDb == nil, true) + Init("./test/filestorage.db") +} + +func TestMetaData(t *testing.T) { + files := GetAllMetadata() + test.IsEqualInt(t, len(files), 0) + + SaveMetaData(models.File{Id: "testfile", Name: "test.txt", ExpireAt: time.Now().Add(time.Hour).Unix()}) + files = GetAllMetadata() + test.IsEqualInt(t, len(files), 1) + test.IsEqualString(t, files["testfile"].Name, "test.txt") + + file, ok := GetMetaDataById("testfile") + test.IsEqualBool(t, ok, true) + test.IsEqualString(t, file.Id, "testfile") + _, ok = GetMetaDataById("invalid") + test.IsEqualBool(t, ok, false) + + test.IsEqualInt(t, len(GetAllMetadata()), 1) + DeleteMetaData("invalid") + test.IsEqualInt(t, len(GetAllMetadata()), 1) + DeleteMetaData("testfile") + test.IsEqualInt(t, len(GetAllMetadata()), 0) +} + +func TestHotlink(t *testing.T) { + SaveHotlink(models.File{Id: "testhfile", Name: "testh.txt", HotlinkId: "testlink", ExpireAt: time.Now().Add(time.Hour).Unix()}) + + hotlink, ok := GetHotlink("testlink") + test.IsEqualBool(t, ok, true) + test.IsEqualString(t, hotlink, "testhfile") + _, ok = GetHotlink("invalid") + test.IsEqualBool(t, ok, false) + + DeleteHotlink("invalid") + _, ok = GetHotlink("testlink") + test.IsEqualBool(t, ok, true) + DeleteHotlink("testlink") + _, ok = GetHotlink("testlink") + test.IsEqualBool(t, ok, false) + + SaveHotlink(models.File{Id: "testhfile", Name: "testh.txt", HotlinkId: "testlink", ExpireAt: 0, UnlimitedTime: true}) + hotlink, ok = GetHotlink("testlink") + test.IsEqualBool(t, ok, true) + test.IsEqualString(t, hotlink, "testhfile") +} + +func TestApiKey(t *testing.T) { + SaveApiKey(models.ApiKey{ + Id: "newkey", + FriendlyName: "New Key", + LastUsed: 100, + LastUsedString: "LastUsed", + }, false) + SaveApiKey(models.ApiKey{ + Id: "newkey2", + FriendlyName: "New Key2", + LastUsed: 200, + LastUsedString: "LastUsed2", + }, true) + + keys := GetAllApiKeys() + test.IsEqualInt(t, len(keys), 2) + test.IsEqualString(t, keys["newkey"].FriendlyName, "New Key") + test.IsEqualString(t, keys["newkey"].Id, "newkey") + test.IsEqualString(t, keys["newkey"].LastUsedString, "LastUsed") + test.IsEqualBool(t, keys["newkey"].LastUsed == 100, true) + + test.IsEqualInt(t, len(GetAllApiKeys()), 2) + DeleteApiKey("newkey2") + test.IsEqualInt(t, len(GetAllApiKeys()), 1) + + key, ok := GetApiKey("newkey") + test.IsEqualBool(t, ok, true) + test.IsEqualString(t, key.FriendlyName, "New Key") + _, ok = GetApiKey("newkey2") + test.IsEqualBool(t, ok, false) + + SaveApiKey(models.ApiKey{ + Id: "newkey", + FriendlyName: "Old Key", + LastUsed: 100, + LastUsedString: "LastUsed", + }, false) + key, ok = GetApiKey("newkey") + test.IsEqualBool(t, ok, true) + test.IsEqualString(t, key.FriendlyName, "Old Key") +} + +func TestSession(t *testing.T) { + renewAt := time.Now().Add(1 * time.Hour).Unix() + SaveSession("newsession", models.Session{ + RenewAt: renewAt, + ValidUntil: time.Now().Add(2 * time.Hour).Unix(), + }, 2*time.Hour) + + session, ok := GetSession("newsession") + test.IsEqualBool(t, ok, true) + test.IsEqualBool(t, session.RenewAt == renewAt, true) + + DeleteSession("newsession") + _, ok = GetSession("newsession") + test.IsEqualBool(t, ok, false) + + SaveSession("newsession", models.Session{ + RenewAt: renewAt, + ValidUntil: time.Now().Add(2 * time.Hour).Unix(), + }, 2*time.Hour) + + SaveSession("anothersession", models.Session{ + RenewAt: renewAt, + ValidUntil: time.Now().Add(2 * time.Hour).Unix(), + }, 2*time.Hour) + _, ok = GetSession("newsession") + test.IsEqualBool(t, ok, true) + _, ok = GetSession("anothersession") + test.IsEqualBool(t, ok, true) + + DeleteAllSessions() + _, ok = GetSession("newsession") + test.IsEqualBool(t, ok, false) + _, ok = GetSession("anothersession") + test.IsEqualBool(t, ok, false) +} + +func TestUploadDefaults(t *testing.T) { + defaults := GetUploadDefaults() + test.IsEqualInt(t, defaults.Downloads, 1) + test.IsEqualInt(t, defaults.TimeExpiry, 14) + test.IsEqualString(t, defaults.Password, "") + test.IsEqualBool(t, defaults.UnlimitedDownload, false) + test.IsEqualBool(t, defaults.UnlimitedTime, false) + + SaveUploadDefaults(models.LastUploadValues{ + Downloads: 20, + TimeExpiry: 30, + Password: "abcd", + UnlimitedDownload: true, + UnlimitedTime: true, + }) + defaults = GetUploadDefaults() + test.IsEqualInt(t, defaults.Downloads, 20) + test.IsEqualInt(t, defaults.TimeExpiry, 30) + test.IsEqualString(t, defaults.Password, "abcd") + test.IsEqualBool(t, defaults.UnlimitedDownload, true) + test.IsEqualBool(t, defaults.UnlimitedTime, true) +} + +func TestBinaryConversion(t *testing.T) { + test.IsEqualInt(t, byteToInt(intToByte(0)), 0) + test.IsEqualInt(t, byteToInt(intToByte(-100)), -100) + test.IsEqualInt(t, byteToInt(intToByte(100)), 100) + test.IsEqualInt(t, byteToInt(intToByte(10000)), 10000) + test.IsEqualInt(t, byteToInt(intToByte(2147483647)), 2147483647) + test.IsEqualInt(t, byteToInt(intToByte(-2147483647)), -2147483647) +} + +func TestRunGc(t *testing.T) { + items := bitcaskDb.Len() + bitcaskDb.PutWithTTL([]byte("test"), []byte("value"), 500*time.Millisecond) + test.IsEqualInt(t, bitcaskDb.Len(), items+1) + time.Sleep(501 * time.Millisecond) + RunGarbageCollection() + test.IsEqualInt(t, bitcaskDb.Len(), items) +} + +func TestGetLengthAvailable(t *testing.T) { + test.IsEqualInt(t, GetLengthAvailable(), 85) +} diff --git a/internal/configuration/database/metadata.go b/internal/configuration/database/metadata.go new file mode 100644 index 0000000..452d673 --- /dev/null +++ b/internal/configuration/database/metadata.go @@ -0,0 +1,165 @@ +package database + +import ( + "bytes" + "database/sql" + "encoding/gob" + "errors" + "github.com/forceu/gokapi/internal/helper" + "github.com/forceu/gokapi/internal/models" +) + +type schemaMetaData struct { + Id string + Name string + Size string + SHA1 string + ExpireAt int64 + SizeBytes int64 + ExpireAtString string + DownloadsRemaining int + DownloadCount int + PasswordHash string + HotlinkId string + ContentType string + AwsBucket string + Encryption []byte + UnlimitedDownloads int + UnlimitedTime int +} + +func (rowData schemaMetaData) ToFileModel() (models.File, error) { + result := models.File{ + Id: rowData.Id, + Name: rowData.Name, + Size: rowData.Size, + SHA1: rowData.SHA1, + ExpireAt: rowData.ExpireAt, + SizeBytes: rowData.SizeBytes, + ExpireAtString: rowData.ExpireAtString, + DownloadsRemaining: rowData.DownloadsRemaining, + DownloadCount: rowData.DownloadCount, + PasswordHash: rowData.PasswordHash, + HotlinkId: rowData.HotlinkId, + ContentType: rowData.ContentType, + AwsBucket: rowData.AwsBucket, + Encryption: models.EncryptionInfo{}, + UnlimitedDownloads: rowData.UnlimitedDownloads == 1, + UnlimitedTime: rowData.UnlimitedTime == 1, + } + + buf := bytes.NewBuffer(rowData.Encryption) + dec := gob.NewDecoder(buf) + err := dec.Decode(&result.Encryption) + return result, err +} + +// GetAllMetadata returns a map of all available files +func GetAllMetadata() map[string]models.File { + if sqliteDb == nil { + panic("Database not loaded!") + } + result := make(map[string]models.File) + rows, err := sqliteDb.Query("SELECT * FROM FileMetaData") + helper.Check(err) + defer rows.Close() + for rows.Next() { + rowData := schemaMetaData{} + err = rows.Scan(&rowData.Id, &rowData.Name, &rowData.Size, &rowData.SHA1, &rowData.ExpireAt, &rowData.SizeBytes, + &rowData.ExpireAtString, &rowData.DownloadsRemaining, &rowData.DownloadCount, &rowData.PasswordHash, + &rowData.HotlinkId, &rowData.ContentType, &rowData.AwsBucket, &rowData.Encryption, + &rowData.UnlimitedDownloads, &rowData.UnlimitedTime) + helper.Check(err) + var metaData models.File + metaData, err = rowData.ToFileModel() + helper.Check(err) + result[metaData.Id] = metaData + } + return result +} + +// GetAllMetaDataIds returns all Ids that contain metadata +func GetAllMetaDataIds() []string { + if sqliteDb == nil { + panic("Database not loaded!") + } + var keys []string + rows, err := sqliteDb.Query("SELECT Id FROM FileMetaData") + helper.Check(err) + defer rows.Close() + for rows.Next() { + rowData := schemaMetaData{} + err = rows.Scan(&rowData.Id) + helper.Check(err) + keys = append(keys, rowData.Id) + } + return keys +} + +// GetMetaDataById returns a models.File from the ID passed or false if the id is not valid +func GetMetaDataById(id string) (models.File, bool) { + result := models.File{} + rowData := schemaMetaData{} + + row := sqliteDb.QueryRow("SELECT * FROM FileMetaData WHERE Id = ?", id) + err := row.Scan(&rowData.Id, &rowData.Name, &rowData.Size, &rowData.SHA1, &rowData.ExpireAt, &rowData.SizeBytes, + &rowData.ExpireAtString, &rowData.DownloadsRemaining, &rowData.DownloadCount, &rowData.PasswordHash, + &rowData.HotlinkId, &rowData.ContentType, &rowData.AwsBucket, &rowData.Encryption, + &rowData.UnlimitedDownloads, &rowData.UnlimitedTime) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return result, false + } + helper.Check(err) + return result, false + } + result, err = rowData.ToFileModel() + helper.Check(err) + return result, true +} + +// SaveMetaData stores the metadata of a file to the disk +func SaveMetaData(file models.File) { + newData := schemaMetaData{ + Id: file.Id, + Name: file.Name, + Size: file.Size, + SHA1: file.SHA1, + ExpireAt: file.ExpireAt, + SizeBytes: file.SizeBytes, + ExpireAtString: file.ExpireAtString, + DownloadsRemaining: file.DownloadsRemaining, + DownloadCount: file.DownloadCount, + PasswordHash: file.PasswordHash, + HotlinkId: file.HotlinkId, + ContentType: file.ContentType, + AwsBucket: file.AwsBucket, + } + + if file.UnlimitedDownloads { + newData.UnlimitedDownloads = 1 + } + if file.UnlimitedTime { + newData.UnlimitedTime = 1 + } + + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + err := enc.Encode(file.Encryption) + helper.Check(err) + newData.Encryption = buf.Bytes() + + _, err = sqliteDb.Exec(`INSERT OR REPLACE INTO FileMetaData (Id, Name, Size, SHA1, ExpireAt, SizeBytes, ExpireAtString, + DownloadsRemaining, DownloadCount, PasswordHash, HotlinkId, ContentType, AwsBucket, Encryption, + UnlimitedDownloads, UnlimitedTime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + newData.Id, newData.Name, newData.Size, newData.SHA1, newData.ExpireAt, newData.SizeBytes, newData.ExpireAtString, + newData.DownloadsRemaining, newData.DownloadCount, newData.PasswordHash, newData.HotlinkId, newData.ContentType, + newData.AwsBucket, newData.Encryption, newData.UnlimitedDownloads, newData.UnlimitedTime) + helper.Check(err) +} + +// DeleteMetaData deletes information about a file +func DeleteMetaData(id string) { + _, err := sqliteDb.Exec("DELETE FROM FileMetaData WHERE Id = ?", id) + helper.Check(err) +} diff --git a/internal/configuration/database/sessions.go b/internal/configuration/database/sessions.go new file mode 100644 index 0000000..b4e83f0 --- /dev/null +++ b/internal/configuration/database/sessions.go @@ -0,0 +1,65 @@ +package database + +import ( + "database/sql" + "errors" + "github.com/forceu/gokapi/internal/helper" + "github.com/forceu/gokapi/internal/models" + "time" +) + +type schemaSessions struct { + Id string + RenewAt int64 + ValidUntil int64 +} + +// GetSession returns the session with the given ID or false if not a valid ID +func GetSession(id string) (models.Session, bool) { + var rowResult schemaSessions + row := sqliteDb.QueryRow("SELECT * FROM Sessions WHERE Id = ?", id) + err := row.Scan(&rowResult.Id, &rowResult.RenewAt, &rowResult.ValidUntil) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return models.Session{}, false + } + helper.Check(err) + return models.Session{}, false + } + result := models.Session{ + RenewAt: rowResult.RenewAt, + ValidUntil: rowResult.ValidUntil, + } + return result, true +} + +// SaveSession stores the given session. After the expiry passed, it will be deleted automatically +func SaveSession(id string, session models.Session) { + newData := schemaSessions{ + Id: id, + RenewAt: session.RenewAt, + ValidUntil: session.ValidUntil, + } + + _, err := sqliteDb.Exec("INSERT OR REPLACE INTO Sessions (Id, RenewAt, ValidUntil) VALUES (?, ?, ?)", + newData.Id, newData.RenewAt, newData.ValidUntil) + helper.Check(err) +} + +// DeleteSession deletes a session with the given ID +func DeleteSession(id string) { + _, err := sqliteDb.Exec("DELETE FROM Sessions WHERE Id = ?", id) + helper.Check(err) +} + +// DeleteAllSessions logs all users out +func DeleteAllSessions() { + //goland:noinspection SqlWithoutWhere + _, err := sqliteDb.Exec("DELETE FROM Sessions") + helper.Check(err) +} + +func cleanExpiredSessions() { + _, err := sqliteDb.Exec("DELETE FROM Sessions WHERE Sessions.ValidUntil < ?", time.Now().Unix()) + helper.Check(err) +} diff --git a/internal/configuration/database/uploaddefaults.go b/internal/configuration/database/uploaddefaults.go new file mode 100644 index 0000000..9aad005 --- /dev/null +++ b/internal/configuration/database/uploaddefaults.go @@ -0,0 +1,69 @@ +package database + +import ( + "database/sql" + "errors" + "github.com/forceu/gokapi/internal/helper" + "github.com/forceu/gokapi/internal/models" +) + +type schemaUploadConfig struct { + Id int64 + Downloads int + TimeExpiry int + Password string + UnlimitedDownloads int + UnlimitedTime int +} + +// GetUploadDefaults returns the last used setting for amount of downloads allowed, last expiry in days and +// a password for the file +func GetUploadDefaults() models.LastUploadValues { + defaultValues := models.LastUploadValues{ + Downloads: 1, + TimeExpiry: 14, + Password: "", + UnlimitedDownload: false, + UnlimitedTime: false, + } + + rowResult := schemaUploadConfig{} + row := sqliteDb.QueryRow("SELECT * FROM UploadConfig WHERE id = 1") + err := row.Scan(&rowResult.Id, &rowResult.Downloads, &rowResult.TimeExpiry, &rowResult.Password, &rowResult.UnlimitedDownloads, &rowResult.UnlimitedTime) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return defaultValues + } + helper.Check(err) + return defaultValues + } + + result := models.LastUploadValues{ + Downloads: rowResult.Downloads, + TimeExpiry: rowResult.TimeExpiry, + Password: rowResult.Password, + UnlimitedDownload: rowResult.UnlimitedDownloads == 1, + UnlimitedTime: rowResult.UnlimitedTime == 1, + } + return result +} + +// SaveUploadDefaults saves the last used setting for an upload +func SaveUploadDefaults(values models.LastUploadValues) { + + newData := schemaUploadConfig{ + Downloads: values.Downloads, + TimeExpiry: values.TimeExpiry, + Password: values.Password, + } + if values.UnlimitedDownload { + newData.UnlimitedDownloads = 1 + } + if values.UnlimitedTime { + newData.UnlimitedTime = 1 + } + + _, err := sqliteDb.Exec("INSERT OR REPLACE INTO UploadConfig (id, Downloads,TimeExpiry,Password,UnlimitedDownloads,UnlimitedTime) VALUES (1, ?, ?, ?, ?, ?)", + newData.Downloads, newData.TimeExpiry, newData.Password, newData.UnlimitedDownloads, newData.UnlimitedTime) + helper.Check(err) +} diff --git a/internal/configuration/database/uploadstatus.go b/internal/configuration/database/uploadstatus.go new file mode 100644 index 0000000..7a2646e --- /dev/null +++ b/internal/configuration/database/uploadstatus.go @@ -0,0 +1,63 @@ +package database + +import ( + "database/sql" + "errors" + "github.com/forceu/gokapi/internal/helper" + "github.com/forceu/gokapi/internal/models" + "time" +) + +type schemaUploadStatus struct { + ChunkId string + CurrentStatus int + LastUpdate int64 + CreationDate int64 +} + +// GetUploadStatus returns a models.UploadStatus from the ID passed or false if the id is not valid +func GetUploadStatus(id string) (models.UploadStatus, bool) { + result := models.UploadStatus{ + ChunkId: id, + CurrentStatus: 0, + LastUpdate: 0, + } + + var rowResult schemaUploadStatus + row := sqliteDb.QueryRow("SELECT * FROM UploadStatus WHERE ChunkId = ?", id) + err := row.Scan(&rowResult.ChunkId, &rowResult.CurrentStatus, &rowResult.LastUpdate, &rowResult.CreationDate) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return models.UploadStatus{}, false + } + helper.Check(err) + return models.UploadStatus{}, false + } + result.CurrentStatus = rowResult.CurrentStatus + result.LastUpdate = rowResult.LastUpdate + return result, true +} + +// currentTime is used in order to modify the current time for testing purposes in unit tests +var currentTime = func() time.Time { + return time.Now() +} + +// SaveUploadStatus stores the upload status of a new file for 24 hours +func SaveUploadStatus(status models.UploadStatus) { + newData := schemaUploadStatus{ + ChunkId: status.ChunkId, + CurrentStatus: status.CurrentStatus, + LastUpdate: status.LastUpdate, + CreationDate: currentTime().Unix(), + } + + _, err := sqliteDb.Exec("INSERT OR REPLACE INTO UploadStatus (ChunkId, CurrentStatus, LastUpdate, CreationDate) VALUES (?, ?, ?, ?)", + newData.ChunkId, newData.CurrentStatus, newData.LastUpdate, newData.CreationDate) + helper.Check(err) +} + +func cleanUploadStatus() { + _, err := sqliteDb.Exec("DELETE FROM UploadStatus WHERE CreationDate < ?", currentTime().Add(-time.Hour*24).Unix()) + helper.Check(err) +} diff --git a/internal/environment/Environment.go b/internal/environment/Environment.go index d2aafb3..64684c2 100644 --- a/internal/environment/Environment.go +++ b/internal/environment/Environment.go @@ -3,11 +3,10 @@ package environment import ( "fmt" envParser "github.com/caarlos0/env/v6" - "github.com/forceu/gokapi/internal/configuration/database" "github.com/forceu/gokapi/internal/environment/flagparser" "github.com/forceu/gokapi/internal/helper" "os" - "strconv" + "path" ) // DefaultPort for the webserver @@ -17,6 +16,7 @@ const DefaultPort = 53842 type Environment struct { ConfigDir string `env:"CONFIG_DIR" envDefault:"config"` ConfigFile string `env:"CONFIG_FILE" envDefault:"config.json"` + ConfigPath string DataDir string `env:"DATA_DIR" envDefault:"data"` WebserverPort int `env:"PORT" envDefault:"53842"` LengthId int `env:"LENGTH_ID" envDefault:"15"` @@ -27,9 +27,12 @@ type Environment struct { AwsKeyId string `env:"AWS_KEY"` AwsKeySecret string `env:"AWS_KEY_SECRET"` AwsEndpoint string `env:"AWS_ENDPOINT"` - ConfigPath string - FileDbPath string - FileDb string `env:"FILE_DB" envDefault:"filestorage.db"` + DatabaseName string `env:"DB_NAME" envDefault:"gokapi.sqlite"` + // Deprecated: will be removed with 1.9 + LegacyDbPath string + // Deprecated: will be removed with 1.9 + // Previously undocumented env "FILE_DB" + LegacyDbFolderName string `env:"LEGACY_FILE_DB" envDefault:"filestorage.db"` } // New parses the env variables @@ -56,21 +59,20 @@ func New() Environment { result.DataDir = flags.DataDir } + result.ConfigDir = path.Clean(result.ConfigDir) + result.DataDir = path.Clean(result.DataDir) result.ConfigPath = result.ConfigDir + "/" + result.ConfigFile if flags.IsConfigPathSet { result.ConfigPath = flags.ConfigPath } - result.FileDbPath = result.DataDir + "/" + result.FileDb + result.LegacyDbPath = result.DataDir + "/" + result.LegacyDbFolderName if IsDockerInstance() && os.Getenv("TMPDIR") == "" { - os.Setenv("TMPDIR", result.DataDir) + err = os.Setenv("TMPDIR", result.DataDir) + helper.Check(err) } if result.LengthId < 5 { result.LengthId = 5 } - if result.LengthId > database.GetLengthAvailable() { - result.LengthId = database.GetLengthAvailable() - fmt.Println("Reduced ID length to " + strconv.Itoa(database.GetLengthAvailable()) + " due to database constraints") - } if result.MaxMemory < 5 { result.MaxMemory = 5 } diff --git a/internal/environment/Environment_test.go b/internal/environment/Environment_test.go index 6f52f7f..2f85281 100644 --- a/internal/environment/Environment_test.go +++ b/internal/environment/Environment_test.go @@ -43,7 +43,7 @@ func TestEnvLoad(t *testing.T) { test.IsEqualInt(t, env.LengthId, 5) os.Setenv("GOKAPI_LENGTH_ID", "86") env = New() - test.IsEqualInt(t, env.LengthId, 85) + test.IsEqualInt(t, env.LengthId, 86) os.Unsetenv("GOKAPI_LENGTH_ID") env = New() os.Setenv("GOKAPI_LENGTH_ID", "15") diff --git a/internal/models/UploadStatus.go b/internal/models/UploadStatus.go index 2e2b86a..13c1f12 100644 --- a/internal/models/UploadStatus.go +++ b/internal/models/UploadStatus.go @@ -6,9 +6,14 @@ import ( // UploadStatus contains information about the current status of a file upload type UploadStatus struct { - ChunkId string `json:"chunkid"` - CurrentStatus int `json:"currentstatus"` - LastUpdate int64 `json:"lastupdate"` + // ChunkId is the identifier for the chunk + ChunkId string `json:"chunkid"` + // CurrentStatus indicates if the chunk is currently being processed (e.g. encrypting or + // hashing) or being moved/uploaded to the file storage + // See processingstatus for definition + CurrentStatus int `json:"currentstatus"` + // LastUpdate indicates the last status change + LastUpdate int64 `json:"lastupdate"` } // ToJson returns the struct as a Json byte array diff --git a/internal/storage/FileServing.go b/internal/storage/FileServing.go index 1f70550..c27ec16 100644 --- a/internal/storage/FileServing.go +++ b/internal/storage/FileServing.go @@ -623,6 +623,7 @@ func CleanUp(periodic bool) { CleanUp(false) } cleanOldTempFiles() + database.RunGarbageCollection() if periodic { go func() { @@ -632,7 +633,6 @@ func CleanUp(periodic bool) { } }() } - database.RunGarbageCollection() } func cleanOldTempFiles() { diff --git a/internal/test/testconfiguration/TestConfiguration.go b/internal/test/testconfiguration/TestConfiguration.go index 349b785..12bdfea 100644 --- a/internal/test/testconfiguration/TestConfiguration.go +++ b/internal/test/testconfiguration/TestConfiguration.go @@ -18,14 +18,16 @@ import ( ) const ( - dataDir = "test" - configFile = dataDir + "/config.json" + baseDir = "test" + dataDir = baseDir + "/data" + configFile = baseDir + "/config.json" ) func SetDirEnv() { - os.Setenv("GOKAPI_CONFIG_DIR", "test") - os.Setenv("GOKAPI_DATA_DIR", "test") - os.Mkdir(dataDir, 0777) + os.Setenv("GOKAPI_CONFIG_DIR", baseDir) + os.Setenv("GOKAPI_DATA_DIR", dataDir) + os.MkdirAll(baseDir, 0777) + os.MkdirAll(dataDir, 0777) } @@ -33,7 +35,7 @@ func SetDirEnv() { func Create(initFiles bool) { SetDirEnv() os.WriteFile(configFile, configTestFile, 0777) - database.Init("./test/filestorage.db") + database.Init(dataDir, "gokapi.sqlite") writeTestSessions() database.SaveUploadDefaults(models.LastUploadValues{ Downloads: 3, @@ -48,13 +50,13 @@ func Create(initFiles bool) { database.Close() if initFiles { - os.Mkdir("test/data", 0777) - os.WriteFile("test/data/a8fdc205a9f19cc1c7507a60c4f01b13d11d7fd0", []byte("123"), 0777) - os.WriteFile("test/data/c4f9375f9834b4e7f0a528cc65c055702bf5f24a", []byte("456"), 0777) - os.WriteFile("test/data/e017693e4a04a59d0b0f400fe98177fe7ee13cf7", []byte("789"), 0777) - os.WriteFile("test/data/2341354656543213246465465465432456898794", []byte("abc"), 0777) - os.WriteFile("test/data/unlimtedtest", []byte("def"), 0777) - os.WriteFile("test/fileupload.jpg", []byte("abc"), 0777) + os.MkdirAll(dataDir, 0777) + os.WriteFile(dataDir+"/a8fdc205a9f19cc1c7507a60c4f01b13d11d7fd0", []byte("123"), 0777) + os.WriteFile(dataDir+"/c4f9375f9834b4e7f0a528cc65c055702bf5f24a", []byte("456"), 0777) + os.WriteFile(dataDir+"/e017693e4a04a59d0b0f400fe98177fe7ee13cf7", []byte("789"), 0777) + os.WriteFile(dataDir+"/2341354656543213246465465465432456898794", []byte("abc"), 0777) + os.WriteFile(dataDir+"/unlimitedtest", []byte("def"), 0777) + os.WriteFile(baseDir+"/fileupload.jpg", []byte("abc"), 0777) } } @@ -76,29 +78,29 @@ func WriteEncryptedFile() string { // WriteSslCertificates writes a valid or invalid SSL certificate func WriteSslCertificates(valid bool) { - os.Mkdir(dataDir, 0777) + os.Mkdir(baseDir, 0777) if valid { - os.WriteFile("test/ssl.crt", sslCertValid, 0700) - os.WriteFile("test/ssl.key", sslKeyValid, 0700) + os.WriteFile(baseDir+"/ssl.crt", sslCertValid, 0700) + os.WriteFile(baseDir+"/ssl.key", sslKeyValid, 0700) } else { - os.WriteFile("test/ssl.crt", sslCertExpired, 0700) - os.WriteFile("test/ssl.key", sslKeyExpired, 0700) + os.WriteFile(baseDir+"/ssl.crt", sslCertExpired, 0700) + os.WriteFile(baseDir+"/ssl.key", sslKeyExpired, 0700) } } // WriteCloudConfigFile writes a valid or invalid AWS config file func WriteCloudConfigFile(valid bool) { - os.Mkdir(dataDir, 0777) + os.Mkdir(baseDir, 0777) if valid { - os.WriteFile("test/cloudconfig.yml", cloudConfigTestFile, 0700) + os.WriteFile(baseDir+"/cloudconfig.yml", cloudConfigTestFile, 0700) } else { - os.WriteFile("test/cloudconfig.yml", []byte("invalid"), 0700) + os.WriteFile(baseDir+"/cloudconfig.yml", []byte("invalid"), 0700) } } // Delete deletes the configuration for unit testing func Delete() { - os.RemoveAll(dataDir) + os.RemoveAll(baseDir) } var testServer *httptest.Server @@ -154,40 +156,40 @@ func writeTestSessions() { database.SaveSession("validsession", models.Session{ RenewAt: 2147483645, ValidUntil: 2147483646, - }, 1*time.Hour) + }) database.SaveSession("logoutsession", models.Session{ RenewAt: 2147483645, ValidUntil: 2147483646, - }, 1*time.Hour) + }) database.SaveSession("needsRenewal", models.Session{ RenewAt: 0, ValidUntil: 2147483646, - }, 1*time.Hour) + }) database.SaveSession("expiredsession", models.Session{ RenewAt: 0, ValidUntil: 0, - }, 1*time.Hour) + }) } func writeApiKeyys() { database.SaveApiKey(models.ApiKey{ Id: "validkey", FriendlyName: "First Key", - }, false) + }) database.SaveApiKey(models.ApiKey{ Id: "GAh1IhXDvYnqfYLazWBqMB9HSFmNPO", FriendlyName: "Second Key", LastUsed: 1620671580, LastUsedString: "used", - }, false) + }) database.SaveApiKey(models.ApiKey{ Id: "jiREglQJW0bOqJakfjdVfe8T1EM8n8", FriendlyName: "Unnamed Key", - }, false) + }) database.SaveApiKey(models.ApiKey{ Id: "okeCMWqhVMZSpt5c1qpCWhKvJJPifb", FriendlyName: "Unnamed Key", - }, false) + }) } func writeTestFiles() { @@ -289,7 +291,7 @@ func writeTestFiles() { Id: "unlimitedDownload", Name: "unlimitedDownload", Size: "8 B", - SHA1: "unlimtedtest", + SHA1: "unlimitedtest", ExpireAt: 2147483646, ExpireAtString: "2021-05-04 15:19", DownloadsRemaining: 0, @@ -300,7 +302,7 @@ func writeTestFiles() { Id: "unlimitedTime", Name: "unlimitedTime", Size: "8 B", - SHA1: "unlimtedtest", + SHA1: "unlimitedtest", ExpireAt: 0, ExpireAtString: "2021-05-04 15:19", DownloadsRemaining: 1, @@ -326,7 +328,7 @@ var configTestFile = []byte(`{ "Port":"127.0.0.1:53843", "ServerUrl": "http://127.0.0.1:53843/", "RedirectUrl": "https://test.com/", - "ConfigVersion": 12, + "ConfigVersion": 15, "LengthId": 20, "DataDir": "test/data", "MaxMemory": 10, diff --git a/internal/test/testconfiguration/TestConfiguration_test.go b/internal/test/testconfiguration/TestConfiguration_test.go index 56ab169..a1007cb 100644 --- a/internal/test/testconfiguration/TestConfiguration_test.go +++ b/internal/test/testconfiguration/TestConfiguration_test.go @@ -24,7 +24,7 @@ func TestDelete(t *testing.T) { } func TestWriteEncryptedFile(t *testing.T) { - database.Init("./test/filestorage.db") + database.Init("./test", "gokapi.sqlite") fileId := WriteEncryptedFile() file, ok := database.GetMetaDataById(fileId) test.IsEqualBool(t, ok, true) diff --git a/internal/webserver/api/Api.go b/internal/webserver/api/Api.go index b105e67..2e9f96c 100644 --- a/internal/webserver/api/Api.go +++ b/internal/webserver/api/Api.go @@ -59,7 +59,7 @@ func NewKey() string { FriendlyName: "Unnamed key", LastUsed: 0, } - database.SaveApiKey(newKey, false) + database.SaveApiKey(newKey) return newKey.Id } @@ -78,7 +78,7 @@ func changeFriendlyName(w http.ResponseWriter, request apiRequest) { } if key.FriendlyName != request.apiInfo.friendlyName { key.FriendlyName = request.apiInfo.friendlyName - database.SaveApiKey(key, false) + database.SaveApiKey(key) } } @@ -304,7 +304,7 @@ func IsValidApiKey(key string, modifyTime bool) bool { if ok && savedKey.Id != "" { if modifyTime { savedKey.LastUsed = time.Now().Unix() - database.SaveApiKey(savedKey, true) + database.UpdateTimeApiKey(savedKey) } return true } diff --git a/internal/webserver/authentication/sessionmanager/SessionManager.go b/internal/webserver/authentication/sessionmanager/SessionManager.go index f225153..36ecb16 100644 --- a/internal/webserver/authentication/sessionmanager/SessionManager.go +++ b/internal/webserver/authentication/sessionmanager/SessionManager.go @@ -57,7 +57,7 @@ func CreateSession(w http.ResponseWriter) { database.SaveSession(sessionString, models.Session{ RenewAt: time.Now().Add(12 * time.Hour).Unix(), ValidUntil: time.Now().Add(cookieLifeAdmin).Unix(), - }, cookieLifeAdmin) + }) writeSessionCookie(w, sessionString, time.Now().Add(cookieLifeAdmin)) } diff --git a/internal/webserver/authentication/sessionmanager/SessionManager_test.go b/internal/webserver/authentication/sessionmanager/SessionManager_test.go index 77a1bf6..e49880d 100644 --- a/internal/webserver/authentication/sessionmanager/SessionManager_test.go +++ b/internal/webserver/authentication/sessionmanager/SessionManager_test.go @@ -13,7 +13,7 @@ import ( var newSession string func TestMain(m *testing.M) { - testconfiguration.Create(true) + testconfiguration.Create(false) configuration.Load() exitVal := m.Run() testconfiguration.Delete() diff --git a/internal/webserver/web/templates/string_constants.tmpl b/internal/webserver/web/templates/string_constants.tmpl index 73b8411..d0a11bf 100644 --- a/internal/webserver/web/templates/string_constants.tmpl +++ b/internal/webserver/web/templates/string_constants.tmpl @@ -1,5 +1,5 @@ // Change these for rebranding -{{define "version"}}1.7.2{{end}} +{{define "version"}}1.8.0beta1{{end}} // Specifies the version of JS files, so that the browser doesn't // use a cached version, if the file has been updated