PandaWiki/backend/usecase/auth.go

181 lines
4.4 KiB
Go

package usecase
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/url"
"slices"
"time"
"github.com/google/uuid"
"github.com/gorilla/sessions"
"github.com/labstack/echo/v4"
"gorm.io/gorm"
v1 "github.com/chaitin/panda-wiki/api/auth/v1"
"github.com/chaitin/panda-wiki/consts"
"github.com/chaitin/panda-wiki/domain"
"github.com/chaitin/panda-wiki/log"
"github.com/chaitin/panda-wiki/repo/pg"
"github.com/chaitin/panda-wiki/store/cache"
)
type AuthUsecase struct {
AuthRepo *pg.AuthRepo
logger *log.Logger
kbRepo *pg.KnowledgeBaseRepository
cache *cache.Cache
}
func NewAuthUsecase(authRepo *pg.AuthRepo, logger *log.Logger, kbRepo *pg.KnowledgeBaseRepository, cache *cache.Cache) (*AuthUsecase, error) {
u := &AuthUsecase{
AuthRepo: authRepo,
kbRepo: kbRepo,
logger: logger.WithModule("usecase.auth"),
cache: cache,
}
return u, nil
}
type StateInfo struct {
KbId string `json:"kb_id"`
RedirectUrl string `json:"redirect_url"`
Verifier string `json:"verifier"`
}
func (u *AuthUsecase) GetAuthBySourceType(ctx context.Context, sourceType consts.SourceType) (*domain.Auth, error) {
return u.AuthRepo.GetAuthBySourceType(ctx, sourceType)
}
func (u *AuthUsecase) DeleteAuth(ctx context.Context, req v1.AuthDeleteReq) error {
return u.AuthRepo.DeleteAuth(ctx, req.KbID, req.ID)
}
func (u *AuthUsecase) SetAuth(ctx context.Context, req v1.AuthSetReq) error {
if err := u.AuthRepo.CreateAuthConfig(ctx, &domain.AuthConfig{
AuthSetting: domain.AuthSetting{
ClientID: req.ClientID,
ClientSecret: req.ClientSecret,
Proxy: req.Proxy,
},
KbID: req.KBID,
SourceType: req.SourceType,
}); err != nil {
return err
}
return nil
}
func (u *AuthUsecase) GetAuthInfo(ctx context.Context, kbId string, authId uint) (*domain.Auth, error) {
auth, err := u.AuthRepo.GetAuthById(ctx, kbId, authId)
if err != nil {
return nil, err
}
return auth, nil
}
func (u *AuthUsecase) GetAuth(ctx context.Context, kbID string, sourceType consts.SourceType) (*v1.AuthGetResp, error) {
authConfig, err := u.AuthRepo.GetAuthConfig(ctx, kbID, sourceType)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
auths, err := u.AuthRepo.GetAuths(ctx, kbID, sourceType)
if err != nil {
return nil, err
}
as := make([]v1.AuthItem, 0, len(auths))
for _, auth := range auths {
as = append(as, v1.AuthItem{
ID: auth.ID,
Username: auth.UserInfo.Username,
IP: auth.IP,
AvatarUrl: auth.UserInfo.AvatarUrl,
SourceType: auth.SourceType,
LastLoginTime: auth.LastLoginTime,
CreatedAt: auth.CreatedAt,
})
}
resp := &v1.AuthGetResp{
ClientID: authConfig.AuthSetting.ClientID,
ClientSecret: authConfig.AuthSetting.ClientSecret,
SourceType: authConfig.SourceType,
Proxy: authConfig.AuthSetting.Proxy,
Auths: as,
}
return resp, nil
}
func (u *AuthUsecase) ValidateRedirectUrl(ctx context.Context, kbId, redirectUrl string) (bool, error) {
kb, err := u.kbRepo.GetKnowledgeBaseByID(ctx, kbId)
if err != nil {
return false, err
}
redirectURL, _ := url.Parse(redirectUrl)
if kb.AccessSettings.BaseURL != "" {
baseUrl, _ := url.Parse(kb.AccessSettings.BaseURL)
if baseUrl.Hostname() != redirectURL.Hostname() {
return false, nil
}
} else {
if !slices.Contains(kb.AccessSettings.Hosts, redirectURL.Hostname()) {
return false, nil
}
}
return true, nil
}
func (u *AuthUsecase) genState(ctx context.Context, stateInfo StateInfo) (string, error) {
state := uuid.New().String()
stateInfoBytes, err := json.Marshal(stateInfo)
if err != nil {
return "", err
}
if err := u.cache.SetNX(ctx, state, stateInfoBytes, 15*time.Minute).Err(); err != nil {
return "", err
}
return state, nil
}
func (u *AuthUsecase) SaveNewSession(c echo.Context, auth *domain.Auth) error {
s := c.Get(domain.SessionCacheKey)
if s == nil {
return fmt.Errorf("failed to get session store")
}
store := s.(sessions.Store)
newSess := sessions.NewSession(store, domain.SessionName)
newSess.IsNew = true
newSess.Options = &sessions.Options{
Path: "/",
MaxAge: 86400 * 30,
HttpOnly: true,
}
newSess.Values["user_id"] = auth.ID
newSess.Values["kb_id"] = auth.KBID
if err := newSess.Save(c.Request(), c.Response()); err != nil {
return err
}
c.Logger().Info("session_saved:", newSess.Values)
return nil
}