[add] admin panel, [add] better logging
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2024-01-09 21:08:40 -05:00
parent d3d89b36f6
commit c5b181dda4
14 changed files with 588 additions and 99 deletions

View File

@@ -14,6 +14,12 @@ import (
"reichard.io/bbank/database"
)
// Authorization Data
type authData struct {
UserName string
IsAdmin bool
}
// KOSync API Auth Headers
type authKOHeader struct {
AuthUser string `header:"x-auth-user"`
@@ -25,25 +31,28 @@ type authOPDSHeader struct {
Authorization string `header:"authorization"`
}
func (api *API) authorizeCredentials(username string, password string) (authorized bool) {
func (api *API) authorizeCredentials(username string, password string) (auth *authData) {
user, err := api.DB.Queries.GetUser(api.DB.Ctx, username)
if err != nil {
return false
return
}
if match, err := argon2.ComparePasswordAndHash(password, *user.Pass); err != nil || match != true {
return false
return
}
return true
return &authData{
UserName: user.ID,
IsAdmin: user.Admin,
}
}
func (api *API) authKOMiddleware(c *gin.Context) {
session := sessions.Default(c)
// Check Session First
if user, ok := getSession(session); ok == true {
c.Set("AuthorizedUser", user)
if auth, ok := getSession(session); ok == true {
c.Set("Authorization", auth)
c.Header("Cache-Control", "private")
c.Next()
return
@@ -61,17 +70,18 @@ func (api *API) authKOMiddleware(c *gin.Context) {
return
}
if authorized := api.authorizeCredentials(rHeader.AuthUser, rHeader.AuthKey); authorized != true {
authData := api.authorizeCredentials(rHeader.AuthUser, rHeader.AuthKey)
if authData == nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
return
}
if err := setSession(session, rHeader.AuthUser); err != nil {
if err := setSession(session, *authData); err != nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
return
}
c.Set("AuthorizedUser", rHeader.AuthUser)
c.Set("Authorization", *authData)
c.Header("Cache-Control", "private")
c.Next()
}
@@ -89,12 +99,13 @@ func (api *API) authOPDSMiddleware(c *gin.Context) {
// Validate Auth
password := fmt.Sprintf("%x", md5.Sum([]byte(rawPassword)))
if authorized := api.authorizeCredentials(user, password); authorized != true {
authData := api.authorizeCredentials(user, password)
if authData == nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
return
}
c.Set("AuthorizedUser", user)
c.Set("Authorization", *authData)
c.Header("Cache-Control", "private")
c.Next()
}
@@ -103,8 +114,8 @@ func (api *API) authWebAppMiddleware(c *gin.Context) {
session := sessions.Default(c)
// Check Session
if user, ok := getSession(session); ok == true {
c.Set("AuthorizedUser", user)
if auth, ok := getSession(session); ok == true {
c.Set("Authorization", auth)
c.Header("Cache-Control", "private")
c.Next()
return
@@ -115,6 +126,20 @@ func (api *API) authWebAppMiddleware(c *gin.Context) {
return
}
func (api *API) authAdminWebAppMiddleware(c *gin.Context) {
if data, _ := c.Get("Authorization"); data != nil {
auth := data.(authData)
if auth.IsAdmin == true {
c.Next()
return
}
}
errorPage(c, http.StatusUnauthorized, "Admin Permissions Required")
c.Abort()
return
}
func (api *API) appAuthFormLogin(c *gin.Context) {
templateVars := api.getBaseTemplateVars("login", c)
@@ -129,7 +154,8 @@ func (api *API) appAuthFormLogin(c *gin.Context) {
// MD5 - KOSync Compatiblity
password := fmt.Sprintf("%x", md5.Sum([]byte(rawPassword)))
if authorized := api.authorizeCredentials(username, password); authorized != true {
authData := api.authorizeCredentials(username, password)
if authData == nil {
templateVars["Error"] = "Invalid Credentials"
c.HTML(http.StatusUnauthorized, "page/login", templateVars)
return
@@ -137,7 +163,7 @@ func (api *API) appAuthFormLogin(c *gin.Context) {
// Set Session
session := sessions.Default(c)
if err := setSession(session, username); err != nil {
if err := setSession(session, *authData); err != nil {
templateVars["Error"] = "Invalid Credentials"
c.HTML(http.StatusUnauthorized, "page/login", templateVars)
return
@@ -194,9 +220,22 @@ func (api *API) appAuthFormRegister(c *gin.Context) {
return
}
// Get User
user, err := api.DB.Queries.GetUser(api.DB.Ctx, username)
if err != nil {
log.Error("[appAuthFormRegister] GetUser DB Error:", err)
templateVars["Error"] = "Registration Disabled or User Already Exists"
c.HTML(http.StatusBadRequest, "page/login", templateVars)
return
}
// Set Session
auth := authData{
UserName: user.ID,
IsAdmin: user.Admin,
}
session := sessions.Default(c)
if err := setSession(session, username); err != nil {
if err := setSession(session, auth); err != nil {
errorPage(c, http.StatusUnauthorized, "Unauthorized.")
return
}
@@ -212,26 +251,35 @@ func (api *API) appAuthLogout(c *gin.Context) {
c.Redirect(http.StatusFound, "/login")
}
func getSession(session sessions.Session) (user string, ok bool) {
func getSession(session sessions.Session) (auth authData, ok bool) {
// Check Session
authorizedUser := session.Get("authorizedUser")
if authorizedUser == nil {
return "", false
isAdmin := session.Get("isAdmin")
expiresAt := session.Get("expiresAt")
if authorizedUser == nil || isAdmin == nil || expiresAt == nil {
return
}
// Create Auth Object
auth = authData{
UserName: authorizedUser.(string),
IsAdmin: isAdmin.(bool),
}
// Refresh
expiresAt := session.Get("expiresAt")
if expiresAt != nil && expiresAt.(int64)-time.Now().Unix() < 60*60*24 {
if expiresAt.(int64)-time.Now().Unix() < 60*60*24 {
log.Info("[getSession] Refreshing Session")
setSession(session, authorizedUser.(string))
setSession(session, auth)
}
return authorizedUser.(string), true
// Authorized
return auth, true
}
func setSession(session sessions.Session, user string) error {
func setSession(session sessions.Session, auth authData) error {
// Set Session Cookie
session.Set("authorizedUser", user)
session.Set("authorizedUser", auth.UserName)
session.Set("isAdmin", auth.IsAdmin)
session.Set("expiresAt", time.Now().Unix()+(60*60*24*7))
return session.Save()
}