diff --git a/.env b/.env deleted file mode 100644 index e69de29..0000000 diff --git a/go.mod b/go.mod index 0ca5994..9165e95 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,8 @@ module github.com/martingallauner/bookclub go 1.22.0 require ( + cloud.google.com/go/compute v1.21.0 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect @@ -22,6 +24,9 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect + github.com/gorilla/sessions v1.2.2 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect github.com/jackc/pgx/v5 v5.5.5 // indirect @@ -57,7 +62,7 @@ require ( golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea // indirect golang.org/x/mod v0.16.0 // indirect - golang.org/x/oauth2 v0.17.0 // indirect + golang.org/x/oauth2 v0.19.0 // indirect golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/go.sum b/go.sum index a3242d6..f6c0947 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,7 @@ +cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk= +cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= @@ -48,9 +52,16 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= +github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= 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/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= @@ -161,6 +172,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= +golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/handler_auth.go b/handler_auth.go new file mode 100644 index 0000000..136d35b --- /dev/null +++ b/handler_auth.go @@ -0,0 +1,70 @@ +package main + +import ( + "context" + "fmt" + "github.com/markbates/goth/gothic" + "html/template" + "net/http" +) + +func (cfg *BookclubServer) handlerCallback(w http.ResponseWriter, r *http.Request) { + r = r.WithContext(context.WithValue(context.Background(), "provider", "google")) //todo I don't understand that tbh + + user, err := gothic.CompleteUserAuth(w, r) + if err != nil { + fmt.Fprintln(w, err) + return + } + fmt.Println(user) //todo delete + t, _ := template.New("foo").Parse(userTemplate) + t.Execute(w, user) +} + +func (cfg *BookclubServer) handlerLogout(w http.ResponseWriter, r *http.Request) { + gothic.Logout(w, r) + w.Header().Set("Location", "/") + w.WriteHeader(http.StatusTemporaryRedirect) +} + +func (cfg *BookclubServer) handlerLogin(w http.ResponseWriter, r *http.Request) { + r = r.WithContext(context.WithValue(context.Background(), "provider", "google")) //todo I don't understand that tbh + // try to get the user without re-authenticating + if gothUser, err := gothic.CompleteUserAuth(w, r); err == nil { + t, _ := template.New("foo").Parse(userTemplate) + t.Execute(w, gothUser) + } else { + gothic.BeginAuthHandler(w, r) + } +} + +func (cfg *BookclubServer) handlerProviders(w http.ResponseWriter, r *http.Request) { + + //providerIndex := &ProviderIndex{Providers: keys, ProvidersMap: m} + + t, _ := template.New("foo").Parse(indexTemplate) + t.Execute(w, ProviderIndex{}) +} + +type ProviderIndex struct { + Providers []string + ProvidersMap map[string]string +} + +var indexTemplate = `{{range $key,$value:=.Providers}} +

Log in with {{index $.ProvidersMap $value}}

+{{end}}` + +var userTemplate = ` +

logout

+

Name: {{.Name}} [{{.LastName}}, {{.FirstName}}]

+

Email: {{.Email}}

+

NickName: {{.NickName}}

+

Location: {{.Location}}

+

AvatarURL: {{.AvatarURL}}

+

Description: {{.Description}}

+

UserID: {{.UserID}}

+

AccessToken: {{.AccessToken}}

+

ExpiresAt: {{.ExpiresAt}}

+

RefreshToken: {{.RefreshToken}}

+` diff --git a/internal/auth/auth.go b/internal/auth/auth.go new file mode 100644 index 0000000..dffbb0f --- /dev/null +++ b/internal/auth/auth.go @@ -0,0 +1,37 @@ +package auth + +import ( + "github.com/gorilla/sessions" + "github.com/joho/godotenv" + "github.com/markbates/goth" + "github.com/markbates/goth/gothic" + "github.com/markbates/goth/providers/google" + "log" + "os" +) + +const ( + key = "jaywalker2-grab-scoop" + MaxAge = 86400 * 30 + IsProd = false +) + +func NewAuth() { + err := godotenv.Load() + if err != nil { + log.Fatal("Error loading .env file") + } + + googleClientId := os.Getenv("GOOGLE_CLIENT_ID") + googleClientSecret := os.Getenv("GOOGLE_CLIENT_SECRET") + + store := sessions.NewCookieStore([]byte(key)) + store.MaxAge(MaxAge) + + store.Options.Path = "/" + store.Options.HttpOnly = true + store.Options.Secure = IsProd + + gothic.Store = store + goth.UseProviders(google.New(googleClientId, googleClientSecret, "http://localhost:8080/auth/google/callback")) +} diff --git a/main.go b/main.go index e135542..eae2ce3 100644 --- a/main.go +++ b/main.go @@ -1,11 +1,15 @@ package main import ( + "github.com/martingallauner/bookclub/internal/auth" "log" "time" ) func main() { + + auth.NewAuth() + db, err := SetupDatabase("host=localhost user=postgres password=password dbname=postgres port=5432 sslmode=disable TimeZone=Europe/Vienna") if err != nil { log.Fatal(err) diff --git a/server.go b/server.go index d94cd0a..087f457 100644 --- a/server.go +++ b/server.go @@ -58,6 +58,10 @@ func NewBookclubServer(client Client, repository BookRepository, userRepository router.Handle("/api/users", http.HandlerFunc(s.handlerCreateUser)) router.Handle("/api/links/{id}", http.HandlerFunc(s.handlerGetLinks)) router.Handle("/api/links", http.HandlerFunc(s.handlerCreateLink)) + router.Handle("/auth/{provider}/callback", http.HandlerFunc(s.handlerCallback)) + router.Handle("/auth/{provider}/logout", http.HandlerFunc(s.handlerLogout)) + router.Handle("/auth/{provider}", http.HandlerFunc(s.handlerLogin)) + router.Handle("/auth", http.HandlerFunc(s.handlerProviders)) s.Handler = router return s