From a99045a03499b0f1f862c1d61975cbb0f8ee415b Mon Sep 17 00:00:00 2001 From: Nya Candy Date: Sun, 29 Jan 2023 14:23:49 +0800 Subject: [PATCH 01/10] feat(refractor): use misskey userinfo key as scope ...and UI tweaks :art: --- consts/redis_key.go | 8 +- consts/time.go | 4 +- handlers/consent/consent_check.go | 15 +- handlers/consent/consent_confirm.go | 18 ++- handlers/login/misskey_auth_callback.go | 18 +-- handlers/user/info.go | 26 ++-- misskey/get_userkey.go | 4 +- templates/consent.tmpl | 123 +++++++++++++--- templates/error.tmpl | 22 ++- templates/head.tmpl | 15 +- templates/index.tmpl | 12 +- types/MisskeyUser.go | 186 +----------------------- utils/get_userinfo.go | 7 +- utils/save_userinfo.go | 2 +- 14 files changed, 208 insertions(+), 252 deletions(-) diff --git a/consts/redis_key.go b/consts/redis_key.go index 1b82715..e7fb534 100644 --- a/consts/redis_key.go +++ b/consts/redis_key.go @@ -1,8 +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_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 + 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_USER_ACCESS_TOKEN = "misso:user:token:%s" // Subject, access token as value + REDIS_KEY_USER_INFO = "misso:user:info:%s" // Subject, user info as value ) diff --git a/consts/time.go b/consts/time.go index 25dbb44..309757e 100644 --- a/consts/time.go +++ b/consts/time.go @@ -5,8 +5,8 @@ import "time" const ( TIME_REQUEST_VALID = 1 * time.Hour - TIME_LOGIN_REMEMBER = 10 * time.Minute + TIME_LOGIN_REMEMBER = 10 * time.Minute TIME_CONSENT_REMEMBER = 0 // Forever - TIME_USERINFO_CACHE = 10 * time.Minute + TIME_USERINFO_CACHE = 1 * time.Hour ) diff --git a/handlers/consent/consent_check.go b/handlers/consent/consent_check.go index 7503f44..6b8c027 100644 --- a/handlers/consent/consent_check.go +++ b/handlers/consent/consent_check.go @@ -56,8 +56,8 @@ func ConsentCheck(ctx *gin.Context) { // Generate CSRF token global.Logger.Debugf("Generating CSRF token...") csrf := utils.RandString(32) - sessKey := fmt.Sprintf(consts.REDIS_KEY_CONSENT_CSRF, csrf) - err := global.Redis.Set(context.Background(), sessKey, oauth2challenge, consts.TIME_REQUEST_VALID).Err() + sessKey := fmt.Sprintf(consts.REDIS_KEY_CONSENT_CSRF, oauth2challenge) + err := global.Redis.Set(context.Background(), sessKey, csrf, consts.TIME_REQUEST_VALID).Err() if err != nil { global.Logger.Errorf("Failed to save csrf into redis with error: %v", err) ctx.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{ @@ -69,7 +69,7 @@ func ConsentCheck(ctx *gin.Context) { // Retrieve context global.Logger.Debugf("Retrieving context...") - userinfoCtx, err := utils.GetUserinfo(*consentReq.Subject) + userinfo, err := utils.GetUserinfo(*consentReq.Subject) if err != nil { global.Logger.Errorf("Failed to retrieve userinfo with error: %v", err) ctx.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{ @@ -81,9 +81,10 @@ func ConsentCheck(ctx *gin.Context) { // Show the consent UI global.Logger.Debugf("Rendering consent UI...") templateFields := gin.H{ - "user": *userinfoCtx, + "user": *userinfo, "challenge": oauth2challenge, "csrf": csrf, + "scopes": consentReq.RequestedScope, } if consentReq.Client.LogoUri != nil && *consentReq.Client.LogoUri != "" { @@ -94,6 +95,12 @@ func ConsentCheck(ctx *gin.Context) { } else { templateFields["clientName"] = *consentReq.Client.ClientId } + if consentReq.Client.PolicyUri != nil && *consentReq.Client.PolicyUri != "" { + templateFields["clientPolicy"] = *consentReq.Client.PolicyUri + } + if consentReq.Client.TosUri != nil && *consentReq.Client.TosUri != "" { + templateFields["clientTos"] = *consentReq.Client.TosUri + } ctx.HTML(http.StatusOK, "consent.tmpl", templateFields) global.Logger.Debugf("User should now see Consent UI.") diff --git a/handlers/consent/consent_confirm.go b/handlers/consent/consent_confirm.go index d93055d..63e06d8 100644 --- a/handlers/consent/consent_confirm.go +++ b/handlers/consent/consent_confirm.go @@ -12,9 +12,10 @@ import ( ) type ConsentConfirmRequest struct { - CSRF string `form:"_csrf"` - Remember bool `form:"remember"` - Action string `form:"action"` + CSRF string `form:"_csrf"` + Challenge string `form:"challenge"` + Remember bool `form:"remember"` + Action string `form:"action"` } func ConsentConfirm(ctx *gin.Context) { @@ -32,16 +33,23 @@ func ConsentConfirm(ctx *gin.Context) { // Validate CSRF global.Logger.Debugf("Validating CSRF...") - sessKey := fmt.Sprintf(consts.REDIS_KEY_CONSENT_CSRF, req.CSRF) - oauth2challenge, err := global.Redis.Get(context.Background(), sessKey).Result() + sessKey := fmt.Sprintf(consts.REDIS_KEY_CONSENT_CSRF, req.Challenge) + csrfSession, err := global.Redis.Get(context.Background(), sessKey).Result() if err != nil { global.Logger.Errorf("Failed to get csrf from redis with error: %v", err) ctx.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{ "error": "Failed to get csrf", }) return + } else if csrfSession != req.CSRF { + ctx.HTML(http.StatusForbidden, "error.tmpl", gin.H{ + "error": "CSRF not match", + }) + return } + oauth2challenge := req.Challenge + // Delete used challenge global.Redis.Del(context.Background(), sessKey) diff --git a/handlers/login/misskey_auth_callback.go b/handlers/login/misskey_auth_callback.go index bdfc35a..05635b5 100644 --- a/handlers/login/misskey_auth_callback.go +++ b/handlers/login/misskey_auth_callback.go @@ -9,7 +9,6 @@ import ( "misso/consts" "misso/global" "misso/misskey" - "misso/utils" "net/http" "time" ) @@ -62,9 +61,10 @@ func MisskeyAuthCallback(ctx *gin.Context) { return } - userid := fmt.Sprintf("%s@%s", usermeta.User.Username, config.Config.Misskey.Instance) + // Save user key + userIdentifier := fmt.Sprintf("%s@%s", usermeta.User.Username, config.Config.Misskey.Instance) - sessAccessTokenKey := fmt.Sprintf(consts.REDIS_KEY_SHARE_ACCESS_TOKEN, userid) + sessAccessTokenKey := fmt.Sprintf(consts.REDIS_KEY_USER_ACCESS_TOKEN, userIdentifier) err = global.Redis.Set(context.Background(), sessAccessTokenKey, usermeta.AccessToken, 0).Err() if err != nil { global.Logger.Errorf("Failed to save session access token into redis with error: %v", err) @@ -74,21 +74,11 @@ func MisskeyAuthCallback(ctx *gin.Context) { return } - // Save context into redis - err = utils.SaveUserinfo(userid, &usermeta.User) - if err != nil { - global.Logger.Errorf("Failed to save session user info into redis with error: %v", err) - ctx.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{ - "error": "Failed to save userinfo", - }) - return - } - global.Logger.Debugf("User accepted the request, reporting back to hydra...") remember := true rememberFor := int64(consts.TIME_LOGIN_REMEMBER / time.Second) acceptReq, _, err := global.Hydra.Admin.OAuth2Api.AcceptOAuth2LoginRequest(context.Background()).LoginChallenge(oauth2challenge).AcceptOAuth2LoginRequest(client.AcceptOAuth2LoginRequest{ - Subject: userid, + Subject: userIdentifier, Remember: &remember, RememberFor: &rememberFor, }).Execute() diff --git a/handlers/user/info.go b/handlers/user/info.go index a318dc4..a74c96f 100644 --- a/handlers/user/info.go +++ b/handlers/user/info.go @@ -4,17 +4,11 @@ import ( "context" "github.com/gin-gonic/gin" "misso/global" - "misso/types" "misso/utils" "net/http" "strings" ) -type UserinfoResponse struct { - types.MisskeyUser - EMail string `json:"email"` -} - func UserInfo(ctx *gin.Context) { // Get token from header accessToken := strings.Replace(ctx.GetHeader("Authorization"), "Bearer ", "", 1) @@ -45,7 +39,7 @@ func UserInfo(ctx *gin.Context) { // Return user info global.Logger.Debugf("Retrieving context...") - userinfoCtx, err := utils.GetUserinfo(*tokenInfo.Sub) + userinfo, err := utils.GetUserinfo(*tokenInfo.Sub) if err != nil { global.Logger.Errorf("Failed to retrieve userinfo with error: %v", err) ctx.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{ @@ -54,9 +48,19 @@ func UserInfo(ctx *gin.Context) { return } - ctx.JSON(http.StatusOK, UserinfoResponse{ - MisskeyUser: *userinfoCtx, - EMail: *tokenInfo.Sub, - }) + userinfoRes := gin.H{} // map[string]interface{} + + // Get scopes + if tokenInfo.Scope != nil && *tokenInfo.Scope != "" { + // Has scopes + scopes := strings.Split(*tokenInfo.Scope, " ") + for _, s := range scopes { + if value, ok := (*userinfo)[s]; ok { + userinfoRes[s] = value + } + } + } + + ctx.JSON(http.StatusOK, userinfoRes) } diff --git a/misskey/get_userkey.go b/misskey/get_userkey.go index a1befd1..3e00f84 100644 --- a/misskey/get_userkey.go +++ b/misskey/get_userkey.go @@ -11,8 +11,8 @@ type AuthSessionUserkey_Request struct { } type AuthSessionUserkey_Response struct { - AccessToken string `json:"accessToken"` - User types.MisskeyUser `json:"user"` + AccessToken string `json:"accessToken"` + User types.MisskeyUserBase `json:"user"` } func GetUserkey(token string) (*AuthSessionUserkey_Response, error) { diff --git a/templates/consent.tmpl b/templates/consent.tmpl index 6e6c878..c7c9349 100644 --- a/templates/consent.tmpl +++ b/templates/consent.tmpl @@ -1,11 +1,58 @@ {{ define "consent.tmpl" }} - + 授权确认 {{ template "head.tmpl" }} @@ -67,25 +114,65 @@
+ - {{ if .logo }} - {{ .clientName }} - {{ else }} - c-warning - {{ end }} + -

- 应用程序 - {{ .clientName }} - 正请求读取 - {{ .user.Name }} - 的信息 -

+
+

+ 应用程序 + {{ .clientName }} + 正请求 +
+ 读取 + {{ .user.name }} + 的这些信息: +

-

- - -

+
    + {{ $user := .user }} + {{ range $scope := .scopes }} +
  • +
    + {{ $scope }} +
    {{ index $user $scope }}
    +
    +
  • + {{ end }} +
+ + {{ if or .clientPolicy .clientTos }} + + {{ end }} +
+ +

diff --git a/templates/error.tmpl b/templates/error.tmpl index a5c80ef..b6e4d30 100644 --- a/templates/error.tmpl +++ b/templates/error.tmpl @@ -1,14 +1,30 @@ {{ define "error.tmpl" }} - + 出错了 {{ template "head.tmpl" }} +

- c-remove +

发生了一些错误

-

{{ .error }}

+

{{ .error }}

diff --git a/templates/head.tmpl b/templates/head.tmpl index ae72b1d..9654f5b 100644 --- a/templates/head.tmpl +++ b/templates/head.tmpl @@ -4,7 +4,7 @@ display: flex; align-items: center; justify-content: center; - background: #282c34; + background-color: #282c34; } #main { @@ -13,12 +13,23 @@ text-align: center; align-items: center; color: white; - padding: 40px; + padding: 80px 40px 40px 40px; background-color: #21252b; border-radius: 12px; margin: 0 40px; width: 100%; max-width: 480px; word-break: break-word; + position: relative; + } + + .logo { + position: absolute; + border: 10px solid #282c34; + top: -70px; + } + + .logo, .logo > * { + border-radius: 120px; } diff --git a/templates/index.tmpl b/templates/index.tmpl index 93e7b19..5438b73 100644 --- a/templates/index.tmpl +++ b/templates/index.tmpl @@ -1,5 +1,5 @@ {{ define "index.tmpl" }} - + MiSSO {{ template "head.tmpl" }} @@ -24,7 +24,15 @@
- access-key +

欢迎来到 MiSSO

直接访问这里好像不太对哦 diff --git a/types/MisskeyUser.go b/types/MisskeyUser.go index 25a7ca2..d089ac0 100644 --- a/types/MisskeyUser.go +++ b/types/MisskeyUser.go @@ -1,186 +1,8 @@ package types -import "time" - -type MisskeyUser struct { - Id string `json:"id"` - Name string `json:"name"` - Username string `json:"username"` - Host interface{} `json:"host"` - AvatarUrl string `json:"avatarUrl"` - AvatarBlurhash string `json:"avatarBlurhash"` - IsBot bool `json:"isBot"` - IsCat bool `json:"isCat"` - OnlineStatus string `json:"onlineStatus"` - Url interface{} `json:"url"` - Uri interface{} `json:"uri"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - LastFetchedAt interface{} `json:"lastFetchedAt"` - BannerUrl string `json:"bannerUrl"` - BannerBlurhash string `json:"bannerBlurhash"` - IsLocked bool `json:"isLocked"` - IsSilenced bool `json:"isSilenced"` - IsSuspended bool `json:"isSuspended"` - Description string `json:"description"` - Location string `json:"location"` - Birthday string `json:"birthday"` - Lang string `json:"lang"` - Fields []struct { - Name string `json:"name"` - Value string `json:"value"` - } `json:"fields"` - FollowersCount int `json:"followersCount"` - FollowingCount int `json:"followingCount"` - NotesCount int `json:"notesCount"` - PinnedNoteIds []string `json:"pinnedNoteIds"` - PinnedNotes []struct { - Id string `json:"id"` - CreatedAt time.Time `json:"createdAt"` - UserId string `json:"userId"` - User struct { - Id string `json:"id"` - Name string `json:"name"` - Username string `json:"username"` - Host interface{} `json:"host"` - AvatarUrl string `json:"avatarUrl"` - AvatarBlurhash string `json:"avatarBlurhash"` - IsBot bool `json:"isBot"` - IsCat bool `json:"isCat"` - OnlineStatus string `json:"onlineStatus"` - } `json:"user"` - Text string `json:"text"` - Cw *string `json:"cw"` - Visibility string `json:"visibility"` - LocalOnly bool `json:"localOnly"` - RenoteCount int `json:"renoteCount"` - RepliesCount int `json:"repliesCount"` - Reactions map[string]int `json:"reactions"` - FileIds []string `json:"fileIds"` - Files []struct { - Id string `json:"id"` - CreatedAt time.Time `json:"createdAt"` - Name string `json:"name"` - Type string `json:"type"` - Md5 string `json:"md5"` - Size int `json:"size"` - IsSensitive bool `json:"isSensitive"` - Blurhash string `json:"blurhash"` - Properties struct { - Width int `json:"width"` - Height int `json:"height"` - } `json:"properties"` - Url string `json:"url"` - ThumbnailUrl string `json:"thumbnailUrl"` - Comment interface{} `json:"comment"` - FolderId interface{} `json:"folderId"` - Folder interface{} `json:"folder"` - UserId interface{} `json:"userId"` - User interface{} `json:"user"` - } `json:"files"` - ReplyId interface{} `json:"replyId"` - RenoteId interface{} `json:"renoteId"` - MyReaction string `json:"myReaction,omitempty"` - } `json:"pinnedNotes"` - PinnedPageId string `json:"pinnedPageId"` - PinnedPage struct { - Id string `json:"id"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - UserId string `json:"userId"` - User struct { - Id string `json:"id"` - Name string `json:"name"` - Username string `json:"username"` - Host interface{} `json:"host"` - AvatarUrl string `json:"avatarUrl"` - AvatarBlurhash string `json:"avatarBlurhash"` - IsBot bool `json:"isBot"` - IsCat bool `json:"isCat"` - OnlineStatus string `json:"onlineStatus"` - } `json:"user"` - Content []struct { - Id string `json:"id"` - Text string `json:"text,omitempty"` - Type string `json:"type"` - Title string `json:"title,omitempty"` - } `json:"content"` - Variables []interface{} `json:"variables"` - Title string `json:"title"` - Name string `json:"name"` - Summary string `json:"summary"` - HideTitleWhenPinned bool `json:"hideTitleWhenPinned"` - AlignCenter bool `json:"alignCenter"` - Font string `json:"font"` - Script string `json:"script"` - EyeCatchingImageId string `json:"eyeCatchingImageId"` - EyeCatchingImage struct { - Id string `json:"id"` - CreatedAt time.Time `json:"createdAt"` - Name string `json:"name"` - Type string `json:"type"` - Md5 string `json:"md5"` - Size int `json:"size"` - IsSensitive bool `json:"isSensitive"` - Blurhash string `json:"blurhash"` - Properties struct { - Width int `json:"width"` - Height int `json:"height"` - } `json:"properties"` - Url string `json:"url"` - ThumbnailUrl string `json:"thumbnailUrl"` - Comment interface{} `json:"comment"` - FolderId interface{} `json:"folderId"` - Folder interface{} `json:"folder"` - UserId interface{} `json:"userId"` - User interface{} `json:"user"` - } `json:"eyeCatchingImage"` - AttachedFiles []interface{} `json:"attachedFiles"` - LikedCount int `json:"likedCount"` - IsLiked bool `json:"isLiked"` - } `json:"pinnedPage"` - PublicReactions bool `json:"publicReactions"` - FfVisibility string `json:"ffVisibility"` - TwoFactorEnabled bool `json:"twoFactorEnabled"` - UsePasswordLessLogin bool `json:"usePasswordLessLogin"` - SecurityKeys bool `json:"securityKeys"` - Roles []struct { - Id string `json:"id"` - Name string `json:"name"` - Color string `json:"color"` - Description string `json:"description"` - IsModerator bool `json:"isModerator"` - IsAdministrator bool `json:"isAdministrator"` - } `json:"roles"` - AvatarId string `json:"avatarId"` - BannerId string `json:"bannerId"` - IsModerator bool `json:"isModerator"` - IsAdmin bool `json:"isAdmin"` - InjectFeaturedNote bool `json:"injectFeaturedNote"` - ReceiveAnnouncementEmail bool `json:"receiveAnnouncementEmail"` - AlwaysMarkNsfw bool `json:"alwaysMarkNsfw"` - AutoSensitive bool `json:"autoSensitive"` - CarefulBot bool `json:"carefulBot"` - AutoAcceptFollowed bool `json:"autoAcceptFollowed"` - NoCrawle bool `json:"noCrawle"` - IsExplorable bool `json:"isExplorable"` - IsDeleted bool `json:"isDeleted"` - HideOnlineStatus bool `json:"hideOnlineStatus"` - HasUnreadSpecifiedNotes bool `json:"hasUnreadSpecifiedNotes"` - HasUnreadMentions bool `json:"hasUnreadMentions"` - HasUnreadAnnouncement bool `json:"hasUnreadAnnouncement"` - HasUnreadAntenna bool `json:"hasUnreadAntenna"` - HasUnreadChannel bool `json:"hasUnreadChannel"` - HasUnreadMessagingMessage bool `json:"hasUnreadMessagingMessage"` - HasUnreadNotification bool `json:"hasUnreadNotification"` - HasPendingReceivedFollowRequest bool `json:"hasPendingReceivedFollowRequest"` - Integrations struct { - } `json:"integrations"` - MutedWords [][]string `json:"mutedWords"` - MutedInstances []string `json:"mutedInstances"` - MutingNotificationTypes []string `json:"mutingNotificationTypes"` - EmailNotificationTypes []string `json:"emailNotificationTypes"` - ShowTimelineReplies bool `json:"showTimelineReplies"` +type MisskeyUserBase struct { + Username string `json:"username"` + // Ignore other fields } -// TODO: Find a better way to split necessary fields and additional fields +type MisskeyUser = map[string]interface{} // Just raw json map diff --git a/utils/get_userinfo.go b/utils/get_userinfo.go index 5d269d1..7c3700c 100644 --- a/utils/get_userinfo.go +++ b/utils/get_userinfo.go @@ -13,7 +13,7 @@ import ( 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) + userinfoCacheKey := fmt.Sprintf(consts.REDIS_KEY_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) @@ -38,7 +38,7 @@ func GetUserinfo(subject string) (*types.MisskeyUser, error) { // 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) + accessTokenCacheKey := fmt.Sprintf(consts.REDIS_KEY_USER_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) @@ -52,6 +52,9 @@ func GetUserinfo(subject string) (*types.MisskeyUser, error) { return nil, err } + // Append subject as email to userinfo + (*userinfo)["email"] = subject + // Save userinfo into redis _ = SaveUserinfo(subject, userinfo) // Ignore errors diff --git a/utils/save_userinfo.go b/utils/save_userinfo.go index d77819c..4b309d6 100644 --- a/utils/save_userinfo.go +++ b/utils/save_userinfo.go @@ -15,7 +15,7 @@ func SaveUserinfo(subject string, userinfo *types.MisskeyUser) error { global.Logger.Errorf("Failed to parse accept context with error: %v", err) return err } - sessUserInfoKey := fmt.Sprintf(consts.REDIS_KEY_SHARE_USER_INFO, subject) + sessUserInfoKey := fmt.Sprintf(consts.REDIS_KEY_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) From a04c5b062e79cd1633b0e713a9bfe670c3703e39 Mon Sep 17 00:00:00 2001 From: Nya Candy Date: Sun, 29 Jan 2023 14:55:56 +0800 Subject: [PATCH 02/10] feat: configurable timings --- .config/misso.yml.example | 5 +++++ consts/time.go | 10 ++++------ handlers/consent/consent_check.go | 4 +++- handlers/consent/consent_confirm.go | 6 +++--- handlers/login/login.go | 4 +++- handlers/login/misskey_auth_callback.go | 19 ++++++++++--------- inits/config.go | 17 +++++++++++++++++ types/Config.go | 6 ++++++ utils/save_userinfo.go | 4 +++- 9 files changed, 54 insertions(+), 21 deletions(-) diff --git a/.config/misso.yml.example b/.config/misso.yml.example index dd581b3..79ef846 100644 --- a/.config/misso.yml.example +++ b/.config/misso.yml.example @@ -7,3 +7,8 @@ misskey: secret: "" hydra: admin_url: "http://localhost:4445" +time: + request_valid: 3600 + login_remember: 600 + consent_remember: 0 + userinfo_cache: 3600 diff --git a/consts/time.go b/consts/time.go index 309757e..dda9e94 100644 --- a/consts/time.go +++ b/consts/time.go @@ -1,12 +1,10 @@ package consts -import "time" - const ( - TIME_REQUEST_VALID = 1 * time.Hour + TIME_DEFAULT_REQUEST_VALID = 3600 // 1 Hour - TIME_LOGIN_REMEMBER = 10 * time.Minute - TIME_CONSENT_REMEMBER = 0 // Forever + TIME_DEFAULT_LOGIN_REMEMBER = 600 // 10 Minute + TIME_DEFAULT_CONSENT_REMEMBER = 0 // Forever - TIME_USERINFO_CACHE = 1 * time.Hour + TIME_DEFAULT_USERINFO_CACHE = 3600 // 1 Hour ) diff --git a/handlers/consent/consent_check.go b/handlers/consent/consent_check.go index 6b8c027..0b5bd09 100644 --- a/handlers/consent/consent_check.go +++ b/handlers/consent/consent_check.go @@ -5,10 +5,12 @@ import ( "fmt" "github.com/gin-gonic/gin" client "github.com/ory/hydra-client-go/v2" + "misso/config" "misso/consts" "misso/global" "misso/utils" "net/http" + "time" ) func ConsentCheck(ctx *gin.Context) { @@ -57,7 +59,7 @@ func ConsentCheck(ctx *gin.Context) { global.Logger.Debugf("Generating CSRF token...") csrf := utils.RandString(32) sessKey := fmt.Sprintf(consts.REDIS_KEY_CONSENT_CSRF, oauth2challenge) - err := global.Redis.Set(context.Background(), sessKey, csrf, consts.TIME_REQUEST_VALID).Err() + err := global.Redis.Set(context.Background(), sessKey, csrf, time.Duration(config.Config.Time.RequestValid)*time.Second).Err() if err != nil { global.Logger.Errorf("Failed to save csrf into redis with error: %v", err) ctx.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{ diff --git a/handlers/consent/consent_confirm.go b/handlers/consent/consent_confirm.go index 63e06d8..7591eb8 100644 --- a/handlers/consent/consent_confirm.go +++ b/handlers/consent/consent_confirm.go @@ -5,10 +5,10 @@ import ( "fmt" "github.com/gin-gonic/gin" client "github.com/ory/hydra-client-go/v2" + "misso/config" "misso/consts" "misso/global" "net/http" - "time" ) type ConsentConfirmRequest struct { @@ -88,9 +88,9 @@ func ConsentConfirm(ctx *gin.Context) { global.Logger.Debugf("User accepted the request, reporting back to hydra...") global.Logger.Debugf("Initializing ID Token...") - rememberFor := int64(consts.TIME_CONSENT_REMEMBER / time.Second) // Remember forever + rememberFor := config.Config.Time.ConsentRemember // Remember forever acceptReq, _, err := global.Hydra.Admin.OAuth2Api.AcceptOAuth2ConsentRequest(context.Background()).ConsentChallenge(oauth2challenge).AcceptOAuth2ConsentRequest(client.AcceptOAuth2ConsentRequest{ - GrantScope: consentReq.RequestedScope, // TODO: Specify scopes + GrantScope: consentReq.RequestedScope, GrantAccessTokenAudience: consentReq.RequestedAccessTokenAudience, Remember: &req.Remember, RememberFor: &rememberFor, diff --git a/handlers/login/login.go b/handlers/login/login.go index a5bac0f..68756f9 100644 --- a/handlers/login/login.go +++ b/handlers/login/login.go @@ -5,10 +5,12 @@ import ( "fmt" "github.com/gin-gonic/gin" client "github.com/ory/hydra-client-go/v2" + "misso/config" "misso/consts" "misso/global" "misso/misskey" "net/http" + "time" ) func Login(ctx *gin.Context) { @@ -69,7 +71,7 @@ func Login(ctx *gin.Context) { // Save login challenge state into redis (misskey cannot keep state info) sessKey := fmt.Sprintf(consts.REDIS_KEY_LOGIN_SESSION, authSess.Token) - err = global.Redis.Set(context.Background(), sessKey, oauth2challenge, consts.TIME_REQUEST_VALID).Err() + err = global.Redis.Set(context.Background(), sessKey, oauth2challenge, time.Duration(config.Config.Time.RequestValid)*time.Second).Err() if err != nil { global.Logger.Errorf("Failed to save session into redis with error: %v", err) ctx.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{ diff --git a/handlers/login/misskey_auth_callback.go b/handlers/login/misskey_auth_callback.go index 05635b5..a9c0b32 100644 --- a/handlers/login/misskey_auth_callback.go +++ b/handlers/login/misskey_auth_callback.go @@ -10,7 +10,6 @@ import ( "misso/global" "misso/misskey" "net/http" - "time" ) func MisskeyAuthCallback(ctx *gin.Context) { @@ -75,13 +74,15 @@ func MisskeyAuthCallback(ctx *gin.Context) { } global.Logger.Debugf("User accepted the request, reporting back to hydra...") - remember := true - rememberFor := int64(consts.TIME_LOGIN_REMEMBER / time.Second) - acceptReq, _, err := global.Hydra.Admin.OAuth2Api.AcceptOAuth2LoginRequest(context.Background()).LoginChallenge(oauth2challenge).AcceptOAuth2LoginRequest(client.AcceptOAuth2LoginRequest{ - Subject: userIdentifier, - Remember: &remember, - RememberFor: &rememberFor, - }).Execute() + acceptReq := client.AcceptOAuth2LoginRequest{ + Subject: userIdentifier, + } + if config.Config.Time.LoginRemember > 0 { + remember := true + acceptReq.Remember = &remember + acceptReq.RememberFor = &config.Config.Time.LoginRemember + } + acceptRes, _, err := global.Hydra.Admin.OAuth2Api.AcceptOAuth2LoginRequest(context.Background()).LoginChallenge(oauth2challenge).AcceptOAuth2LoginRequest(acceptReq).Execute() if err != nil { global.Logger.Errorf("Failed to accept login request with error: %v", err) ctx.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{ @@ -91,7 +92,7 @@ func MisskeyAuthCallback(ctx *gin.Context) { } // Redirect to target uri - ctx.Redirect(http.StatusTemporaryRedirect, acceptReq.RedirectTo) + ctx.Redirect(http.StatusTemporaryRedirect, acceptRes.RedirectTo) global.Logger.Debugf("User should now be redirecting to target URI.") diff --git a/inits/config.go b/inits/config.go index f7b74d7..a63c42a 100644 --- a/inits/config.go +++ b/inits/config.go @@ -3,6 +3,7 @@ package inits import ( "gopkg.in/yaml.v3" "misso/config" + "misso/consts" "os" ) @@ -23,5 +24,21 @@ func Config() error { return err } + // Validate time + if config.Config.Time.RequestValid <= 0 { + config.Config.Time.RequestValid = consts.TIME_DEFAULT_REQUEST_VALID + } + if config.Config.Time.LoginRemember < 0 { + // 0 means don't remember (in extreme account switch situations) + config.Config.Time.LoginRemember = consts.TIME_DEFAULT_LOGIN_REMEMBER + } + if config.Config.Time.ConsentRemember < 0 { + // 0 means remember forever (default behavior) + config.Config.Time.ConsentRemember = consts.TIME_DEFAULT_CONSENT_REMEMBER + } + if config.Config.Time.UserinfoCache <= 0 { + config.Config.Time.UserinfoCache = consts.TIME_DEFAULT_USERINFO_CACHE + } + return nil } diff --git a/types/Config.go b/types/Config.go index 99d0e59..9b98f97 100644 --- a/types/Config.go +++ b/types/Config.go @@ -14,4 +14,10 @@ type Config struct { Hydra struct { AdminUrl string `yaml:"admin_url"` } `yaml:"hydra"` + Time struct { + RequestValid int64 `yaml:"request_valid"` + LoginRemember int64 `yaml:"login_remember"` + ConsentRemember int64 `yaml:"consent_remember"` + UserinfoCache int64 `yaml:"userinfo_cache"` + } `yaml:"time"` } diff --git a/utils/save_userinfo.go b/utils/save_userinfo.go index 4b309d6..9c25e03 100644 --- a/utils/save_userinfo.go +++ b/utils/save_userinfo.go @@ -4,9 +4,11 @@ import ( "context" "encoding/json" "fmt" + "misso/config" "misso/consts" "misso/global" "misso/types" + "time" ) func SaveUserinfo(subject string, userinfo *types.MisskeyUser) error { @@ -16,7 +18,7 @@ func SaveUserinfo(subject string, userinfo *types.MisskeyUser) error { return err } sessUserInfoKey := fmt.Sprintf(consts.REDIS_KEY_USER_INFO, subject) - err = global.Redis.Set(context.Background(), sessUserInfoKey, userinfoBytes, consts.TIME_USERINFO_CACHE).Err() + err = global.Redis.Set(context.Background(), sessUserInfoKey, userinfoBytes, time.Duration(config.Config.Time.UserinfoCache)*time.Second).Err() if err != nil { global.Logger.Errorf("Failed to save session user info into redis with error: %v", err) return err From 369db325693e995cc7b1baae586d6d3719803a1a Mon Sep 17 00:00:00 2001 From: Nya Candy Date: Sun, 29 Jan 2023 14:57:31 +0800 Subject: [PATCH 03/10] fix: page not full on firefox --- templates/head.tmpl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/templates/head.tmpl b/templates/head.tmpl index 9654f5b..9df8e47 100644 --- a/templates/head.tmpl +++ b/templates/head.tmpl @@ -1,5 +1,11 @@