aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Resnick <max@ofmax.li>2020-11-08 11:45:16 -0800
committerMax Resnick <max@ofmax.li>2021-01-01 10:50:14 -0800
commita397341ad471cc761f7fb930d77e53cf7eb40a2a (patch)
tree76fb8318269569687fdd30467dc61ecba3499d09
parent689a57ec4a444f8233fe2e5ec7ceb0903218218d (diff)
downloadiserv-a397341ad471cc761f7fb930d77e53cf7eb40a2a.tar.gz
adds casbin and accounts
Diffstat (limited to '')
-rw-r--r--auth_model.ini15
-rw-r--r--cmd/web/main.go22
-rw-r--r--go.mod8
-rw-r--r--go.sum100
-rw-r--r--internal/acct/acct.go106
-rw-r--r--internal/auth/handler.go35
-rw-r--r--internal/auth/middleware.go45
-rw-r--r--internal/auth/model.go15
-rw-r--r--internal/auth/repo.go13
-rw-r--r--internal/auth/service.go36
-rw-r--r--internal/auth/service_test.go3
-rw-r--r--internal/db/redis/acct.go44
-rw-r--r--internal/db/redis/auth.go51
-rw-r--r--internal/db/redis/image.go2
-rw-r--r--internal/goog/goog.go89
-rw-r--r--internal/image/handler.go5
-rw-r--r--internal/image/service.go1
-rw-r--r--policy.csv6
18 files changed, 528 insertions, 68 deletions
diff --git a/auth_model.ini b/auth_model.ini
new file mode 100644
index 0000000..44507a6
--- /dev/null
+++ b/auth_model.ini
@@ -0,0 +1,15 @@
+[request_definition]
+r = sub, obj, act
+
+[policy_definition]
+p = sub, obj, act
+
+[role_definition]
+g = _, _
+g2 = _, _
+
+[policy_effect]
+e = some(where (p.eft == allow))
+
+[matchers]
+m = g(r.sub, p.sub) && g2(r.obj, p.obj) && regexMatch(r.act, p.act)
diff --git a/cmd/web/main.go b/cmd/web/main.go
index 093dad6..8456ad8 100644
--- a/cmd/web/main.go
+++ b/cmd/web/main.go
@@ -9,14 +9,17 @@ import (
"time"
"github.com/alexedwards/scs/v2"
+ "github.com/casbin/casbin"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
+ "git.ofmax.li/iserv/internal/acct"
"git.ofmax.li/iserv/internal/auth"
"git.ofmax.li/iserv/internal/db/redis"
"git.ofmax.li/iserv/internal/fs"
+ "git.ofmax.li/iserv/internal/goog"
"git.ofmax.li/iserv/internal/image"
"go.ofmax.li/tmpl"
)
@@ -54,6 +57,9 @@ func main() {
sessionManager := scs.New()
sessionManager.Lifetime = 24 * time.Hour
+ // Google
+ googService := goog.NewService(oauthClientConfig)
+
// Image
imgdb := redis.NewRedisImageRepo(connPool)
imageService := image.NewService(imgdb, storagePath, renderer)
@@ -61,22 +67,32 @@ func main() {
imageFile := fs.NewHandler(storagePath)
// Auth
+ // Auth Enforcer
+ enf := casbin.NewEnforcer("auth_model.ini", "policy.csv")
authdb := redis.NewRedisAuthRepo(connPool)
- authService := auth.NewService(authdb)
- authHandler := auth.NewHandler(authService, sessionManager, oauthClientConfig)
+ authService := auth.NewService(authdb, googService, enf)
+ authHandler := auth.NewHandler(authService, sessionManager)
+
+ // Acct
+ acctDb := redis.NewAcctRepo(connPool)
+ acctService := acct.NewService(acctDb, authdb, googService)
+ acctHandler := acct.NewHandler(acctService, sessionManager)
// Static Files
staticFiles := fs.NewHandler(path.Join(storagePath, "static"))
r := chi.NewRouter()
+ r.Use(middleware.StripSlashes)
r.Use(middleware.Logger)
r.Use(sessionManager.LoadAndSave)
+ r.Use(auth.AuthOnly(authService, sessionManager))
r.Get("/a/g", authHandler.OauthCallback)
r.Get("/l", authHandler.Login)
+ r.Get("/u/register", acctHandler.Register)
r.Get("/i/{fileName}", imageHandler.GetImage)
- r.Post("/u", imageHandler.PostImage)
+ r.Post("/i", imageHandler.PostImage)
r.Get("/f/*", imageFile)
r.Get("/static/*", staticFiles)
diff --git a/go.mod b/go.mod
index 7ff0ba8..4f359c5 100644
--- a/go.mod
+++ b/go.mod
@@ -4,10 +4,15 @@ go 1.14
require (
github.com/alexedwards/scs/v2 v2.4.0
+ github.com/apex/log v1.9.0
github.com/brianvoe/gofakeit v3.18.0+incompatible
github.com/bwmarrin/snowflake v0.3.0 // indirect
+ github.com/casbin/casbin v1.9.1
+ github.com/casbin/casbin/v2 v2.19.8 // indirect
+ github.com/casbin/chi-authz v0.0.0-20170726155602-f9f57e3793f2 // indirect
github.com/gbrlsnchs/jwt/v3 v3.0.0-rc.2
github.com/go-chi/chi v4.1.0+incompatible
+ github.com/go-delve/delve v1.5.0 // indirect
github.com/golang/mock v1.4.4
github.com/gomodule/redigo v2.0.0+incompatible
github.com/matoous/go-nanoid v1.3.0
@@ -15,11 +20,12 @@ require (
github.com/pkg/errors v0.9.1
github.com/rafaeljusto/redigomock v2.3.0+incompatible
github.com/speps/go-hashids v2.0.0+incompatible // indirect
- github.com/stretchr/testify v1.5.1
+ github.com/stretchr/testify v1.6.1
gitlab.com/grumps/environ v0.0.0-20190605051324-730aa37373e1 // indirect
go.ofmax.li/environ v0.1.0
go.ofmax.li/tmpl v0.1.0
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/tools v0.0.0-20201031021630-582c62ec74d0 // indirect
google.golang.org/api v0.21.0
+ gopkg.in/yaml.v2 v2.2.2 // indirect
)
diff --git a/go.sum b/go.sum
index f4693d1..89d2933 100644
--- a/go.sum
+++ b/go.sum
@@ -4,28 +4,55 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/alexedwards/scs v1.4.1 h1:/5L5a07IlqApODcEfZyMsu8Smd1S7Q4nBjEyKxIRTp0=
github.com/alexedwards/scs/v2 v2.3.0 h1:V8rtn2P5QGh8C9S7T/ikBo/AdA27vDoQJPbiAaOCmFg=
github.com/alexedwards/scs/v2 v2.3.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
github.com/alexedwards/scs/v2 v2.4.0 h1:XfnMamKnvp1muJVNr1WzikQTclopsBXWZtzz0NBjOK0=
github.com/alexedwards/scs/v2 v2.4.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
+github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0=
+github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA=
+github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
+github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
+github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
+github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/brianvoe/gofakeit v1.2.0 h1:GGbzCqQx9ync4ObAUhRa3F/M73eL9VZL3X09WoTwphM=
github.com/brianvoe/gofakeit v3.18.0+incompatible h1:wDOmHc9DLG4nRjUVVaxA+CEglKOW72Y5+4WNxUIkjM8=
github.com/brianvoe/gofakeit v3.18.0+incompatible/go.mod h1:kfwdRA90vvNhPutZWfH7WPaDzUjz+CZFqG+rPkOjGOc=
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
+github.com/casbin/casbin v1.9.1 h1:ucjbS5zTrmSLtH4XogqOG920Poe6QatdXtz1FEbApeM=
+github.com/casbin/casbin v1.9.1/go.mod h1:z8uPsfBJGUsnkagrt3G8QvjgTKFMBJ32UP8HpZllfog=
+github.com/casbin/casbin/v2 v2.19.8 h1:hmlbARamCCE9hmcE7N/NRQqzti6Wu8CdF+QwpXzhFQU=
+github.com/casbin/casbin/v2 v2.19.8/go.mod h1:wUgota0cQbTXE6Vd+KWpg41726jFRi7upxio0sR+Xd0=
+github.com/casbin/chi-authz v0.0.0-20170726155602-f9f57e3793f2 h1:lWi4Rzt/ERv26z3UTaf7DEKlGmkYJRYqMHK35k5I80g=
+github.com/casbin/chi-authz v0.0.0-20170726155602-f9f57e3793f2/go.mod h1:i93bCyqcO3IKbKqjg/FqtocZt5LOM75rpX/Gj7v8kvo=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cosiner/argv v0.1.0 h1:BVDiEL32lwHukgJKP87btEPenzrrHUjajs/8yzaqcXg=
+github.com/cosiner/argv v0.1.0/go.mod h1:EusR6TucWKX+zFgtdUsKT2Cvg45K5rtpCcWz4hK06d8=
+github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
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/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gbrlsnchs/jwt v1.1.0 h1:Gh2CoXcIfk8/LxV8ks0GDOmUDCpVIrw8Oa34Ozmw/10=
github.com/gbrlsnchs/jwt/v3 v3.0.0-rc.2 h1:3t7jvTkeQfk1FdP0noXSNiM6AdBokLz7QmZDmnCHAAA=
github.com/gbrlsnchs/jwt/v3 v3.0.0-rc.2/go.mod h1:AncDcjXz18xetI3A6STfXq2w+LuTx8pQ8bGEwRN8zVM=
github.com/go-chi/chi v1.0.0 h1:s/kv1cTXfivYjdKJdyUzNGyAWZ/2t7duW1gKn5ivu+c=
github.com/go-chi/chi v4.1.0+incompatible h1:ETj3cggsVIY2Xao5ExCu6YhEh5MD6JTfcBzS37R260w=
github.com/go-chi/chi v4.1.0+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
+github.com/go-delve/delve v1.5.0 h1:gQsRvFdR0BGk19NROQZsAv6iG4w5QIZoJlxJeEUBb0c=
+github.com/go-delve/delve v1.5.0/go.mod h1:c6b3a1Gry6x8a4LGCe/CWzrocrfaHvkUxCj3k4bvSUQ=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@@ -34,6 +61,7 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
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/gomodule/redigo v1.7.0 h1:ZKld1VOtsGhAe37E7wMxEDgAlGM5dvFY+DiOhSkhP9Y=
@@ -44,21 +72,51 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-dap v0.2.0 h1:whjIGQRumwbR40qRU7CEKuFLmePUUc2s4Nt9DoXXxWk=
+github.com/google/go-dap v0.2.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/uuid v1.1.1/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 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magefile/mage v1.9.0 h1:t3AU2wNwehMCW97vuqQLtw6puppWXHO+O2MHo5a50XE=
github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/matoous/go-nanoid v1.3.0 h1:ynznZVSo9t0E8BTYLZx9geceRYZr8yLIrkOv3C/CU8M=
github.com/matoous/go-nanoid v1.3.0/go.mod h1:fvGBnhcQ+zcrB3qJIG32PAN11J/y1IYkGX2/VeHzuH0=
+github.com/mattn/go-colorable v0.0.0-20170327083344-ded68f7a9561 h1:isR/L+BIZ+rqODWYR/f526ygrBMGKZYFhaaFRDGvuZ8=
+github.com/mattn/go-colorable v0.0.0-20170327083344-ded68f7a9561/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+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-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/muyo/sno v1.1.0 h1:WLsHreJnNFtc29Z2grb9Y9A6nXLrDJS0KqpWZzTYGLg=
github.com/muyo/sno v1.1.0/go.mod h1:Hjr5WzLleYD7bJYvQGo5UK7hpE2kSvMbihc0bMWF2bU=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b h1:8uaXtUkxiy+T/zdLWuxa/PG4so0TPZDZfafFNNSaptE=
+github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -66,13 +124,36 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rafaeljusto/redigomock v2.3.0+incompatible h1:mW+5Fc1qpEgyPBIsT1ZdYAqoC/hRgq9bxUGiToBMr6A=
github.com/rafaeljusto/redigomock v2.3.0+incompatible/go.mod h1:JaY6n2sDr+z2WTsXkOmNRUfDy6FN0L6Nk7x06ndm4tY=
+github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
+github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
+github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
github.com/speps/go-hashids v1.0.0 h1:jdFC07PrExRM4Og5Ev4411Tox75aFpkC77NlmutadNI=
github.com/speps/go-hashids v2.0.0+incompatible h1:kSfxGfESueJKTx0mpER9Y/1XHl+FVQjtCqRyYcviFbw=
github.com/speps/go-hashids v2.0.0+incompatible/go.mod h1:P7hqPzMdnZOfyIk+xrlG1QaSMw+gCBdHKsBDnhpaZvc=
+github.com/spf13/cobra v0.0.0-20170417170307-b6cb39589372 h1:eRfW1vRS4th8IX2iQeyqQ8cOUNOySvAYJ0IUvTXGoYA=
+github.com/spf13/cobra v0.0.0-20170417170307-b6cb39589372/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/pflag v0.0.0-20170417173400-9e4c21054fa1 h1:7bozMfSdo41n2NOc0GsVTTVUiA+Ncaj6pXNpm4UHKys=
+github.com/spf13/pflag v0.0.0-20170417173400-9e4c21054fa1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/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.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/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
+github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk=
+github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc=
+github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=
+github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=
+github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
gitlab.com/grumps/environ v0.0.0-20190605051324-730aa37373e1 h1:Jjns+kL26DLZhyrxqBZHJn1ymX33jtfnmv2xufSXOaA=
gitlab.com/grumps/environ v0.0.0-20190605051324-730aa37373e1/go.mod h1:GPGILReyQ0kLhYL5BcbmvTUGCmHC+upQgUZBQMqvcDY=
@@ -82,7 +163,12 @@ go.ofmax.li/tmpl v0.1.0 h1:itGhtIes5ba/s/0x0i9x+e/6my6MDTkd9KUhwRr/cVc=
go.ofmax.li/tmpl v0.1.0/go.mod h1:gzv8lp+KPxqP6f7FqoBdGl8UwXANmuLOXxyOaKNUaQg=
go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.starlark.net v0.0.0-20190702223751-32f345186213 h1:lkYv5AKwvvduv5XWP6szk/bvvgO6aDeUujhZQXIFTes=
+go.starlark.net v0.0.0-20190702223751-32f345186213/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg=
+golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4 h1:QlVATYS7JBoZMVaf+cNjb90WD/beKVHnIxFKT4QaHVI=
+golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -98,6 +184,7 @@ golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -119,10 +206,14 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-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-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
@@ -143,6 +234,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e h1:1xWUkZQQ9Z9UuZgNaIR6OQOE7rUFglXUUBZlO+dGg6I=
golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201031021630-582c62ec74d0 h1:obBdJPIfkOi5/rVh102giHaq0G8BZGE4eGB+NU6SgBo=
golang.org/x/tools v0.0.0-20201031021630-582c62ec74d0/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -169,8 +261,16 @@ google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
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/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
+gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/internal/acct/acct.go b/internal/acct/acct.go
new file mode 100644
index 0000000..48a71e6
--- /dev/null
+++ b/internal/acct/acct.go
@@ -0,0 +1,106 @@
+package acct
+
+import (
+ "context"
+ "net/http"
+
+ "git.ofmax.li/iserv/internal/auth"
+ "git.ofmax.li/iserv/internal/goog"
+ "github.com/alexedwards/scs/v2"
+ "golang.org/x/oauth2"
+)
+
+// handler
+
+// Handler interface to http handler
+type Handler interface {
+ Register(w http.ResponseWriter, r *http.Request)
+}
+
+type acctHandler struct {
+ svc Servicer
+ ses *scs.SessionManager
+}
+
+func (h *acctHandler) Register(w http.ResponseWriter, r *http.Request) {
+ userID := h.ses.GetString(r.Context(), "profid")
+ if userID == "" {
+ http.Redirect(w, r, "/l", http.StatusFound)
+ }
+ h.svc.GetGoogProfile(r.Context(), userID)
+ return
+}
+
+// NewHandler create new instance of handler
+// Servicer, session, and oauth client required
+func NewHandler(service Servicer, session *scs.SessionManager) Handler {
+ return &acctHandler{
+ service,
+ session,
+ }
+}
+
+// endhandler
+
+// model
+
+// Profile application account profile
+type Profile interface {
+ ProfileKeyValues() (string, []string)
+}
+
+// endmodel
+
+// repo
+// Repo storage interface
+
+type Repo interface {
+ UpdateAcctProfile(p Profile) error
+}
+
+// endrepo
+
+// service
+
+type Servicer interface {
+ UpdateProfile(p *Profile) error
+ GetGoogProfile(ctx context.Context, id string) error
+}
+
+func NewService(repo Repo, authRepo auth.Repo, goog goog.Servicer) *service {
+ return &service{
+ repo,
+ authRepo,
+ goog,
+ }
+}
+
+type service struct {
+ repo Repo
+ authRepo auth.Repo
+ goog goog.Servicer
+}
+
+func (s *service) UpdateProfile(p *Profile) error {
+ return nil
+}
+
+func (s *service) GetGoogProfile(ctx context.Context, id string) error {
+ token, err := s.authRepo.GetProfileToken(id)
+ if err != nil {
+ return err
+ }
+ client := s.goog.UserClient(ctx, token)
+ gp, _, err := s.goog.Profile(client)
+ if err != nil {
+ return err
+ }
+ s.repo.UpdateAcctProfile(gp)
+ return nil
+}
+
+func (s *service) GetProfileToken(id string) (*oauth2.Token, error) {
+ return s.authRepo.GetProfileToken(id)
+}
+
+// endservice
diff --git a/internal/auth/handler.go b/internal/auth/handler.go
index 992608c..d57d47e 100644
--- a/internal/auth/handler.go
+++ b/internal/auth/handler.go
@@ -3,15 +3,12 @@ package auth
import (
"encoding/json"
"io/ioutil"
- "log"
"net/http"
"github.com/alexedwards/scs/v2"
"golang.org/x/oauth2"
-)
-var (
- profileURL = "https://www.googleapis.com/oauth2/v3/userinfo"
+ "git.ofmax.li/iserv/internal/goog"
)
// Handler authentication handler
@@ -22,30 +19,28 @@ type Handler interface {
}
type authHandler struct {
- service Servicer
- ses *scs.SessionManager
- oclient *oauth2.Config
+ svc Servicer
+ ses *scs.SessionManager
}
+// TODO migrate to Goog
// NewHandler create new instance of handler
// Servicer, session, and oauth client required
func NewHandler(service Servicer,
- session *scs.SessionManager,
- oclient *oauth2.Config) Handler {
+ session *scs.SessionManager) Handler {
return &authHandler{
service,
session,
- oclient,
}
}
func (h *authHandler) Login(w http.ResponseWriter, r *http.Request) {
- stateValue, err := h.service.GenerateStateToken()
+ stateValue, err := h.svc.GenerateStateToken()
if err != nil {
return
}
h.ses.Put(r.Context(), "state", stateValue)
- url := h.oclient.AuthCodeURL(stateValue, oauth2.AccessTypeOnline)
+ url := h.svc.Goog().Config().AuthCodeURL(stateValue, oauth2.AccessTypeOnline)
http.Redirect(w, r, url, 302)
}
@@ -58,7 +53,7 @@ func (h *authHandler) OauthCallback(w http.ResponseWriter, r *http.Request) {
http.Error(w, "state value miss match bad data", 400)
return
}
- stateValid, err := h.service.ValidateStateToken(stateFromCallback, stateFromSession)
+ stateValid, err := h.svc.ValidateStateToken(stateFromCallback, stateFromSession)
if err != nil {
http.Error(w, "error validating", 400)
return
@@ -69,15 +64,14 @@ func (h *authHandler) OauthCallback(w http.ResponseWriter, r *http.Request) {
}
// valid and same as state
code := r.FormValue("code")
- token, err := h.oclient.Exchange(r.Context(), code)
+ token, err := h.svc.Goog().Config().Exchange(r.Context(), code)
if err != nil {
http.Error(w, err.Error(), 400)
return
}
- log.Printf("returned token %v", token)
// google profile
- client := h.oclient.Client(r.Context(), token)
- resp, err := client.Get(profileURL)
+ client := h.svc.Goog().UserClient(r.Context(), token)
+ resp, err := client.Get(goog.ProfileURL)
if err != nil {
http.Error(w, err.Error(), 400)
return
@@ -88,9 +82,9 @@ func (h *authHandler) OauthCallback(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), 400)
return
}
- gp := &GoogleAuthProfile{}
+ gp := &goog.GoogleProfile{}
err = json.Unmarshal(data, &gp)
- profileID, newProfile, err := h.service.LoginOrRegisterSessionID(token, gp)
+ profileID, newProfile, err := h.svc.LoginOrRegisterSessionID(token, gp)
if err != nil {
http.Error(w, err.Error(), 400)
return
@@ -98,8 +92,9 @@ func (h *authHandler) OauthCallback(w http.ResponseWriter, r *http.Request) {
h.ses.Put(r.Context(), "profid", profileID)
// send to registration
if newProfile == true {
- http.Redirect(w, r, "/account/register", 302)
+ http.Redirect(w, r, "/u/register", 302)
return
}
http.Redirect(w, r, "/", 302)
+ return
}
diff --git a/internal/auth/middleware.go b/internal/auth/middleware.go
new file mode 100644
index 0000000..0be033c
--- /dev/null
+++ b/internal/auth/middleware.go
@@ -0,0 +1,45 @@
+package auth
+
+import (
+ "net/http"
+
+ "github.com/alexedwards/scs/v2"
+ "github.com/apex/log"
+)
+
+const (
+ loginURL = "/login"
+)
+
+func AuthOnly(s Servicer, ses *scs.SessionManager) func(next http.Handler) http.Handler {
+ return func(next http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ userID := ses.GetString(r.Context(), "profid")
+ if userID == "" {
+ userID = "anon"
+ }
+ resource := r.URL.Path
+ // set the action to something that will never match
+ action := "forbidden"
+ switch r.Method {
+ case "POST", "PUT", "PATCH":
+ action = "write"
+ case "HEAD", "GET":
+ action = "read"
+ }
+ // TODO determine action
+ enforced, err := s.Enf().EnforceSafe(userID, resource, action)
+ if err != nil {
+ log.Errorf("%s", err)
+ return
+ }
+ if !enforced {
+ // TODO probably need to do something about suggesting to login
+ http.Error(w, "not found, are you signed in?", http.StatusNotFound)
+ return
+ }
+ next.ServeHTTP(w, r)
+ }
+ return http.HandlerFunc(fn)
+ }
+}
diff --git a/internal/auth/model.go b/internal/auth/model.go
index c51ff05..240b11b 100644
--- a/internal/auth/model.go
+++ b/internal/auth/model.go
@@ -6,20 +6,10 @@ import (
"golang.org/x/oauth2"
)
-// GoogleAuthProfile auth'd user profile
-// ProfileId, Email, Name, PictureURL
-type GoogleAuthProfile struct {
- ProfileID string `json:"sub"`
- Email string `json:"email"`
- Name string `json:"name"`
- PictureURL string `json:"picture"`
-}
-
// Profile profile and token
// Identifier + Token
type Profile struct {
ID string `json:"sub"`
- Email string `json:"email"`
AccessToken string `json:"access_token"`
TokenType string `json:"token_type,omitempty"`
RefreshToken string `json:"refresh_token,omitempty"`
@@ -37,10 +27,9 @@ func (ap *Profile) Token() (*oauth2.Token, error) {
}
// NewAuthProfile merge token and profile
-func NewAuthProfile(t *oauth2.Token, u *GoogleAuthProfile) *Profile {
+func NewAuthProfile(t *oauth2.Token, id string) *Profile {
return &Profile{
- u.ProfileID,
- u.Email,
+ id,
t.AccessToken,
t.TokenType,
t.RefreshToken,
diff --git a/internal/auth/repo.go b/internal/auth/repo.go
index f404c94..9a0420e 100644
--- a/internal/auth/repo.go
+++ b/internal/auth/repo.go
@@ -1,8 +1,15 @@
package auth
+import (
+ "git.ofmax.li/iserv/internal/goog"
+ "golang.org/x/oauth2"
+)
+
// Repo storage interface
type Repo interface {
- IsAuthorized(gp *GoogleAuthProfile) (bool, error)
- LookUpAuthProfileID(gp *GoogleAuthProfile) (string, error)
- SaveAuthProfile(ap *Profile) error
+ IsAuthorized(gp *goog.GoogleProfile) (bool, error)
+ LookUpAuthProfileID(gp *goog.GoogleProfile) (string, error)
+ SaveAuthProfile(email string, ap *Profile) error
+ CheckProfileID(id string) (bool, error)
+ GetProfileToken(id string) (*oauth2.Token, error)
}
diff --git a/internal/auth/service.go b/internal/auth/service.go
index 9997264..e85c705 100644
--- a/internal/auth/service.go
+++ b/internal/auth/service.go
@@ -2,11 +2,14 @@ package auth
import (
"errors"
+ "fmt"
"log"
"time"
+ "git.ofmax.li/iserv/internal/goog"
"golang.org/x/oauth2"
+ "github.com/casbin/casbin"
"github.com/gbrlsnchs/jwt/v3"
)
@@ -22,23 +25,40 @@ var (
// Servicer access to auth functionality
type Servicer interface {
- LoginOrRegisterSessionID(t *oauth2.Token, gp *GoogleAuthProfile) (string, bool, error)
+ Goog() goog.Servicer
+ LoginOrRegisterSessionID(t *oauth2.Token, gp *goog.GoogleProfile) (string, bool, error)
GenerateStateToken() (string, error)
ValidateStateToken(token string, sessionToken string) (bool, error)
+ CheckProfileID(id string) (bool, error)
+ Enf() *casbin.Enforcer
}
// Service a container for auth deps
type Service struct {
repo Repo
+ goog goog.Servicer
+ enf *casbin.Enforcer
}
// NewService create auth service
-func NewService(repo Repo) *Service {
+func NewService(repo Repo, goog goog.Servicer, enf *casbin.Enforcer) *Service {
return &Service{
repo,
+ goog,
+ enf,
}
}
+// Goog get google interface
+func (a *Service) Goog() goog.Servicer {
+ return a.goog
+}
+
+// Enf enforcer instance
+func (a *Service) Enf() *casbin.Enforcer {
+ return a.enf
+}
+
// GenerateStateToken create a random token for oauth exchange
func (a *Service) GenerateStateToken() (string, error) {
now := time.Now()
@@ -67,8 +87,13 @@ func (a *Service) ValidateStateToken(token string, sessionToken string) (bool, e
return false, ErrInvalidToken
}
+// CheckProfileID check if a profileid exists
+func (a *Service) CheckProfileID(id string) (bool, error) {
+ return a.repo.CheckProfileID(id)
+}
+
// LoginOrRegisterSessionID create a login
-func (a *Service) LoginOrRegisterSessionID(t *oauth2.Token, gp *GoogleAuthProfile) (string, bool, error) {
+func (a *Service) LoginOrRegisterSessionID(t *oauth2.Token, gp *goog.GoogleProfile) (string, bool, error) {
isAuthorized, err := a.repo.IsAuthorized(gp)
newRegistration := false
if err != nil {
@@ -84,10 +109,9 @@ func (a *Service) LoginOrRegisterSessionID(t *oauth2.Token, gp *GoogleAuthProfil
if profileID == "" {
// create profile
log.Printf("creating new profile")
- profile := NewAuthProfile(t, gp)
+ profile := NewAuthProfile(t, fmt.Sprintf("goog:%s", gp.ProfileID))
profileID = profile.ID
- log.Printf("new profile %+v", profile)
- err = a.repo.SaveAuthProfile(profile)
+ err = a.repo.SaveAuthProfile(gp.Email, profile)
if err != nil {
return "", newRegistration, err
}
diff --git a/internal/auth/service_test.go b/internal/auth/service_test.go
index 72ff709..b992696 100644
--- a/internal/auth/service_test.go
+++ b/internal/auth/service_test.go
@@ -11,6 +11,7 @@ import (
"github.com/golang/mock/gomock"
"git.ofmax.li/iserv/internal/auth"
+ "git.ofmax.li/iserv/internal/goog"
"git.ofmax.li/iserv/internal/mock/mock_auth"
)
@@ -77,7 +78,7 @@ func (s *serviceSuite) testValidateStateToken() func(t *testing.T) {
func (s *serviceSuite) testLoginOrRegsiterSessionId() func(t *testing.T) {
return func(t *testing.T) {
// is authorized err
- gp := &auth.GoogleAuthProfile{}
+ gp := &goog.GoogleProfile{}
token := &oauth2.Token{}
gofakeit.Struct(token)
gofakeit.Struct(gp)
diff --git a/internal/db/redis/acct.go b/internal/db/redis/acct.go
new file mode 100644
index 0000000..72df741
--- /dev/null
+++ b/internal/db/redis/acct.go
@@ -0,0 +1,44 @@
+package redis
+
+import (
+ "fmt"
+
+ "github.com/gomodule/redigo/redis"
+ "github.com/pkg/errors"
+
+ "git.ofmax.li/iserv/internal/acct"
+)
+
+// AcctRepo account
+type AcctRepo struct {
+ db *redis.Pool
+}
+
+var (
+ acctProfileKey string = "acct:email:%s"
+)
+
+// NewAcctRepo account repo
+func NewAcctRepo(conn *redis.Pool) *AcctRepo {
+ return &AcctRepo{
+ conn,
+ }
+}
+
+// UpdateAcctProfile write profile to redis
+func (db *AcctRepo) UpdateAcctProfile(p acct.Profile) error {
+ conn := db.db.Get()
+ defer conn.Close()
+ profileID, profileKeyValues := p.ProfileKeyValues()
+ acctProfileKey := fmt.Sprintf(acctProfileKey, profileID)
+ profileArgs := redis.Args{}.Add(acctProfileKey).AddFlat(profileKeyValues)
+ res, err := redis.String(conn.Do("HMSET", profileArgs...))
+ if err != nil {
+ fmt.Print(err)
+ return err
+ }
+ if res != "OK" {
+ return errors.Errorf("%s acct was not saved", acctProfileKey)
+ }
+ return nil
+}
diff --git a/internal/db/redis/auth.go b/internal/db/redis/auth.go
index 0c5246c..1f99fac 100644
--- a/internal/db/redis/auth.go
+++ b/internal/db/redis/auth.go
@@ -1,12 +1,14 @@
package redis
import (
+ "fmt"
"log"
"github.com/gomodule/redigo/redis"
"golang.org/x/oauth2"
"git.ofmax.li/iserv/internal/auth"
+ "git.ofmax.li/iserv/internal/goog"
)
var (
@@ -16,6 +18,14 @@ var (
end
return nil
`)
+ checkActiveAuthLua = redis.NewScript(1, `
+ local email = redis.call("HMGET",KEYS[1],"email")
+ if email == nil then
+ return false
+ end
+ return redis.call("SISMEMBER",email)
+ `)
+ authProfileKey = func(id string) string { return fmt.Sprintf("auth:%s") }
)
// AuthRepo supporting auth
@@ -32,11 +42,11 @@ func NewRedisAuthRepo(conn *redis.Pool) *AuthRepo {
}
// IsAuthorized is member of invites
-func (db *AuthRepo) IsAuthorized(gp *auth.GoogleAuthProfile) (bool, error) {
+func (db *AuthRepo) IsAuthorized(gp *goog.GoogleProfile) (bool, error) {
conn := db.db.Get()
defer conn.Close()
- authProfileKey := "auth:goog:" + gp.Email
- reply, err := redis.Bool(conn.Do("SISMEMBER", "invites", authProfileKey))
+ inviteKey := "goog:" + gp.Email
+ reply, err := redis.Bool(conn.Do("SISMEMBER", "invites", inviteKey))
if err != nil {
return reply, err
}
@@ -44,16 +54,12 @@ func (db *AuthRepo) IsAuthorized(gp *auth.GoogleAuthProfile) (bool, error) {
}
// LookUpAuthProfileID get internal profileid
-func (db *AuthRepo) LookUpAuthProfileID(gp *auth.GoogleAuthProfile) (string, error) {
+func (db *AuthRepo) LookUpAuthProfileID(gp *goog.GoogleProfile) (string, error) {
conn := db.db.Get()
var id string
defer conn.Close()
- authProfileKey := "auth:goog:" + gp.ProfileID
- reply, err := redis.Values(conn.Do("HMGET", authProfileKey, "id"))
- if err == redis.ErrNil {
- // no profile
- return "", nil
- } else if err != nil {
+ reply, err := redis.Values(conn.Do("HMGET", authProfileKey(gp.ProfileID), "id"))
+ if err != nil {
// some other error
return "", err
}
@@ -64,24 +70,35 @@ func (db *AuthRepo) LookUpAuthProfileID(gp *auth.GoogleAuthProfile) (string, err
}
// SaveAuthProfile save profile, validate against invites
-func (db *AuthRepo) SaveAuthProfile(ap *auth.Profile) error {
+func (db *AuthRepo) SaveAuthProfile(email string, ap *auth.Profile) error {
// TODO this will over-write refresh tokens
conn := db.db.Get()
defer conn.Close()
- authProfileKey := "auth:goog:" + ap.ID
- prof := redis.Args{}.Add(ap.Email).Add(authProfileKey).AddFlat(ap)
- res, err := createAuthLua.Do(conn, prof...)
- log.Printf("auth save response %+v", res)
+ prof := redis.Args{}.Add(email).Add(ap.ID).AddFlat(ap)
+ _, err := createAuthLua.Do(conn, prof...)
conn.Flush()
return err
}
+// CheckProfileID return true if the profile exists and authorized
+func (db *AuthRepo) CheckProfileID(id string) (bool, error) {
+ conn := db.db.Get()
+ defer conn.Close()
+ res, err := redis.Int(checkActiveAuthLua.Do(conn, authProfileKey(id)))
+ if err == redis.ErrNil {
+ return false, nil
+ } else if err != nil {
+ return false, err
+ }
+ // there could be profile created but later revoked authorization
+ return res == 1, nil
+}
+
func (db *AuthRepo) getAuthProfile(id string) (*auth.Profile, error) {
conn := db.db.Get()
defer conn.Close()
- authProfileKey := "auth:goog:" + id
authProfile := auth.Profile{}
- res, err := redis.Values(conn.Do("HGETALL", authProfileKey))
+ res, err := redis.Values(conn.Do("HGETALL", authProfileKey(id)))
if err != nil {
log.Fatal(err)
}
diff --git a/internal/db/redis/image.go b/internal/db/redis/image.go
index f216531..3622728 100644
--- a/internal/db/redis/image.go
+++ b/internal/db/redis/image.go
@@ -48,7 +48,7 @@ func (r *ImageRepo) GetFile(fileUrl string) (*image.PostMeta, error) {
key := fileKey(fileUrl, V1FilePathFmt)
res, err := redis.Values(conn.Do("HGETALL", key))
if err != nil {
- return &image.PostMeta{}, ErrNotFound
+ return &image.PostMeta{}, err
}
err = redis.ScanStruct(res, imageMeta)
if imageMeta.FilePath == "" {
diff --git a/internal/goog/goog.go b/internal/goog/goog.go
new file mode 100644
index 0000000..5102a95
--- /dev/null
+++ b/internal/goog/goog.go
@@ -0,0 +1,89 @@
+package goog
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+
+ "golang.org/x/oauth2"
+)
+
+var (
+ ProfileURL = "https://www.googleapis.com/oauth2/v3/userinfo"
+ ProfileKeyFmt = "goog:%s"
+)
+
+// GoogleProfile auth'd user profile
+// ProfileId, Email, Name, PictureURL
+type GoogleProfile struct {
+ ProfileID string `json:"sub"`
+ Email string `json:"email"`
+ Name string `json:"name"`
+ PictureURL string `json:"picture"`
+}
+
+// ProfileKeys conform to ProfileKeys
+func (gp *GoogleProfile) ProfileKeyValues() (string, []string) {
+ return fmt.Sprintf(ProfileKeyFmt, gp.Email), []string{
+ "profile_id", gp.ProfileID,
+ "email", gp.Email,
+ "name", gp.Name,
+ "picture_url", gp.PictureURL,
+ }
+}
+
+type Servicer interface {
+ Config() *oauth2.Config
+ Profile(client *http.Client) (*GoogleProfile, *oauth2.Token, error)
+ UserClient(ctx context.Context, token *oauth2.Token) *http.Client
+}
+
+// NewService container for interacting with Google
+func NewService(o *oauth2.Config) Servicer {
+ return &Goog{
+ o,
+ }
+
+}
+
+type Goog struct {
+ oauthConfig *oauth2.Config
+}
+
+func (g *Goog) Config() *oauth2.Config {
+ return g.oauthConfig
+}
+
+// UserCient just calls oauth2.Client
+func (g *Goog) UserClient(ctx context.Context, token *oauth2.Token) *http.Client {
+ return g.oauthConfig.Client(ctx, token)
+}
+
+// Profile get profile from google
+func (g *Goog) Profile(client *http.Client) (*GoogleProfile, *oauth2.Token, error) {
+ client.Get(ProfileURL)
+ resp, err := client.Get(ProfileURL)
+ if err != nil {
+ return &GoogleProfile{}, &oauth2.Token{}, err
+ }
+ defer resp.Body.Close()
+ data, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return &GoogleProfile{}, &oauth2.Token{}, err
+ }
+ // Google Profile
+ gp := &GoogleProfile{}
+ err = json.Unmarshal(data, gp)
+ if err != nil {
+ return &GoogleProfile{}, &oauth2.Token{}, err
+ }
+ // Token
+ token := &oauth2.Token{}
+ err = json.Unmarshal(data, token)
+ if err != nil {
+ return &GoogleProfile{}, &oauth2.Token{}, err
+ }
+ return gp, token, nil
+}
diff --git a/internal/image/handler.go b/internal/image/handler.go
index f41ed4d..71a5383 100644
--- a/internal/image/handler.go
+++ b/internal/image/handler.go
@@ -35,9 +35,8 @@ func (h *imageHandler) GetImage(w http.ResponseWriter, r *http.Request) {
fileID := chi.URLParam(r, "fileName")
fileMeta, err := h.service.GetFile(fileID)
if err != nil {
- w.WriteHeader(400)
- log.Printf("error: %+v", err)
- w.Write([]byte("WTF Incorrect Content Type"))
+ http.Error(w, "an error has occured", http.StatusBadRequest)
+ return
}
fileUrl := fmt.Sprintf("/f/%s", fileMeta.FilePath)
data := struct {
diff --git a/internal/image/service.go b/internal/image/service.go
index 10f4148..2a60c67 100644
--- a/internal/image/service.go
+++ b/internal/image/service.go
@@ -78,6 +78,7 @@ func (is *Service) AddFile(extension string, postMeta *PostMeta, fileBytes []byt
func (is *Service) GetFile(fileUrl string) (*PostMeta, error) {
result, err := is.db.GetFile(fileUrl)
if err != nil {
+ return &PostMeta{}, err
}
return result, err
}
diff --git a/policy.csv b/policy.csv
new file mode 100644
index 0000000..1784828
--- /dev/null
+++ b/policy.csv
@@ -0,0 +1,6 @@
+p, goog:113063035911692090595, /i/dixiesdfsf.jpg, write
+p, goog:113063035911692090595, /u/register, read
+p, anon, /l, read|write
+p, anon, /a/g, read|write
+g, goog:113063035911692090595, member
+g2, member , /, read