Files

132 lines
3.1 KiB
Go

/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*/
package handler
import (
"context"
"fmt"
"regexp"
"mstore/app/router"
"mstore/pkg/auxhttp"
"mstore/pkg/auxpwd"
"mstore/pkg/terms"
)
const (
authTag = "authpass"
userTag = "accountID"
)
func (hand *Handler) AuthMiddleware(next router.Handler) router.Handler {
var handlerFunc router.HandlerFunc
handlerFunc = func(rctx *router.Context) {
success, accountID, err := hand.CheckAccess(rctx)
if success {
rctx.SetBool(authTag, true)
rctx.SetString(userTag, string(accountID))
}
if err != nil {
hand.logg.Errorf("Authorization middleware error: %v", err)
}
next.ServeHTTP(rctx)
}
return handlerFunc
}
// Authentification
func (hand *Handler) CheckAccess(rctx *router.Context) (bool, string, error) {
var err error
var success bool
var username string
var password string
var accountID string
accountID = terms.AnonymousID
//hand.logg.Debugf("URL: %s", rctx.URL().String())
authHeader := rctx.GetHeader("Authorization")
hand.logg.Debugf("Authorization: [%s]", authHeader)
if authHeader != "" {
username, password, err = auxhttp.ParseBasicAuth(authHeader)
if err != nil {
return success, accountID, err
}
if username == "" || password == "" {
goto anonymous
}
success, id, err := hand.ValidatePassword(rctx.Ctx, username, password)
if err != nil {
return false, accountID, err
}
if !success {
err = fmt.Errorf("Incorrect username or password")
return false, accountID, err
}
accountID = id
return success, accountID, err
}
anonymous:
success = true
accountID = terms.AnonymousID
return success, accountID, err
}
func (hand *Handler) ValidatePassword(ctx context.Context, username, password string) (bool, string, error) {
var err error
var accountID string
valid := false
accountExists, accountDescr, err := hand.mdb.GetAccountByUsername(ctx, username)
if !accountExists {
err := fmt.Errorf("Account not exists")
return valid, accountID, err
}
if !auxpwd.PasswordMatch([]byte(password), accountDescr.Passhash) {
err := fmt.Errorf("Login data mismatch")
return valid, accountID, err
}
valid = true
accountID = accountDescr.ID
return valid, accountID, err
}
// Authorization
func (hand *Handler) CheckRight(ctx context.Context, accountID, reqRight, subject string) (bool, error) {
var err error
var res bool
hand.logg.Debugf("Check right %s: right=[%s] subj=[%s]", accountID, reqRight, subject)
exists, grants, err := hand.mdb.ListGrantsByAccoundIDRight(ctx, accountID, reqRight)
if err != nil {
return res, err
}
if !exists {
return res, err
}
switch reqRight {
case terms.RightReadFiles, terms.RightWriteFiles, terms.RightReadImages, terms.RightWriteImages:
for _, grant := range grants {
//hand.logg.Debugf("Grant accountID=[%s] pattern=[%s], subject=[%s]", accountID, grant.Pattern, subject)
re, err := regexp.Compile(grant.Pattern)
if err != nil {
hand.logg.Warningf("Wrong regexp %s for grant %s: %v", grant.Pattern, grant.ID, err)
err = nil
continue
}
if re.MatchString(subject) {
res = true
break
}
}
default:
res = true
}
return res, err
}