Files
mstore/app/handler/aaafunc.go
T
2026-02-21 12:31:39 +02:00

142 lines
3.3 KiB
Go

/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package handler
import (
"context"
"fmt"
"regexp"
"mstore/app/router"
"mstore/pkg/auxhttp"
"mstore/pkg/auxpwd"
"mstore/pkg/term"
)
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 = term.AnonymousID
authHeader := rctx.GetHeader("Authorization")
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 = term.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("Cop check your right %s: %s %s", accountID, reqRight, subject)
// =[]=
// .------. ---
// .---[-] [#] \--, ---
// >| [ ] [ ] | ---...
// '--0-------0----'
// Bad news for you, baby.... #
//
exists, grants, err := hand.mdb.ListGrantsByAccoundIDRight(ctx, accountID, reqRight)
if err != nil {
return res, err
}
if !exists {
return res, err
}
switch reqRight {
case term.RightReadFiles, term.RightWriteFiles:
for _, grant := range grants {
re, err := regexp.Compile(grant.Pattern)
if err != nil {
hand.logg.Warningf("Wrong pattern %s for grant %s: %v", grant.Pattern, grant.ID, err)
err = nil
continue
}
if re.MatchString(subject) {
res = true
break
}
}
default:
// NOP
}
res = true
return res, err
}