mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 11:39:17 +00:00
327 lines
9.6 KiB
Go
327 lines
9.6 KiB
Go
package databag
|
|
|
|
import (
|
|
"databag/internal/store"
|
|
"encoding/base64"
|
|
"errors"
|
|
"golang.org/x/crypto/bcrypt"
|
|
"gorm.io/gorm"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
//AccountLogin retrieves account specified by username and password
|
|
func AccountLogin(r *http.Request) (*store.Account, error) {
|
|
|
|
// extract request auth
|
|
username, password, ok := r.BasicAuth()
|
|
if !ok || username == "" || password == "" {
|
|
return nil, errors.New("invalid login")
|
|
}
|
|
|
|
// find account
|
|
account := &store.Account{}
|
|
if store.DB.Model(&store.Account{}).Where("Username = ?", username).First(&account).Error != nil {
|
|
return nil, errors.New("username not found")
|
|
}
|
|
|
|
// compare password
|
|
if bcrypt.CompareHashAndPassword(account.Password, []byte(password)) != nil {
|
|
return nil, errors.New("invalid password")
|
|
}
|
|
|
|
return account, nil
|
|
}
|
|
|
|
//BearerAccountToken retrieves AccountToken object specified by authorization header
|
|
func BearerAccountToken(r *http.Request) (*store.AccountToken, error) {
|
|
|
|
// parse bearer authentication
|
|
auth := r.Header.Get("Authorization")
|
|
token := strings.TrimSpace(strings.TrimPrefix(auth, "Bearer"))
|
|
|
|
// find token record
|
|
var accountToken store.AccountToken
|
|
if err := store.DB.Preload("Account").Where("token = ?", token).First(&accountToken).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if accountToken.Expires < time.Now().Unix() {
|
|
return nil, errors.New("expired token")
|
|
}
|
|
return &accountToken, nil
|
|
}
|
|
|
|
//AccessToken retrieves AccountToken specified by token query param
|
|
func AccessToken(r *http.Request) (*store.AccountToken, int, error) {
|
|
|
|
// parse authentication token
|
|
token := r.FormValue("token")
|
|
if token == "" {
|
|
return nil, http.StatusUnauthorized, errors.New("token not set")
|
|
}
|
|
|
|
// find token record
|
|
var accountToken store.AccountToken
|
|
if err := store.DB.Preload("Account").Where("token = ?", token).First(&accountToken).Error; err != nil {
|
|
return nil, http.StatusUnauthorized, err
|
|
}
|
|
if accountToken.Expires < time.Now().Unix() {
|
|
return nil, http.StatusUnauthorized, errors.New("expired token")
|
|
}
|
|
return &accountToken, http.StatusOK, nil
|
|
}
|
|
|
|
//ParamAdminToken compares admin token with token query param
|
|
func ParamAdminToken(r *http.Request) (int, error) {
|
|
|
|
// parse authentication token
|
|
token := r.FormValue("token")
|
|
if token == "" {
|
|
return http.StatusUnauthorized, errors.New("token not set")
|
|
}
|
|
|
|
// nothing to do if not configured
|
|
if !getBoolConfigValue(CNFConfigured, false) {
|
|
return http.StatusUnauthorized, errors.New("node not configured")
|
|
}
|
|
|
|
// compare password
|
|
value := getStrConfigValue(CNFToken, "")
|
|
if value != token {
|
|
return http.StatusUnauthorized, errors.New("invalid admin token")
|
|
}
|
|
|
|
return http.StatusOK, nil
|
|
}
|
|
|
|
//GetSession retrieves account specified by agent query param
|
|
func GetSession(r *http.Request) (*store.Session, int, error) {
|
|
|
|
// parse authentication token
|
|
target, access, err := ParseToken(r.FormValue("agent"))
|
|
if err != nil {
|
|
return nil, http.StatusBadRequest, err
|
|
}
|
|
|
|
// find session record
|
|
var session store.Session;
|
|
if err := store.DB.Preload("Account").Where("account_id = ? AND token = ?", target, access).Find(&session).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, http.StatusNotFound, err
|
|
}
|
|
return nil, http.StatusInternalServerError, err
|
|
}
|
|
|
|
if session.Account.Disabled {
|
|
return nil, http.StatusGone, errors.New("account is inactive")
|
|
}
|
|
|
|
return &session, http.StatusOK, nil
|
|
}
|
|
|
|
//ParamAgentToken retrieves account specified by agent query param
|
|
func ParamAgentToken(r *http.Request, detail bool) (*store.Account, int, error) {
|
|
|
|
// parse authentication token
|
|
target, access, err := ParseToken(r.FormValue("agent"))
|
|
if err != nil {
|
|
return nil, http.StatusBadRequest, err
|
|
}
|
|
|
|
// find session record
|
|
var session store.Session;
|
|
if detail {
|
|
if err := store.DB.Preload("Account.AccountDetail").Where("account_id = ? AND token =?", target, access).Find(&session).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, http.StatusNotFound, err
|
|
}
|
|
return nil, http.StatusInternalServerError, err
|
|
}
|
|
} else {
|
|
if err := store.DB.Preload("Account").Where("account_id = ? AND token =?", target, access).Find(&session).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, http.StatusNotFound, err
|
|
}
|
|
return nil, http.StatusInternalServerError, err
|
|
}
|
|
}
|
|
|
|
if session.Account.Disabled {
|
|
return nil, http.StatusGone, errors.New("account is inactive")
|
|
}
|
|
|
|
return &session.Account, http.StatusOK, nil
|
|
}
|
|
|
|
//BearerAppToken retrieves account specified by authorization header
|
|
func BearerAppToken(r *http.Request, detail bool) (*store.Account, int, error) {
|
|
|
|
// parse bearer authentication
|
|
auth := r.Header.Get("Authorization")
|
|
token := strings.TrimSpace(strings.TrimPrefix(auth, "Bearer"))
|
|
target, access, err := ParseToken(token)
|
|
if err != nil {
|
|
return nil, http.StatusBadRequest, err
|
|
}
|
|
|
|
// find token record
|
|
var app store.App
|
|
if detail {
|
|
if err := store.DB.Preload("Account.AccountDetail").Where("account_id = ? AND token = ?", target, access).First(&app).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, http.StatusNotFound, err
|
|
}
|
|
return nil, http.StatusInternalServerError, err
|
|
}
|
|
} else {
|
|
if err := store.DB.Preload("Account").Where("account_id = ? AND token = ?", target, access).First(&app).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, http.StatusNotFound, err
|
|
}
|
|
return nil, http.StatusInternalServerError, err
|
|
}
|
|
}
|
|
if app.Account.Disabled {
|
|
return nil, http.StatusGone, errors.New("account is inactive")
|
|
}
|
|
|
|
return &app.Account, http.StatusOK, nil
|
|
}
|
|
|
|
//ParseToken separates access token into its guid and random value parts
|
|
func ParseToken(token string) (string, string, error) {
|
|
|
|
split := strings.Split(token, ".")
|
|
if len(split) != 2 {
|
|
return "", "", errors.New("invalid token format")
|
|
}
|
|
return split[0], split[1], nil
|
|
}
|
|
|
|
//ParamTokenType returns type of access token specified
|
|
func ParamTokenType(r *http.Request) string {
|
|
if r.FormValue(APPTokenContact) != "" {
|
|
return APPTokenContact
|
|
}
|
|
if r.FormValue(APPTokenAgent) != "" {
|
|
return APPTokenAgent
|
|
}
|
|
if r.FormValue(APPTokenAttach) != "" {
|
|
return APPTokenAttach
|
|
}
|
|
if r.FormValue(APPTokenCreate) != "" {
|
|
return APPTokenCreate
|
|
}
|
|
if r.FormValue(APPTokenReset) != "" {
|
|
return APPTokenReset
|
|
}
|
|
return ""
|
|
}
|
|
|
|
//ParamContactToken retrieves card specified by contact query param
|
|
func ParamContactToken(r *http.Request, detail bool) (*store.Card, int, error) {
|
|
|
|
// parse authentication token
|
|
target, access, err := ParseToken(r.FormValue("contact"))
|
|
if err != nil {
|
|
return nil, http.StatusBadRequest, err
|
|
}
|
|
|
|
// find token record
|
|
var card store.Card
|
|
if detail {
|
|
if err := store.DB.Preload("CardSlot").Preload("Account.AccountDetail").Where("account_id = ? AND in_token = ?", target, access).First(&card).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, http.StatusNotFound, err
|
|
}
|
|
return nil, http.StatusInternalServerError, err
|
|
}
|
|
} else {
|
|
if err := store.DB.Preload("CardSlot").Preload("Account").Where("account_id = ? AND in_token = ?", target, access).First(&card).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, http.StatusNotFound, err
|
|
}
|
|
return nil, http.StatusInternalServerError, err
|
|
}
|
|
}
|
|
if card.Account.Disabled {
|
|
return nil, http.StatusGone, errors.New("account is inactive")
|
|
}
|
|
if card.Status != APPCardConnecting && card.Status != APPCardConnected {
|
|
return nil, http.StatusUnauthorized, errors.New("invalid connection state")
|
|
}
|
|
|
|
return &card, http.StatusOK, nil
|
|
}
|
|
|
|
//BearerContactToken retrieves card specified by authorization header
|
|
func BearerContactToken(r *http.Request, detail bool) (*store.Card, int, error) {
|
|
|
|
// parse bearer authentication
|
|
auth := r.Header.Get("Authorization")
|
|
token := strings.TrimSpace(strings.TrimPrefix(auth, "Bearer"))
|
|
target, access, err := ParseToken(token)
|
|
if err != nil {
|
|
return nil, http.StatusBadRequest, err
|
|
}
|
|
|
|
// find token record
|
|
var card store.Card
|
|
if detail {
|
|
if err := store.DB.Preload("Account.AccountDetail").Where("account_id = ? AND in_token = ?", target, access).First(&card).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, http.StatusNotFound, err
|
|
}
|
|
return nil, http.StatusInternalServerError, err
|
|
}
|
|
} else {
|
|
if err := store.DB.Preload("Account").Where("account_id = ? AND in_token = ?", target, access).First(&card).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, http.StatusNotFound, err
|
|
}
|
|
return nil, http.StatusInternalServerError, err
|
|
}
|
|
}
|
|
if card.Account.Disabled {
|
|
return nil, http.StatusGone, errors.New("account is inactive")
|
|
}
|
|
if card.Status != APPCardConnecting && card.Status != APPCardConnected {
|
|
return nil, http.StatusUnauthorized, errors.New("invalid connection state")
|
|
}
|
|
|
|
return &card, http.StatusOK, nil
|
|
}
|
|
|
|
//BasicCredentials extracts username and password set it credentials header
|
|
func BasicCredentials(r *http.Request) (string, []byte, error) {
|
|
|
|
var username string
|
|
var password []byte
|
|
|
|
// parse bearer authentication
|
|
auth := r.Header.Get("Credentials")
|
|
token := strings.TrimSpace(strings.TrimPrefix(auth, "Basic"))
|
|
|
|
// decode basic auth
|
|
credentials, err := base64.StdEncoding.DecodeString(token)
|
|
if err != nil {
|
|
return username, password, err
|
|
}
|
|
|
|
// parse credentials
|
|
login := strings.Split(string(credentials), ":")
|
|
if login[0] == "" || login[1] == "" {
|
|
return username, password, errors.New("invalid credentials")
|
|
}
|
|
username = login[0]
|
|
|
|
// hash password
|
|
password, err = bcrypt.GenerateFromPassword([]byte(login[1]), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return username, password, err
|
|
}
|
|
|
|
return username, password, nil
|
|
}
|