audon/oauth.go

166 wiersze
4.4 KiB
Go
Czysty Zwykły widok Historia

2022-12-03 03:20:49 +00:00
package main
import (
2022-12-04 05:19:41 +00:00
"crypto/rand"
2022-12-03 03:20:49 +00:00
"net/http"
"net/url"
"time"
"github.com/gorilla/sessions"
"github.com/labstack/echo/v4"
mastodon "github.com/mattn/go-mastodon"
2022-12-04 05:19:41 +00:00
"github.com/oklog/ulid/v2"
2022-12-03 03:20:49 +00:00
"go.mongodb.org/mongo-driver/mongo"
)
func verifyTokenInSession(c echo.Context, sess *sessions.Session) (valid bool, err error) {
2022-12-04 17:52:44 +00:00
data, err := getSessionData(sess)
2022-12-03 03:20:49 +00:00
if err != nil {
return false, err
}
2022-12-04 17:52:44 +00:00
if data.MastodonConfig.AccessToken == "" {
2022-12-03 03:20:49 +00:00
return false, nil
}
2022-12-04 17:52:44 +00:00
mastoClient := mastodon.NewClient(data.MastodonConfig)
2022-12-03 03:20:49 +00:00
2022-12-04 17:52:44 +00:00
acc, err := mastoClient.GetAccountCurrentUser(c.Request().Context())
user, dbErr := findUserByID(c.Request().Context(), data.AudonID)
2022-12-03 03:20:49 +00:00
2022-12-04 17:52:44 +00:00
if err != nil || dbErr != nil || string(acc.ID) != user.RemoteID {
2022-12-03 03:20:49 +00:00
return false, err
}
return true, nil
}
// handler for POST to /login
func loginHandler(c echo.Context) (err error) {
serverHost := c.FormValue("server")
2022-12-04 05:19:41 +00:00
if err = mainValidator.Var(serverHost, "required,hostname,fqdn"); err != nil {
2022-12-03 03:20:49 +00:00
return wrapValidationError(err)
}
sess, err := getSession(c)
if err != nil {
c.Logger().Error(err)
return ErrSessionNotAvailable
}
valid, _ := verifyTokenInSession(c, sess)
if !valid {
serverURL := &url.URL{
Host: serverHost,
Scheme: "https",
Path: "/",
}
appConfig, err := getAppConfig(serverURL.String())
if err != nil {
return ErrInvalidRequestFormat
}
mastApp, err := mastodon.RegisterApp(c.Request().Context(), appConfig)
if err != nil {
return echo.NewHTTPError(http.StatusNotFound, "server_not_found")
}
userSession := &SessionData{
MastodonConfig: &mastodon.Config{
Server: serverURL.String(),
ClientID: mastApp.ClientID,
ClientSecret: mastApp.ClientSecret,
},
}
if err = writeSessionData(c, userSession); err != nil {
c.Logger().Error(err)
return echo.NewHTTPError(http.StatusInternalServerError)
}
return c.String(http.StatusCreated, mastApp.AuthURI)
}
return c.NoContent(http.StatusNoContent)
}
// handler for GET to /oauth?code=****
func oauthHandler(c echo.Context) (err error) {
authCode := c.QueryParam("code")
if authCode == "" {
if errMsg := c.QueryParam("error"); errMsg == "access_denied" {
return c.Redirect(http.StatusFound, "/login")
}
return echo.NewHTTPError(http.StatusBadRequest, "authentication code needed")
}
sess, err := getSession(c)
if err != nil {
c.Logger().Error(err)
return ErrSessionNotAvailable
}
data, err := getSessionData(sess)
if err != nil {
return ErrInvalidCookie
}
appConf, err := getAppConfig(data.MastodonConfig.Server)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
data.AuthCode = authCode
client := mastodon.NewClient(data.MastodonConfig)
err = client.AuthenticateToken(c.Request().Context(), authCode, appConf.RedirectURIs)
if err != nil {
return echo.NewHTTPError(http.StatusForbidden, err.Error())
}
data.MastodonConfig = client.Config
acc, err := client.GetAccountCurrentUser(c.Request().Context())
if err != nil {
return echo.NewHTTPError(http.StatusForbidden, err.Error())
}
coll := mainDB.Collection(COLLECTION_USER)
if result, dbErr := findUserByRemote(c.Request().Context(), string(acc.ID), acc.URL); dbErr == mongo.ErrNoDocuments {
// Create user if not yet registered
2022-12-04 05:19:41 +00:00
// canonic, err := nanoid.Standard(21) // Should AudonID be sortable?
// if err != nil {
// c.Logger().Error(err)
// return echo.NewHTTPError(http.StatusInternalServerError)
// }
entropy := ulid.Monotonic(rand.Reader, 0)
2022-12-04 17:52:44 +00:00
id, err := ulid.New(ulid.Timestamp(time.Now().UTC()), entropy)
2022-12-03 03:20:49 +00:00
if err != nil {
c.Logger().Error(err)
return echo.NewHTTPError(http.StatusInternalServerError)
}
2022-12-04 05:19:41 +00:00
data.AudonID = id.String()
2022-12-03 03:20:49 +00:00
newUser := AudonUser{
AudonID: data.AudonID,
RemoteID: string(acc.ID),
RemoteURL: acc.URL,
2022-12-04 17:52:44 +00:00
CreatedAt: time.Now().UTC(),
2022-12-03 03:20:49 +00:00
}
if _, insertErr := coll.InsertOne(c.Request().Context(), newUser); insertErr != nil {
c.Logger().Error(insertErr)
return echo.NewHTTPError(http.StatusInternalServerError)
}
} else if dbErr != nil {
c.Logger().Error(dbErr)
return echo.NewHTTPError(http.StatusInternalServerError)
} else if result != nil {
// Set setssion's Audon ID if already registered
2022-12-03 03:20:49 +00:00
data.AudonID = result.AudonID
}
err = writeSessionData(c, data)
if err != nil {
c.Logger().Error(err)
return echo.NewHTTPError(http.StatusInternalServerError)
}
2022-12-04 05:19:41 +00:00
return c.Redirect(http.StatusFound, "/")
// return c.Redirect(http.StatusFound, "http://localhost:5173")
2022-12-03 03:20:49 +00:00
}