diff --git a/indieauth.go b/indieauth.go new file mode 100644 index 0000000..731879a --- /dev/null +++ b/indieauth.go @@ -0,0 +1,109 @@ +package main + +import ( + "fmt" + "log" + "net/http" + "net/url" + "p83.nl/go/indieauth" +) + +const ClientID = "https://p83.nl/track-me" + +type IndieAuthHandler struct { +} + +func performIndieauthCallback(state, code string, sess *Session) (bool, *indieauth.AuthResponse, error) { + if state != sess.State { + return false, &indieauth.AuthResponse{}, fmt.Errorf("mismatched state %q != %q", state, sess.State) + } + return indieauth.VerifyAuthCode(ClientID, code, sess.RedirectURI, sess.AuthorizationEndpoint) +} + +func (h *IndieAuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + log.Println(r.URL.Path) + + sess, err := NewSession(w, r) + if err != nil { + http.Error(w, err.Error(), 500) + return + } + defer sess.Flush() + + if r.Method == http.MethodGet { + if r.URL.Path == "" { + fmt.Fprint(w, ` + + +
+
+
+ +
+
+
+ +`) + return + } else if r.URL.Path == "callback" { + state := r.URL.Query().Get("state") + code := r.URL.Query().Get("code") + verified, authResponse, err := performIndieauthCallback(state, code, sess) + if err != nil { + fmt.Fprintf(w, "ERROR: %q\n", err) + return + } + if verified { + sess.Me = authResponse.Me + sess.LoggedIn = true + + log.Printf("SESSION: %#v\n", sess) + if sess.NextURI != "" { + http.Redirect(w, r, sess.NextURI, 302) + } else { + http.Redirect(w, r, "/", 302) + } + return + } + return + } + } else if r.Method == http.MethodPost { + r.ParseForm() + if r.URL.Path == "login" { + // redirect to endpoint + me := r.Form.Get("url") + meURL, err := url.Parse(me) + if err != nil { + http.Error(w, fmt.Sprintf("Bad Request: %s, %s", err.Error(), me), 400) + return + } + endpoints, err := indieauth.GetEndpoints(meURL) + if err != nil { + http.Error(w, fmt.Sprintf("Bad Request: while getting endpoints for %s: %s", me, err.Error()), 400) + return + } + log.Println(endpoints) + + authURL, err := url.Parse(endpoints.AuthorizationEndpoint) + if err != nil { + http.Error(w, fmt.Sprintf("Bad Request: %s %s", err.Error(), me), 400) + return + } + log.Println(authURL) + + state := RandStringBytes(16) + redirectURI := fmt.Sprintf("%s/auth/callback", "http://localhost:8096") + + sess.AuthorizationEndpoint = endpoints.AuthorizationEndpoint + sess.Me = meURL.String() + sess.State = state + sess.RedirectURI = redirectURI + sess.LoggedIn = false + + authenticationURL := indieauth.CreateAuthenticationURL(*authURL, meURL.String(), ClientID, redirectURI, state) + + http.Redirect(w, r, authenticationURL, 302) + return + } + } +} diff --git a/main.go b/main.go index 7ef7bcd..5ce5241 100644 --- a/main.go +++ b/main.go @@ -133,6 +133,9 @@ func main() { } defer db.Close() + indieAuthHandler := &IndieAuthHandler{} + http.Handle("/auth/", http.StripPrefix("/auth/", indieAuthHandler)) + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { sess, err := NewSession(w, r) if err != nil { @@ -213,6 +216,7 @@ func main() { return } }) + log.Fatal(http.ListenAndServe(":8096", nil)) } diff --git a/session.go b/session.go index ce1a0c4..814f0e7 100644 --- a/session.go +++ b/session.go @@ -3,13 +3,20 @@ package main import ( "encoding/json" "fmt" + "log" "net/http" "os" "time" ) type Session struct { - ID string + ID string + LoggedIn bool + Me string + AuthorizationEndpoint string + RedirectURI string + State string + NextURI string } func NewSession(w http.ResponseWriter, r *http.Request) (*Session, error) { @@ -22,6 +29,7 @@ func NewSession(w http.ResponseWriter, r *http.Request) (*Session, error) { if err != nil { return nil, err } + log.Printf("%+v", session) return session, nil }