From 897f9035e232b5cccd799e875400f4d6e49111a4 Mon Sep 17 00:00:00 2001 From: nicksherron Date: Sun, 9 Feb 2020 18:30:05 -0500 Subject: [PATCH] jwt working --- cmd/root.go | 13 ++++ go.mod | 4 +- go.sum | 58 +++++++-------- internal/db.go | 159 +++++++++++++++++++++++++-------------- internal/server.go | 180 +++++++++++++++++++++++++++------------------ 5 files changed, 253 insertions(+), 161 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 56562c9..c8f3a11 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -30,8 +30,21 @@ func Execute() { func init() { cobra.OnInitialize() rootCmd.PersistentFlags().StringVar(&internal.DbPath, "db", dbPath(), "DB location (sqlite or postgres)") + rootCmd.PersistentFlags().StringVarP(&internal.Addr, "addr", "a", listenAddr(), "Ip and port to listen and serve on.") } + +func listenAddr() string { + var a string + if os.Getenv("BH_HOST") != "" { + a = os.Getenv("BH_HOST") + return a + } + a = "0.0.0.0:8080" + return a + +} + func dbPath() string { dbFile := "data.db" f := filepath.Join(appDir(), dbFile) diff --git a/go.mod b/go.mod index 420cb69..3e11beb 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,16 @@ module github.com/nicksherron/bashhub-server require ( + github.com/appleboy/gin-jwt/v2 v2.6.3 github.com/dgrijalva/jwt-go v3.2.0+incompatible - github.com/gin-gonic/contrib v0.0.0-20191209060500-d6e26eeaa607 // indirect github.com/gin-gonic/gin v1.5.0 github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jinzhu/gorm v1.9.12 - github.com/lacion/cookiecutter_golang_example v0.0.0-20191209145422-f4f6c7d38761 github.com/lib/pq v1.3.0 github.com/mattn/go-sqlite3 v2.0.1+incompatible github.com/spf13/cobra v0.0.3 github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd ) go 1.13 diff --git a/go.sum b/go.sum index d21bbc3..8a9f386 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/appleboy/gin-jwt/v2 v2.6.3 h1:aK4E3DjihWEBUTjEeRnGkA5nUkmwJPL1CPonMa2usRs= +github.com/appleboy/gin-jwt/v2 v2.6.3/go.mod h1:MfPYA4ogzvOcVkRwAxT7quHOtQmVKDpTwxyUrC2DNw0= +github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4= +github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw= 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= @@ -11,11 +11,10 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= 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/contrib v0.0.0-20191209060500-d6e26eeaa607 h1:MrIm8EEPue08JS4eh+b08IOG+wd0WRWEHWnewNfWFX0= -github.com/gin-gonic/contrib v0.0.0-20191209060500-d6e26eeaa607/go.mod h1:iqneQ2Df3omzIVTkIfn7c1acsVnMGiSLn4XF5Blh3Yg= +github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc= github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= @@ -27,10 +26,10 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= @@ -39,78 +38,71 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/lacion/cookiecutter_golang_example v0.0.0-20191209145422-f4f6c7d38761 h1:OyKcyDSgyvO+QgfeRtuNLZ5aEg81h13A9fUO08cNPYE= -github.com/lacion/cookiecutter_golang_example v0.0.0-20191209145422-f4f6c7d38761/go.mod h1:zs+aYQ9Xrc97DqpYv5KFQBq4cZ7m1KSJLOPwFVyd6hw= github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= 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 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/tidwall/gjson v1.3.5 h1:2oW9FBNu8qt9jy5URgrzsVx/T/KSn3qn/smJQ0crlDQ= +github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd h1:GGJVjV8waZKRHrgwvtH66z9ZGVurTD1MT0n1Bb+q4aM= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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/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-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191206204035-259af5ff87bd/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/db.go b/internal/db.go index 20de342..498110f 100644 --- a/internal/db.go +++ b/internal/db.go @@ -13,6 +13,7 @@ import ( _ "github.com/jinzhu/gorm/dialects/sqlite" _ "github.com/lib/pq" "github.com/mattn/go-sqlite3" + "golang.org/x/crypto/bcrypt" ) var ( @@ -73,7 +74,6 @@ func DbInit() { gormdb.AutoMigrate(&Command{}) gormdb.AutoMigrate(&System{}) gormdb.Model(&User{}).AddIndex("idx_user", "username") - gormdb.Model(&User{}).AddIndex("idx_token", "token") gormdb.Model(&System{}).AddIndex("idx_mac", "mac") gormdb.Model(&Command{}).AddIndex("idx_exit_command", "exit_status, command") @@ -81,10 +81,71 @@ func DbInit() { gormdb.Close() } +func hashAndSalt(password string) string { + hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.MinCost) + if err != nil { + log.Println(err) + } + return string(hash) +} + +func comparePasswords(hashedPwd string, plainPwd string) bool { + byteHash := []byte(hashedPwd) + err := bcrypt.CompareHashAndPassword(byteHash, []byte(plainPwd)) + if err != nil { + log.Println(err) + return false + } + return true +} + func (user User) userExists() bool { + var password string + err := DB.QueryRow("SELECT password FROM users WHERE username = $1", + user.Username).Scan(&password) + if err != nil && err != sql.ErrNoRows { + log.Fatalf("error checking if row exists %v", err) + } + if password != "" { + return comparePasswords(password, user.Password) + } + return false +} +func (user User) userGetId() uint { + var id uint + err := DB.QueryRow("SELECT id FROM users WHERE username = $1", + user.Username).Scan(&id) + if err != nil && err != sql.ErrNoRows { + log.Fatalf("error checking if row exists %v", err) + } + return id +} +func (user User) userGetSystemName() string { + var systemName string + err := DB.QueryRow(`SELECT name + FROM systems + WHERE user_id in (select id from users where username = $1) + AND mac = $2`, + user.Username, user.Mac).Scan(&systemName) + if err != nil && err != sql.ErrNoRows { + log.Fatalf("error checking if row exists %v", err) + } + return systemName +} + +func (user User) usernameExists() bool { var exists bool - err := DB.QueryRow("SELECT exists (select id FROM users WHERE username = $1 AND password = $2)", - user.Username, user.Password).Scan(&exists) + err := DB.QueryRow(`SELECT exists (select id FROM users WHERE "username" = $1)`, + user.Username).Scan(&exists) + if err != nil && err != sql.ErrNoRows { + log.Fatalf("error checking if row exists %v", err) + } + return exists +} +func (user User) emailExists() bool { + var exists bool + err := DB.QueryRow(`SELECT exists (select id FROM users WHERE "email" = $1)`, + user.Email).Scan(&exists) if err != nil && err != sql.ErrNoRows { log.Fatalf("error checking if row exists %v", err) } @@ -105,27 +166,11 @@ func (user User) userCreate() int64 { return inserted } -func (user User) updateToken() { - _, err := DB.Exec(`UPDATE users SET "token" = $1 WHERE "username" = $2 `, user.Token, user.Username) - if err != nil { - log.Fatal(err) - } -} - -func (user User) tokenExists() bool { - var exists bool - err := DB.QueryRow("SELECT exists (select id FROM users WHERE token = $1)", - user.Token).Scan(&exists) - if err != nil && err != sql.ErrNoRows { - log.Fatalf("error checking if row exists %v", err) - } - return exists -} func (cmd Command) commandInsert() int64 { res, err := DB.Exec(`INSERT INTO commands("process_id","process_start_time","exit_status","uuid", "command", "created", "path", "user_id") - VALUES ($1,$2,$3,$4,$5,$6,$7,(select "id" FROM users WHERE "token" = $8))`, - cmd.ProcessId, cmd.ProcessStartTime, cmd.ExitStatus, cmd.Uuid, cmd.Command, cmd.Created, cmd.Path, cmd.Token) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8)`, + cmd.ProcessId, cmd.ProcessStartTime, cmd.ExitStatus, cmd.Uuid, cmd.Command, cmd.Created, cmd.Path, cmd.User.ID) if err != nil { log.Fatal(err) } @@ -147,140 +192,140 @@ func (cmd Command) commandGet() []Query { rows, err = DB.Query(`SELECT * FROM ( SELECT DISTINCT ON ("command") command, "uuid", "created" FROM commands - WHERE "user_id" IN (SELECT "id" FROM users WHERE "token" = $1) + WHERE "user_id" = $1 AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like 'bh%' AND "path" = $3 AND "command" ~ $4 ) c - ORDER BY "created" DESC limit $2;`, cmd.Token, cmd.Limit, cmd.Path, cmd.Query) + ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit, cmd.Path, cmd.Query) } else if cmd.Path != "" && cmd.Query != "" { rows, err = DB.Query(`SELECT "command", "uuid", "created" FROM commands - WHERE "user_id" IN (SELECT "id" FROM users WHERE "token" = $1) + WHERE "user_id" = $1 AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like 'bh%' AND "path" = $3 AND "command" ~ $4 - ORDER BY "created" DESC limit $2;`, cmd.Token, cmd.Limit, cmd.Path, cmd.Query) + ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit, cmd.Path, cmd.Query) } else if cmd.Path != "" && cmd.Unique { rows, err = DB.Query(`SELECT * FROM ( SELECT DISTINCT ON ("command") command, "uuid", "created" FROM commands - WHERE "user_id" IN (SELECT "id" FROM users WHERE "token" = $1) + WHERE "user_id" = $1 AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like 'bh%' AND "path" = $3 ) c - ORDER BY "created" DESC limit $2;`, cmd.Token, cmd.Limit, cmd.Path) + ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit, cmd.Path) } else if cmd.Query != "" && cmd.Unique { rows, err = DB.Query(`SELECT * FROM ( SELECT DISTINCT ON ("command") command, "uuid", "created" FROM commands - WHERE "user_id" IN (SELECT "id" FROM users WHERE "token" = $1) + WHERE "user_id" = $1 AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like 'bh%' AND "command" ~ $3 ) c - ORDER BY "created" DESC limit $2;`, cmd.Token, cmd.Limit, cmd.Query) + ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit, cmd.Query) } else if cmd.Query != "" { rows, err = DB.Query(`SELECT "command", "uuid", "created" FROM commands - WHERE "user_id" IN (SELECT "id" FROM users WHERE "token" = $1) + WHERE "user_id" = $1 AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like 'bh%' AND "command" ~ $3 - ORDER BY "created" DESC limit $2;`, cmd.Token, cmd.Limit, cmd.Query) + ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit, cmd.Query) } else { // unique rows, err = DB.Query(`SELECT * FROM ( SELECT DISTINCT ON ("command") command, "uuid", "created" FROM commands - WHERE "user_id" IN (SELECT "id" FROM users WHERE "token" = $1) + WHERE "user_id" = $1 AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like 'bh%' ) c - ORDER BY "created" DESC limit $2;`, cmd.Token, cmd.Limit) + ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit) } } else { // sqlite if cmd.Path != "" && cmd.Query != "" && cmd.Unique { query := fmt.Sprintf(`SELECT "command", "uuid", "created" FROM commands - WHERE "user_id" IN (select "id" FROM users WHERE "token" = '%v') + WHERE "user_id" = '%v' AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like '%v' AND "path" = '%v' AND "command" regexp '%v' GROUP BY "command" ORDER BY "created" DESC limit '%v'`, - cmd.Token, "bh%", cmd.Path, cmd.Query, cmd.Limit) + cmd.User.ID, "bh%", cmd.Path, cmd.Query, cmd.Limit) rows, err = DB.Query(query) } else if cmd.Path != "" && cmd.Query != "" { query := fmt.Sprintf(`SELECT "command", "uuid", "created" FROM commands - WHERE "user_id" IN (select "id" FROM users WHERE "token" = '%v') + WHERE "user_id" = '%v' AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like '%v' AND "path" = %v' AND "command" regexp %v' ORDER BY "created" DESC limit '%v'`, - cmd.Token, "bh%", cmd.Path, cmd.Query, cmd.Limit) + cmd.User.ID, "bh%", cmd.Path, cmd.Query, cmd.Limit) rows, err = DB.Query(query) } else if cmd.Path != "" && cmd.Unique { rows, err = DB.Query(`SELECT "command", "uuid", "created" FROM commands - WHERE "user_id" IN (select "id" FROM users WHERE "token" = $1) + WHERE "user_id" = $1 AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like 'bh%' AND "path" = $2 GROUP BY "command" ORDER BY "created" DESC limit $3`, - cmd.Token, cmd.Path, cmd.Limit) + cmd.User.ID, cmd.Path, cmd.Limit) } else if cmd.Query != "" && cmd.Unique { query := fmt.Sprintf(`SELECT "command", "uuid", "created" FROM commands - WHERE "user_id" IN (select "id" FROM users WHERE "token" = '%v') + WHERE "user_id" = '%v' AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like '%v' AND "command" regexp '%v' GROUP BY "command" ORDER BY "created" DESC limit '%v'`, - cmd.Token, "bh%", cmd.Query, cmd.Limit) + cmd.User.ID, "bh%", cmd.Query, cmd.Limit) rows, err = DB.Query(query) } else if cmd.Query != "" { query := fmt.Sprintf(`SELECT "command", "uuid", "created" FROM commands - WHERE "user_id" IN (select "id" FROM users WHERE "token" = '%v') + WHERE "user_id" = '%v' AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like '%v' AND "command" regexp'%v' ORDER BY "created" DESC limit '%v'`, - cmd.Token, "bh%", cmd.Query, cmd.Limit) + cmd.User.ID, "bh%", cmd.Query, cmd.Limit) rows, err = DB.Query(query) } else { // unique rows, err = DB.Query(`SELECT "command", "uuid", "created" FROM commands - WHERE "user_id" IN (SELECT "id" FROM users WHERE "token" = $1) + WHERE "user_id" = $1 AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like 'bh%' - GROUP BY "command" ORDER BY "created" DESC limit $2;`, cmd.Token, cmd.Limit) + GROUP BY "command" ORDER BY "created" DESC limit $2;`, cmd.User.ID, cmd.Limit) } } } else { if cmd.Path != "" { rows, err = DB.Query(`SELECT "command", "uuid", "created" FROM commands - WHERE "user_id" IN (select "id" FROM users WHERE "token" = $1) AND "path" = $3 + WHERE "user_id" = $1 AND "path" = $3 AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like 'bh%' - ORDER BY "created" DESC limit $2`, cmd.Token, cmd.Limit, cmd.Path) + ORDER BY "created" DESC limit $2`, cmd.User.ID, cmd.Limit, cmd.Path) } else { rows, err = DB.Query(`SELECT "command", "uuid", "created" FROM commands - WHERE "user_id" IN (select "id" FROM users WHERE "token" = $1) + WHERE "user_id" = $1 AND ("exit_status" = 0 OR "exit_status" = 130) AND "command" not like 'bh%' - ORDER BY "created" DESC limit $2`, cmd.Token, cmd.Limit) + ORDER BY "created" DESC limit $2`, cmd.User.ID, cmd.Limit) } } @@ -305,8 +350,8 @@ func (sys System) systemInsert() int64 { t := time.Now().Unix() res, err := DB.Exec(`INSERT INTO systems ("name", "mac", "user_id", "hostname", "client_version", "created", "updated") - VALUES ($1, $2, (select "id" FROM users WHERE "token" = $3), $4, $5, $6, $7)`, - sys.Name, sys.Mac, sys.Token, sys.Hostname, sys.ClientVersion, t, t) + VALUES ($1, $2, $3, $4, $5, $6, $7)`, + sys.Name, sys.Mac, sys.User.ID, sys.Hostname, sys.ClientVersion, t, t) if err != nil { log.Fatal(err) } @@ -317,14 +362,16 @@ func (sys System) systemInsert() int64 { return inserted } -func (sys System) systemGet() (SystemQuery, error) { +func (sys System) systemGet() SystemQuery { var row SystemQuery err := DB.QueryRow(`SELECT "name", "mac", "user_id", "hostname", "client_version", - "id", "created", "updated" FROM systems WHERE mac = $1`, - sys.Mac).Scan(&row) + "id", "created", "updated" FROM systems + WHERE "user_id" $1 + AND "mac" = $2`, + sys.User.ID, sys.Mac).Scan(&row) if err != nil { - return SystemQuery{}, err + return SystemQuery{} } - return row, nil + return row } diff --git a/internal/server.go b/internal/server.go index d833438..8bb56a2 100644 --- a/internal/server.go +++ b/internal/server.go @@ -1,26 +1,24 @@ package internal import ( - "crypto/sha256" "fmt" "log" "net/http" "strconv" - "strings" "time" - jwt_lib "github.com/dgrijalva/jwt-go" + "github.com/appleboy/gin-jwt/v2" "github.com/gin-gonic/gin" ) type User struct { - ID uint `gorm:"primary_key"` + ID uint `form:"id" json:"id" xml:"id" gorm:"primary_key"` Username string `form:"Username" json:"Username" xml:"Username" gorm:"type:varchar(200);unique_index"` Email string `form:"email" json:"email" xml:"email"` Password string `form:"password" json:"password" xml:"password"` - Mac *string `form:"mac" json:"mac" xml:"mac"` + Mac *string `gorm:"-" form:"mac" json:"mac" xml:"mac"` RegistrationCode *string `form:"registrationCode" json:"registrationCode" xml:"registrationCode"` - Token string + SystemName string `gorm:"-" json:"systemName" ` } type Query struct { @@ -48,7 +46,6 @@ type Command struct { ExitStatus int `form:"exitStatus" json:"exitStatus" xml:"exitStatus"` User User `gorm:"association_foreignkey:ID"` UserId uint - Token string `gorm:"-"` Limit int `gorm:"-"` Unique bool `gorm:"-"` Query string `gorm:"-"` @@ -60,37 +57,89 @@ type System struct { ID uint `form:"id" json:"id" xml:"id" gorm:"primary_key"` Created int64 Updated int64 - Mac string `form:"mac" json:"mac" xml:"mac"` + Mac *string `form:"mac" json:"mac" xml:"mac"` Hostname *string `form:"hostname" json:"hostname" xml:"hostname"` Name *string `form:"name" json:"name" xml:"name"` ClientVersion *string `form:"clientVersion" json:"clientVersion" xml:"clientVersion"` User User `gorm:"association_foreignkey:ID"` UserId uint `form:"userId" json:"userId" xml:"userId"` - Token string `gorm:"-"` } -func auth() gin.HandlerFunc { - return func(c *gin.Context) { - var user User - err := func() error { - user.Token = strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ") - if user.tokenExists() { - return nil - } else { - return fmt.Errorf("token doesn't exist") - } - }() - if err != nil { - c.AbortWithError(401, err) - } - } -} +var ( + Addr string +) + +//TODO: Figure out a better way to do this. +const secret = "bashub-server-secret" func Run() { DbInit() - r := gin.Default() + // the jwt middleware + authMiddleware, err := jwt.New(&jwt.GinJWTMiddleware{ + Realm: "bashhub-server zone", + Key: []byte(secret), + Timeout: 1000 * time.Hour, + MaxRefresh: 1000 * time.Hour, + IdentityKey: "username", + LoginResponse: func(c *gin.Context, code int, token string, expire time.Time) { + c.JSON(http.StatusOK, gin.H{ + "accessToken": token, + }) + }, + PayloadFunc: func(data interface{}) jwt.MapClaims { + if v, ok := data.(*User); ok { + return jwt.MapClaims{ + "username": v.Username, + "systemName": v.SystemName, + } + } + return jwt.MapClaims{} + }, + IdentityHandler: func(c *gin.Context) interface{} { + claims := jwt.ExtractClaims(c) + return &User{ + Username: claims["username"].(string), + SystemName: claims["systemName"].(string), + } + }, + Authenticator: func(c *gin.Context) (interface{}, error) { + var user User + + if err := c.ShouldBind(&user); err != nil { + return "", jwt.ErrMissingLoginValues + } + if user.userExists() { + return &User{ + Username: user.Username, + SystemName: user.userGetSystemName(), + }, nil + } + fmt.Println("failed") + + return nil, jwt.ErrFailedAuthentication + }, + Authorizator: func(data interface{}, c *gin.Context) bool { + if v, ok := data.(*User); ok && v.usernameExists() { + return true + } + return false + }, + Unauthorized: func(c *gin.Context, code int, message string) { + c.JSON(code, gin.H{ + "code": code, + "message": message, + }) + }, + TokenLookup: "header: Authorization, query: token, cookie: jwt", + TokenHeadName: "Bearer", + TimeFunc: time.Now, + }) + + if err != nil { + log.Fatal("JWT Error:" + err.Error()) + } r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ @@ -98,36 +147,7 @@ func Run() { }) }) - r.POST("/api/v1/login", func(c *gin.Context) { - var user User - if err := c.ShouldBindJSON(&user); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - user.Password = fmt.Sprintf("%v", sha256.Sum256([]byte(user.Password))) - - if !user.userExists() { - c.String(401, "Bad credentials") - return - } - - token := jwt_lib.New(jwt_lib.GetSigningMethod("HS256")) - - token.Claims = jwt_lib.MapClaims{ - "Id": user.Username, - "exp": time.Now().Add(time.Hour * 20000).Unix(), - } - // Sign and get the complete encoded token as a string - tokenString, err := token.SignedString([]byte(user.Password)) - if err != nil { - c.JSON(500, gin.H{"message": "Could not generate token"}) - } - user.Token = tokenString - user.updateToken() - - c.JSON(200, gin.H{"accessToken": tokenString}) - - }) + r.POST("/api/v1/login", authMiddleware.LoginHandler) r.POST("/api/v1/user", func(c *gin.Context) { var user User @@ -139,23 +159,33 @@ func Run() { c.JSON(http.StatusBadRequest, gin.H{"error": "email required"}) return } + if user.usernameExists() { + c.String(409, "Username already taken") + return + } + if user.emailExists() { + c.String(409, "This email address is already registered.") + return + } - user.Password = fmt.Sprintf("%v", sha256.Sum256([]byte(user.Password))) - + user.Password = hashAndSalt(user.Password) user.userCreate() }) - r.Use(auth()) + r.Use(authMiddleware.MiddlewareFunc()) r.GET("/api/v1/command/search", func(c *gin.Context) { var command Command - command.Token = strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ") + var user User + claims := jwt.ExtractClaims(c) + user.Username = claims["username"].(string) + command.User.ID = user.userGetId() command.Limit = 100 if c.Query("limit") != "" { if num, err := strconv.Atoi(c.Query("limit")); err != nil { command.Limit = 100 - }else { + } else { command.Limit = num } } @@ -182,32 +212,42 @@ func Run() { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } - command.Token = strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ") + var user User + claims := jwt.ExtractClaims(c) + user.Username = claims["username"].(string) + command.User.ID = user.userGetId() command.commandInsert() }) r.POST("/api/v1/system", func(c *gin.Context) { var system System + var user User err := c.Bind(&system) if err != nil { log.Fatal(err) } - system.Token = strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ") + + claims := jwt.ExtractClaims(c) + user.Username = claims["username"].(string) + system.User.ID = user.userGetId() + system.systemInsert() c.AbortWithStatus(201) }) r.GET("/api/v1/system", func(c *gin.Context) { var system System - system.Token = strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ") - system.Mac = c.Query("mac") - if system.Mac == "" { + var user User + claims := jwt.ExtractClaims(c) + mac := c.Query("mac") + if mac == "" { c.AbortWithStatus(http.StatusBadRequest) return - } - result, err := system.systemGet() - if err != nil { + user.Username = claims["username"].(string) + system.User.ID = user.userGetId() + result := system.systemGet() + if len(result.Mac) == 0 { c.AbortWithStatus(404) return } @@ -215,5 +255,5 @@ func Run() { }) - r.Run() + r.Run(Addr) }