audon/server.go

211 wiersze
4.9 KiB
Go
Czysty Zwykły widok Historia

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()
mainConfig *AppConfig
2022-12-03 03:20:49 +00:00
)
func init() {
gob.Register(&SessionData{})
gob.Register(&M{})
}
func main() {
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-04 17:52:44 +00:00
backContext, cancel := context.WithTimeout(context.Background(), 5*time.Second)
2022-12-03 03:20:49 +00:00
defer cancel()
2022-12-04 17:52:44 +00:00
// Setup database client
dbClient, err := mongo.Connect(backContext, options.Client().ApplyURI(mainConfig.MongoURL.String()))
2022-12-03 03:20:49 +00:00
if err != nil {
log.Fatalln(err)
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-04 17:52:44 +00:00
err = createIndexes(backContext)
2022-12-03 03:20:49 +00:00
if err != nil {
log.Fatalln(err)
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-04 17:52:44 +00:00
cookieStore := sessions.NewCookieStore([]byte(mainConfig.SeesionSecret))
cookieStore.Options = &sessions.Options{
Path: "/",
Domain: mainConfig.LocalDomain,
MaxAge: 86400 * 30,
HttpOnly: true,
SameSite: http.SameSiteStrictMode,
Secure: true,
}
if mainConfig.Environment == "development" {
cookieStore.Options.Domain = ""
cookieStore.Options.SameSite = http.SameSiteNoneMode
cookieStore.Options.Secure = false
cookieStore.Options.MaxAge = 3600 * 24
cookieStore.Options.HttpOnly = false
}
e.Use(session.Middleware(cookieStore))
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"
u := &url.URL{
Host: mainConfig.LocalDomain,
2022-12-04 05:19:41 +00:00
Scheme: "https",
Path: "/",
2022-12-03 03:20:49 +00:00
}
2022-12-04 05:19:41 +00:00
u = u.JoinPath("api", "oauth")
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
}
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
}