From 4f1425febf6efb45eaf91aff19b215b8c7e77bec Mon Sep 17 00:00:00 2001 From: r Date: Sat, 30 Jan 2021 16:51:09 +0000 Subject: Add filters --- service/service.go | 25 +++++++++++++++++++++++++ service/transport.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) (limited to 'service') diff --git a/service/service.go b/service/service.go index ce689fd..8149f33 100644 --- a/service/service.go +++ b/service/service.go @@ -641,6 +641,22 @@ func (s *service) SettingsPage(c *client) (err error) { return s.renderer.Render(rCtx, c, renderer.SettingsPage, data) } +func (svc *service) FiltersPage(c *client) (err error) { + filters, err := c.GetFilters(ctx) + if err != nil { + return + } + + commonData := svc.getCommonData(c, "filters") + data := &renderer.FiltersData{ + CommonData: commonData, + Filters: filters, + } + + rCtx := getRendererContext(c) + return svc.renderer.Render(rCtx, c, renderer.FiltersPage, data) +} + func (s *service) SingleInstance() (instance string, ok bool) { if len(s.singleInstance) > 0 { instance = s.singleInstance @@ -908,3 +924,12 @@ func (s *service) UnBookmark(c *client, id string) (err error) { _, err = c.Unbookmark(ctx, id) return } + +func (svc *service) Filter(c *client, phrase string, wholeWord bool) (err error) { + fctx := []string{"home", "notifications", "public", "thread"} + return c.AddFilter(ctx, phrase, fctx, true, wholeWord, nil) +} + +func (svc *service) UnFilter(c *client, id string) (err error) { + return c.RemoveFilter(ctx, id) +} diff --git a/service/transport.go b/service/transport.go index 096b44e..1180f6c 100644 --- a/service/transport.go +++ b/service/transport.go @@ -262,6 +262,10 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { return s.SettingsPage(c) }, SESSION, HTML) + filtersPage := handle(func(c *client) error { + return s.FiltersPage(c) + }, SESSION, HTML) + signin := handle(func(c *client) error { instance := c.Req.FormValue("instance") url, sid, err := s.NewSession(instance) @@ -589,6 +593,27 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { return nil }, CSRF, HTML) + filter := handle(func(c *client) error { + phrase := c.Req.FormValue("phrase") + wholeWord := c.Req.FormValue("whole_word") == "true" + err := s.Filter(c, phrase, wholeWord) + if err != nil { + return err + } + redirect(c, c.Req.FormValue("referrer")) + return nil + }, CSRF, HTML) + + unFilter := handle(func(c *client) error { + id, _ := mux.Vars(c.Req)["id"] + err := s.UnFilter(c, id) + if err != nil { + return err + } + redirect(c, c.Req.FormValue("referrer")) + return nil + }, CSRF, HTML) + signout := handle(func(c *client) error { s.Signout(c) setSessionCookie(c, "", 0) @@ -648,6 +673,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { r.HandleFunc("/emojis", emojisPage).Methods(http.MethodGet) r.HandleFunc("/search", searchPage).Methods(http.MethodGet) r.HandleFunc("/settings", settingsPage).Methods(http.MethodGet) + r.HandleFunc("/filters", filtersPage).Methods(http.MethodGet) r.HandleFunc("/signin", signin).Methods(http.MethodPost) r.HandleFunc("/oauth_callback", oauthCallback).Methods(http.MethodGet) r.HandleFunc("/post", post).Methods(http.MethodPost) @@ -673,6 +699,8 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { r.HandleFunc("/notifications/read", readNotifications).Methods(http.MethodPost) r.HandleFunc("/bookmark/{id}", bookmark).Methods(http.MethodPost) r.HandleFunc("/unbookmark/{id}", unBookmark).Methods(http.MethodPost) + r.HandleFunc("/filter", filter).Methods(http.MethodPost) + r.HandleFunc("/unfilter/{id}", unFilter).Methods(http.MethodPost) r.HandleFunc("/signout", signout).Methods(http.MethodPost) r.HandleFunc("/fluoride/like/{id}", fLike).Methods(http.MethodPost) r.HandleFunc("/fluoride/unlike/{id}", fUnlike).Methods(http.MethodPost) -- cgit v1.2.3 From 6ddcb16694424ec5da9311d81388676e55700290 Mon Sep 17 00:00:00 2001 From: r Date: Sat, 30 Jan 2021 16:54:37 +0000 Subject: Add username to page title Makes it easier to search a user page in browser history --- service/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'service') diff --git a/service/service.go b/service/service.go index 8149f33..ebfc8c7 100644 --- a/service/service.go +++ b/service/service.go @@ -508,7 +508,7 @@ func (s *service) UserPage(c *client, id string, pageType string, } } - commonData := s.getCommonData(c, user.DisplayName) + commonData := s.getCommonData(c, user.DisplayName+" @"+user.Acct) data := &renderer.UserData{ User: user, IsCurrent: isCurrent, -- cgit v1.2.3 From 6c5de7656257ffd8f2dcc441a313ab9aed97e834 Mon Sep 17 00:00:00 2001 From: r Date: Sat, 20 Mar 2021 05:12:48 +0000 Subject: Refactor --- service/service.go | 467 +++++++++++++++++++++++++-------------------------- service/transport.go | 301 +++++++++++++++------------------ 2 files changed, 361 insertions(+), 407 deletions(-) (limited to 'service') diff --git a/service/service.go b/service/service.go index ebfc8c7..1028765 100644 --- a/service/service.go +++ b/service/service.go @@ -1,7 +1,6 @@ package service import ( - "context" "errors" "fmt" "html/template" @@ -16,146 +15,145 @@ import ( ) var ( - ctx = context.Background() - errInvalidArgument = errors.New("invalid argument") + errInvalidArgument = errors.New("invalid argument") + errInvalidSession = errors.New("invalid session") + errInvalidCSRFToken = errors.New("invalid csrf token") ) type service struct { - clientName string - clientScope string - clientWebsite string - customCSS string - postFormats []model.PostFormat - renderer renderer.Renderer - sessionRepo model.SessionRepo - appRepo model.AppRepo - singleInstance string -} - -func NewService(clientName string, - clientScope string, - clientWebsite string, - customCSS string, - postFormats []model.PostFormat, - renderer renderer.Renderer, - sessionRepo model.SessionRepo, - appRepo model.AppRepo, - singleInstance string, -) *service { + cname string + cscope string + cwebsite string + css string + instance string + postFormats []model.PostFormat + renderer renderer.Renderer + sessionRepo model.SessionRepo + appRepo model.AppRepo +} + +func NewService(cname string, cscope string, cwebsite string, + css string, instance string, postFormats []model.PostFormat, + renderer renderer.Renderer, sessionRepo model.SessionRepo, + appRepo model.AppRepo) *service { return &service{ - clientName: clientName, - clientScope: clientScope, - clientWebsite: clientWebsite, - customCSS: customCSS, - postFormats: postFormats, - renderer: renderer, - sessionRepo: sessionRepo, - appRepo: appRepo, - singleInstance: singleInstance, - } -} - -func getRendererContext(c *client) *renderer.Context { - var settings model.Settings - var session model.Session - var referrer string - if c != nil { - settings = c.Session.Settings - session = c.Session - referrer = c.url() - } else { - settings = *model.NewSettings() + cname: cname, + cscope: cscope, + cwebsite: cwebsite, + css: css, + instance: instance, + postFormats: postFormats, + renderer: renderer, + sessionRepo: sessionRepo, + appRepo: appRepo, + } +} + +func (s *service) authenticate(c *client, sid string, csrf string, ref string, t int) (err error) { + var sett *model.Settings + defer func() { + if sett == nil { + sett = model.NewSettings() + } + c.rctx = &renderer.Context{ + HideAttachments: sett.HideAttachments, + MaskNSFW: sett.MaskNSFW, + ThreadInNewTab: sett.ThreadInNewTab, + FluorideMode: sett.FluorideMode, + DarkMode: sett.DarkMode, + CSRFToken: c.s.CSRFToken, + UserID: c.s.UserID, + AntiDopamineMode: sett.AntiDopamineMode, + Referrer: ref, + } + }() + if t < SESSION { + return } - return &renderer.Context{ - HideAttachments: settings.HideAttachments, - MaskNSFW: settings.MaskNSFW, - ThreadInNewTab: settings.ThreadInNewTab, - FluorideMode: settings.FluorideMode, - DarkMode: settings.DarkMode, - CSRFToken: session.CSRFToken, - UserID: session.UserID, - AntiDopamineMode: settings.AntiDopamineMode, - Referrer: referrer, + if len(sid) < 1 { + return errInvalidSession } -} - -func addToReplyMap(m map[string][]mastodon.ReplyInfo, key interface{}, - val string, number int) { - if key == nil { - return + c.s, err = s.sessionRepo.Get(sid) + if err != nil { + return errInvalidSession } - keyStr, ok := key.(string) - if !ok { - return + sett = &c.s.Settings + app, err := s.appRepo.Get(c.s.InstanceDomain) + if err != nil { + return err } - _, ok = m[keyStr] - if !ok { - m[keyStr] = []mastodon.ReplyInfo{} + c.Client = mastodon.NewClient(&mastodon.Config{ + Server: app.InstanceURL, + ClientID: app.ClientID, + ClientSecret: app.ClientSecret, + AccessToken: c.s.AccessToken, + }) + if t >= CSRF && (len(csrf) < 1 || csrf != c.s.CSRFToken) { + return errInvalidCSRFToken } - m[keyStr] = append(m[keyStr], mastodon.ReplyInfo{val, number}) + return } -func (s *service) getCommonData(c *client, title string) (data *renderer.CommonData) { +func (s *service) cdata(c *client, title string, count int, rinterval int, + target string) (data *renderer.CommonData) { data = &renderer.CommonData{ - Title: title + " - " + s.clientName, - CustomCSS: s.customCSS, + Title: title + " - " + s.cname, + CustomCSS: s.css, + Count: count, + RefreshInterval: rinterval, + Target: target, } - if c != nil && c.Session.IsLoggedIn() { - data.CSRFToken = c.Session.CSRFToken + if c != nil && c.s.IsLoggedIn() { + data.CSRFToken = c.s.CSRFToken } return } -func (s *service) ErrorPage(c *client, err error) { +func (s *service) ErrorPage(c *client, err error) error { var errStr string if err != nil { errStr = err.Error() } - commonData := s.getCommonData(nil, "error") + cdata := s.cdata(nil, "error", 0, 0, "") data := &renderer.ErrorData{ - CommonData: commonData, + CommonData: cdata, Error: errStr, } - rCtx := getRendererContext(c) - s.renderer.Render(rCtx, c, renderer.ErrorPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.ErrorPage, data) } func (s *service) SigninPage(c *client) (err error) { - commonData := s.getCommonData(nil, "signin") + cdata := s.cdata(nil, "signin", 0, 0, "") data := &renderer.SigninData{ - CommonData: commonData, + CommonData: cdata, } - rCtx := getRendererContext(nil) - return s.renderer.Render(rCtx, c, renderer.SigninPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.SigninPage, data) } func (s *service) RootPage(c *client) (err error) { data := &renderer.RootData{ - Title: s.clientName, + Title: s.cname, } - rCtx := getRendererContext(c) - return s.renderer.Render(rCtx, c, renderer.RootPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.RootPage, data) } func (s *service) NavPage(c *client) (err error) { - u, err := c.GetAccountCurrentUser(ctx) + u, err := c.GetAccountCurrentUser(c.ctx) if err != nil { return } - postContext := model.PostContext{ - DefaultVisibility: c.Session.Settings.DefaultVisibility, - DefaultFormat: c.Session.Settings.DefaultFormat, + pctx := model.PostContext{ + DefaultVisibility: c.s.Settings.DefaultVisibility, + DefaultFormat: c.s.Settings.DefaultFormat, Formats: s.postFormats, } - commonData := s.getCommonData(c, "nav") - commonData.Target = "main" + cdata := s.cdata(c, "nav", 0, 0, "main") data := &renderer.NavData{ User: u, - CommonData: commonData, - PostContext: postContext, + CommonData: cdata, + PostContext: pctx, } - rCtx := getRendererContext(c) - return s.renderer.Render(rCtx, c, renderer.NavPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.NavPage, data) } func (s *service) TimelinePage(c *client, tType string, instance string, @@ -173,21 +171,21 @@ func (s *service) TimelinePage(c *client, tType string, instance string, default: return errInvalidArgument case "home": - statuses, err = c.GetTimelineHome(ctx, &pg) + statuses, err = c.GetTimelineHome(c.ctx, &pg) title = "Timeline" case "direct": - statuses, err = c.GetTimelineDirect(ctx, &pg) + statuses, err = c.GetTimelineDirect(c.ctx, &pg) title = "Direct Timeline" case "local": - statuses, err = c.GetTimelinePublic(ctx, true, "", &pg) + statuses, err = c.GetTimelinePublic(c.ctx, true, "", &pg) title = "Local Timeline" case "remote": if len(instance) > 0 { - statuses, err = c.GetTimelinePublic(ctx, false, instance, &pg) + statuses, err = c.GetTimelinePublic(c.ctx, false, instance, &pg) } title = "Remote Timeline" case "twkn": - statuses, err = c.GetTimelinePublic(ctx, false, "", &pg) + statuses, err = c.GetTimelinePublic(c.ctx, false, "", &pg) title = "The Whole Known Network" } if err != nil { @@ -218,7 +216,7 @@ func (s *service) TimelinePage(c *client, tType string, instance string, nextLink = "/timeline/" + tType + "?" + v.Encode() } - commonData := s.getCommonData(c, tType+" timeline ") + cdata := s.cdata(c, tType+" timeline ", 0, 0, "") data := &renderer.TimelineData{ Title: title, Type: tType, @@ -226,17 +224,31 @@ func (s *service) TimelinePage(c *client, tType string, instance string, Statuses: statuses, NextLink: nextLink, PrevLink: prevLink, - CommonData: commonData, + CommonData: cdata, } + return s.renderer.Render(c.rctx, c.w, renderer.TimelinePage, data) +} - rCtx := getRendererContext(c) - return s.renderer.Render(rCtx, c, renderer.TimelinePage, data) +func addToReplyMap(m map[string][]mastodon.ReplyInfo, key interface{}, + val string, number int) { + if key == nil { + return + } + keyStr, ok := key.(string) + if !ok { + return + } + _, ok = m[keyStr] + if !ok { + m[keyStr] = []mastodon.ReplyInfo{} + } + m[keyStr] = append(m[keyStr], mastodon.ReplyInfo{val, number}) } func (s *service) ThreadPage(c *client, id string, reply bool) (err error) { - var postContext model.PostContext + var pctx model.PostContext - status, err := c.GetStatus(ctx, id) + status, err := c.GetStatus(c.ctx, id) if err != nil { return } @@ -244,26 +256,26 @@ func (s *service) ThreadPage(c *client, id string, reply bool) (err error) { if reply { var content string var visibility string - if c.Session.UserID != status.Account.ID { + if c.s.UserID != status.Account.ID { content += "@" + status.Account.Acct + " " } for i := range status.Mentions { - if status.Mentions[i].ID != c.Session.UserID && + if status.Mentions[i].ID != c.s.UserID && status.Mentions[i].ID != status.Account.ID { content += "@" + status.Mentions[i].Acct + " " } } isDirect := status.Visibility == "direct" - if isDirect || c.Session.Settings.CopyScope { + if isDirect || c.s.Settings.CopyScope { visibility = status.Visibility } else { - visibility = c.Session.Settings.DefaultVisibility + visibility = c.s.Settings.DefaultVisibility } - postContext = model.PostContext{ + pctx = model.PostContext{ DefaultVisibility: visibility, - DefaultFormat: c.Session.Settings.DefaultFormat, + DefaultFormat: c.s.Settings.DefaultFormat, Formats: s.postFormats, ReplyContext: &model.ReplyContext{ InReplyToID: id, @@ -274,7 +286,7 @@ func (s *service) ThreadPage(c *client, id string, reply bool) (err error) { } } - context, err := c.GetStatusContext(ctx, id) + context, err := c.GetStatusContext(c.ctx, id) if err != nil { return } @@ -293,44 +305,40 @@ func (s *service) ThreadPage(c *client, id string, reply bool) (err error) { addToReplyMap(replies, statuses[i].InReplyToID, statuses[i].ID, i+1) } - commonData := s.getCommonData(c, "post by "+status.Account.DisplayName) + cdata := s.cdata(c, "post by "+status.Account.DisplayName, 0, 0, "") data := &renderer.ThreadData{ Statuses: statuses, - PostContext: postContext, + PostContext: pctx, ReplyMap: replies, - CommonData: commonData, + CommonData: cdata, } - - rCtx := getRendererContext(c) - return s.renderer.Render(rCtx, c, renderer.ThreadPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.ThreadPage, data) } func (s *service) LikedByPage(c *client, id string) (err error) { - likers, err := c.GetFavouritedBy(ctx, id, nil) + likers, err := c.GetFavouritedBy(c.ctx, id, nil) if err != nil { return } - commonData := s.getCommonData(c, "likes") + cdata := s.cdata(c, "likes", 0, 0, "") data := &renderer.LikedByData{ - CommonData: commonData, + CommonData: cdata, Users: likers, } - rCtx := getRendererContext(c) - return s.renderer.Render(rCtx, c, renderer.LikedByPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.LikedByPage, data) } func (s *service) RetweetedByPage(c *client, id string) (err error) { - retweeters, err := c.GetRebloggedBy(ctx, id, nil) + retweeters, err := c.GetRebloggedBy(c.ctx, id, nil) if err != nil { return } - commonData := s.getCommonData(c, "retweets") + cdata := s.cdata(c, "retweets", 0, 0, "") data := &renderer.RetweetedByData{ - CommonData: commonData, + CommonData: cdata, Users: retweeters, } - rCtx := getRendererContext(c) - return s.renderer.Render(rCtx, c, renderer.RetweetedByPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.RetweetedByPage, data) } func (s *service) NotificationPage(c *client, maxID string, @@ -346,11 +354,11 @@ func (s *service) NotificationPage(c *client, maxID string, Limit: 20, } - if c.Session.Settings.AntiDopamineMode { + if c.s.Settings.AntiDopamineMode { excludes = []string{"follow", "favourite", "reblog"} } - notifications, err := c.GetNotifications(ctx, &pg, excludes) + notifications, err := c.GetNotifications(c.ctx, &pg, excludes) if err != nil { return } @@ -368,19 +376,16 @@ func (s *service) NotificationPage(c *client, maxID string, nextLink = "/notifications?max_id=" + pg.MaxID } - commonData := s.getCommonData(c, "notifications") - commonData.RefreshInterval = c.Session.Settings.NotificationInterval - commonData.Target = "main" - commonData.Count = unreadCount + cdata := s.cdata(c, "notifications", unreadCount, + c.s.Settings.NotificationInterval, "main") data := &renderer.NotificationData{ Notifications: notifications, UnreadCount: unreadCount, ReadID: readID, NextLink: nextLink, - CommonData: commonData, + CommonData: cdata, } - rCtx := getRendererContext(c) - return s.renderer.Render(rCtx, c, renderer.NotificationPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.NotificationPage, data) } func (s *service) UserPage(c *client, id string, pageType string, @@ -395,15 +400,15 @@ func (s *service) UserPage(c *client, id string, pageType string, Limit: 20, } - user, err := c.GetAccount(ctx, id) + user, err := c.GetAccount(c.ctx, id) if err != nil { return } - isCurrent := c.Session.UserID == user.ID + isCurrent := c.s.UserID == user.ID switch pageType { case "": - statuses, err = c.GetAccountStatuses(ctx, id, false, &pg) + statuses, err = c.GetAccountStatuses(c.ctx, id, false, &pg) if err != nil { return } @@ -412,7 +417,7 @@ func (s *service) UserPage(c *client, id string, pageType string, pg.MaxID) } case "following": - users, err = c.GetAccountFollowing(ctx, id, &pg) + users, err = c.GetAccountFollowing(c.ctx, id, &pg) if err != nil { return } @@ -421,7 +426,7 @@ func (s *service) UserPage(c *client, id string, pageType string, id, pg.MaxID) } case "followers": - users, err = c.GetAccountFollowers(ctx, id, &pg) + users, err = c.GetAccountFollowers(c.ctx, id, &pg) if err != nil { return } @@ -430,7 +435,7 @@ func (s *service) UserPage(c *client, id string, pageType string, id, pg.MaxID) } case "media": - statuses, err = c.GetAccountStatuses(ctx, id, true, &pg) + statuses, err = c.GetAccountStatuses(c.ctx, id, true, &pg) if err != nil { return } @@ -442,7 +447,7 @@ func (s *service) UserPage(c *client, id string, pageType string, if !isCurrent { return errInvalidArgument } - statuses, err = c.GetBookmarks(ctx, &pg) + statuses, err = c.GetBookmarks(c.ctx, &pg) if err != nil { return } @@ -454,7 +459,7 @@ func (s *service) UserPage(c *client, id string, pageType string, if !isCurrent { return errInvalidArgument } - users, err = c.GetMutes(ctx, &pg) + users, err = c.GetMutes(c.ctx, &pg) if err != nil { return } @@ -466,7 +471,7 @@ func (s *service) UserPage(c *client, id string, pageType string, if !isCurrent { return errInvalidArgument } - users, err = c.GetBlocks(ctx, &pg) + users, err = c.GetBlocks(c.ctx, &pg) if err != nil { return } @@ -478,7 +483,7 @@ func (s *service) UserPage(c *client, id string, pageType string, if !isCurrent { return errInvalidArgument } - statuses, err = c.GetFavourites(ctx, &pg) + statuses, err = c.GetFavourites(c.ctx, &pg) if err != nil { return } @@ -490,7 +495,7 @@ func (s *service) UserPage(c *client, id string, pageType string, if !isCurrent { return errInvalidArgument } - users, err = c.GetFollowRequests(ctx, &pg) + users, err = c.GetFollowRequests(c.ctx, &pg) if err != nil { return } @@ -508,7 +513,7 @@ func (s *service) UserPage(c *client, id string, pageType string, } } - commonData := s.getCommonData(c, user.DisplayName+" @"+user.Acct) + cdata := s.cdata(c, user.DisplayName+" @"+user.Acct, 0, 0, "") data := &renderer.UserData{ User: user, IsCurrent: isCurrent, @@ -516,10 +521,9 @@ func (s *service) UserPage(c *client, id string, pageType string, Users: users, Statuses: statuses, NextLink: nextLink, - CommonData: commonData, + CommonData: cdata, } - rCtx := getRendererContext(c) - return s.renderer.Render(rCtx, c, renderer.UserPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.UserPage, data) } func (s *service) UserSearchPage(c *client, @@ -528,14 +532,14 @@ func (s *service) UserSearchPage(c *client, var nextLink string var title = "search" - user, err := c.GetAccount(ctx, id) + user, err := c.GetAccount(c.ctx, id) if err != nil { return } var results *mastodon.Results if len(q) > 0 { - results, err = c.Search(ctx, q, "statuses", 20, true, offset, id) + results, err = c.Search(c.ctx, q, "statuses", 20, true, offset, id) if err != nil { return err } @@ -554,39 +558,36 @@ func (s *service) UserSearchPage(c *client, title += " \"" + qq + "\"" } - commonData := s.getCommonData(c, title) + cdata := s.cdata(c, title, 0, 0, "") data := &renderer.UserSearchData{ - CommonData: commonData, + CommonData: cdata, User: user, Q: qq, Statuses: results.Statuses, NextLink: nextLink, } - rCtx := getRendererContext(c) - return s.renderer.Render(rCtx, c, renderer.UserSearchPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.UserSearchPage, data) } func (s *service) AboutPage(c *client) (err error) { - commonData := s.getCommonData(c, "about") + cdata := s.cdata(c, "about", 0, 0, "") data := &renderer.AboutData{ - CommonData: commonData, + CommonData: cdata, } - rCtx := getRendererContext(c) - return s.renderer.Render(rCtx, c, renderer.AboutPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.AboutPage, data) } func (s *service) EmojiPage(c *client) (err error) { - emojis, err := c.GetInstanceEmojis(ctx) + emojis, err := c.GetInstanceEmojis(c.ctx) if err != nil { return } - commonData := s.getCommonData(c, "emojis") + cdata := s.cdata(c, "emojis", 0, 0, "") data := &renderer.EmojiData{ Emojis: emojis, - CommonData: commonData, + CommonData: cdata, } - rCtx := getRendererContext(c) - return s.renderer.Render(rCtx, c, renderer.EmojiPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.EmojiPage, data) } func (s *service) SearchPage(c *client, @@ -597,7 +598,7 @@ func (s *service) SearchPage(c *client, var results *mastodon.Results if len(q) > 0 { - results, err = c.Search(ctx, q, qType, 20, true, offset, "") + results, err = c.Search(c.ctx, q, qType, 20, true, offset, "") if err != nil { return err } @@ -617,55 +618,50 @@ func (s *service) SearchPage(c *client, title += " \"" + qq + "\"" } - commonData := s.getCommonData(c, title) + cdata := s.cdata(c, title, 0, 0, "") data := &renderer.SearchData{ - CommonData: commonData, + CommonData: cdata, Q: qq, Type: qType, Users: results.Accounts, Statuses: results.Statuses, NextLink: nextLink, } - rCtx := getRendererContext(c) - return s.renderer.Render(rCtx, c, renderer.SearchPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.SearchPage, data) } func (s *service) SettingsPage(c *client) (err error) { - commonData := s.getCommonData(c, "settings") + cdata := s.cdata(c, "settings", 0, 0, "") data := &renderer.SettingsData{ - CommonData: commonData, - Settings: &c.Session.Settings, + CommonData: cdata, + Settings: &c.s.Settings, PostFormats: s.postFormats, } - rCtx := getRendererContext(c) - return s.renderer.Render(rCtx, c, renderer.SettingsPage, data) + return s.renderer.Render(c.rctx, c.w, renderer.SettingsPage, data) } func (svc *service) FiltersPage(c *client) (err error) { - filters, err := c.GetFilters(ctx) + filters, err := c.GetFilters(c.ctx) if err != nil { return } - - commonData := svc.getCommonData(c, "filters") + cdata := svc.cdata(c, "filters", 0, 0, "") data := &renderer.FiltersData{ - CommonData: commonData, + CommonData: cdata, Filters: filters, } - - rCtx := getRendererContext(c) - return svc.renderer.Render(rCtx, c, renderer.FiltersPage, data) + return svc.renderer.Render(c.rctx, c.w, renderer.FiltersPage, data) } func (s *service) SingleInstance() (instance string, ok bool) { - if len(s.singleInstance) > 0 { - instance = s.singleInstance + if len(s.instance) > 0 { + instance = s.instance ok = true } return } -func (s *service) NewSession(instance string) (rurl string, sid string, err error) { +func (s *service) NewSession(c *client, instance string) (rurl string, sid string, err error) { var instanceURL string if strings.HasPrefix(instance, "https://") { instanceURL = instance @@ -678,18 +674,18 @@ func (s *service) NewSession(instance string) (rurl string, sid string, err erro if err != nil { return } - csrfToken, err := util.NewCSRFToken() + csrf, err := util.NewCSRFToken() if err != nil { return } - session := model.Session{ + sess := model.Session{ ID: sid, InstanceDomain: instance, - CSRFToken: csrfToken, + CSRFToken: csrf, Settings: *model.NewSettings(), } - err = s.sessionRepo.Add(session) + err = s.sessionRepo.Add(sess) if err != nil { return } @@ -699,12 +695,12 @@ func (s *service) NewSession(instance string) (rurl string, sid string, err erro if err != model.ErrAppNotFound { return } - mastoApp, err := mastodon.RegisterApp(ctx, &mastodon.AppConfig{ + mastoApp, err := mastodon.RegisterApp(c.ctx, &mastodon.AppConfig{ Server: instanceURL, - ClientName: s.clientName, - Scopes: s.clientScope, - Website: s.clientWebsite, - RedirectURIs: s.clientWebsite + "/oauth_callback", + ClientName: s.cname, + Scopes: s.cscope, + Website: s.cwebsite, + RedirectURIs: s.cwebsite + "/oauth_callback", }) if err != nil { return "", "", err @@ -730,36 +726,33 @@ func (s *service) NewSession(instance string) (rurl string, sid string, err erro q.Set("scope", "read write follow") q.Set("client_id", app.ClientID) q.Set("response_type", "code") - q.Set("redirect_uri", s.clientWebsite+"/oauth_callback") + q.Set("redirect_uri", s.cwebsite+"/oauth_callback") u.RawQuery = q.Encode() rurl = instanceURL + u.String() return } -func (s *service) Signin(c *client, code string) (token string, - userID string, err error) { - +func (s *service) Signin(c *client, code string) (err error) { if len(code) < 1 { err = errInvalidArgument return } - err = c.AuthenticateToken(ctx, code, s.clientWebsite+"/oauth_callback") + err = c.AuthenticateToken(c.ctx, code, s.cwebsite+"/oauth_callback") if err != nil { return } - token = c.GetAccessToken(ctx) - - u, err := c.GetAccountCurrentUser(ctx) + u, err := c.GetAccountCurrentUser(c.ctx) if err != nil { return } - userID = u.ID - return + c.s.AccessToken = c.GetAccessToken(c.ctx) + c.s.UserID = u.ID + return s.sessionRepo.Add(c.s) } func (s *service) Signout(c *client) (err error) { - s.sessionRepo.Remove(c.Session.ID) + s.sessionRepo.Remove(c.s.ID) return } @@ -769,7 +762,7 @@ func (s *service) Post(c *client, content string, replyToID string, var mediaIDs []string for _, f := range files { - a, err := c.UploadMediaFromMultipartFileHeader(ctx, f) + a, err := c.UploadMediaFromMultipartFileHeader(c.ctx, f) if err != nil { return "", err } @@ -784,7 +777,7 @@ func (s *service) Post(c *client, content string, replyToID string, Visibility: visibility, Sensitive: isNSFW, } - st, err := c.PostStatus(ctx, tweet) + st, err := c.PostStatus(c.ctx, tweet) if err != nil { return } @@ -792,7 +785,7 @@ func (s *service) Post(c *client, content string, replyToID string, } func (s *service) Like(c *client, id string) (count int64, err error) { - st, err := c.Favourite(ctx, id) + st, err := c.Favourite(c.ctx, id) if err != nil { return } @@ -801,7 +794,7 @@ func (s *service) Like(c *client, id string) (count int64, err error) { } func (s *service) UnLike(c *client, id string) (count int64, err error) { - st, err := c.Unfavourite(ctx, id) + st, err := c.Unfavourite(c.ctx, id) if err != nil { return } @@ -810,7 +803,7 @@ func (s *service) UnLike(c *client, id string) (count int64, err error) { } func (s *service) Retweet(c *client, id string) (count int64, err error) { - st, err := c.Reblog(ctx, id) + st, err := c.Reblog(c.ctx, id) if err != nil { return } @@ -822,7 +815,7 @@ func (s *service) Retweet(c *client, id string) (count int64, err error) { func (s *service) UnRetweet(c *client, id string) ( count int64, err error) { - st, err := c.Unreblog(ctx, id) + st, err := c.Unreblog(c.ctx, id) if err != nil { return } @@ -831,55 +824,55 @@ func (s *service) UnRetweet(c *client, id string) ( } func (s *service) Vote(c *client, id string, choices []string) (err error) { - _, err = c.Vote(ctx, id, choices) + _, err = c.Vote(c.ctx, id, choices) return } func (s *service) Follow(c *client, id string, reblogs *bool) (err error) { - _, err = c.AccountFollow(ctx, id, reblogs) + _, err = c.AccountFollow(c.ctx, id, reblogs) return } func (s *service) UnFollow(c *client, id string) (err error) { - _, err = c.AccountUnfollow(ctx, id) + _, err = c.AccountUnfollow(c.ctx, id) return } func (s *service) Accept(c *client, id string) (err error) { - return c.FollowRequestAuthorize(ctx, id) + return c.FollowRequestAuthorize(c.ctx, id) } func (s *service) Reject(c *client, id string) (err error) { - return c.FollowRequestReject(ctx, id) + return c.FollowRequestReject(c.ctx, id) } func (s *service) Mute(c *client, id string) (err error) { - _, err = c.AccountMute(ctx, id) + _, err = c.AccountMute(c.ctx, id) return } func (s *service) UnMute(c *client, id string) (err error) { - _, err = c.AccountUnmute(ctx, id) + _, err = c.AccountUnmute(c.ctx, id) return } func (s *service) Block(c *client, id string) (err error) { - _, err = c.AccountBlock(ctx, id) + _, err = c.AccountBlock(c.ctx, id) return } func (s *service) UnBlock(c *client, id string) (err error) { - _, err = c.AccountUnblock(ctx, id) + _, err = c.AccountUnblock(c.ctx, id) return } func (s *service) Subscribe(c *client, id string) (err error) { - _, err = c.Subscribe(ctx, id) + _, err = c.Subscribe(c.ctx, id) return } func (s *service) UnSubscribe(c *client, id string) (err error) { - _, err = c.UnSubscribe(ctx, id) + _, err = c.UnSubscribe(c.ctx, id) return } @@ -889,47 +882,47 @@ func (s *service) SaveSettings(c *client, settings *model.Settings) (err error) default: return errInvalidArgument } - session, err := s.sessionRepo.Get(c.Session.ID) + sess, err := s.sessionRepo.Get(c.s.ID) if err != nil { return } - session.Settings = *settings - return s.sessionRepo.Add(session) + sess.Settings = *settings + return s.sessionRepo.Add(sess) } func (s *service) MuteConversation(c *client, id string) (err error) { - _, err = c.MuteConversation(ctx, id) + _, err = c.MuteConversation(c.ctx, id) return } func (s *service) UnMuteConversation(c *client, id string) (err error) { - _, err = c.UnmuteConversation(ctx, id) + _, err = c.UnmuteConversation(c.ctx, id) return } func (s *service) Delete(c *client, id string) (err error) { - return c.DeleteStatus(ctx, id) + return c.DeleteStatus(c.ctx, id) } func (s *service) ReadNotifications(c *client, maxID string) (err error) { - return c.ReadNotifications(ctx, maxID) + return c.ReadNotifications(c.ctx, maxID) } func (s *service) Bookmark(c *client, id string) (err error) { - _, err = c.Bookmark(ctx, id) + _, err = c.Bookmark(c.ctx, id) return } func (s *service) UnBookmark(c *client, id string) (err error) { - _, err = c.Unbookmark(ctx, id) + _, err = c.Unbookmark(c.ctx, id) return } func (svc *service) Filter(c *client, phrase string, wholeWord bool) (err error) { fctx := []string{"home", "notifications", "public", "thread"} - return c.AddFilter(ctx, phrase, fctx, true, wholeWord, nil) + return c.AddFilter(c.ctx, phrase, fctx, true, wholeWord, nil) } func (svc *service) UnFilter(c *client, id string) (err error) { - return c.RemoveFilter(ctx, id) + return c.RemoveFilter(c.ctx, id) } diff --git a/service/transport.go b/service/transport.go index 1180f6c..317ce5b 100644 --- a/service/transport.go +++ b/service/transport.go @@ -1,8 +1,8 @@ package service import ( + "context" "encoding/json" - "errors" "log" "net/http" "strconv" @@ -10,44 +10,34 @@ import ( "bloat/mastodon" "bloat/model" + "bloat/renderer" "github.com/gorilla/mux" ) -var ( - errInvalidSession = errors.New("invalid session") - errInvalidCSRFToken = errors.New("invalid csrf token") -) - const ( sessionExp = 365 * 24 * time.Hour ) -type respType int - const ( - HTML respType = iota + HTML int = iota JSON ) -type authType int - const ( - NOAUTH authType = iota + NOAUTH int = iota SESSION CSRF ) type client struct { *mastodon.Client - http.ResponseWriter - Req *http.Request - CSRFToken string - Session model.Session -} - -func (c *client) url() string { - return c.Req.URL.RequestURI() + w http.ResponseWriter + r *http.Request + s model.Session + csrf string + ctx context.Context + rctx *renderer.Context } func setSessionCookie(w http.ResponseWriter, sid string, exp time.Duration) { @@ -59,66 +49,50 @@ func setSessionCookie(w http.ResponseWriter, sid string, exp time.Duration) { } func writeJson(c *client, data interface{}) error { - return json.NewEncoder(c).Encode(map[string]interface{}{ + return json.NewEncoder(c.w).Encode(map[string]interface{}{ "data": data, }) } func redirect(c *client, url string) { - c.Header().Add("Location", url) - c.WriteHeader(http.StatusFound) + c.w.Header().Add("Location", url) + c.w.WriteHeader(http.StatusFound) } func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { r := mux.NewRouter() - writeError := func(c *client, err error, t respType) { + writeError := func(c *client, err error, t int) { switch t { case HTML: - c.WriteHeader(http.StatusInternalServerError) + c.w.WriteHeader(http.StatusInternalServerError) s.ErrorPage(c, err) case JSON: - c.WriteHeader(http.StatusInternalServerError) - json.NewEncoder(c).Encode(map[string]string{ + c.w.WriteHeader(http.StatusInternalServerError) + json.NewEncoder(c.w).Encode(map[string]string{ "error": err.Error(), }) } } - authenticate := func(c *client, t authType) error { - if t >= SESSION { - cookie, err := c.Req.Cookie("session_id") - if err != nil || len(cookie.Value) < 1 { - return errInvalidSession - } - c.Session, err = s.sessionRepo.Get(cookie.Value) - if err != nil { - return errInvalidSession - } - app, err := s.appRepo.Get(c.Session.InstanceDomain) - if err != nil { - return err - } - c.Client = mastodon.NewClient(&mastodon.Config{ - Server: app.InstanceURL, - ClientID: app.ClientID, - ClientSecret: app.ClientSecret, - AccessToken: c.Session.AccessToken, - }) + authenticate := func(c *client, t int) error { + var sid string + if cookie, _ := c.r.Cookie("session_id"); cookie != nil { + sid = cookie.Value } - if t >= CSRF { - c.CSRFToken = c.Req.FormValue("csrf_token") - if len(c.CSRFToken) < 1 || c.CSRFToken != c.Session.CSRFToken { - return errInvalidCSRFToken - } - } - return nil + csrf := c.r.FormValue("csrf_token") + ref := c.r.URL.RequestURI() + return s.authenticate(c, sid, csrf, ref, t) } - handle := func(f func(c *client) error, at authType, rt respType) http.HandlerFunc { + handle := func(f func(c *client) error, at int, rt int) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { var err error - c := &client{Req: req, ResponseWriter: w} + c := &client{ + ctx: req.Context(), + w: w, + r: req, + } defer func(begin time.Time) { logger.Printf("path=%s, err=%v, took=%v\n", @@ -132,7 +106,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { case JSON: ct = "application/json" } - c.Header().Add("Content-Type", ct) + c.w.Header().Add("Content-Type", ct) err = authenticate(c, at) if err != nil { @@ -149,12 +123,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { } rootPage := handle(func(c *client) error { - sid, _ := c.Req.Cookie("session_id") - if sid == nil || len(sid.Value) < 0 { - redirect(c, "/signin") - return nil - } - session, err := s.sessionRepo.Get(sid.Value) + err := authenticate(c, SESSION) if err != nil { if err == errInvalidSession { redirect(c, "/signin") @@ -162,7 +131,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { } return err } - if len(session.AccessToken) < 1 { + if !c.s.IsLoggedIn() { redirect(c, "/signin") return nil } @@ -178,18 +147,18 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { if !ok { return s.SigninPage(c) } - url, sid, err := s.NewSession(instance) + url, sid, err := s.NewSession(c, instance) if err != nil { return err } - setSessionCookie(c, sid, sessionExp) + setSessionCookie(c.w, sid, sessionExp) redirect(c, url) return nil }, NOAUTH, HTML) timelinePage := handle(func(c *client) error { - tType, _ := mux.Vars(c.Req)["type"] - q := c.Req.URL.Query() + tType, _ := mux.Vars(c.r)["type"] + q := c.r.URL.Query() instance := q.Get("instance") maxID := q.Get("max_id") minID := q.Get("min_id") @@ -202,41 +171,41 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { }, SESSION, HTML) threadPage := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] - q := c.Req.URL.Query() + id, _ := mux.Vars(c.r)["id"] + q := c.r.URL.Query() reply := q.Get("reply") return s.ThreadPage(c, id, len(reply) > 1) }, SESSION, HTML) likedByPage := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] return s.LikedByPage(c, id) }, SESSION, HTML) retweetedByPage := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] return s.RetweetedByPage(c, id) }, SESSION, HTML) notificationsPage := handle(func(c *client) error { - q := c.Req.URL.Query() + q := c.r.URL.Query() maxID := q.Get("max_id") minID := q.Get("min_id") return s.NotificationPage(c, maxID, minID) }, SESSION, HTML) userPage := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] - pageType, _ := mux.Vars(c.Req)["type"] - q := c.Req.URL.Query() + id, _ := mux.Vars(c.r)["id"] + pageType, _ := mux.Vars(c.r)["type"] + q := c.r.URL.Query() maxID := q.Get("max_id") minID := q.Get("min_id") return s.UserPage(c, id, pageType, maxID, minID) }, SESSION, HTML) userSearchPage := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] - q := c.Req.URL.Query() + id, _ := mux.Vars(c.r)["id"] + q := c.r.URL.Query() sq := q.Get("q") offset, _ := strconv.Atoi(q.Get("offset")) return s.UserSearchPage(c, id, sq, offset) @@ -251,7 +220,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { }, SESSION, HTML) searchPage := handle(func(c *client) error { - q := c.Req.URL.Query() + q := c.r.URL.Query() sq := q.Get("q") qType := q.Get("type") offset, _ := strconv.Atoi(q.Get("offset")) @@ -267,49 +236,41 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { }, SESSION, HTML) signin := handle(func(c *client) error { - instance := c.Req.FormValue("instance") - url, sid, err := s.NewSession(instance) + instance := c.r.FormValue("instance") + url, sid, err := s.NewSession(c, instance) if err != nil { return err } - setSessionCookie(c, sid, sessionExp) + setSessionCookie(c.w, sid, sessionExp) redirect(c, url) return nil }, NOAUTH, HTML) oauthCallback := handle(func(c *client) error { - q := c.Req.URL.Query() + q := c.r.URL.Query() token := q.Get("code") - token, userID, err := s.Signin(c, token) - if err != nil { - return err - } - - c.Session.AccessToken = token - c.Session.UserID = userID - err = s.sessionRepo.Add(c.Session) + err := s.Signin(c, token) if err != nil { return err } - redirect(c, "/") return nil }, SESSION, HTML) post := handle(func(c *client) error { - content := c.Req.FormValue("content") - replyToID := c.Req.FormValue("reply_to_id") - format := c.Req.FormValue("format") - visibility := c.Req.FormValue("visibility") - isNSFW := c.Req.FormValue("is_nsfw") == "on" - files := c.Req.MultipartForm.File["attachments"] + content := c.r.FormValue("content") + replyToID := c.r.FormValue("reply_to_id") + format := c.r.FormValue("format") + visibility := c.r.FormValue("visibility") + isNSFW := c.r.FormValue("is_nsfw") == "true" + files := c.r.MultipartForm.File["attachments"] id, err := s.Post(c, content, replyToID, format, visibility, isNSFW, files) if err != nil { return err } - location := c.Req.FormValue("referrer") + location := c.r.FormValue("referrer") if len(replyToID) > 0 { location = "/thread/" + replyToID + "#status-" + id } @@ -318,8 +279,8 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { }, CSRF, HTML) like := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] - rid := c.Req.FormValue("retweeted_by_id") + id, _ := mux.Vars(c.r)["id"] + rid := c.r.FormValue("retweeted_by_id") _, err := s.Like(c, id) if err != nil { return err @@ -327,13 +288,13 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { if len(rid) > 0 { id = rid } - redirect(c, c.Req.FormValue("referrer")+"#status-"+id) + redirect(c, c.r.FormValue("referrer")+"#status-"+id) return nil }, CSRF, HTML) unlike := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] - rid := c.Req.FormValue("retweeted_by_id") + id, _ := mux.Vars(c.r)["id"] + rid := c.r.FormValue("retweeted_by_id") _, err := s.UnLike(c, id) if err != nil { return err @@ -341,13 +302,13 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { if len(rid) > 0 { id = rid } - redirect(c, c.Req.FormValue("referrer")+"#status-"+id) + redirect(c, c.r.FormValue("referrer")+"#status-"+id) return nil }, CSRF, HTML) retweet := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] - rid := c.Req.FormValue("retweeted_by_id") + id, _ := mux.Vars(c.r)["id"] + rid := c.r.FormValue("retweeted_by_id") _, err := s.Retweet(c, id) if err != nil { return err @@ -355,13 +316,13 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { if len(rid) > 0 { id = rid } - redirect(c, c.Req.FormValue("referrer")+"#status-"+id) + redirect(c, c.r.FormValue("referrer")+"#status-"+id) return nil }, CSRF, HTML) unretweet := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] - rid := c.Req.FormValue("retweeted_by_id") + id, _ := mux.Vars(c.r)["id"] + rid := c.r.FormValue("retweeted_by_id") _, err := s.UnRetweet(c, id) if err != nil { return err @@ -369,25 +330,25 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { if len(rid) > 0 { id = rid } - redirect(c, c.Req.FormValue("referrer")+"#status-"+id) + redirect(c, c.r.FormValue("referrer")+"#status-"+id) return nil }, CSRF, HTML) vote := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] - statusID := c.Req.FormValue("status_id") - choices, _ := c.Req.PostForm["choices"] + id, _ := mux.Vars(c.r)["id"] + statusID := c.r.FormValue("status_id") + choices, _ := c.r.PostForm["choices"] err := s.Vote(c, id, choices) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")+"#status-"+statusID) + redirect(c, c.r.FormValue("referrer")+"#status-"+statusID) return nil }, CSRF, HTML) follow := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] - q := c.Req.URL.Query() + id, _ := mux.Vars(c.r)["id"] + q := c.r.URL.Query() var reblogs *bool if r, ok := q["reblogs"]; ok && len(r) > 0 { reblogs = new(bool) @@ -397,111 +358,111 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) unfollow := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] err := s.UnFollow(c, id) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) accept := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] err := s.Accept(c, id) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) reject := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] err := s.Reject(c, id) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) mute := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] err := s.Mute(c, id) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) unMute := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] err := s.UnMute(c, id) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) block := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] err := s.Block(c, id) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) unBlock := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] err := s.UnBlock(c, id) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) subscribe := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] err := s.Subscribe(c, id) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) unSubscribe := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] err := s.UnSubscribe(c, id) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) settings := handle(func(c *client) error { - visibility := c.Req.FormValue("visibility") - format := c.Req.FormValue("format") - copyScope := c.Req.FormValue("copy_scope") == "true" - threadInNewTab := c.Req.FormValue("thread_in_new_tab") == "true" - hideAttachments := c.Req.FormValue("hide_attachments") == "true" - maskNSFW := c.Req.FormValue("mask_nsfw") == "true" - ni, _ := strconv.Atoi(c.Req.FormValue("notification_interval")) - fluorideMode := c.Req.FormValue("fluoride_mode") == "true" - darkMode := c.Req.FormValue("dark_mode") == "true" - antiDopamineMode := c.Req.FormValue("anti_dopamine_mode") == "true" + visibility := c.r.FormValue("visibility") + format := c.r.FormValue("format") + copyScope := c.r.FormValue("copy_scope") == "true" + threadInNewTab := c.r.FormValue("thread_in_new_tab") == "true" + hideAttachments := c.r.FormValue("hide_attachments") == "true" + maskNSFW := c.r.FormValue("mask_nsfw") == "true" + ni, _ := strconv.Atoi(c.r.FormValue("notification_interval")) + fluorideMode := c.r.FormValue("fluoride_mode") == "true" + darkMode := c.r.FormValue("dark_mode") == "true" + antiDopamineMode := c.r.FormValue("anti_dopamine_mode") == "true" settings := &model.Settings{ DefaultVisibility: visibility, @@ -525,49 +486,49 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { }, CSRF, HTML) muteConversation := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] err := s.MuteConversation(c, id) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) unMuteConversation := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] err := s.UnMuteConversation(c, id) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) delete := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] err := s.Delete(c, id) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) readNotifications := handle(func(c *client) error { - q := c.Req.URL.Query() + q := c.r.URL.Query() maxID := q.Get("max_id") err := s.ReadNotifications(c, maxID) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) bookmark := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] - rid := c.Req.FormValue("retweeted_by_id") + id, _ := mux.Vars(c.r)["id"] + rid := c.r.FormValue("retweeted_by_id") err := s.Bookmark(c, id) if err != nil { return err @@ -575,13 +536,13 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { if len(rid) > 0 { id = rid } - redirect(c, c.Req.FormValue("referrer")+"#status-"+id) + redirect(c, c.r.FormValue("referrer")+"#status-"+id) return nil }, CSRF, HTML) unBookmark := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] - rid := c.Req.FormValue("retweeted_by_id") + id, _ := mux.Vars(c.r)["id"] + rid := c.r.FormValue("retweeted_by_id") err := s.UnBookmark(c, id) if err != nil { return err @@ -589,40 +550,40 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { if len(rid) > 0 { id = rid } - redirect(c, c.Req.FormValue("referrer")+"#status-"+id) + redirect(c, c.r.FormValue("referrer")+"#status-"+id) return nil }, CSRF, HTML) filter := handle(func(c *client) error { - phrase := c.Req.FormValue("phrase") - wholeWord := c.Req.FormValue("whole_word") == "true" + phrase := c.r.FormValue("phrase") + wholeWord := c.r.FormValue("whole_word") == "true" err := s.Filter(c, phrase, wholeWord) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) unFilter := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] err := s.UnFilter(c, id) if err != nil { return err } - redirect(c, c.Req.FormValue("referrer")) + redirect(c, c.r.FormValue("referrer")) return nil }, CSRF, HTML) signout := handle(func(c *client) error { s.Signout(c) - setSessionCookie(c, "", 0) + setSessionCookie(c.w, "", 0) redirect(c, "/") return nil }, CSRF, HTML) fLike := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] count, err := s.Like(c, id) if err != nil { return err @@ -631,7 +592,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { }, CSRF, JSON) fUnlike := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] count, err := s.UnLike(c, id) if err != nil { return err @@ -640,7 +601,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { }, CSRF, JSON) fRetweet := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] count, err := s.Retweet(c, id) if err != nil { return err @@ -649,7 +610,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { }, CSRF, JSON) fUnretweet := handle(func(c *client) error { - id, _ := mux.Vars(c.Req)["id"] + id, _ := mux.Vars(c.r)["id"] count, err := s.UnRetweet(c, id) if err != nil { return err -- cgit v1.2.3 From 2cb6a515ac019bf5621a4d5bd54cf388f5d65e20 Mon Sep 17 00:00:00 2001 From: r Date: Sat, 3 Apr 2021 06:39:06 +0000 Subject: Update error page - Add retry button for GET requests - Only show signin button when it's a session error --- service/service.go | 10 ++++++++-- service/transport.go | 8 ++++---- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'service') diff --git a/service/service.go b/service/service.go index 1028765..a29345e 100644 --- a/service/service.go +++ b/service/service.go @@ -109,15 +109,21 @@ func (s *service) cdata(c *client, title string, count int, rinterval int, return } -func (s *service) ErrorPage(c *client, err error) error { +func (s *service) ErrorPage(c *client, err error, retry bool) error { var errStr string + var sessionErr bool if err != nil { errStr = err.Error() + if err == errInvalidSession || err == errInvalidCSRFToken { + sessionErr = true + } } cdata := s.cdata(nil, "error", 0, 0, "") data := &renderer.ErrorData{ CommonData: cdata, - Error: errStr, + Err: errStr, + Retry: retry, + SessionErr: sessionErr, } return s.renderer.Render(c.rctx, c.w, renderer.ErrorPage, data) } diff --git a/service/transport.go b/service/transport.go index 317ce5b..50bf9be 100644 --- a/service/transport.go +++ b/service/transport.go @@ -62,11 +62,11 @@ func redirect(c *client, url string) { func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { r := mux.NewRouter() - writeError := func(c *client, err error, t int) { + writeError := func(c *client, err error, t int, retry bool) { switch t { case HTML: c.w.WriteHeader(http.StatusInternalServerError) - s.ErrorPage(c, err) + s.ErrorPage(c, err, retry) case JSON: c.w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(c.w).Encode(map[string]string{ @@ -110,13 +110,13 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { err = authenticate(c, at) if err != nil { - writeError(c, err, rt) + writeError(c, err, rt, req.Method == http.MethodGet) return } err = f(c) if err != nil { - writeError(c, err, rt) + writeError(c, err, rt, req.Method == http.MethodGet) return } } -- cgit v1.2.3 From 76c5baef6ae8f5520ab40fef48532b6b5759384f Mon Sep 17 00:00:00 2001 From: r Date: Sat, 3 Apr 2021 09:22:43 +0000 Subject: Add option for user CSS --- service/service.go | 4 ++++ service/transport.go | 2 ++ 2 files changed, 6 insertions(+) (limited to 'service') diff --git a/service/service.go b/service/service.go index a29345e..5d80c28 100644 --- a/service/service.go +++ b/service/service.go @@ -64,6 +64,7 @@ func (s *service) authenticate(c *client, sid string, csrf string, ref string, t CSRFToken: c.s.CSRFToken, UserID: c.s.UserID, AntiDopamineMode: sett.AntiDopamineMode, + UserCSS: sett.CSS, Referrer: ref, } }() @@ -888,6 +889,9 @@ func (s *service) SaveSettings(c *client, settings *model.Settings) (err error) default: return errInvalidArgument } + if len(settings.CSS) > 1<<20 { + return errInvalidArgument + } sess, err := s.sessionRepo.Get(c.s.ID) if err != nil { return diff --git a/service/transport.go b/service/transport.go index 50bf9be..f448cc3 100644 --- a/service/transport.go +++ b/service/transport.go @@ -463,6 +463,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { fluorideMode := c.r.FormValue("fluoride_mode") == "true" darkMode := c.r.FormValue("dark_mode") == "true" antiDopamineMode := c.r.FormValue("anti_dopamine_mode") == "true" + css := c.r.FormValue("css") settings := &model.Settings{ DefaultVisibility: visibility, @@ -475,6 +476,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { FluorideMode: fluorideMode, DarkMode: darkMode, AntiDopamineMode: antiDopamineMode, + CSS: css, } err := s.SaveSettings(c, settings) -- cgit v1.2.3 From 469f2d1d25f0b266abb15eab410131ebe1856aad Mon Sep 17 00:00:00 2001 From: r Date: Fri, 23 Apr 2021 10:19:09 +0000 Subject: Fix HTML escaping --- service/service.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'service') diff --git a/service/service.go b/service/service.go index 5d80c28..d548342 100644 --- a/service/service.go +++ b/service/service.go @@ -3,7 +3,6 @@ package service import ( "errors" "fmt" - "html/template" "mime/multipart" "net/url" "strings" @@ -560,16 +559,15 @@ func (s *service) UserSearchPage(c *client, url.QueryEscape(q), offset) } - qq := template.HTMLEscapeString(q) if len(q) > 0 { - title += " \"" + qq + "\"" + title += " \"" + q + "\"" } cdata := s.cdata(c, title, 0, 0, "") data := &renderer.UserSearchData{ CommonData: cdata, User: user, - Q: qq, + Q: q, Statuses: results.Statuses, NextLink: nextLink, } @@ -620,15 +618,14 @@ func (s *service) SearchPage(c *client, url.QueryEscape(q), qType, offset) } - qq := template.HTMLEscapeString(q) if len(q) > 0 { - title += " \"" + qq + "\"" + title += " \"" + q + "\"" } cdata := s.cdata(c, title, 0, 0, "") data := &renderer.SearchData{ CommonData: cdata, - Q: qq, + Q: q, Type: qType, Users: results.Accounts, Statuses: results.Statuses, -- cgit v1.2.3