mirror of https://github.com/chaitin/PandaWiki.git
181 lines
4.4 KiB
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
|
|
}
|