2022-12-03 03:20:49 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/gob"
|
|
|
|
"errors"
|
|
|
|
"html/template"
|
|
|
|
"io"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/go-playground/validator/v10"
|
|
|
|
"github.com/gorilla/sessions"
|
|
|
|
"github.com/labstack/echo-contrib/session"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
|
|
"github.com/mattn/go-mastodon"
|
|
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
|
|
|
Template struct {
|
|
|
|
templates *template.Template
|
|
|
|
}
|
|
|
|
|
|
|
|
CustomValidator struct {
|
|
|
|
validator *validator.Validate
|
|
|
|
}
|
|
|
|
|
|
|
|
M map[string]interface{}
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
err_invalid_cookie error = errors.New("invalid cookie")
|
|
|
|
mastAppConfigBase *mastodon.AppConfig = nil
|
|
|
|
mainDB *mongo.Database = nil
|
|
|
|
mainValidator = validator.New()
|
2022-12-03 17:44:11 +00:00
|
|
|
mainConfig *AppConfig
|
2022-12-03 03:20:49 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
gob.Register(&SessionData{})
|
|
|
|
gob.Register(&M{})
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
2022-12-03 17:44:11 +00:00
|
|
|
var err error
|
|
|
|
|
|
|
|
// Load config from environment variables and .env
|
|
|
|
mainConfig, err = loadConfig(os.Getenv("AUDON_ENV"))
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln(err)
|
|
|
|
os.Exit(1)
|
2022-12-03 03:20:49 +00:00
|
|
|
}
|
2022-12-03 17:44:11 +00:00
|
|
|
|
2022-12-04 05:19:41 +00:00
|
|
|
dbContext, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
2022-12-03 03:20:49 +00:00
|
|
|
defer cancel()
|
2022-12-03 17:44:11 +00:00
|
|
|
dbClient, err := mongo.Connect(dbContext, options.Client().ApplyURI(mainConfig.MongoURL.String()))
|
2022-12-03 03:20:49 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalln(err)
|
2022-12-03 17:44:11 +00:00
|
|
|
os.Exit(2)
|
2022-12-03 03:20:49 +00:00
|
|
|
}
|
2022-12-04 05:19:41 +00:00
|
|
|
mainDB = dbClient.Database(mainConfig.Database.Name)
|
2022-12-03 03:20:49 +00:00
|
|
|
err = createIndexes(dbContext)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalln(err)
|
2022-12-03 17:44:11 +00:00
|
|
|
os.Exit(3)
|
2022-12-03 03:20:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
e := echo.New()
|
|
|
|
defer e.Close()
|
|
|
|
|
|
|
|
t := &Template{
|
|
|
|
templates: template.Must(template.ParseFiles("audon-fe/index.html", "audon-fe/dist/index.html")),
|
|
|
|
}
|
|
|
|
e.Renderer = t
|
|
|
|
e.Validator = &CustomValidator{validator: mainValidator}
|
2022-12-03 17:44:11 +00:00
|
|
|
e.Use(session.Middleware(sessions.NewCookieStore([]byte(mainConfig.SeesionSecret))))
|
2022-12-03 03:20:49 +00:00
|
|
|
// e.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{
|
|
|
|
// CookiePath: "/",
|
2022-12-04 05:19:41 +00:00
|
|
|
// TokenLookup: "header:X-XSRF-TOKEN",
|
2022-12-03 03:20:49 +00:00
|
|
|
// }))
|
|
|
|
|
2022-12-04 05:19:41 +00:00
|
|
|
e.GET("/api/verify", verifyHandler)
|
|
|
|
e.POST("/api/room", createRoomHandler)
|
|
|
|
e.POST("/api/login", loginHandler)
|
|
|
|
e.GET("/api/oauth", oauthHandler)
|
|
|
|
e.Static("/", "audon-fe/dist/assets")
|
2022-12-03 03:20:49 +00:00
|
|
|
|
|
|
|
e.Logger.Debug(e.Start(":1323"))
|
|
|
|
}
|
|
|
|
|
|
|
|
// handler for GET to /api/v1/verify
|
|
|
|
func verifyHandler(c echo.Context) (err error) {
|
|
|
|
sess, err := getSession(c)
|
|
|
|
if err != nil {
|
|
|
|
c.Logger().Error(err)
|
|
|
|
return echo.NewHTTPError(http.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
|
|
|
|
valid, _ := verifyTokenInSession(c, sess)
|
|
|
|
if !valid {
|
|
|
|
return c.NoContent(http.StatusUnauthorized)
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.NoContent(http.StatusOK)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
|
|
|
|
return t.templates.ExecuteTemplate(w, name, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cv *CustomValidator) Validate(i interface{}) error {
|
|
|
|
if err := cv.validator.Struct(i); err != nil {
|
|
|
|
return wrapValidationError(err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getAppConfig(server string) (*mastodon.AppConfig, error) {
|
|
|
|
if mastAppConfigBase != nil {
|
|
|
|
return &mastodon.AppConfig{
|
|
|
|
Server: server,
|
|
|
|
ClientName: mastAppConfigBase.ClientName,
|
|
|
|
Scopes: mastAppConfigBase.Scopes,
|
|
|
|
Website: mastAppConfigBase.Website,
|
|
|
|
RedirectURIs: mastAppConfigBase.RedirectURIs,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
redirectURI := "urn:ietf:wg:oauth:2.0:oob"
|
2022-12-03 17:44:11 +00:00
|
|
|
u := &url.URL{
|
|
|
|
Host: mainConfig.LocalDomain,
|
2022-12-04 05:19:41 +00:00
|
|
|
Scheme: "https",
|
2022-12-03 17:44:11 +00:00
|
|
|
Path: "/",
|
2022-12-03 03:20:49 +00:00
|
|
|
}
|
2022-12-04 05:19:41 +00:00
|
|
|
u = u.JoinPath("api", "oauth")
|
2022-12-03 17:44:11 +00:00
|
|
|
redirectURI = u.String()
|
2022-12-03 03:20:49 +00:00
|
|
|
|
|
|
|
conf := &mastodon.AppConfig{
|
|
|
|
ClientName: "Audon",
|
|
|
|
Scopes: "read:accounts read:follows",
|
|
|
|
Website: "https://github.com/nmkj-io/audon",
|
|
|
|
RedirectURIs: redirectURI,
|
|
|
|
}
|
|
|
|
|
|
|
|
mastAppConfigBase = conf
|
|
|
|
|
|
|
|
return &mastodon.AppConfig{
|
|
|
|
Server: server,
|
|
|
|
ClientName: conf.ClientName,
|
|
|
|
Scopes: conf.Scopes,
|
|
|
|
Website: conf.Website,
|
|
|
|
RedirectURIs: conf.RedirectURIs,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSession(c echo.Context) (sess *sessions.Session, err error) {
|
|
|
|
sess, err = session.Get(SESSION_NAME, c)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
sess.Options = &sessions.Options{
|
|
|
|
Path: "/",
|
|
|
|
MaxAge: 0,
|
|
|
|
HttpOnly: true,
|
2022-12-04 05:19:41 +00:00
|
|
|
SameSite: http.SameSiteStrictMode,
|
|
|
|
Secure: true,
|
2022-12-03 03:20:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return sess, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// retrieve user's session, returns invalid cookie error if failed
|
|
|
|
func getSessionData(sess *sessions.Session) (data *SessionData, err error) {
|
|
|
|
val := sess.Values[SESSION_DATASTORE_NAME]
|
|
|
|
data, ok := val.(*SessionData)
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
return nil, err_invalid_cookie
|
|
|
|
}
|
|
|
|
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// write user's session, returns error if failed
|
|
|
|
func writeSessionData(c echo.Context, data *SessionData) error {
|
|
|
|
sess, err := getSession(c)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
sess.Values[SESSION_DATASTORE_NAME] = data
|
|
|
|
|
2022-12-04 05:19:41 +00:00
|
|
|
return sess.Save(c.Request(), c.Response())
|
2022-12-03 03:20:49 +00:00
|
|
|
}
|