diff --git a/.gitignore b/.gitignore index adf8f72..0ef17ed 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,7 @@ # Go workspace file go.work +# config +*.toml +/.idea/dataSources.xml +/.idea/vcs.xml diff --git a/go.mod b/go.mod index 5d23dee..b778ec6 100644 --- a/go.mod +++ b/go.mod @@ -3,17 +3,36 @@ module mc-client-updater-server go 1.19 require ( + github.com/BurntSushi/toml v0.3.1 + github.com/antonfisher/nested-logrus-formatter v1.3.1 + github.com/gin-gonic/gin v1.8.1 + github.com/sirupsen/logrus v1.9.0 + gorm.io/driver/postgres v1.3.10 + gorm.io/gorm v1.23.10 +) + +require ( + github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-gonic/gin v1.8.1 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-playground/validator/v10 v10.11.1 // indirect github.com/goccy/go-json v0.9.11 // indirect + github.com/golang-jwt/jwt/v4 v4.4.2 // indirect + github.com/jackc/chunkreader/v2 v2.0.1 // indirect + github.com/jackc/pgconn v1.13.0 // indirect + github.com/jackc/pgio v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.1 // indirect + github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect + github.com/jackc/pgtype v1.12.0 // indirect + github.com/jackc/pgx/v4 v4.17.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mcuadros/go-defaults v1.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect @@ -24,5 +43,4 @@ require ( golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gorm.io/gorm v1.23.10 // indirect ) diff --git a/go.sum b/go.sum index 9eceba0..b0ecf54 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,27 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387 h1:loy0fjI90vF44BPW4ZYOkE3tDkGTy7yHURusOJimt+I= +github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387/go.mod h1:GuR5j/NW7AU7tDAQUDGCtpiPxWIOy/c3kiRDnlwiCHc= +github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ= +github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/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/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= @@ -12,11 +29,65 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= +github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/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= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= +github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= +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/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= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= +github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= +github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= +github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= +github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= +github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= @@ -24,68 +95,178 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/lib/pq v1.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= +github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mcuadros/go-defaults v1.2.0 h1:FODb8WSf0uGaY8elWJAkoLL0Ri6AlZ1bFlenk56oZtc= +github.com/mcuadros/go-defaults v1.2.0/go.mod h1:WEZtHEVIGYVDqkKSWBdWKUVdRyKlMfulPaGDWIVeCWY= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +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/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A= golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20221002022538-bcab6841153b h1:6e93nYa3hNqAvLr0pD4PN1fFS+gKzp2zAXqrnTCstqU= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-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/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.3.10 h1:Fsd+pQpFMGlGxxVMUPJhNo8gG8B1lKtk8QQ4/VZZAJw= +gorm.io/driver/postgres v1.3.10/go.mod h1:whNfh5WhhHs96honoLjBAMwJGYEuA3m1hvgUbNXhPCw= +gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.10 h1:4Ne9ZbzID9GUxRkllxN4WjJKpsHx8YbKvekVdgyWh24= gorm.io/gorm v1.23.10/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/internal/api/v1/handler/admin.go b/internal/api/v1/handler/admin.go new file mode 100644 index 0000000..ad5fb54 --- /dev/null +++ b/internal/api/v1/handler/admin.go @@ -0,0 +1,23 @@ +package handler + +import ( + "github.com/gin-gonic/gin" + "mc-client-updater-server/internal/service" + "mc-client-updater-server/pkg/param" + "mc-client-updater-server/pkg/result" +) + +func HandleLogin(c *gin.Context) { + srv := service.NewUserService(c) + res := result.NewResult(c) + + loginParam := param.LoginParam{} + err := c.ShouldBindJSON(&loginParam) + if err != nil { + res.BadRequest() + return + } + + srv.Login(loginParam.Username, loginParam.Password) + +} diff --git a/internal/api/v1/middleware/admin.go b/internal/api/v1/middleware/admin.go new file mode 100644 index 0000000..b024a09 --- /dev/null +++ b/internal/api/v1/middleware/admin.go @@ -0,0 +1,39 @@ +package middleware + +import ( + "github.com/gin-gonic/gin" + "mc-client-updater-server/internal/service" + "mc-client-updater-server/pkg/result" + "strings" +) + +func AdminRequired(c *gin.Context) { + res := result.NewResult(c) + authorization := c.GetHeader("Authorization") + if authorization == "" { + res.Unauthorized() + return + } + + split := strings.Split(authorization, " ") + if len(split) <= 1 || (len(split) >= 2 && split[0] != "Bearer") { + res.BadRequest() + return + } + + tokenSrv := service.NewTokenService(c) + token := split[1] + tokenRow, ok := tokenSrv.VerifyToken(token) + // 若!ok,则返回值已被service处理,无需再次返回 + if !ok { + return + } + + userSrv := service.NewUserService(c) + hasRole := userSrv.JudgeRoleByToken("ROLE_admin", tokenRow) + if !hasRole { + res.NoPermission() + return + } + c.Next() +} diff --git a/internal/api/v1/middleware/grant.go b/internal/api/v1/middleware/grant.go new file mode 100644 index 0000000..c714eac --- /dev/null +++ b/internal/api/v1/middleware/grant.go @@ -0,0 +1,11 @@ +package middleware + +import ( + "github.com/gin-gonic/gin" + "mc-client-updater-server/pkg/log" +) + +func GrantRequired(c *gin.Context) { + instName := c.Param("name") + log.Logger.Info(instName) +} diff --git a/internal/api/v1/middleware/logger.go b/internal/api/v1/middleware/logger.go new file mode 100644 index 0000000..7c5fcf1 --- /dev/null +++ b/internal/api/v1/middleware/logger.go @@ -0,0 +1,43 @@ +package middleware + +import ( + "fmt" + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" + "mc-client-updater-server/pkg/log" + "time" +) + +func LoggerMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + startTime := time.Now() + c.Next() // 调用该请求的剩余处理程序 + stopTime := time.Since(startTime) + spendTime := fmt.Sprintf("%.3f ms", float64(stopTime.Nanoseconds())/1000000) + + statusCode := c.Writer.Status() + dataSize := c.Writer.Size() + if dataSize < 0 { + dataSize = 0 + } + method := c.Request.Method + url := c.Request.RequestURI + + Log := log.Logger.WithFields(logrus.Fields{ + "spendTime": spendTime, + "path": url, + "method": method, + "status": statusCode, + }) + if len(c.Errors) > 0 { // 内部错误 + Log.Error(c.Errors.ByType(gin.ErrorTypePrivate)) + } + if statusCode == 500 || (statusCode >= 5000 && statusCode < 6000) { + Log.Error() + } else if statusCode >= 400 && statusCode < 500 { + Log.Warn() + } else { + Log.Info() + } + } +} diff --git a/internal/api/v1/router.go b/internal/api/v1/router.go index 876b56a..32bee74 100644 --- a/internal/api/v1/router.go +++ b/internal/api/v1/router.go @@ -1,45 +1,46 @@ package v1 -import "github.com/gin-gonic/gin" +import ( + "github.com/gin-gonic/gin" + "mc-client-updater-server/internal/api/v1/handler" + "mc-client-updater-server/internal/api/v1/middleware" + "net/http" +) func NewRouter() *gin.Engine { - r := gin.Default() + r := gin.New() + r.Use() + r.Use(middleware.LoggerMiddleware()) + r.Use(gin.Recovery()) + + r.GET("/", func(c *gin.Context) { + c.String(http.StatusOK, "Hello Minecraft-Client-Updater service!") + }) v1 := r.Group("/api/v1") - /** - GET /status - */ v1.GET("/status") + v1.POST("/login", handler.HandleLogin) /** GROUP /instance/:name - Auth required - ROLE == ROLE_inst_{name} || ROLE >= ROLE_admin + Grant required */ - inst := v1.Group("/instance/:name") - /** - GET /instance/:name/detail - */ - inst.GET("/detail") + inst := v1.Group("/instance/:name", middleware.GrantRequired) + { + inst.GET("/detail") + } /** GROUP /admin Auth required ROLE >= ROLE_admin */ - admin := v1.Group("/admin") - /** - GET /admin/instances - */ - admin.GET("/instances") - /** - GET /admin/users - */ - admin.GET("/users") - /** - GET /admin/updates - */ - admin.GET("/updates") + admin := v1.Group("/admin", middleware.AdminRequired) + { + admin.GET("/instances") + admin.GET("/users") + admin.GET("/updates") + } return r } diff --git a/internal/service/token.go b/internal/service/token.go new file mode 100644 index 0000000..7c27861 --- /dev/null +++ b/internal/service/token.go @@ -0,0 +1,57 @@ +package service + +import ( + "github.com/gin-gonic/gin" + "gorm.io/gorm" + "mc-client-updater-server/pkg/dao" + "mc-client-updater-server/pkg/dao/entity" + "mc-client-updater-server/pkg/result" + "time" +) + +type TokenService struct { + ctx *gin.Context +} + +func NewTokenService(c *gin.Context) *TokenService { + return &TokenService{ctx: c} +} + +func (s *TokenService) VerifyToken(token string) (*entity.Token, bool) { + res := result.NewResult(s.ctx) + // 是否存在 + tokenRow := s.getToken(token) + if tokenRow == nil { + res.Unauthorized() + return nil, false + } + // 是否过期 + if tokenRow.TTL != 0 && int(time.Since(tokenRow.CreatedAt).Seconds()) > tokenRow.TTL { + res.LoginExpired() + return tokenRow, false + } + return tokenRow, true +} + +func (s *TokenService) getToken(token string) *entity.Token { + tokenRow := entity.Token{Token: token} + tx := dao.DB().Last(&tokenRow) + if tx.Error == gorm.ErrRecordNotFound { + return nil + } + return &tokenRow +} + +func (s *TokenService) getTokenByUsername(username string) *entity.Token { + tokenRow := entity.Token{GrantTo: username} + tx := dao.DB().First(&tokenRow) + if tx.Error == gorm.ErrRecordNotFound { + return nil + } + return &tokenRow +} + +func (s *TokenService) AddToken(tokenObj *entity.Token) error { + tx := dao.DB().Create(tokenObj) + return tx.Error +} diff --git a/internal/service/user.go b/internal/service/user.go new file mode 100644 index 0000000..c817c4a --- /dev/null +++ b/internal/service/user.go @@ -0,0 +1,78 @@ +package service + +import ( + "github.com/gin-gonic/gin" + "gorm.io/gorm" + "mc-client-updater-server/pkg/dao" + "mc-client-updater-server/pkg/dao/entity" + "mc-client-updater-server/pkg/password" + "mc-client-updater-server/pkg/result" + "mc-client-updater-server/pkg/token" + "mc-client-updater-server/pkg/util" + "strings" +) + +type UserService struct { + ctx *gin.Context +} + +func NewUserService(c *gin.Context) *UserService { + return &UserService{ctx: c} +} + +func (s *UserService) Login(username, pwd string) { + res := result.NewResult(s.ctx) + + user := entity.User{Username: username} + tx := dao.DB().First(&user) + if tx.Error != nil { + switch tx.Error { + case gorm.ErrRecordNotFound: + res.LoginError() + return + default: + res.LoginError() + return + } + } + + // 验证密码 + ok, err := password.Password().Verify(pwd, user.Password) + if err != nil || !ok { + res.LoginError() + return + } + + tokenStr := token.NewToken(user.Username) + tokenResult := &entity.Token{ + Token: tokenStr, + GrantTo: user.Username, + TTL: 86400, + } + tokenSrv := NewTokenService(s.ctx) + err = tokenSrv.AddToken(tokenResult) + if err != nil { + res.InternalServerError("创建登录记录时发生意外错误") + return + } + res.Success(tokenResult) +} + +func (s *UserService) hasRole(role string, user *entity.User) bool { + roles := strings.Split(user.Roles, ",") + return util.InStringSlice(roles, role) +} + +func (s *UserService) getUserByUsername(name string) *entity.User { + user := entity.User{Username: name} + tx := dao.DB().First(&user) + if tx.Error != nil { + return nil + } + return &user +} + +func (s *UserService) JudgeRoleByToken(role string, token *entity.Token) bool { + user := s.getUserByUsername(token.GrantTo) + return s.hasRole(role, user) +} diff --git a/main.go b/main.go index b48d66c..e9e645f 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,31 @@ package main -import v1 "mc-client-updater-server/internal/api/v1" +import ( + "flag" + router "mc-client-updater-server/internal/api/v1" + "mc-client-updater-server/pkg/conf" + "mc-client-updater-server/pkg/dao" + "mc-client-updater-server/pkg/log" + "strconv" +) + +var ( + debug bool + config string +) + +func init() { + flag.BoolVar(&debug, "debug", false, "启用debug输出") + flag.StringVar(&config, "config", "config.toml", "配置文件路径") + flag.Parse() +} func main() { - r := v1.NewRouter() + log.InitLogger(debug) + conf.InitConfig(config) + // 初始化DB对象 + dao.DB() + r := router.NewRouter() - _ = r.Run(":8080") + _ = r.Run(conf.Conf.Common.Host + ":" + strconv.Itoa(int(conf.Conf.Common.Port))) } diff --git a/pkg/common/errcode.go b/pkg/common/errcode.go new file mode 100644 index 0000000..7c45dd8 --- /dev/null +++ b/pkg/common/errcode.go @@ -0,0 +1,7 @@ +package common + +const ( + LoginErrorCode = 2001 + NoPermission = 2002 + LoginExpired = 2003 +) diff --git a/pkg/conf/conf.go b/pkg/conf/conf.go new file mode 100644 index 0000000..603f731 --- /dev/null +++ b/pkg/conf/conf.go @@ -0,0 +1,85 @@ +package conf + +import ( + "encoding/json" + "github.com/BurntSushi/toml" + "github.com/mcuadros/go-defaults" + "mc-client-updater-server/pkg/log" + "mc-client-updater-server/pkg/util" + "os" +) + +type Config struct { + Common Common `toml:"common"` + Database Database `toml:"database"` + Security Security `toml:"security"` +} + +type Common struct { + Host string `toml:"host" default:"0.0.0.0"` + Port uint16 `toml:"port" default:"8080"` +} + +type Database struct { + Host string `toml:"host" default:"localhost"` + Port uint16 `toml:"port" default:"5432"` + User string `toml:"user" default:"user"` + Password string `toml:"password" default:"password"` + DB string `toml:"db" default:"mc_client_updater"` +} + +type Security struct { + PasswordEncoder string `toml:"password_encoder" default:"argon2id"` + JWTSecret string `toml:"jwt_secret"` +} + +var ( + Conf *Config +) + +// 释放默认配置文件 +func releaseConfig(file string, config *Config) { + f, err := util.CreateNestedFile(file) + if err != nil { + log.Logger.Fatalf("创建默认配置文件失败: %s", err.Error()) + } + + if config.Security.JWTSecret == "" { + config.Security.JWTSecret = util.RandStr(32) + } + + encoder := toml.NewEncoder(f) + err = encoder.Encode(config) + if err != nil { + log.Logger.Fatalf("创建默认配置文件失败: %s", err.Error()) + } +} + +func InitConfig(file string) { + Conf = &Config{} + defaults.SetDefaults(Conf) + + if util.NotExists(file) { + // 默认配置文件不存在则创建 + if file == "config.toml" { + releaseConfig(file, Conf) + log.Logger.Infof("已创建默认配置文件: %s,请修改配置文件内容后重新启动", file) + os.Exit(0) + } else { + log.Logger.Fatalf("配置文件不存在: %s", file) + } + } + + // 解析配置文件 + _, err := toml.DecodeFile(file, &Conf) + if err != nil { + log.Logger.Fatalf("配置文件解析出错: %s", err.Error()) + } + + // 配置预检查 + + jsonConfig, err := json.Marshal(Conf) + if err == nil { + log.Logger.Debugf("配置文件已加载: %s", string(jsonConfig)) + } +} diff --git a/pkg/dao/dao.go b/pkg/dao/dao.go index 07a0cc0..7d18551 100644 --- a/pkg/dao/dao.go +++ b/pkg/dao/dao.go @@ -1 +1,76 @@ package dao + +import ( + "fmt" + "github.com/sirupsen/logrus" + "gorm.io/driver/postgres" + "gorm.io/gorm" + "gorm.io/gorm/logger" + "mc-client-updater-server/pkg/conf" + "mc-client-updater-server/pkg/dao/entity" + "mc-client-updater-server/pkg/log" + "sync" + "time" +) + +type LogrusWriter struct { + log *logrus.Logger +} + +func (w *LogrusWriter) Printf(format string, v ...interface{}) { + logStr := fmt.Sprintf(format, v...) + w.log.WithField("method", "GORM").Warn(logStr) +} + +func NewLogger() *LogrusWriter { + return &LogrusWriter{log: log.Logger} +} + +var ( + once sync.Once + db *gorm.DB +) + +func DB() *gorm.DB { + once.Do(NewDBConn) + return db +} + +func NewDBConn() { + var err error + dsn := fmt.Sprintf( + "host=%s user=%s password=%s dbname=%s port=%d sslmode=disable TimeZone=Asia/Shanghai", + conf.Conf.Database.Host, + conf.Conf.Database.User, + conf.Conf.Database.Password, + conf.Conf.Database.DB, + conf.Conf.Database.Port, + ) + + // >= 1s SQL慢查询 + slowLogger := logger.New(NewLogger(), logger.Config{ + SlowThreshold: time.Second * 1, + LogLevel: logger.Warn, + }) + db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{ + Logger: slowLogger, + }) + if err != nil { + log.Logger.Fatal("创建数据库连接失败:", err) + } + + migrate() +} + +func migrate() { + var err error + err = db.AutoMigrate(&entity.User{}) + err = db.AutoMigrate(&entity.Instance{}) + err = db.AutoMigrate(&entity.Update{}) + err = db.AutoMigrate(&entity.Grant{}) + err = db.AutoMigrate(&entity.Token{}) + + if err != nil { + log.Logger.Fatal("关联数据表失败:", err) + } +} diff --git a/pkg/dao/entity/grant.go b/pkg/dao/entity/grant.go new file mode 100644 index 0000000..78ebc78 --- /dev/null +++ b/pkg/dao/entity/grant.go @@ -0,0 +1,13 @@ +package entity + +import ( + "gorm.io/gorm" +) + +// Grant Grant是授权给实例的,给予实例访问权限 +type Grant struct { + gorm.Model `json:"model"` + Token string `gorm:"unique;not null" json:"token,omitempty"` + TTL int `gorm:"not null;default:0" json:"ttl,omitempty"` + GrantTo uint `gorm:"not null;default:0;comment:instances(id) 授权给实例,0表示无指定(所有)" json:"grant_to,omitempty"` +} diff --git a/pkg/dao/entity/instance.go b/pkg/dao/entity/instance.go new file mode 100644 index 0000000..f2e6feb --- /dev/null +++ b/pkg/dao/entity/instance.go @@ -0,0 +1,11 @@ +package entity + +import ( + "gorm.io/gorm" +) + +type Instance struct { + gorm.Model `json:"model"` + Name string `gorm:"unique;not null" json:"name,omitempty"` + UpdateURL string `gorm:"column:update_url;not null;default:'';comment:更新URL,未指定使用默认" json:"update_url,omitempty"` +} diff --git a/pkg/dao/entity/token.go b/pkg/dao/entity/token.go new file mode 100644 index 0000000..4e01e04 --- /dev/null +++ b/pkg/dao/entity/token.go @@ -0,0 +1,11 @@ +package entity + +import "gorm.io/gorm" + +// Token Token是授权给用户的,给予用户登录权限 +type Token struct { + gorm.Model `json:"model"` + Token string `gorm:"unique;not null" json:"token,omitempty"` + GrantTo string `gorm:"index;not null;default:''" json:"grant_to,omitempty"` + TTL int `gorm:"not null;default:0" json:"ttl,omitempty"` +} diff --git a/pkg/dao/entity/update.go b/pkg/dao/entity/update.go new file mode 100644 index 0000000..6ba74ea --- /dev/null +++ b/pkg/dao/entity/update.go @@ -0,0 +1,10 @@ +package entity + +import "gorm.io/gorm" + +type Update struct { + gorm.Model `json:"model"` + HashID string `gorm:"index;not null" json:"hash_id,omitempty"` + Comment string `gorm:"not null;default:'';comment:更新内容或注释" json:"comment,omitempty"` + Changes string `gorm:"not null;comment:更改的文件列表,逗号分隔,引用files(hash_id)" json:"changes,omitempty"` +} diff --git a/pkg/dao/entity/user.go b/pkg/dao/entity/user.go index f632389..968a1d6 100644 --- a/pkg/dao/entity/user.go +++ b/pkg/dao/entity/user.go @@ -3,9 +3,8 @@ package entity import "gorm.io/gorm" type User struct { - gorm.Model - Username string `gorm:"unique;not null"` - Password string `gorm:"not null"` - Instance string `gorm:"not null;default:''"` - Role string `gorm:"not null;default:0"` + gorm.Model `json:"model"` + Username string `gorm:"unique;not null" json:"username,omitempty"` + Password string `gorm:"not null" json:"password,omitempty"` + Roles string `gorm:"not null;default:''" json:"roles,omitempty"` } diff --git a/pkg/dto/user.go b/pkg/dto/user.go new file mode 100644 index 0000000..4994b8f --- /dev/null +++ b/pkg/dto/user.go @@ -0,0 +1,18 @@ +package dto + +import ( + "mc-client-updater-server/pkg/dao/entity" + "strings" +) + +type User struct { + Username string + Roles []string +} + +func UserEntity2DTO(user *entity.User) *User { + return &User{ + Username: user.Username, + Roles: strings.Split(user.Roles, ","), + } +} diff --git a/pkg/log/logger.go b/pkg/log/logger.go new file mode 100644 index 0000000..c19b96b --- /dev/null +++ b/pkg/log/logger.go @@ -0,0 +1,28 @@ +package log + +import ( + nested "github.com/antonfisher/nested-logrus-formatter" + "github.com/sirupsen/logrus" +) + +var Logger *logrus.Logger + +func InitLogger(debug bool) { + log := logrus.New() + log.SetFormatter(&nested.Formatter{ + FieldsOrder: []string{"method", "url", "statusCode", "spendTime"}, + HideKeys: true, + NoFieldsColors: true, + TimestampFormat: "2006-01-02 15:04:05.000", + }) + + var lvl logrus.Level + switch debug { + case true: + lvl = logrus.DebugLevel + case false: + lvl = logrus.InfoLevel + } + log.SetLevel(lvl) + Logger = log +} diff --git a/pkg/param/authorize.go b/pkg/param/authorize.go new file mode 100644 index 0000000..33a5273 --- /dev/null +++ b/pkg/param/authorize.go @@ -0,0 +1,10 @@ +package param + +type AuthorizeQueryParam struct { + ClientId uint `form:"client_id" binding:"required"` + ResponseType string `form:"response_type" binding:"required"` + State string `form:"state" binding:"required"` + Scope string `form:"scope" binding:"required"` + CodeChallenge string `form:"code_challenge" binding:"required"` + CodeChallengeMethod string `form:"code_challenge_method" binding:"required"` +} diff --git a/pkg/param/login.go b/pkg/param/login.go new file mode 100644 index 0000000..de246ad --- /dev/null +++ b/pkg/param/login.go @@ -0,0 +1,6 @@ +package param + +type LoginParam struct { + Username string `json:"username"` + Password string `json:"password"` +} diff --git a/pkg/password/argon2id.go b/pkg/password/argon2id.go new file mode 100644 index 0000000..1578509 --- /dev/null +++ b/pkg/password/argon2id.go @@ -0,0 +1,16 @@ +package password + +import "github.com/alexedwards/argon2id" + +type Argon2id struct { +} + +func (a *Argon2id) Create(password string) (hash string, err error) { + hash, err = argon2id.CreateHash(password, argon2id.DefaultParams) + return +} + +func (a *Argon2id) Verify(password, hash string) (match bool, err error) { + match, err = argon2id.ComparePasswordAndHash(password, hash) + return +} diff --git a/pkg/password/password.go b/pkg/password/password.go new file mode 100644 index 0000000..9e4cd90 --- /dev/null +++ b/pkg/password/password.go @@ -0,0 +1,29 @@ +package password + +import ( + "mc-client-updater-server/pkg/conf" + "mc-client-updater-server/pkg/log" + "sync" +) + +var ( + once sync.Once + encoder Encoder +) + +func Password() Encoder { + once.Do(func() { + switch conf.Conf.Security.PasswordEncoder { + case "argon2id": + encoder = &Argon2id{} + default: + log.Logger.Fatal("非法的PasswordEncoder类型:", conf.Conf.Security.PasswordEncoder) + } + }) + return encoder +} + +type Encoder interface { + Create(string) (string, error) + Verify(password, hash string) (bool, error) +} diff --git a/pkg/result/base.go b/pkg/result/base.go new file mode 100644 index 0000000..b0f53e0 --- /dev/null +++ b/pkg/result/base.go @@ -0,0 +1,74 @@ +package result + +import ( + "github.com/gin-gonic/gin" + "mc-client-updater-server/pkg/common" + "net/http" +) + +type Result struct { + ctx *gin.Context +} + +type Root struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data interface{} `json:"data"` +} + +func NewResult(c *gin.Context) *Result { + return &Result{ctx: c} +} + +func (r *Result) Success(data interface{}) { + if data == nil { + data = gin.H{} + } + res := Root{ + Code: http.StatusOK, + Msg: "", + Data: data, + } + r.ctx.JSON(http.StatusOK, res) + r.ctx.Next() +} + +func (r *Result) Fail(code int, msg string) { + res := Root{ + Code: code, + Msg: msg, + Data: gin.H{}, + } + r.ctx.JSON(http.StatusOK, res) + r.ctx.Abort() +} + +//func (r *Result) Redirect302(location string) { +// r.ctx.Header("Location", location) +// r.ctx.Status(http.StatusFound) +// r.ctx.Next() +//} + +func (r *Result) InternalServerError(msg string) { + r.Fail(http.StatusInternalServerError, msg) +} + +func (r *Result) BadRequest() { + r.Fail(http.StatusBadRequest, "请求参数错误") +} + +func (r *Result) LoginError() { + r.Fail(common.LoginErrorCode, "账号或密码错误") +} + +func (r *Result) Unauthorized() { + r.Fail(http.StatusUnauthorized, "未登录") +} + +func (r *Result) NoPermission() { + r.Fail(common.NoPermission, "权限不足") +} + +func (r *Result) LoginExpired() { + r.Fail(common.LoginExpired, "登录过期") +} diff --git a/pkg/token/jwt.go b/pkg/token/jwt.go new file mode 100644 index 0000000..c4b8dc4 --- /dev/null +++ b/pkg/token/jwt.go @@ -0,0 +1,25 @@ +package token + +import ( + "github.com/golang-jwt/jwt/v4" + "mc-client-updater-server/pkg/conf" + "mc-client-updater-server/pkg/log" + "time" +) + +func NewToken(aud string) string { + auds := make([]string, 1) + auds = append(auds, aud) + now := time.Now() + token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ + "aud": auds, + "iat": now, + "nbf": now, + }) + tokenStr, err := token.SignedString([]byte(conf.Conf.Security.JWTSecret)) + if err != nil { + log.Logger.Error("生成Token失败:", err) + return "" + } + return tokenStr +} diff --git a/pkg/util/file.go b/pkg/util/file.go new file mode 100644 index 0000000..017be57 --- /dev/null +++ b/pkg/util/file.go @@ -0,0 +1,30 @@ +package util + +import ( + "os" + "path/filepath" +) + +func Exists(name string) bool { + if _, err := os.Stat(name); err != nil { + if os.IsNotExist(err) { + return false + } + } + return true +} + +func NotExists(name string) bool { + return !Exists(name) +} + +func CreateNestedFile(path string) (*os.File, error) { + basePath := filepath.Dir(path) + if !Exists(basePath) { + err := os.MkdirAll(basePath, 0700) + if err != nil { + return nil, err + } + } + return os.Create(path) +} diff --git a/pkg/util/rand.go b/pkg/util/rand.go new file mode 100644 index 0000000..a585cc7 --- /dev/null +++ b/pkg/util/rand.go @@ -0,0 +1,36 @@ +package util + +import ( + "math/rand" + "time" + "unsafe" +) + +const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" + +var src = rand.NewSource(time.Now().UnixNano()) + +const ( + // 6 bits to represent a letter index + letterIdBits = 6 + // All 1-bits as many as letterIdBits + letterIdMask = 1<= 0; { + if remain == 0 { + cache, remain = src.Int63(), letterIdMax + } + if idx := int(cache & letterIdMask); idx < len(letters) { + b[i] = letters[idx] + i-- + } + cache >>= letterIdBits + remain-- + } + return *(*string)(unsafe.Pointer(&b)) +} diff --git a/pkg/util/slice.go b/pkg/util/slice.go new file mode 100644 index 0000000..026cec9 --- /dev/null +++ b/pkg/util/slice.go @@ -0,0 +1,21 @@ +package util + +func InStringSlice(sl []string, ele string) bool { + slMap := convertStrSlice2Map(sl) + return inMap(slMap, ele) +} + +// ConvertStrSlice2Map 将字符串 slice 转为 map[string]struct{}。 +func convertStrSlice2Map(sl []string) map[string]struct{} { + set := make(map[string]struct{}, len(sl)) + for _, v := range sl { + set[v] = struct{}{} + } + return set +} + +// InMap 判断字符串是否在 map 中。 +func inMap(m map[string]struct{}, s string) bool { + _, ok := m[s] + return ok +} diff --git a/pkg/util/token.go b/pkg/util/token.go new file mode 100644 index 0000000..f013a34 --- /dev/null +++ b/pkg/util/token.go @@ -0,0 +1,5 @@ +package util + +func GenSessionID() string { + return RandStr(32) +}