mirror of
https://github.com/lus/pasty.git
synced 2023-08-10 21:13:09 +03:00
restructure startup & config logic
This commit is contained in:
parent
e93b292daf
commit
3575c02c1e
@ -1,52 +1,65 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"context"
|
||||
"github.com/lus/pasty/internal/config"
|
||||
"github.com/lus/pasty/internal/meta"
|
||||
"github.com/lus/pasty/internal/storage"
|
||||
"github.com/lus/pasty/internal/web"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"os"
|
||||
"os/signal"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Load the configuration
|
||||
log.Println("Loading the application configuration...")
|
||||
config.Load()
|
||||
// Set up the logger
|
||||
zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMs
|
||||
if !meta.IsProdEnvironment() {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{
|
||||
Out: os.Stderr,
|
||||
})
|
||||
log.Warn().Msg("This distribution was compiled for development mode and is thus not meant to be run in production!")
|
||||
}
|
||||
|
||||
// Load the configured storage driver
|
||||
log.Println("Loading the configured storage driver...")
|
||||
err := storage.Load()
|
||||
// Load the configuration
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Fatal().Err(err).Msg("Could not load the configuration.")
|
||||
}
|
||||
|
||||
// Adjust the log level
|
||||
if !meta.IsProdEnvironment() {
|
||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||
} else {
|
||||
level, err := zerolog.ParseLevel(cfg.LogLevel)
|
||||
if err != nil {
|
||||
log.Warn().Msg("An invalid log level was configured. Falling back to 'info'.")
|
||||
level = zerolog.InfoLevel
|
||||
}
|
||||
zerolog.SetGlobalLevel(level)
|
||||
}
|
||||
|
||||
// Initialize the configured storage driver
|
||||
driver, ok := storage.ResolveDriver(cfg.StorageDriver)
|
||||
if !ok {
|
||||
log.Fatal().Str("driver_name", cfg.StorageDriver).Msg("An invalid storage driver name was given.")
|
||||
return
|
||||
}
|
||||
log.Info().Str("driver_name", cfg.StorageDriver).Msg("Initializing the storage driver...")
|
||||
if err := driver.Initialize(context.Background(), cfg); err != nil {
|
||||
log.Fatal().Err(err).Str("driver_name", cfg.StorageDriver).Msg("The storage driver could not be initialized.")
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
log.Println("Terminating the storage driver...")
|
||||
err := storage.Current.Terminate()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Info().Msg("Shutting down the storage driver...")
|
||||
if err := driver.Close(); err != nil {
|
||||
log.Err(err).Str("driver_name", cfg.StorageDriver).Msg("Could not shut down the storage driver.")
|
||||
}
|
||||
}()
|
||||
|
||||
// Schedule the AutoDelete task
|
||||
if config.Current.AutoDelete.Enabled {
|
||||
log.Println("Scheduling the AutoDelete task...")
|
||||
go func() {
|
||||
for {
|
||||
// Run the cleanup sequence
|
||||
deleted, err := storage.Current.Cleanup()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
log.Printf("AutoDelete: Deleted %d expired pastes", deleted)
|
||||
|
||||
// Wait until the process should repeat
|
||||
time.Sleep(config.Current.AutoDelete.TaskInterval)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Serve the web resources
|
||||
log.Println("Serving the web resources...")
|
||||
panic(web.Serve())
|
||||
// Wait for an interrupt signal
|
||||
log.Info().Msg("The application has been started. Use Ctrl+C to shut it down.")
|
||||
shutdownChan := make(chan os.Signal, 1)
|
||||
signal.Notify(shutdownChan, os.Interrupt)
|
||||
<-shutdownChan
|
||||
}
|
||||
|
@ -1,81 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/lus/pasty/internal/config"
|
||||
"github.com/lus/pasty/internal/storage"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Validate the command line arguments
|
||||
if len(os.Args) != 3 {
|
||||
panic("Invalid command line arguments")
|
||||
}
|
||||
|
||||
// Load the configuration
|
||||
log.Println("Loading the application configuration...")
|
||||
config.Load()
|
||||
|
||||
// Create and initialize the first (from) driver
|
||||
from, err := storage.GetDriver(storage.Type(os.Args[1]))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = from.Initialize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create and initialize the second (to) driver
|
||||
to, err := storage.GetDriver(storage.Type(os.Args[2]))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = to.Initialize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Retrieve a list of IDs from the first (from) driver
|
||||
ids, err := from.ListIDs()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Transfer every paste to the second (to) driver
|
||||
for _, id := range ids {
|
||||
log.Println("Transferring ID " + id + "...")
|
||||
|
||||
// Retrieve the paste
|
||||
paste, err := from.Get(id)
|
||||
if err != nil {
|
||||
log.Println("[ERR]", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
// Move the content of the deletion token field to the modification field
|
||||
if paste.DeletionToken != "" {
|
||||
if paste.ModificationToken == "" {
|
||||
paste.ModificationToken = paste.DeletionToken
|
||||
}
|
||||
paste.DeletionToken = ""
|
||||
log.Println("[INFO] Paste " + id + " was a legacy one.")
|
||||
}
|
||||
|
||||
// Initialize a new metadata map if the old one is null
|
||||
if paste.Metadata == nil {
|
||||
paste.Metadata = make(map[string]interface{})
|
||||
}
|
||||
|
||||
// Save the paste
|
||||
err = to.Save(paste)
|
||||
if err != nil {
|
||||
log.Println("[ERR]", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
log.Println("Transferred ID " + id + ".")
|
||||
}
|
||||
}
|
35
go.mod
35
go.mod
@ -1,23 +1,32 @@
|
||||
module github.com/lus/pasty
|
||||
|
||||
go 1.16
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/alexedwards/argon2id v0.0.0-20200802152012-2464efd3196b
|
||||
github.com/fasthttp/router v1.2.4
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/golang-migrate/migrate/v4 v4.14.2-0.20201125065321-a53e6fc42574
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/jackc/pgx/v4 v4.11.0
|
||||
github.com/johejo/golang-migrate-extra v0.0.0-20210217013041-51a992e50d16
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/klauspost/compress v1.15.1 // indirect
|
||||
github.com/minio/minio-go/v7 v7.0.5
|
||||
github.com/ulule/limiter/v3 v3.5.0
|
||||
github.com/valyala/fasthttp v1.16.0
|
||||
github.com/xdg-go/scram v1.1.1 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
|
||||
go.mongodb.org/mongo-driver v1.8.4
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
github.com/kelseyhightower/envconfig v1.4.0
|
||||
github.com/rs/zerolog v1.29.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgconn v1.8.1 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.0.6 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
||||
github.com/jackc/pgtype v1.7.0 // indirect
|
||||
github.com/jackc/puddle v1.1.3 // indirect
|
||||
github.com/lib/pq v1.8.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
|
||||
golang.org/x/text v0.3.3 // indirect
|
||||
)
|
||||
|
131
go.sum
131
go.sum
@ -52,8 +52,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alexedwards/argon2id v0.0.0-20200802152012-2464efd3196b h1:rcCpjI1OMGtBY8nnBvExeM1pXNoaM35zqmXBGpgJR2o=
|
||||
github.com/alexedwards/argon2id v0.0.0-20200802152012-2464efd3196b/go.mod h1:GFtu6vaWaRJV5EvSFaVqgq/3Iq95xyYElBV/aupGzUo=
|
||||
github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4=
|
||||
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20200601151325-b2287a20f230/go.mod h1:QNYViu/X0HXDHw7m3KXzWSVXIbfUvJqBFe6Gj8/pYA0=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
@ -96,6 +94,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
@ -126,16 +125,12 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fasthttp/router v1.2.4 h1:RBWbCv4vVf+boczSZh/rX9PDSdR9F8I9zSnVJx5YJfU=
|
||||
github.com/fasthttp/router v1.2.4/go.mod h1:Au2V1CaqqAdzQQcPKrbkFAsImd1aHpadrce21AIPnvE=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
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=
|
||||
@ -145,18 +140,12 @@ github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgO
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-redis/redis/v7 v7.2.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
||||
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
||||
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
|
||||
github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||
@ -199,8 +188,6 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
@ -211,8 +198,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@ -228,11 +213,9 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/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 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
@ -272,7 +255,6 @@ github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmK
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
|
||||
@ -292,7 +274,6 @@ github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye47
|
||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
|
||||
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
|
||||
@ -336,30 +317,18 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
|
||||
github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
||||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.9.6/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A=
|
||||
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
|
||||
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@ -369,7 +338,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/ktrysmt/go-bitbucket v0.6.4/go.mod h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq19sBYvuMoyQ4=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
@ -384,6 +352,8 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
@ -391,21 +361,15 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
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/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4=
|
||||
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
|
||||
github.com/minio/minio-go/v7 v7.0.5 h1:I2NIJ2ojwJqD/YByemC1M59e1b4FW9kS7NlOar7HPV4=
|
||||
github.com/minio/minio-go/v7 v7.0.5/go.mod h1:TA0CQCjJZHM5SJj9IjqR0NmpmQJ6bCbXifAJ3mUU6Hw=
|
||||
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
|
||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
@ -413,12 +377,9 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY=
|
||||
@ -437,10 +398,8 @@ github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQ
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
@ -491,16 +450,16 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
|
||||
github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/savsgio/gotils v0.0.0-20200616100644-13ff1fd2c28c h1:KKqhycXW1WVNkX7r4ekTV2gFkbhdyihlWD8c0/FiWmk=
|
||||
github.com/savsgio/gotils v0.0.0-20200616100644-13ff1fd2c28c/go.mod h1:TWNAOTaVzGOXq8RbEvHnhzA/A2sLZzgn0m6URjnukY8=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc h1:jUIKcSPO9MoMJBbEoyE/RJoE8vz7Mb8AjvifMMwSyvY=
|
||||
@ -512,10 +471,7 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/snowflakedb/glog v0.0.0-20180824191149-f5055e6f21ce/go.mod h1:EB/w24pR5VKI60ecFnKqXzxX3dOorz1rnVicQTQrGM0=
|
||||
github.com/snowflakedb/gosnowflake v1.3.5/go.mod h1:13Ky+lxzIm3VqNDZJdyvu9MCGy+WgRdYFdXp96UcLZU=
|
||||
@ -533,41 +489,16 @@ github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ulule/limiter/v3 v3.5.0 h1:QRAebbswjlezHIfiSQgM8+jMxaz/zsrxGRuiUJ43MHo=
|
||||
github.com/ulule/limiter/v3 v3.5.0/go.mod h1:TgOUQZKZ2KHjemqrC8UHUbKPqpTmSY43/2wbQ7YN1h8=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.9.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
||||
github.com/valyala/fasthttp v1.15.1/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA=
|
||||
github.com/valyala/fasthttp v1.16.0 h1:9zAqOYLl8Tuy3E5R6ckzGDJ1g8+pw15oQp2iL9Jl6gQ=
|
||||
github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
|
||||
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
|
||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
|
||||
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
|
||||
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
||||
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@ -576,8 +507,6 @@ gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.mongodb.org/mongo-driver v1.8.4 h1:NruvZPPL0PBcRJKmbswoWSrmHeUvzdxA3GCPfD/NEOA=
|
||||
go.mongodb.org/mongo-driver v1.8.4/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
@ -607,16 +536,13 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o=
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
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=
|
||||
@ -670,8 +596,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@ -683,15 +607,13 @@ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201029221708-28c70e62bb1d/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@ -707,8 +629,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
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=
|
||||
@ -733,7 +653,6 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -752,27 +671,21 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
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=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
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=
|
||||
@ -792,7 +705,6 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn
|
||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
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=
|
||||
@ -836,7 +748,6 @@ golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
@ -932,15 +843,12 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
|
||||
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
@ -949,9 +857,8 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
@ -1,123 +1,55 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/kelseyhightower/envconfig"
|
||||
"time"
|
||||
|
||||
"github.com/lus/pasty/internal/env"
|
||||
)
|
||||
|
||||
// Config represents the general application configuration structure
|
||||
// Config represents the general application configuration
|
||||
type Config struct {
|
||||
WebAddress string
|
||||
StorageType string
|
||||
HastebinSupport bool
|
||||
IDLength int
|
||||
IDCharacters string
|
||||
ModificationTokens bool
|
||||
ModificationTokenMaster string
|
||||
ModificationTokenLength int
|
||||
ModificationTokenCharacters string
|
||||
RateLimit string
|
||||
LengthCap int
|
||||
AutoDelete *AutoDeleteConfig
|
||||
LogLevel string `default:"info" split_words:"true"`
|
||||
WebAddress string `default:":8080" split_words:"true"`
|
||||
StorageDriver string `default:"sqlite" split_words:"true"`
|
||||
HastebinSupport bool `default:"false" split_words:"true"`
|
||||
IDLength int `default:"6" split_words:"true"`
|
||||
IDCharacters string `default:"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" split_words:"true"`
|
||||
ModificationTokens bool `default:"true" split_words:"true"`
|
||||
ModificationTokenMaster string `split_words:"true"`
|
||||
ModificationTokenLength int `default:"12" split_words:"true"`
|
||||
ModificationTokenCharacters string `default:"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" split_words:"true"`
|
||||
RateLimit string `default:"30-M" split_words:"true"`
|
||||
LengthCap int `default:"50000" split_words:"true"`
|
||||
AutoDelete *AutoDeleteConfig `split_words:"true"`
|
||||
Reports *ReportConfig
|
||||
File *FileConfig
|
||||
Postgres *PostgresConfig
|
||||
MongoDB *MongoDBConfig
|
||||
S3 *S3Config
|
||||
}
|
||||
|
||||
// AutoDeleteConfig represents the configuration specific for the AutoDelete behaviour
|
||||
type AutoDeleteConfig struct {
|
||||
Enabled bool
|
||||
Lifetime time.Duration
|
||||
TaskInterval time.Duration
|
||||
}
|
||||
|
||||
// FileConfig represents the configuration specific for the file storage driver
|
||||
type FileConfig struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
// PostgresConfig represents the configuration specific for the Postgres storage driver
|
||||
type PostgresConfig struct {
|
||||
DSN string
|
||||
}
|
||||
|
||||
// MongoDBConfig represents the configuration specific for the MongoDB storage driver
|
||||
type MongoDBConfig struct {
|
||||
DSN string
|
||||
Database string
|
||||
Collection string
|
||||
}
|
||||
|
||||
// S3Config represents the configuration specific for the S3 storage driver
|
||||
type S3Config struct {
|
||||
Endpoint string
|
||||
AccessKeyID string
|
||||
SecretAccessKey string
|
||||
SecretToken string
|
||||
Secure bool
|
||||
Region string
|
||||
Bucket string
|
||||
Enabled bool `default:"false"`
|
||||
Lifetime time.Duration `default:"720h"`
|
||||
TaskInterval time.Duration `default:"5m" split_words:"true"`
|
||||
}
|
||||
|
||||
// ReportConfig represents the configuration specific for the report system
|
||||
type ReportConfig struct {
|
||||
Reports bool
|
||||
ReportWebhook string
|
||||
ReportWebhookToken string
|
||||
Enabled bool `default:"false" split_words:"true"`
|
||||
WebhookURL string `split_words:"true"`
|
||||
WebhookToken string `split_words:"true"`
|
||||
}
|
||||
|
||||
// Current holds the currently loaded config
|
||||
var Current *Config
|
||||
// PostgresConfig represents the configuration specific for the Postgres storage driver
|
||||
type PostgresConfig struct {
|
||||
DSN string `default:"postgres://pasty:pasty@localhost/pasty"`
|
||||
}
|
||||
|
||||
// Load loads the current config from environment variables and an optional .env file
|
||||
func Load() {
|
||||
env.Load()
|
||||
|
||||
Current = &Config{
|
||||
WebAddress: env.MustString("WEB_ADDRESS", ":8080"),
|
||||
StorageType: strings.ToLower(env.MustString("STORAGE_TYPE", "file")),
|
||||
HastebinSupport: env.MustBool("HASTEBIN_SUPPORT", false),
|
||||
IDLength: env.MustInt("ID_LENGTH", 6),
|
||||
IDCharacters: env.MustString("ID_CHARACTERS", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"),
|
||||
ModificationTokens: env.MustBool("MODIFICATION_TOKENS", true),
|
||||
ModificationTokenMaster: env.MustString("MODIFICATION_TOKEN_MASTER", ""),
|
||||
ModificationTokenLength: env.MustInt("MODIFICATION_TOKEN_LENGTH", 12),
|
||||
ModificationTokenCharacters: env.MustString("MODIFICATION_TOKEN_CHARACTERS", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"),
|
||||
RateLimit: env.MustString("RATE_LIMIT", "30-M"),
|
||||
LengthCap: env.MustInt("LENGTH_CAP", 50000),
|
||||
AutoDelete: &AutoDeleteConfig{
|
||||
Enabled: env.MustBool("AUTODELETE", false),
|
||||
Lifetime: env.MustDuration("AUTODELETE_LIFETIME", 720*time.Hour),
|
||||
TaskInterval: env.MustDuration("AUTODELETE_TASK_INTERVAL", 5*time.Minute),
|
||||
},
|
||||
Reports: &ReportConfig{
|
||||
Reports: env.MustBool("REPORTS", false),
|
||||
ReportWebhook: env.MustString("REPORT_WEBHOOK", ""),
|
||||
ReportWebhookToken: env.MustString("REPORT_WEBHOOK_TOKEN", ""),
|
||||
},
|
||||
File: &FileConfig{
|
||||
Path: env.MustString("STORAGE_FILE_PATH", "./data"),
|
||||
},
|
||||
Postgres: &PostgresConfig{
|
||||
DSN: env.MustString("STORAGE_POSTGRES_DSN", "postgres://pasty:pasty@localhost/pasty"),
|
||||
},
|
||||
MongoDB: &MongoDBConfig{
|
||||
DSN: env.MustString("STORAGE_MONGODB_CONNECTION_STRING", "mongodb://pasty:pasty@localhost/pasty"),
|
||||
Database: env.MustString("STORAGE_MONGODB_DATABASE", "pasty"),
|
||||
Collection: env.MustString("STORAGE_MONGODB_COLLECTION", "pastes"),
|
||||
},
|
||||
S3: &S3Config{
|
||||
Endpoint: env.MustString("STORAGE_S3_ENDPOINT", ""),
|
||||
AccessKeyID: env.MustString("STORAGE_S3_ACCESS_KEY_ID", ""),
|
||||
SecretAccessKey: env.MustString("STORAGE_S3_SECRET_ACCESS_KEY", ""),
|
||||
SecretToken: env.MustString("STORAGE_S3_SECRET_TOKEN", ""),
|
||||
Secure: env.MustBool("STORAGE_S3_SECURE", true),
|
||||
Region: env.MustString("STORAGE_S3_REGION", ""),
|
||||
Bucket: env.MustString("STORAGE_S3_BUCKET", "pasty"),
|
||||
},
|
||||
func Load() (*Config, error) {
|
||||
_ = godotenv.Overload()
|
||||
cfg := new(Config)
|
||||
if err := envconfig.Process("pasty", cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
42
internal/env/env.go
vendored
42
internal/env/env.go
vendored
@ -1,42 +0,0 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/lus/pasty/internal/static"
|
||||
)
|
||||
|
||||
// Load loads an optional .env file
|
||||
func Load() {
|
||||
godotenv.Load()
|
||||
}
|
||||
|
||||
// MustString returns the content of the environment variable with the given key or the given fallback
|
||||
func MustString(key, fallback string) string {
|
||||
value, found := os.LookupEnv(static.EnvironmentVariablePrefix + key)
|
||||
if !found {
|
||||
return fallback
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// MustBool uses MustString and parses it into a boolean
|
||||
func MustBool(key string, fallback bool) bool {
|
||||
parsed, _ := strconv.ParseBool(MustString(key, strconv.FormatBool(fallback)))
|
||||
return parsed
|
||||
}
|
||||
|
||||
// MustInt uses MustString and parses it into an integer
|
||||
func MustInt(key string, fallback int) int {
|
||||
parsed, _ := strconv.Atoi(MustString(key, strconv.Itoa(fallback)))
|
||||
return parsed
|
||||
}
|
||||
|
||||
// MustDuration uses MustString and parses it into a duration
|
||||
func MustDuration(key string, fallback time.Duration) time.Duration {
|
||||
parsed, _ := time.ParseDuration(MustString(key, fallback.String()))
|
||||
return parsed
|
||||
}
|
13
internal/meta/metadata.go
Normal file
13
internal/meta/metadata.go
Normal file
@ -0,0 +1,13 @@
|
||||
package meta
|
||||
|
||||
import "strings"
|
||||
|
||||
const devEnvironmentName = "dev"
|
||||
|
||||
var (
|
||||
Environment = devEnvironmentName
|
||||
)
|
||||
|
||||
func IsProdEnvironment() bool {
|
||||
return strings.ToLower(Environment) != devEnvironmentName
|
||||
}
|
@ -23,7 +23,7 @@ func (paste *Paste) HashModificationToken() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckModificationToken checks whether or not the given modification token is correct
|
||||
// CheckModificationToken checks whether the given modification token is correct
|
||||
func (paste *Paste) CheckModificationToken(modificationToken string) bool {
|
||||
match, err := argon2id.ComparePasswordAndHash(modificationToken, paste.ModificationToken)
|
||||
return err == nil && match
|
||||
|
14
internal/randx/string.go
Normal file
14
internal/randx/string.go
Normal file
@ -0,0 +1,14 @@
|
||||
package randx
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
// String returns a random string with the given length
|
||||
func String(characters string, length int) string {
|
||||
bytes := make([]byte, length)
|
||||
for i := range bytes {
|
||||
bytes[i] = characters[rand.Int63()%int64(len(characters))]
|
||||
}
|
||||
return string(bytes)
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package report
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/lus/pasty/internal/config"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// ReportRequest represents a report request sent to the report webhook
|
||||
type ReportRequest struct {
|
||||
Paste string `json:"paste"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// ReportResponse represents a report response received from the report webhook
|
||||
type ReportResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// SendReport sends a report request to the report webhook
|
||||
func SendReport(reportRequest *ReportRequest) (*ReportResponse, error) {
|
||||
request := fasthttp.AcquireRequest()
|
||||
defer fasthttp.ReleaseRequest(request)
|
||||
|
||||
response := fasthttp.AcquireResponse()
|
||||
defer fasthttp.ReleaseResponse(response)
|
||||
|
||||
request.Header.SetMethod(fasthttp.MethodPost)
|
||||
request.SetRequestURI(config.Current.Reports.ReportWebhook)
|
||||
if config.Current.Reports.ReportWebhookToken != "" {
|
||||
request.Header.Set("Authorization", "Bearer "+config.Current.Reports.ReportWebhookToken)
|
||||
}
|
||||
|
||||
data, err := json.Marshal(reportRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.SetBody(data)
|
||||
|
||||
if err := fasthttp.Do(request, response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
status := response.StatusCode()
|
||||
if status < 200 || status > 299 {
|
||||
return nil, fmt.Errorf("the report webhook responded with an unexpected error: %d (%s)", status, string(response.Body()))
|
||||
}
|
||||
|
||||
reportResponse := new(ReportResponse)
|
||||
if err := json.Unmarshal(response.Body(), reportResponse); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return reportResponse, nil
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package static
|
||||
|
||||
// These variables represent the values that may be changed using ldflags
|
||||
var (
|
||||
Version = "dev"
|
||||
EnvironmentVariablePrefix = "PASTY_"
|
||||
|
||||
// TempFrontendPath defines the path where pasty loads the web frontend from; it will be removed any time soon
|
||||
// TODO: Remove this when issue #37 is fixed
|
||||
TempFrontendPath = "./web"
|
||||
)
|
@ -1,24 +1,18 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"context"
|
||||
"github.com/lus/pasty/internal/config"
|
||||
"strings"
|
||||
|
||||
"github.com/lus/pasty/internal/config"
|
||||
"github.com/lus/pasty/internal/paste"
|
||||
"github.com/lus/pasty/internal/storage/file"
|
||||
"github.com/lus/pasty/internal/storage/mongodb"
|
||||
"github.com/lus/pasty/internal/storage/postgres"
|
||||
"github.com/lus/pasty/internal/storage/s3"
|
||||
)
|
||||
|
||||
// Current holds the current storage driver
|
||||
var Current Driver
|
||||
|
||||
// Driver represents a storage driver
|
||||
type Driver interface {
|
||||
Initialize() error
|
||||
Terminate() error
|
||||
Initialize(ctx context.Context, cfg *config.Config) error
|
||||
Close() error
|
||||
ListIDs() ([]string, error)
|
||||
Get(id string) (*paste.Paste, error)
|
||||
Save(paste *paste.Paste) error
|
||||
@ -26,35 +20,12 @@ type Driver interface {
|
||||
Cleanup() (int, error)
|
||||
}
|
||||
|
||||
// Load loads the current storage driver
|
||||
func Load() error {
|
||||
// Define the driver to use
|
||||
driver, err := GetDriver(config.Current.StorageType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize the driver
|
||||
err = driver.Initialize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
Current = driver
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDriver returns the driver with the given type if it exists
|
||||
func GetDriver(storageType string) (Driver, error) {
|
||||
switch strings.TrimSpace(strings.ToLower(storageType)) {
|
||||
case "file":
|
||||
return new(file.FileDriver), nil
|
||||
// ResolveDriver returns the driver with the given name if it exists
|
||||
func ResolveDriver(name string) (Driver, bool) {
|
||||
switch strings.TrimSpace(strings.ToLower(name)) {
|
||||
case "postgres":
|
||||
return new(postgres.PostgresDriver), nil
|
||||
case "mongodb":
|
||||
return new(mongodb.MongoDBDriver), nil
|
||||
case "s3":
|
||||
return new(s3.S3Driver), nil
|
||||
return new(postgres.Driver), true
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid storage type '%s'", storageType)
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
@ -1,145 +0,0 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/lus/pasty/internal/config"
|
||||
"github.com/lus/pasty/internal/paste"
|
||||
)
|
||||
|
||||
// FileDriver represents the file storage driver
|
||||
type FileDriver struct {
|
||||
filePath string
|
||||
}
|
||||
|
||||
// Initialize initializes the file storage driver
|
||||
func (driver *FileDriver) Initialize() error {
|
||||
driver.filePath = config.Current.File.Path
|
||||
return os.MkdirAll(driver.filePath, os.ModePerm)
|
||||
}
|
||||
|
||||
// Terminate terminates the file storage driver (does nothing, because the file storage driver does not need any termination)
|
||||
func (driver *FileDriver) Terminate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListIDs returns a list of all existing paste IDs
|
||||
func (driver *FileDriver) ListIDs() ([]string, error) {
|
||||
// Define the IDs slice
|
||||
var ids []string
|
||||
|
||||
// Fill the IDs slice
|
||||
err := filepath.Walk(driver.filePath, func(_ string, info os.FileInfo, err error) error {
|
||||
// Check if a walking error occurred
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Only count JSON files
|
||||
if !strings.HasSuffix(info.Name(), ".json") {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode the file name
|
||||
decoded, err := base64.StdEncoding.DecodeString(strings.TrimSuffix(info.Name(), ".json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Append the ID to the IDs slice
|
||||
ids = append(ids, string(decoded))
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return the IDs slice
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// Get loads a paste
|
||||
func (driver *FileDriver) Get(id string) (*paste.Paste, error) {
|
||||
// Read the file
|
||||
id = base64.StdEncoding.EncodeToString([]byte(id))
|
||||
data, err := ioutil.ReadFile(filepath.Join(driver.filePath, id+".json"))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Unmarshal the file into a paste
|
||||
paste := new(paste.Paste)
|
||||
err = json.Unmarshal(data, &paste)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return paste, nil
|
||||
}
|
||||
|
||||
// Save saves a paste
|
||||
func (driver *FileDriver) Save(paste *paste.Paste) error {
|
||||
// Marshal the paste
|
||||
jsonBytes, err := json.Marshal(paste)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the file to save the paste to
|
||||
id := base64.StdEncoding.EncodeToString([]byte(paste.ID))
|
||||
file, err := os.Create(filepath.Join(driver.filePath, id+".json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Write the JSON data into the file
|
||||
_, err = file.Write(jsonBytes)
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete deletes a paste
|
||||
func (driver *FileDriver) Delete(id string) error {
|
||||
id = base64.StdEncoding.EncodeToString([]byte(id))
|
||||
return os.Remove(filepath.Join(driver.filePath, id+".json"))
|
||||
}
|
||||
|
||||
// Cleanup cleans up the expired pastes
|
||||
func (driver *FileDriver) Cleanup() (int, error) {
|
||||
// Retrieve all paste IDs
|
||||
ids, err := driver.ListIDs()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Define the amount of deleted items
|
||||
deleted := 0
|
||||
|
||||
// Loop through all pastes
|
||||
for _, id := range ids {
|
||||
// Retrieve the paste object
|
||||
paste, err := driver.Get(id)
|
||||
if err != nil {
|
||||
return deleted, err
|
||||
}
|
||||
|
||||
// Delete the paste if it is expired
|
||||
lifetime := config.Current.AutoDelete.Lifetime
|
||||
if paste.Created+int64(lifetime.Seconds()) < time.Now().Unix() {
|
||||
err = driver.Delete(id)
|
||||
if err != nil {
|
||||
return deleted, err
|
||||
}
|
||||
deleted++
|
||||
}
|
||||
}
|
||||
return deleted, nil
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"github.com/lus/pasty/internal/config"
|
||||
"github.com/lus/pasty/internal/utils"
|
||||
)
|
||||
|
||||
// AcquireID generates a new unique ID
|
||||
func AcquireID() (string, error) {
|
||||
for {
|
||||
id := utils.RandomString(config.Current.IDCharacters, config.Current.IDLength)
|
||||
paste, err := Current.Get(id)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if paste == nil {
|
||||
return id, nil
|
||||
}
|
||||
}
|
||||
}
|
@ -1,171 +0,0 @@
|
||||
package mongodb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/lus/pasty/internal/config"
|
||||
"github.com/lus/pasty/internal/paste"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"go.mongodb.org/mongo-driver/mongo/readpref"
|
||||
)
|
||||
|
||||
// MongoDBDriver represents the MongoDB storage driver
|
||||
type MongoDBDriver struct {
|
||||
client *mongo.Client
|
||||
database string
|
||||
collection string
|
||||
}
|
||||
|
||||
// Initialize initializes the MongoDB storage driver
|
||||
func (driver *MongoDBDriver) Initialize() error {
|
||||
// Define the context for the following database operation
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Connect to the MongoDB host
|
||||
client, err := mongo.Connect(ctx, options.Client().ApplyURI(config.Current.MongoDB.DSN))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ping the MongoDB host
|
||||
err = client.Ping(ctx, readpref.Primary())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the driver attributes
|
||||
driver.client = client
|
||||
driver.database = config.Current.MongoDB.Database
|
||||
driver.collection = config.Current.MongoDB.Collection
|
||||
return nil
|
||||
}
|
||||
|
||||
// Terminate terminates the MongoDB storage driver
|
||||
func (driver *MongoDBDriver) Terminate() error {
|
||||
return driver.client.Disconnect(context.TODO())
|
||||
}
|
||||
|
||||
// ListIDs returns a list of all existing paste IDs
|
||||
func (driver *MongoDBDriver) ListIDs() ([]string, error) {
|
||||
// Define the collection to use for this database operation
|
||||
collection := driver.client.Database(driver.database).Collection(driver.collection)
|
||||
|
||||
// Define the context for the following database operation
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Retrieve all paste documents
|
||||
result, err := collection.Find(ctx, bson.M{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Decode all paste documents
|
||||
var pasteSlice []paste.Paste
|
||||
err = result.All(ctx, &pasteSlice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read and return the IDs of all paste objects
|
||||
var ids []string
|
||||
for _, paste := range pasteSlice {
|
||||
ids = append(ids, paste.ID)
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// Get loads a paste
|
||||
func (driver *MongoDBDriver) Get(id string) (*paste.Paste, error) {
|
||||
// Define the collection to use for this database operation
|
||||
collection := driver.client.Database(driver.database).Collection(driver.collection)
|
||||
|
||||
// Define the context for the following database operation
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Try to retrieve the corresponding paste document
|
||||
filter := bson.M{"_id": id}
|
||||
result := collection.FindOne(ctx, filter)
|
||||
err := result.Err()
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return the retrieved paste object
|
||||
paste := new(paste.Paste)
|
||||
err = result.Decode(paste)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return paste, nil
|
||||
}
|
||||
|
||||
// Save saves a paste
|
||||
func (driver *MongoDBDriver) Save(paste *paste.Paste) error {
|
||||
// Define the collection to use for this database operation
|
||||
collection := driver.client.Database(driver.database).Collection(driver.collection)
|
||||
|
||||
// Define the context for the following database operation
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Upsert the paste object
|
||||
filter := bson.M{"_id": paste.ID}
|
||||
_, err := collection.UpdateOne(ctx, filter, bson.M{"$set": paste}, options.Update().SetUpsert(true))
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete deletes a paste
|
||||
func (driver *MongoDBDriver) Delete(id string) error {
|
||||
// Define the collection to use for this database operation
|
||||
collection := driver.client.Database(driver.database).Collection(driver.collection)
|
||||
|
||||
// Define the context for the following database operation
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Delete the document
|
||||
filter := bson.M{"_id": id}
|
||||
_, err := collection.DeleteOne(ctx, filter)
|
||||
return err
|
||||
}
|
||||
|
||||
// Cleanup cleans up the expired pastes
|
||||
func (driver *MongoDBDriver) Cleanup() (int, error) {
|
||||
// Retrieve all paste IDs
|
||||
ids, err := driver.ListIDs()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Define the amount of deleted items
|
||||
deleted := 0
|
||||
|
||||
// Loop through all pastes
|
||||
for _, id := range ids {
|
||||
// Retrieve the paste object
|
||||
paste, err := driver.Get(id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Delete the paste if it is expired
|
||||
lifetime := config.Current.AutoDelete.Lifetime
|
||||
if paste.Created+int64(lifetime.Seconds()) < time.Now().Unix() {
|
||||
err = driver.Delete(id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
deleted++
|
||||
}
|
||||
}
|
||||
return deleted, nil
|
||||
}
|
@ -18,14 +18,15 @@ import (
|
||||
//go:embed migrations/*.sql
|
||||
var migrations embed.FS
|
||||
|
||||
// PostgresDriver represents the Postgres storage driver
|
||||
type PostgresDriver struct {
|
||||
pool *pgxpool.Pool
|
||||
// Driver represents the Postgres storage driver
|
||||
type Driver struct {
|
||||
pool *pgxpool.Pool
|
||||
autoDeleteLifetime time.Duration
|
||||
}
|
||||
|
||||
// Initialize initializes the Postgres storage driver
|
||||
func (driver *PostgresDriver) Initialize() error {
|
||||
pool, err := pgxpool.Connect(context.Background(), config.Current.Postgres.DSN)
|
||||
func (driver *Driver) Initialize(ctx context.Context, cfg *config.Config) error {
|
||||
pool, err := pgxpool.Connect(ctx, cfg.Postgres.DSN)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -35,7 +36,7 @@ func (driver *PostgresDriver) Initialize() error {
|
||||
return err
|
||||
}
|
||||
|
||||
migrator, err := migrate.NewWithSourceInstance("iofs", source, config.Current.Postgres.DSN)
|
||||
migrator, err := migrate.NewWithSourceInstance("iofs", source, cfg.Postgres.DSN)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -45,17 +46,18 @@ func (driver *PostgresDriver) Initialize() error {
|
||||
}
|
||||
|
||||
driver.pool = pool
|
||||
driver.autoDeleteLifetime = cfg.AutoDelete.Lifetime
|
||||
return nil
|
||||
}
|
||||
|
||||
// Terminate terminates the Postgres storage driver
|
||||
func (driver *PostgresDriver) Terminate() error {
|
||||
// Close terminates the Postgres storage driver
|
||||
func (driver *Driver) Close() error {
|
||||
driver.pool.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListIDs returns a list of all existing paste IDs
|
||||
func (driver *PostgresDriver) ListIDs() ([]string, error) {
|
||||
func (driver *Driver) ListIDs() ([]string, error) {
|
||||
query := "SELECT id FROM pastes"
|
||||
|
||||
rows, err := driver.pool.Query(context.Background(), query)
|
||||
@ -76,7 +78,7 @@ func (driver *PostgresDriver) ListIDs() ([]string, error) {
|
||||
}
|
||||
|
||||
// Get loads a paste
|
||||
func (driver *PostgresDriver) Get(id string) (*paste.Paste, error) {
|
||||
func (driver *Driver) Get(id string) (*paste.Paste, error) {
|
||||
query := "SELECT * FROM pastes WHERE id = $1"
|
||||
|
||||
row := driver.pool.QueryRow(context.Background(), query, id)
|
||||
@ -92,7 +94,7 @@ func (driver *PostgresDriver) Get(id string) (*paste.Paste, error) {
|
||||
}
|
||||
|
||||
// Save saves a paste
|
||||
func (driver *PostgresDriver) Save(paste *paste.Paste) error {
|
||||
func (driver *Driver) Save(paste *paste.Paste) error {
|
||||
query := `
|
||||
INSERT INTO pastes (id, content, "modificationToken", created, metadata)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
@ -108,7 +110,7 @@ func (driver *PostgresDriver) Save(paste *paste.Paste) error {
|
||||
}
|
||||
|
||||
// Delete deletes a paste
|
||||
func (driver *PostgresDriver) Delete(id string) error {
|
||||
func (driver *Driver) Delete(id string) error {
|
||||
query := "DELETE FROM pastes WHERE id = $1"
|
||||
|
||||
_, err := driver.pool.Exec(context.Background(), query, id)
|
||||
@ -116,10 +118,10 @@ func (driver *PostgresDriver) Delete(id string) error {
|
||||
}
|
||||
|
||||
// Cleanup cleans up the expired pastes
|
||||
func (driver *PostgresDriver) Cleanup() (int, error) {
|
||||
func (driver *Driver) Cleanup() (int, error) {
|
||||
query := "DELETE FROM pastes WHERE created < $1"
|
||||
|
||||
tag, err := driver.pool.Exec(context.Background(), query, time.Now().Add(-config.Current.AutoDelete.Lifetime).Unix())
|
||||
tag, err := driver.pool.Exec(context.Background(), query, time.Now().Add(-driver.autoDeleteLifetime).Unix())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -1,136 +0,0 @@
|
||||
package s3
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/lus/pasty/internal/config"
|
||||
"github.com/lus/pasty/internal/paste"
|
||||
"github.com/minio/minio-go/v7"
|
||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||
)
|
||||
|
||||
// S3Driver represents the AWS S3 storage driver
|
||||
type S3Driver struct {
|
||||
client *minio.Client
|
||||
bucket string
|
||||
}
|
||||
|
||||
// Initialize initializes the AWS S3 storage driver
|
||||
func (driver *S3Driver) Initialize() error {
|
||||
client, err := minio.New(config.Current.S3.Endpoint, &minio.Options{
|
||||
Creds: credentials.NewStaticV4(config.Current.S3.AccessKeyID, config.Current.S3.SecretAccessKey, config.Current.S3.SecretToken),
|
||||
Secure: config.Current.S3.Secure,
|
||||
Region: config.Current.S3.Region,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
driver.client = client
|
||||
driver.bucket = config.Current.S3.Bucket
|
||||
return nil
|
||||
}
|
||||
|
||||
// Terminate terminates the AWS S3 storage driver (does nothing, because the AWS S3 storage driver does not need any termination)
|
||||
func (driver *S3Driver) Terminate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListIDs returns a list of all existing paste IDs
|
||||
func (driver *S3Driver) ListIDs() ([]string, error) {
|
||||
// Define the IDs slice
|
||||
var ids []string
|
||||
|
||||
// Fill the IDs slice
|
||||
channel := driver.client.ListObjects(context.Background(), driver.bucket, minio.ListObjectsOptions{})
|
||||
for object := range channel {
|
||||
if object.Err != nil {
|
||||
return nil, object.Err
|
||||
}
|
||||
ids = append(ids, strings.TrimSuffix(object.Key, ".json"))
|
||||
}
|
||||
|
||||
// Return the IDs slice
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// Get loads a paste
|
||||
func (driver *S3Driver) Get(id string) (*paste.Paste, error) {
|
||||
// Read the object
|
||||
object, err := driver.client.GetObject(context.Background(), driver.bucket, id+".json", minio.GetObjectOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := ioutil.ReadAll(object)
|
||||
if err != nil {
|
||||
if minio.ToErrorResponse(err).Code == "NoSuchKey" {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Unmarshal the object into a paste
|
||||
paste := new(paste.Paste)
|
||||
err = json.Unmarshal(data, &paste)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return paste, nil
|
||||
}
|
||||
|
||||
// Save saves a paste
|
||||
func (driver *S3Driver) Save(paste *paste.Paste) error {
|
||||
// Marshal the paste
|
||||
jsonBytes, err := json.Marshal(paste)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Put the object
|
||||
reader := bytes.NewReader(jsonBytes)
|
||||
_, err = driver.client.PutObject(context.Background(), driver.bucket, paste.ID+".json", reader, reader.Size(), minio.PutObjectOptions{
|
||||
ContentType: "application/json",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete deletes a paste
|
||||
func (driver *S3Driver) Delete(id string) error {
|
||||
return driver.client.RemoveObject(context.Background(), driver.bucket, id+".json", minio.RemoveObjectOptions{})
|
||||
}
|
||||
|
||||
// Cleanup cleans up the expired pastes
|
||||
func (driver *S3Driver) Cleanup() (int, error) {
|
||||
// Retrieve all paste IDs
|
||||
ids, err := driver.ListIDs()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Define the amount of deleted items
|
||||
deleted := 0
|
||||
|
||||
// Loop through all pastes
|
||||
for _, id := range ids {
|
||||
// Retrieve the paste object
|
||||
paste, err := driver.Get(id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Delete the paste if it is expired
|
||||
lifetime := config.Current.AutoDelete.Lifetime
|
||||
if paste.Created+int64(lifetime.Seconds()) < time.Now().Unix() {
|
||||
err = driver.Delete(id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
deleted++
|
||||
}
|
||||
}
|
||||
return deleted, nil
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RandomString returns a random string with the given length
|
||||
func RandomString(characters string, length int) string {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
bytes := make([]byte, length)
|
||||
for i := range bytes {
|
||||
bytes[i] = characters[rand.Int63()%int64(len(characters))]
|
||||
}
|
||||
return string(bytes)
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package web
|
||||
|
||||
// nilLogger represents a logger that does not print anything
|
||||
type nilLogger struct {
|
||||
}
|
||||
|
||||
// Printf prints nothing
|
||||
func (logger *nilLogger) Printf(string, ...interface{}) {
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
routing "github.com/fasthttp/router"
|
||||
"github.com/lus/pasty/internal/config"
|
||||
"github.com/lus/pasty/internal/static"
|
||||
"github.com/lus/pasty/internal/storage"
|
||||
v2 "github.com/lus/pasty/internal/web/v2"
|
||||
"github.com/ulule/limiter/v3"
|
||||
limitFasthttp "github.com/ulule/limiter/v3/drivers/middleware/fasthttp"
|
||||
"github.com/ulule/limiter/v3/drivers/store/memory"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// Serve serves the web resources
|
||||
func Serve() error {
|
||||
// Create the router
|
||||
router := routing.New()
|
||||
|
||||
// Define the 404 handler
|
||||
router.NotFound = func(ctx *fasthttp.RequestCtx) {
|
||||
ctx.SetStatusCode(fasthttp.StatusNotFound)
|
||||
ctx.SetBodyString("not found")
|
||||
}
|
||||
|
||||
// Route the frontend requests
|
||||
frontend := frontendHandler()
|
||||
raw := rawHandler()
|
||||
router.GET("/{path:*}", func(ctx *fasthttp.RequestCtx) {
|
||||
path := string(ctx.Path())
|
||||
if !strings.HasPrefix(path, "/api") && (strings.Count(path, "/") == 1 || strings.HasPrefix(path, "/assets")) {
|
||||
if strings.HasPrefix(path, "/assets/js/") {
|
||||
ctx.SetContentType("text/javascript")
|
||||
}
|
||||
frontend(ctx)
|
||||
return
|
||||
} else if strings.HasSuffix(strings.TrimSuffix(path, "/"), "/raw") {
|
||||
raw(ctx)
|
||||
return
|
||||
}
|
||||
router.NotFound(ctx)
|
||||
})
|
||||
|
||||
// Set up the rate limiter
|
||||
rate, err := limiter.NewRateFromFormatted(config.Current.RateLimit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rateLimiter := limiter.New(memory.NewStore(), rate)
|
||||
rateLimiterMiddleware := limitFasthttp.NewMiddleware(rateLimiter)
|
||||
|
||||
// Route the API endpoints
|
||||
apiRoute := router.Group("/api")
|
||||
{
|
||||
v2Route := apiRoute.Group("/v2")
|
||||
{
|
||||
pasteLifetime := int64(-1)
|
||||
if config.Current.AutoDelete.Enabled {
|
||||
pasteLifetime = config.Current.AutoDelete.Lifetime.Milliseconds()
|
||||
}
|
||||
v2Route.GET("/info", func(ctx *fasthttp.RequestCtx) {
|
||||
jsonData, _ := json.Marshal(map[string]interface{}{
|
||||
"version": static.Version,
|
||||
"modificationTokens": config.Current.ModificationTokens,
|
||||
"reports": config.Current.Reports.Reports,
|
||||
"pasteLifetime": pasteLifetime,
|
||||
})
|
||||
ctx.SetBody(jsonData)
|
||||
})
|
||||
v2.InitializePastesController(v2Route.Group("/pastes"), rateLimiterMiddleware)
|
||||
}
|
||||
}
|
||||
|
||||
// Route the hastebin documents route if hastebin support is enabled
|
||||
if config.Current.HastebinSupport {
|
||||
// TODO: Reimplement hastebin support
|
||||
}
|
||||
|
||||
// Serve the web resources
|
||||
return (&fasthttp.Server{
|
||||
Handler: func(ctx *fasthttp.RequestCtx) {
|
||||
// Add the CORS headers
|
||||
ctx.Response.Header.Set("Access-Control-Allow-Methods", "GET,POST,DELETE,OPTIONS")
|
||||
ctx.Response.Header.Set("Access-Control-Allow-Origin", "*")
|
||||
|
||||
// Call the router handler
|
||||
router.Handler(ctx)
|
||||
},
|
||||
Logger: new(nilLogger),
|
||||
}).ListenAndServe(config.Current.WebAddress)
|
||||
}
|
||||
|
||||
// frontendHandler handles the frontend routing
|
||||
func frontendHandler() fasthttp.RequestHandler {
|
||||
// Create the file server
|
||||
fs := &fasthttp.FS{
|
||||
Root: static.TempFrontendPath,
|
||||
IndexNames: []string{"index.html"},
|
||||
CacheDuration: 0,
|
||||
}
|
||||
fs.PathNotFound = func(ctx *fasthttp.RequestCtx) {
|
||||
if strings.HasPrefix(string(ctx.Path()), "/assets") {
|
||||
ctx.SetStatusCode(fasthttp.StatusNotFound)
|
||||
ctx.SetBodyString("not found")
|
||||
return
|
||||
}
|
||||
ctx.SendFile(filepath.Join(fs.Root, "index.html"))
|
||||
}
|
||||
return fs.NewRequestHandler()
|
||||
}
|
||||
|
||||
func rawHandler() fasthttp.RequestHandler {
|
||||
return func(ctx *fasthttp.RequestCtx) {
|
||||
path := string(ctx.Path())
|
||||
pathSanitized := strings.TrimPrefix(strings.TrimSuffix(path, "/"), "/")
|
||||
pasteID := strings.TrimSuffix(pathSanitized, "/raw")
|
||||
|
||||
paste, err := storage.Current.Get(pasteID)
|
||||
if err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if paste == nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusNotFound)
|
||||
ctx.SetBodyString("paste not found")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SetBodyString(paste.Content)
|
||||
}
|
||||
}
|
@ -1,273 +0,0 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fasthttp/router"
|
||||
"github.com/lus/pasty/internal/config"
|
||||
"github.com/lus/pasty/internal/paste"
|
||||
"github.com/lus/pasty/internal/report"
|
||||
"github.com/lus/pasty/internal/storage"
|
||||
"github.com/lus/pasty/internal/utils"
|
||||
limitFasthttp "github.com/ulule/limiter/v3/drivers/middleware/fasthttp"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// InitializePastesController initializes the '/v2/pastes/*' controller
|
||||
func InitializePastesController(group *router.Group, rateLimiterMiddleware *limitFasthttp.Middleware) {
|
||||
// moms spaghetti
|
||||
group.GET("/{id}", rateLimiterMiddleware.Handle(middlewareInjectPaste(endpointGetPaste)))
|
||||
group.POST("", rateLimiterMiddleware.Handle(endpointCreatePaste))
|
||||
group.PATCH("/{id}", rateLimiterMiddleware.Handle(middlewareInjectPaste(middlewareValidateModificationToken(endpointModifyPaste))))
|
||||
group.DELETE("/{id}", rateLimiterMiddleware.Handle(middlewareInjectPaste(middlewareValidateModificationToken(endpointDeletePaste))))
|
||||
|
||||
if config.Current.Reports.Reports {
|
||||
group.POST("/{id}/report", rateLimiterMiddleware.Handle(middlewareInjectPaste(endpointReportPaste)))
|
||||
}
|
||||
}
|
||||
|
||||
// middlewareInjectPaste retrieves and injects the paste with the specified ID
|
||||
func middlewareInjectPaste(next fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||
return func(ctx *fasthttp.RequestCtx) {
|
||||
pasteID := ctx.UserValue("id").(string)
|
||||
|
||||
paste, err := storage.Current.Get(pasteID)
|
||||
if err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
if paste == nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusNotFound)
|
||||
ctx.SetBodyString("paste not found")
|
||||
return
|
||||
}
|
||||
|
||||
if paste.Metadata == nil {
|
||||
paste.Metadata = map[string]interface{}{}
|
||||
}
|
||||
|
||||
ctx.SetUserValue("_paste", paste)
|
||||
|
||||
next(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// middlewareValidateModificationToken extracts and validates a given modification token for an injected paste
|
||||
func middlewareValidateModificationToken(next fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||
return func(ctx *fasthttp.RequestCtx) {
|
||||
paste := ctx.UserValue("_paste").(*paste.Paste)
|
||||
|
||||
authHeaderSplit := strings.SplitN(string(ctx.Request.Header.Peek("Authorization")), " ", 2)
|
||||
if len(authHeaderSplit) < 2 || authHeaderSplit[0] != "Bearer" {
|
||||
ctx.SetStatusCode(fasthttp.StatusUnauthorized)
|
||||
ctx.SetBodyString("unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
modificationToken := authHeaderSplit[1]
|
||||
if config.Current.ModificationTokenMaster != "" && modificationToken == config.Current.ModificationTokenMaster {
|
||||
next(ctx)
|
||||
return
|
||||
}
|
||||
valid := paste.CheckModificationToken(modificationToken)
|
||||
if !valid {
|
||||
ctx.SetStatusCode(fasthttp.StatusUnauthorized)
|
||||
ctx.SetBodyString("unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
next(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// endpointGetPaste handles the 'GET /v2/pastes/{id}' endpoint
|
||||
func endpointGetPaste(ctx *fasthttp.RequestCtx) {
|
||||
paste := ctx.UserValue("_paste").(*paste.Paste)
|
||||
paste.ModificationToken = ""
|
||||
|
||||
jsonData, err := json.Marshal(paste)
|
||||
if err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
ctx.SetBody(jsonData)
|
||||
}
|
||||
|
||||
type endpointCreatePastePayload struct {
|
||||
Content string `json:"content"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
}
|
||||
|
||||
// endpointCreatePaste handles the 'POST /v2/pastes' endpoint
|
||||
func endpointCreatePaste(ctx *fasthttp.RequestCtx) {
|
||||
// Read, parse and validate the request payload
|
||||
payload := new(endpointCreatePastePayload)
|
||||
if err := json.Unmarshal(ctx.PostBody(), payload); err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
if payload.Content == "" {
|
||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||
ctx.SetBodyString("missing paste content")
|
||||
return
|
||||
}
|
||||
if config.Current.LengthCap > 0 && len(payload.Content) > config.Current.LengthCap {
|
||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||
ctx.SetBodyString("too large paste content")
|
||||
return
|
||||
}
|
||||
|
||||
// Acquire a new paste ID
|
||||
id, err := storage.AcquireID()
|
||||
if err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Prepare the paste object
|
||||
if payload.Metadata == nil {
|
||||
payload.Metadata = map[string]interface{}{}
|
||||
}
|
||||
paste := &paste.Paste{
|
||||
ID: id,
|
||||
Content: payload.Content,
|
||||
Created: time.Now().Unix(),
|
||||
Metadata: payload.Metadata,
|
||||
}
|
||||
|
||||
// Create a new modification token if enabled
|
||||
modificationToken := ""
|
||||
if config.Current.ModificationTokens {
|
||||
modificationToken = utils.RandomString(config.Current.ModificationTokenCharacters, config.Current.ModificationTokenLength)
|
||||
paste.ModificationToken = modificationToken
|
||||
|
||||
err = paste.HashModificationToken()
|
||||
if err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Save the paste
|
||||
err = storage.Current.Save(paste)
|
||||
if err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Respond with the paste
|
||||
pasteCopy := *paste
|
||||
pasteCopy.ModificationToken = modificationToken
|
||||
jsonData, err := json.Marshal(pasteCopy)
|
||||
if err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
ctx.SetStatusCode(fasthttp.StatusCreated)
|
||||
ctx.SetBody(jsonData)
|
||||
}
|
||||
|
||||
type endpointModifyPastePayload struct {
|
||||
Content *string `json:"content"`
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
}
|
||||
|
||||
// endpointModifyPaste handles the 'PATCH /v2/pastes/{id}' endpoint
|
||||
func endpointModifyPaste(ctx *fasthttp.RequestCtx) {
|
||||
// Read, parse and validate the request payload
|
||||
payload := new(endpointModifyPastePayload)
|
||||
if err := json.Unmarshal(ctx.PostBody(), payload); err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
if payload.Content != nil && *payload.Content == "" {
|
||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||
ctx.SetBodyString("missing paste content")
|
||||
return
|
||||
}
|
||||
if payload.Content != nil && config.Current.LengthCap > 0 && len(*payload.Content) > config.Current.LengthCap {
|
||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||
ctx.SetBodyString("too large paste content")
|
||||
return
|
||||
}
|
||||
|
||||
// Modify the paste itself
|
||||
paste := ctx.UserValue("_paste").(*paste.Paste)
|
||||
if payload.Content != nil {
|
||||
paste.Content = *payload.Content
|
||||
}
|
||||
if payload.Metadata != nil {
|
||||
for key, value := range payload.Metadata {
|
||||
if value == nil {
|
||||
delete(paste.Metadata, key)
|
||||
continue
|
||||
}
|
||||
paste.Metadata[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// Save the modified paste
|
||||
if err := storage.Current.Save(paste); err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// endpointDeletePaste handles the 'DELETE /v2/pastes/{id}' endpoint
|
||||
func endpointDeletePaste(ctx *fasthttp.RequestCtx) {
|
||||
paste := ctx.UserValue("_paste").(*paste.Paste)
|
||||
if err := storage.Current.Delete(paste.ID); err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type endpointReportPastePayload struct {
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
func endpointReportPaste(ctx *fasthttp.RequestCtx) {
|
||||
// Read, parse and validate the request payload
|
||||
payload := new(endpointReportPastePayload)
|
||||
if err := json.Unmarshal(ctx.PostBody(), payload); err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
if payload.Reason == "" {
|
||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||
ctx.SetBodyString("missing report reason")
|
||||
return
|
||||
}
|
||||
|
||||
request := &report.ReportRequest{
|
||||
Paste: ctx.UserValue("_paste").(*paste.Paste).ID,
|
||||
Reason: payload.Reason,
|
||||
}
|
||||
response, err := report.SendReport(request)
|
||||
if err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
ctx.SetBody(jsonData)
|
||||
}
|
Loading…
Reference in New Issue
Block a user