parent
83daefe9f0
commit
24efbe8127
@ -1,7 +1,8 @@
|
||||
package consts
|
||||
|
||||
const (
|
||||
REDIS_KEY_LOGIN_SESSION = "misso:login:%s" // Username, token as value
|
||||
REDIS_KEY_CONSENT_CSRF = "misso:consent:%s" // Random string, consent challenge as value
|
||||
REDIS_KEY_SHARE_CONTEXT = "misso:share:%s" // Subject, context as value
|
||||
REDIS_KEY_LOGIN_SESSION = "misso:login:%s" // Username, token as value
|
||||
REDIS_KEY_CONSENT_CSRF = "misso:consent:%s" // Random string, consent challenge as value
|
||||
REDIS_KEY_SHARE_ACCESS_TOKEN = "misso:share:at:%s" // Subject, access token as value
|
||||
REDIS_KEY_SHARE_USER_INFO = "misso:share:ui:%s" // Subject, user info as value
|
||||
)
|
||||
|
@ -0,0 +1,30 @@
|
||||
package logout
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gin-gonic/gin"
|
||||
"misso/global"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func Logout(ctx *gin.Context) {
|
||||
oauth2challenge := ctx.Query("logout_challenge") // OAuth2 login
|
||||
if oauth2challenge == "" {
|
||||
ctx.HTML(http.StatusBadRequest, "error.tmpl", gin.H{
|
||||
"error": "Necessary challenge not provided",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
acceptReq, _, err := global.Hydra.Admin.OAuth2Api.AcceptOAuth2LogoutRequest(context.Background()).LogoutChallenge(oauth2challenge).Execute()
|
||||
if err != nil {
|
||||
global.Logger.Errorf("Failed to accept logout request with error: %v", err)
|
||||
ctx.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{
|
||||
"error": "Failed to accept logout request",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Redirect(http.StatusTemporaryRedirect, acceptReq.RedirectTo)
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package misskey
|
||||
|
||||
import "misso/types"
|
||||
|
||||
type I_Request struct {
|
||||
I string `json:"i"`
|
||||
}
|
||||
|
||||
type I_Response = types.MisskeyUser
|
||||
|
||||
func GetUserinfo(accessToken string) (*I_Response, error) {
|
||||
return PostAPIRequest[I_Response]("/api/i", &I_Request{
|
||||
I: accessToken,
|
||||
})
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"misso/handlers/logout"
|
||||
)
|
||||
|
||||
func Logout(rg *gin.RouterGroup) {
|
||||
rg.GET("/logout", logout.Logout)
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package types
|
||||
|
||||
type SessionContext struct {
|
||||
MisskeyToken string `json:"token"`
|
||||
User MisskeyUser `json:"user"`
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"misso/consts"
|
||||
"misso/global"
|
||||
"misso/misskey"
|
||||
"misso/types"
|
||||
)
|
||||
|
||||
func GetUserinfo(subject string) (*types.MisskeyUser, error) {
|
||||
// Check cache key
|
||||
global.Logger.Debugf("Checking userinfo cache...")
|
||||
userinfoCacheKey := fmt.Sprintf(consts.REDIS_KEY_SHARE_USER_INFO, subject)
|
||||
exist, err := global.Redis.Exists(context.Background(), userinfoCacheKey).Result()
|
||||
if err != nil {
|
||||
global.Logger.Errorf("Failed to check userinfo exist status with error: %v", err)
|
||||
} else if exist > 0 {
|
||||
// Exist, get from cache
|
||||
userinfoCacheBytes, err := global.Redis.Get(context.Background(), userinfoCacheKey).Bytes()
|
||||
if err != nil {
|
||||
global.Logger.Errorf("Userinfo cache exists, but failed to retrieve with error: %v", err)
|
||||
} else {
|
||||
// Parse into user
|
||||
var userinfo types.MisskeyUser
|
||||
err = json.Unmarshal(userinfoCacheBytes, &userinfo)
|
||||
if err != nil {
|
||||
global.Logger.Errorf("Failed to parse userinfo cache into json with error: %v", err)
|
||||
} else {
|
||||
// Works!
|
||||
global.Logger.Debugf("Get cached userinfo successfully.")
|
||||
return &userinfo, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to get info directly, we need user's access token.
|
||||
global.Logger.Debugf("No cached userinfo found (or valid), trying to get latest response.")
|
||||
accessTokenCacheKey := fmt.Sprintf(consts.REDIS_KEY_SHARE_ACCESS_TOKEN, subject)
|
||||
accessToken, err := global.Redis.Get(context.Background(), accessTokenCacheKey).Result()
|
||||
if err != nil {
|
||||
global.Logger.Errorf("Failed to get user access token with error: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get userinfo with access token
|
||||
userinfo, err := misskey.GetUserinfo(accessToken)
|
||||
if err != nil {
|
||||
global.Logger.Errorf("Failed to get user info with saved access token with error: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Save userinfo into redis
|
||||
_ = SaveUserinfo(subject, userinfo) // Ignore errors
|
||||
|
||||
return userinfo, nil
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"misso/consts"
|
||||
"misso/global"
|
||||
"misso/types"
|
||||
)
|
||||
|
||||
func SaveUserinfo(subject string, userinfo *types.MisskeyUser) error {
|
||||
userinfoBytes, err := json.Marshal(userinfo)
|
||||
if err != nil {
|
||||
global.Logger.Errorf("Failed to parse accept context with error: %v", err)
|
||||
return err
|
||||
}
|
||||
sessUserInfoKey := fmt.Sprintf(consts.REDIS_KEY_SHARE_USER_INFO, subject)
|
||||
err = global.Redis.Set(context.Background(), sessUserInfoKey, userinfoBytes, consts.TIME_USERINFO_CACHE).Err()
|
||||
if err != nil {
|
||||
global.Logger.Errorf("Failed to save session user info into redis with error: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in new issue