213 lines
5.7 KiB
Go
213 lines
5.7 KiB
Go
// Copyright (c) 2026 Zeni Kim <zenik@smarteching.com>
|
|
// Use of this source code is governed by MIT-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package controllers
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"net/http"
|
|
"os"
|
|
"strconv"
|
|
|
|
"git.smarteching.com/goffee/core"
|
|
"git.smarteching.com/goffee/core/template/components"
|
|
"git.smarteching.com/goffee/cup/models"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func AppSignin(c *core.Context) *core.Response {
|
|
email := c.GetRequestParam("email")
|
|
password := c.GetRequestParam("password")
|
|
|
|
// check if template engine is enable
|
|
TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE")
|
|
if TemplateEnableStr == "" {
|
|
TemplateEnableStr = "false"
|
|
}
|
|
TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr)
|
|
|
|
// Apps web only works if template is enabled in environment
|
|
if !TemplateEnable {
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
"email": email,
|
|
"password": password,
|
|
}
|
|
rules := map[string]interface{}{
|
|
"email": "required|email",
|
|
"password": "required",
|
|
}
|
|
v := c.GetValidator().Validate(data, rules)
|
|
|
|
if v.Failed() {
|
|
c.GetLogger().Error(v.GetErrorMessagesJson())
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
|
|
var user models.User
|
|
res := c.GetGorm().Where("email = ?", c.CastToString(email)).First(&user)
|
|
if res.Error != nil && !errors.Is(res.Error, gorm.ErrRecordNotFound) {
|
|
c.GetLogger().Error(res.Error.Error())
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
|
|
if res.Error != nil && errors.Is(res.Error, gorm.ErrRecordNotFound) {
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
|
|
ok, err := c.GetHashing().CheckPasswordHash(user.Password, c.CastToString(password))
|
|
if err != nil {
|
|
c.GetLogger().Error(err.Error())
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
|
|
if !ok {
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
|
|
token, err := c.GetJWT().GenerateToken(map[string]interface{}{
|
|
"userID": user.ID,
|
|
})
|
|
|
|
if err != nil {
|
|
c.GetLogger().Error(err.Error())
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
// cache the token
|
|
userAgent := c.GetUserAgent()
|
|
hashedCacheKey := core.CreateAuthTokenHashedCacheKey(user.ID, userAgent)
|
|
err = c.GetCache().Set(hashedCacheKey, token)
|
|
|
|
// delete data from old sessions
|
|
sessionKey := fmt.Sprintf("sess_%v", userAgent)
|
|
hashedSessionKey := core.CreateAuthTokenHashedCacheKey(user.ID, sessionKey)
|
|
_ = c.GetCache().Delete(hashedSessionKey)
|
|
|
|
if err != nil {
|
|
c.GetLogger().Error(err.Error())
|
|
// TODO set error in session
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
|
|
// create cookie
|
|
err = core.SetCookie(c.Response.HttpResponseWriter, email.(string), token)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Error write encrypted cookie: %v", err))
|
|
return c.Response.SetStatusCode(http.StatusInternalServerError)
|
|
}
|
|
|
|
// redirect to app
|
|
return c.Response.Redirect("/dashboard")
|
|
|
|
}
|
|
|
|
func AppSignout(c *core.Context) *core.Response {
|
|
|
|
// check if template engine is enable
|
|
TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE")
|
|
if TemplateEnableStr == "" {
|
|
TemplateEnableStr = "false"
|
|
}
|
|
TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr)
|
|
|
|
// Apps web only works if template is enabled in environment
|
|
if !TemplateEnable {
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
|
|
token := ""
|
|
|
|
// get cookie
|
|
usercookie, err := c.GetCookie()
|
|
if err != nil {
|
|
// the cookie could not be read/decrypted, still make sure it is removed from the client
|
|
core.ClearCookie(c.Response.HttpResponseWriter)
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
token = usercookie.Token
|
|
|
|
if token == "" {
|
|
// no token present, still clear any (possibly present) cookie on the client
|
|
core.ClearCookie(c.Response.HttpResponseWriter)
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
payload, err := c.GetJWT().DecodeToken(token)
|
|
if err != nil {
|
|
// the token is invalid, clear the cookie on the client
|
|
core.ClearCookie(c.Response.HttpResponseWriter)
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
userAgent := c.GetUserAgent()
|
|
hashedCacheKey := core.CreateAuthTokenHashedCacheKey(uint(c.CastToInt(payload["userID"])), userAgent)
|
|
|
|
err = c.GetCache().Delete(hashedCacheKey)
|
|
if err != nil {
|
|
// failed to invalidate the cached token, still clear the cookie on the client
|
|
core.ClearCookie(c.Response.HttpResponseWriter)
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
|
|
// successful signout: the token is removed from the cache, also clear
|
|
// the cookie on the client before the final redirect
|
|
core.ClearCookie(c.Response.HttpResponseWriter)
|
|
|
|
return c.Response.Redirect("/applogin")
|
|
}
|
|
|
|
// Show basic app login
|
|
func AppLogin(c *core.Context) *core.Response {
|
|
|
|
// check if template engine is enable
|
|
TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE")
|
|
if TemplateEnableStr == "" {
|
|
TemplateEnableStr = "false"
|
|
}
|
|
TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr)
|
|
|
|
if TemplateEnable {
|
|
// initiate authority
|
|
session := c.GetSession()
|
|
// true if session is active
|
|
hassession := session.Init(c)
|
|
// only show login if no has session
|
|
if !hassession {
|
|
|
|
type templateData struct{}
|
|
tmplData := templateData{}
|
|
return c.Response.Template("login.html", tmplData)
|
|
|
|
} else {
|
|
// first, include all compoments
|
|
type templateData struct {
|
|
PageCard components.PageCard
|
|
}
|
|
|
|
// now fill data of the components
|
|
tmplData := templateData{
|
|
PageCard: components.PageCard{
|
|
CardTitle: "Golang Framework",
|
|
CardBody: "Welcome to Goffee",
|
|
},
|
|
}
|
|
return c.Response.Template("welcome.html", tmplData)
|
|
}
|
|
} else {
|
|
return c.Response.SetStatusCode(http.StatusInternalServerError).Json(c.MapToJson(map[string]interface{}{
|
|
"message": "Apps web only works if template is enabled in environment",
|
|
}))
|
|
}
|
|
}
|
|
|
|
// This page is cookie protected by hook
|
|
func WelcomeToDashboard(c *core.Context) *core.Response {
|
|
|
|
type templateData struct{}
|
|
|
|
return c.Response.Template("dashboard.html", templateData{})
|
|
|
|
}
|