Skip to content

Commit

Permalink
Add Google login endpoints (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
earthboundkid authored Dec 13, 2024
1 parent b519fdd commit 82b3460
Show file tree
Hide file tree
Showing 7 changed files with 248 additions and 11 deletions.
23 changes: 23 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,41 @@ require (
github.com/carlmjohnson/exitcode v0.20.2
github.com/carlmjohnson/flagx v0.22.2
github.com/carlmjohnson/requests v0.24.2
github.com/dghubble/gologin/v2 v2.5.0
github.com/earthboundkid/mid v0.24.1
github.com/earthboundkid/versioninfo/v2 v2.24.1
github.com/getsentry/sentry-go v0.29.1
github.com/go-chi/chi/v5 v5.1.0
github.com/go-logfmt/logfmt v0.6.0
github.com/gorilla/schema v1.4.1
github.com/mattn/go-sqlite3 v1.14.24
golang.org/x/oauth2 v0.24.0
)

require (
cloud.google.com/go/auth v0.10.1 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.5 // indirect
cloud.google.com/go/compute/metadata v0.5.2 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
github.com/lib/pq v1.10.9 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 // indirect
go.opentelemetry.io/otel v1.32.0 // indirect
go.opentelemetry.io/otel/metric v1.32.0 // indirect
go.opentelemetry.io/otel/trace v1.32.0 // indirect
golang.org/x/crypto v0.29.0 // indirect
golang.org/x/net v0.31.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.20.0 // indirect
google.golang.org/api v0.205.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect
google.golang.org/grpc v1.68.0 // indirect
google.golang.org/protobuf v1.35.1 // indirect
)
145 changes: 143 additions & 2 deletions go.sum

Large diffs are not rendered by default.

18 changes: 11 additions & 7 deletions internal/commentthan/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ func (app *appEnv) ParseArgs(args []string) error {
fl.StringVar(&app.redirectSuccess, "redirect-success", "https://www.spotlightpa.org/contact/thanks/", "")
fl.StringVar(&app.sentryDSN, "sentry-dsn", "", "DSN `pseudo-URL` for Sentry")
fl.BoolVar(&app.isLocalhost, "localhost", true, "")
fl.StringVar(&app.googleClientID, "google-client-id", "", "")
fl.StringVar(&app.googleClientSecret, "google-client-secret", "", "")
fl.Func("level", "log level", func(s string) error {
l, _ := strconv.Atoi(s)
clogger.Level.Set(slog.Level(l))
Expand Down Expand Up @@ -69,12 +71,14 @@ Options:
}

type appEnv struct {
port string
dbname string
sentryDSN string
svc *service
redirectSuccess string
isLocalhost bool
port string
dbname string
sentryDSN string
svc *service
redirectSuccess string
isLocalhost bool
googleClientID string
googleClientSecret string
}

func (app *appEnv) Exec(ctx context.Context) (err error) {
Expand All @@ -85,7 +89,7 @@ func (app *appEnv) Exec(ctx context.Context) (err error) {
}
defer svc.closeService()

handler := svc.router()
handler := app.router(svc)
srv := &http.Server{
Addr: app.port,
Handler: handler,
Expand Down
10 changes: 10 additions & 0 deletions internal/commentthan/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/earthboundkid/mid"
"github.com/earthboundkid/versioninfo/v2"
"golang.org/x/oauth2"
)

func maxBytesMiddleware(n int64) mid.Middleware {
Expand All @@ -32,3 +33,12 @@ func versionMiddleware(next http.Handler) http.Handler {
next.ServeHTTP(w, r)
})
}

func (svc *service) oauthClientMiddleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ctx = context.WithValue(ctx, oauth2.HTTPClient, svc.cl)
r2 := r.WithContext(ctx)
h.ServeHTTP(w, r2)
})
}
34 changes: 33 additions & 1 deletion internal/commentthan/router.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package commentthan

import (
"fmt"
"io/fs"
"net/http"
"time"

"github.com/dghubble/gologin/v2"
gologingoogle "github.com/dghubble/gologin/v2/google"
"github.com/earthboundkid/mid"
sentryhttp "github.com/getsentry/sentry-go/http"
"github.com/spotlightpa/moreofa/internal/clogger"
"github.com/spotlightpa/moreofa/static"
"golang.org/x/oauth2"
oauth2google "golang.org/x/oauth2/google"
)

type router struct {
Expand All @@ -22,7 +27,7 @@ func (rr *router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
rr.h.ServeHTTP(w, r)
}

func (svc *service) router() http.Handler {
func (app *appEnv) router(svc *service) http.Handler {
rr := &router{svc: svc}
srv := http.NewServeMux()
srv.Handle("GET /", rr.notFound())
Expand All @@ -48,6 +53,33 @@ func (svc *service) router() http.Handler {
timeoutMiddleware(10 * time.Second),
versionMiddleware,
}

// Add login handlers
redirectURL := "https://moreofa.spotlightpa.org/google-callback"
if app.isLocalhost {
redirectURL = fmt.Sprintf("http://localhost%s/google-callback", app.port)
}
oauthConf := &oauth2.Config{
ClientID: app.googleClientID,
ClientSecret: app.googleClientSecret,
RedirectURL: redirectURL,
Scopes: []string{"profile", "email"},
Endpoint: oauth2google.Endpoint,
}
cookieConf := gologin.DefaultCookieConfig
if app.isLocalhost {
cookieConf = gologin.DebugOnlyCookieConfig
}

loginRedirect := gologingoogle.LoginHandler(oauthConf, rr.googleCallbackError())
loginRedirect = gologingoogle.StateHandler(cookieConf, loginRedirect)
srv.Handle("GET /login/{$}", loginRedirect)

googleCallback := gologingoogle.CallbackHandler(oauthConf, rr.googleCallback(), rr.googleCallbackError())
googleCallback = gologingoogle.StateHandler(cookieConf, googleCallback)
googleCallback = svc.oauthClientMiddleware(googleCallback)
srv.Handle("GET /google-callback", googleCallback)

rr.h = baseMW.Handler(srv)
return rr
}
24 changes: 24 additions & 0 deletions internal/commentthan/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"net/http"
"strings"

"github.com/dghubble/gologin/v2"
gologingoogle "github.com/dghubble/gologin/v2/google"
"github.com/earthboundkid/mid"
"github.com/gorilla/schema"
"github.com/spotlightpa/moreofa/internal/clogger"
Expand Down Expand Up @@ -86,3 +88,25 @@ func (rr *router) postComment() mid.Controller {
return nil
}
}

func (rr *router) googleCallback() mid.Controller {
return func(w http.ResponseWriter, r *http.Request) http.Handler {
ctx := r.Context()
googleUser, err := gologingoogle.UserFromContext(ctx)
if err != nil {
return rr.replyHTMLErr(err)
}

clogger.FromContext(ctx).Info("googleCallback", "user", googleUser)
// TODO save info in session
http.Redirect(w, r, "/", http.StatusSeeOther)
return nil
}
}

func (rr *router) googleCallbackError() mid.Controller {
return func(w http.ResponseWriter, r *http.Request) http.Handler {
err := gologin.ErrorFromContext(r.Context())
return rr.replyHTMLErr(errx.E{S: http.StatusBadRequest, E: err})
}
}
5 changes: 4 additions & 1 deletion internal/commentthan/routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ func testService(t *testing.T) *service {
}

func (svc *service) testRouter() *httptest.Server {
h := svc.router()
app := appEnv{
isLocalhost: true,
}
h := app.router(svc)
srv := httptest.NewServer(h)
srv.Client().CheckRedirect = requests.NoFollow
return srv
Expand Down

0 comments on commit 82b3460

Please sign in to comment.