client.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package service
  2. import (
  3. "context"
  4. "encoding/base64"
  5. "encoding/json"
  6. "errors"
  7. "net/http"
  8. "strings"
  9. "time"
  10. "bloat/mastodon"
  11. "bloat/model"
  12. "bloat/renderer"
  13. )
  14. type client struct {
  15. *mastodon.Client
  16. w http.ResponseWriter
  17. r *http.Request
  18. s *model.Session
  19. csrf string
  20. ctx context.Context
  21. rctx *renderer.Context
  22. }
  23. func (c *client) setSession(sess *model.Session) error {
  24. var sb strings.Builder
  25. bw := base64.NewEncoder(base64.URLEncoding, &sb)
  26. err := json.NewEncoder(bw).Encode(sess)
  27. bw.Close()
  28. if err != nil {
  29. return err
  30. }
  31. http.SetCookie(c.w, &http.Cookie{
  32. Name: "session",
  33. Path: "/",
  34. HttpOnly: true,
  35. Value: sb.String(),
  36. Expires: time.Now().Add(365 * 24 * time.Hour),
  37. })
  38. return nil
  39. }
  40. func (c *client) getSession() (sess *model.Session, err error) {
  41. cookie, _ := c.r.Cookie("session")
  42. if cookie == nil {
  43. return nil, errInvalidSession
  44. }
  45. br := base64.NewDecoder(base64.URLEncoding, strings.NewReader(cookie.Value))
  46. err = json.NewDecoder(br).Decode(&sess)
  47. return
  48. }
  49. func (c *client) unsetSession() {
  50. http.SetCookie(c.w, &http.Cookie{
  51. Name: "session",
  52. Path: "/",
  53. Value: "",
  54. Expires: time.Now(),
  55. })
  56. }
  57. func (c *client) writeJson(data interface{}) error {
  58. return json.NewEncoder(c.w).Encode(map[string]interface{}{
  59. "data": data,
  60. })
  61. }
  62. func (c *client) redirect(url string) {
  63. c.w.Header().Add("Location", url)
  64. c.w.WriteHeader(http.StatusFound)
  65. }
  66. func (c *client) authenticate(t int, instance string) (err error) {
  67. csrf := c.r.FormValue("csrf_token")
  68. ref := c.r.URL.RequestURI()
  69. defer func() {
  70. if c.s == nil {
  71. c.s = &model.Session{
  72. Settings: *model.NewSettings(),
  73. }
  74. }
  75. c.rctx = &renderer.Context{
  76. HideAttachments: c.s.Settings.HideAttachments,
  77. MaskNSFW: c.s.Settings.MaskNSFW,
  78. ThreadInNewTab: c.s.Settings.ThreadInNewTab,
  79. FluorideMode: c.s.Settings.FluorideMode,
  80. DarkMode: c.s.Settings.DarkMode,
  81. CSRFToken: c.s.CSRFToken,
  82. UserID: c.s.UserID,
  83. AntiDopamineMode: c.s.Settings.AntiDopamineMode,
  84. InstanceEmojiFilter: c.s.Settings.InstanceEmojiFilter,
  85. AddReactionsFilter: c.s.Settings.AddReactionsFilter,
  86. UserCSS: c.s.Settings.CSS,
  87. Referrer: ref,
  88. }
  89. }()
  90. if t < SESSION {
  91. return
  92. }
  93. sess, err := c.getSession()
  94. if err != nil {
  95. return err
  96. }
  97. c.s = sess
  98. if len(instance) > 0 && c.s.Instance != instance {
  99. return errors.New("invalid instance")
  100. }
  101. c.Client = mastodon.NewClient(&mastodon.Config{
  102. Server: "https://" + c.s.Instance,
  103. ClientID: c.s.ClientID,
  104. ClientSecret: c.s.ClientSecret,
  105. AccessToken: c.s.AccessToken,
  106. })
  107. if t >= CSRF && (len(csrf) < 1 || csrf != c.s.CSRFToken) {
  108. return errInvalidCSRFToken
  109. }
  110. return
  111. }