2022-05-19 19:51:12 +00:00
|
|
|
package httpserver
|
|
|
|
|
|
|
|
import (
|
2022-05-19 20:35:00 +00:00
|
|
|
"context"
|
2022-05-19 19:51:12 +00:00
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"path/filepath"
|
|
|
|
"text/template"
|
|
|
|
|
|
|
|
"git.netflux.io/rob/elon-eats-my-tweets/config"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
|
|
"golang.org/x/oauth2"
|
|
|
|
)
|
|
|
|
|
|
|
|
type handler struct {
|
|
|
|
oauth2Config *oauth2.Config
|
|
|
|
}
|
|
|
|
|
|
|
|
func newHandler(cfg config.Config) *handler {
|
|
|
|
return &handler{
|
|
|
|
&oauth2.Config{
|
|
|
|
ClientID: cfg.Twitter.ClientID,
|
|
|
|
ClientSecret: cfg.Twitter.ClientSecret,
|
|
|
|
RedirectURL: cfg.Twitter.CallbackURL,
|
|
|
|
Scopes: []string{"tweet.read", "tweet.write", "users.read", "offline.access"},
|
|
|
|
Endpoint: oauth2.Endpoint{
|
|
|
|
AuthURL: "https://twitter.com/i/oauth2/authorize",
|
2022-05-19 20:35:00 +00:00
|
|
|
TokenURL: "https://api.twitter.com/2/oauth2/token",
|
2022-05-19 19:51:12 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *handler) getIndex(c echo.Context) error {
|
|
|
|
return c.Render(http.StatusOK, "index", nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *handler) getLogin(c echo.Context) error {
|
|
|
|
url := h.oauth2Config.AuthCodeURL(
|
2022-05-19 20:35:00 +00:00
|
|
|
// TODO: implement state and code_challenge tokens
|
2022-05-19 19:51:12 +00:00
|
|
|
"state",
|
|
|
|
oauth2.SetAuthURLParam("code_challenge", "challenge"),
|
|
|
|
oauth2.SetAuthURLParam("code_challenge_method", "plain"),
|
|
|
|
)
|
|
|
|
return c.Redirect(http.StatusTemporaryRedirect, url)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *handler) getCallback(c echo.Context) error {
|
2022-05-19 20:35:00 +00:00
|
|
|
code := c.QueryParam("code")
|
|
|
|
if code == "" {
|
|
|
|
return echo.NewHTTPError(http.StatusBadRequest, "empty code")
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := h.oauth2Config.Exchange(context.Background(), code, oauth2.SetAuthURLParam("code_verifier", "challenge"))
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("error exchanging code: %v", err)
|
|
|
|
return echo.NewHTTPError(http.StatusInternalServerError, "error exchanging code")
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.String(http.StatusOK, "ok")
|
2022-05-19 19:51:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func Start(cfg config.Config) error {
|
|
|
|
e := echo.New()
|
|
|
|
|
|
|
|
e.Renderer = &Template{
|
|
|
|
templates: template.Must(template.ParseGlob(filepath.Join(cfg.PublicPath, "views/", "*.html"))),
|
|
|
|
}
|
|
|
|
|
|
|
|
h := newHandler(cfg)
|
|
|
|
e.GET("/", h.getIndex)
|
|
|
|
e.GET("/login", h.getLogin)
|
|
|
|
e.GET("/callback", h.getCallback)
|
|
|
|
|
|
|
|
return e.Start(":8000")
|
|
|
|
}
|