2019-12-13 20:08:26 +02:00
|
|
|
package service
|
|
|
|
|
|
|
|
import (
|
2020-01-08 20:16:06 +02:00
|
|
|
"encoding/json"
|
2020-11-22 19:29:58 +02:00
|
|
|
"errors"
|
|
|
|
"log"
|
2019-12-13 20:08:26 +02:00
|
|
|
"net/http"
|
2019-12-26 21:18:09 +02:00
|
|
|
"strconv"
|
2019-12-29 07:59:31 +02:00
|
|
|
"time"
|
2020-01-01 17:58:27 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
"bloat/mastodon"
|
2020-01-01 17:58:27 +02:00
|
|
|
"bloat/model"
|
2019-12-13 20:08:26 +02:00
|
|
|
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
)
|
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
var (
|
|
|
|
errInvalidSession = errors.New("invalid session")
|
|
|
|
errInvalidCSRFToken = errors.New("invalid csrf token")
|
|
|
|
)
|
|
|
|
|
2020-04-19 11:18:36 +03:00
|
|
|
const (
|
|
|
|
sessionExp = 365 * 24 * time.Hour
|
|
|
|
)
|
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
type respType int
|
|
|
|
|
|
|
|
const (
|
|
|
|
HTML respType = iota
|
|
|
|
JSON
|
|
|
|
)
|
|
|
|
|
|
|
|
type authType int
|
|
|
|
|
|
|
|
const (
|
|
|
|
NOAUTH authType = iota
|
|
|
|
SESSION
|
|
|
|
CSRF
|
|
|
|
)
|
|
|
|
|
|
|
|
type client struct {
|
|
|
|
*mastodon.Client
|
|
|
|
http.ResponseWriter
|
|
|
|
Req *http.Request
|
|
|
|
CSRFToken string
|
|
|
|
Session model.Session
|
2020-01-28 19:51:00 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
func setSessionCookie(w http.ResponseWriter, sid string, exp time.Duration) {
|
2020-04-19 11:18:36 +03:00
|
|
|
http.SetCookie(w, &http.Cookie{
|
|
|
|
Name: "session_id",
|
2020-11-22 19:29:58 +02:00
|
|
|
Value: sid,
|
2020-04-19 11:18:36 +03:00
|
|
|
Expires: time.Now().Add(exp),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
func writeJson(c *client, data interface{}) error {
|
|
|
|
return json.NewEncoder(c).Encode(map[string]interface{}{
|
|
|
|
"data": data,
|
|
|
|
})
|
2020-01-28 19:51:00 +02:00
|
|
|
}
|
2019-12-13 20:08:26 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
func redirect(c *client, url string) {
|
|
|
|
c.Header().Add("Location", url)
|
|
|
|
c.WriteHeader(http.StatusFound)
|
2020-01-31 04:44:33 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler {
|
2019-12-13 20:08:26 +02:00
|
|
|
r := mux.NewRouter()
|
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
writeError := func(c *client, err error, t respType) {
|
|
|
|
switch t {
|
|
|
|
case HTML:
|
|
|
|
c.WriteHeader(http.StatusInternalServerError)
|
|
|
|
s.ErrorPage(c, err)
|
|
|
|
case JSON:
|
|
|
|
c.WriteHeader(http.StatusInternalServerError)
|
|
|
|
json.NewEncoder(c).Encode(map[string]string{
|
|
|
|
"error": err.Error(),
|
|
|
|
})
|
2020-02-19 00:15:37 +02:00
|
|
|
}
|
2020-01-28 19:51:00 +02:00
|
|
|
}
|
2019-12-13 20:08:26 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
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)
|
2020-04-19 11:18:36 +03:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return errInvalidSession
|
2020-04-19 11:18:36 +03:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
app, err := s.appRepo.Get(c.Session.InstanceDomain)
|
2020-04-19 11:18:36 +03:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
c.Client = mastodon.NewClient(&mastodon.Config{
|
|
|
|
Server: app.InstanceURL,
|
|
|
|
ClientID: app.ClientID,
|
|
|
|
ClientSecret: app.ClientSecret,
|
|
|
|
AccessToken: c.Session.AccessToken,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if t >= CSRF {
|
|
|
|
c.CSRFToken = c.Req.FormValue("csrf_token")
|
|
|
|
if len(c.CSRFToken) < 1 || c.CSRFToken != c.Session.CSRFToken {
|
|
|
|
return errInvalidCSRFToken
|
2020-04-19 11:18:36 +03:00
|
|
|
}
|
2019-12-13 20:08:26 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
return nil
|
2020-01-28 19:51:00 +02:00
|
|
|
}
|
2019-12-13 20:08:26 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
handle := func(f func(c *client) error, at authType, rt respType) http.HandlerFunc {
|
|
|
|
return func(w http.ResponseWriter, req *http.Request) {
|
|
|
|
var err error
|
|
|
|
c := &client{Req: req, ResponseWriter: w}
|
2019-12-13 20:08:26 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
defer func(begin time.Time) {
|
|
|
|
logger.Printf("path=%s, err=%v, took=%v\n",
|
|
|
|
req.URL.Path, err, time.Since(begin))
|
|
|
|
}(time.Now())
|
2020-01-05 20:55:37 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
var ct string
|
|
|
|
switch rt {
|
|
|
|
case HTML:
|
|
|
|
ct = "text/html; charset=utf-8"
|
|
|
|
case JSON:
|
|
|
|
ct = "application/json"
|
|
|
|
}
|
|
|
|
c.Header().Add("Content-Type", ct)
|
2020-01-30 17:32:37 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
err = authenticate(c, at)
|
2020-01-30 17:32:37 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
writeError(c, err, rt)
|
2020-01-30 17:32:37 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
err = f(c)
|
2020-01-28 19:51:00 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
writeError(c, err, rt)
|
2020-01-28 19:51:00 +02:00
|
|
|
return
|
|
|
|
}
|
2020-01-08 20:16:06 +02:00
|
|
|
}
|
2020-01-28 19:51:00 +02:00
|
|
|
}
|
2020-01-25 12:07:06 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
rootPage := handle(func(c *client) error {
|
|
|
|
sid, _ := c.Req.Cookie("session_id")
|
|
|
|
if sid == nil || len(sid.Value) < 0 {
|
|
|
|
redirect(c, "/signin")
|
|
|
|
return nil
|
2020-01-08 20:16:06 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
session, err := s.sessionRepo.Get(sid.Value)
|
2020-01-08 20:16:06 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
if err == errInvalidSession {
|
|
|
|
redirect(c, "/signin")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return err
|
2020-01-08 20:16:06 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
if len(session.AccessToken) < 1 {
|
|
|
|
redirect(c, "/signin")
|
|
|
|
return nil
|
2020-01-08 20:16:06 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
return s.RootPage(c)
|
|
|
|
}, NOAUTH, HTML)
|
2020-01-08 20:16:06 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
navPage := handle(func(c *client) error {
|
|
|
|
return s.NavPage(c)
|
|
|
|
}, SESSION, HTML)
|
2019-12-14 22:19:02 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
signinPage := handle(func(c *client) error {
|
|
|
|
instance, ok := s.SingleInstance()
|
|
|
|
if !ok {
|
|
|
|
return s.SigninPage(c)
|
|
|
|
}
|
|
|
|
url, sid, err := s.NewSession(instance)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
setSessionCookie(c, 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()
|
|
|
|
maxID := q.Get("max_id")
|
|
|
|
minID := q.Get("min_id")
|
2021-01-14 11:41:53 +02:00
|
|
|
instance := q.Get("instance")
|
|
|
|
return s.TimelinePage(c, tType, maxID, minID, instance)
|
2020-11-22 19:29:58 +02:00
|
|
|
}, SESSION, HTML)
|
|
|
|
|
|
|
|
defaultTimelinePage := handle(func(c *client) error {
|
|
|
|
redirect(c, "/timeline/home")
|
|
|
|
return nil
|
|
|
|
}, SESSION, HTML)
|
|
|
|
|
|
|
|
threadPage := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
|
|
|
q := c.Req.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"]
|
|
|
|
return s.LikedByPage(c, id)
|
|
|
|
}, SESSION, HTML)
|
|
|
|
|
|
|
|
retweetedByPage := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
|
|
|
return s.RetweetedByPage(c, id)
|
|
|
|
}, SESSION, HTML)
|
|
|
|
|
|
|
|
notificationsPage := handle(func(c *client) error {
|
|
|
|
q := c.Req.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()
|
|
|
|
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()
|
|
|
|
sq := q.Get("q")
|
|
|
|
offset, _ := strconv.Atoi(q.Get("offset"))
|
|
|
|
return s.UserSearchPage(c, id, sq, offset)
|
|
|
|
}, SESSION, HTML)
|
|
|
|
|
|
|
|
aboutPage := handle(func(c *client) error {
|
|
|
|
return s.AboutPage(c)
|
|
|
|
}, SESSION, HTML)
|
|
|
|
|
|
|
|
emojisPage := handle(func(c *client) error {
|
|
|
|
return s.EmojiPage(c)
|
|
|
|
}, SESSION, HTML)
|
|
|
|
|
|
|
|
searchPage := handle(func(c *client) error {
|
|
|
|
q := c.Req.URL.Query()
|
|
|
|
sq := q.Get("q")
|
|
|
|
qType := q.Get("type")
|
|
|
|
offset, _ := strconv.Atoi(q.Get("offset"))
|
|
|
|
return s.SearchPage(c, sq, qType, offset)
|
|
|
|
}, SESSION, HTML)
|
|
|
|
|
|
|
|
settingsPage := handle(func(c *client) error {
|
|
|
|
return s.SettingsPage(c)
|
|
|
|
}, SESSION, HTML)
|
|
|
|
|
|
|
|
signin := handle(func(c *client) error {
|
|
|
|
instance := c.Req.FormValue("instance")
|
|
|
|
url, sid, err := s.NewSession(instance)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
setSessionCookie(c, sid, sessionExp)
|
|
|
|
redirect(c, url)
|
|
|
|
return nil
|
|
|
|
}, NOAUTH, HTML)
|
|
|
|
|
|
|
|
oauthCallback := handle(func(c *client) error {
|
|
|
|
q := c.Req.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)
|
|
|
|
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"]
|
2019-12-14 22:19:02 +02:00
|
|
|
|
2020-05-24 07:38:34 +03:00
|
|
|
id, err := s.Post(c, content, replyToID, format, visibility, isNSFW, files)
|
2019-12-13 20:08:26 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2019-12-13 20:08:26 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
location := c.Req.Header.Get("Referer")
|
2019-12-13 22:23:15 +02:00
|
|
|
if len(replyToID) > 0 {
|
2019-12-14 20:12:48 +02:00
|
|
|
location = "/thread/" + replyToID + "#status-" + id
|
2019-12-13 22:23:15 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, location)
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2019-12-20 20:30:20 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
like := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
|
|
|
rid := c.Req.FormValue("retweeted_by_id")
|
2020-05-24 07:38:34 +03:00
|
|
|
_, err := s.Like(c, id)
|
2019-12-20 20:30:20 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2019-12-20 20:30:20 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
if len(rid) > 0 {
|
|
|
|
id = rid
|
2020-01-28 19:51:00 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer")+"#status-"+id)
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2019-12-20 20:30:20 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
unlike := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
|
|
|
rid := c.Req.FormValue("retweeted_by_id")
|
2020-05-24 07:38:34 +03:00
|
|
|
_, err := s.UnLike(c, id)
|
2019-12-20 20:30:20 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2019-12-20 20:30:20 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
if len(rid) > 0 {
|
|
|
|
id = rid
|
2020-01-28 19:51:00 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer")+"#status-"+id)
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2019-12-20 20:30:20 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
retweet := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
|
|
|
rid := c.Req.FormValue("retweeted_by_id")
|
2020-05-24 07:38:34 +03:00
|
|
|
_, err := s.Retweet(c, id)
|
2019-12-20 20:30:20 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2019-12-20 20:30:20 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
if len(rid) > 0 {
|
|
|
|
id = rid
|
2020-01-28 19:51:00 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer")+"#status-"+id)
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2019-12-21 07:48:48 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
unretweet := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
|
|
|
rid := c.Req.FormValue("retweeted_by_id")
|
2020-05-24 07:38:34 +03:00
|
|
|
_, err := s.UnRetweet(c, id)
|
2019-12-21 07:48:48 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2019-12-21 07:48:48 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
if len(rid) > 0 {
|
|
|
|
id = rid
|
2019-12-22 20:10:42 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer")+"#status-"+id)
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2019-12-26 21:18:09 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
vote := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
|
|
|
statusID := c.Req.FormValue("status_id")
|
|
|
|
choices, _ := c.Req.PostForm["choices"]
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.Vote(c, id, choices)
|
2020-02-09 15:42:16 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-02-09 15:42:16 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer")+"#status-"+statusID)
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-02-09 15:42:16 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
follow := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
|
|
|
q := c.Req.URL.Query()
|
2020-04-19 08:57:40 +03:00
|
|
|
var reblogs *bool
|
2020-11-22 19:29:58 +02:00
|
|
|
if r, ok := q["reblogs"]; ok && len(r) > 0 {
|
2020-04-19 08:57:40 +03:00
|
|
|
reblogs = new(bool)
|
|
|
|
*reblogs = r[0] == "true"
|
|
|
|
}
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.Follow(c, id, reblogs)
|
2019-12-26 21:18:09 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2019-12-26 21:18:09 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer"))
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2019-12-26 21:18:09 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
unfollow := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.UnFollow(c, id)
|
2019-12-27 10:06:43 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2019-12-27 10:06:43 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer"))
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2019-12-27 10:06:43 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
mute := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.Mute(c, id)
|
2020-02-08 12:49:06 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-02-08 12:49:06 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer"))
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-02-08 12:49:06 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
unMute := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.UnMute(c, id)
|
2020-02-08 12:49:06 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-02-08 12:49:06 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer"))
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-02-08 12:49:06 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
block := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.Block(c, id)
|
2020-02-08 12:49:06 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-02-08 12:49:06 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer"))
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-02-08 12:49:06 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
unBlock := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.UnBlock(c, id)
|
2020-02-08 12:49:06 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-02-08 12:49:06 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer"))
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-02-08 12:49:06 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
subscribe := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.Subscribe(c, id)
|
2020-04-17 20:19:11 +03:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-04-17 20:19:11 +03:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer"))
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-04-17 20:19:11 +03:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
unSubscribe := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.UnSubscribe(c, id)
|
2020-04-17 20:19:11 +03:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-04-17 20:19:11 +03:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer"))
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-04-17 20:19:11 +03:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
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"
|
2020-01-28 19:51:00 +02:00
|
|
|
|
2019-12-27 10:06:43 +02:00
|
|
|
settings := &model.Settings{
|
2020-11-14 16:08:16 +02:00
|
|
|
DefaultVisibility: visibility,
|
|
|
|
DefaultFormat: format,
|
|
|
|
CopyScope: copyScope,
|
|
|
|
ThreadInNewTab: threadInNewTab,
|
|
|
|
HideAttachments: hideAttachments,
|
|
|
|
MaskNSFW: maskNSFW,
|
|
|
|
NotificationInterval: ni,
|
|
|
|
FluorideMode: fluorideMode,
|
|
|
|
DarkMode: darkMode,
|
|
|
|
AntiDopamineMode: antiDopamineMode,
|
2019-12-27 10:06:43 +02:00
|
|
|
}
|
|
|
|
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.SaveSettings(c, settings)
|
2019-12-27 10:06:43 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2019-12-27 10:06:43 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, "/")
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2019-12-27 10:06:43 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
muteConversation := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.MuteConversation(c, id)
|
2020-02-02 09:24:06 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-02-02 09:24:06 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer"))
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-02-02 09:24:06 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
unMuteConversation := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.UnMuteConversation(c, id)
|
2020-02-02 09:24:06 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-02-02 09:24:06 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer"))
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-02-02 09:24:06 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
delete := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.Delete(c, id)
|
2020-02-02 10:30:40 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-02-02 10:30:40 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer"))
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-02-02 10:30:40 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
readNotifications := handle(func(c *client) error {
|
|
|
|
q := c.Req.URL.Query()
|
|
|
|
maxID := q.Get("max_id")
|
2020-05-24 07:38:34 +03:00
|
|
|
err := s.ReadNotifications(c, maxID)
|
2020-02-19 00:15:37 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-02-19 00:15:37 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer"))
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-02-19 00:15:37 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
bookmark := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
|
|
|
rid := c.Req.FormValue("retweeted_by_id")
|
2020-09-27 12:29:17 +03:00
|
|
|
err := s.Bookmark(c, id)
|
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-09-27 12:29:17 +03:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
if len(rid) > 0 {
|
|
|
|
id = rid
|
2020-09-27 12:29:17 +03:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer")+"#status-"+id)
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-09-27 12:29:17 +03:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
unBookmark := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
|
|
|
rid := c.Req.FormValue("retweeted_by_id")
|
2020-09-27 12:29:17 +03:00
|
|
|
err := s.UnBookmark(c, id)
|
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-09-27 12:29:17 +03:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
if len(rid) > 0 {
|
|
|
|
id = rid
|
2020-09-27 12:29:17 +03:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
redirect(c, c.Req.Header.Get("Referer")+"#status-"+id)
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-03-04 17:59:59 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
signout := handle(func(c *client) error {
|
2020-05-24 07:38:34 +03:00
|
|
|
s.Signout(c)
|
2020-11-22 19:29:58 +02:00
|
|
|
setSessionCookie(c, "", 0)
|
|
|
|
redirect(c, "/")
|
|
|
|
return nil
|
|
|
|
}, CSRF, HTML)
|
2020-03-04 17:59:59 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
fLike := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
count, err := s.Like(c, id)
|
2020-01-28 19:51:00 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-01-28 19:51:00 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
return writeJson(c, count)
|
|
|
|
}, CSRF, JSON)
|
2020-01-28 19:51:00 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
fUnlike := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
count, err := s.UnLike(c, id)
|
2020-01-28 19:51:00 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-01-28 19:51:00 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
return writeJson(c, count)
|
|
|
|
}, CSRF, JSON)
|
2020-01-28 19:51:00 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
fRetweet := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
count, err := s.Retweet(c, id)
|
2020-01-28 19:51:00 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-01-28 19:51:00 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
return writeJson(c, count)
|
|
|
|
}, CSRF, JSON)
|
2020-01-28 19:51:00 +02:00
|
|
|
|
2020-11-22 19:29:58 +02:00
|
|
|
fUnretweet := handle(func(c *client) error {
|
|
|
|
id, _ := mux.Vars(c.Req)["id"]
|
2020-05-24 07:38:34 +03:00
|
|
|
count, err := s.UnRetweet(c, id)
|
2020-01-28 19:51:00 +02:00
|
|
|
if err != nil {
|
2020-11-22 19:29:58 +02:00
|
|
|
return err
|
2020-01-28 19:51:00 +02:00
|
|
|
}
|
2020-11-22 19:29:58 +02:00
|
|
|
return writeJson(c, count)
|
|
|
|
}, CSRF, JSON)
|
2020-01-28 19:51:00 +02:00
|
|
|
|
|
|
|
r.HandleFunc("/", rootPage).Methods(http.MethodGet)
|
2020-02-19 00:15:37 +02:00
|
|
|
r.HandleFunc("/nav", navPage).Methods(http.MethodGet)
|
2020-01-28 19:51:00 +02:00
|
|
|
r.HandleFunc("/signin", signinPage).Methods(http.MethodGet)
|
|
|
|
r.HandleFunc("/timeline/{type}", timelinePage).Methods(http.MethodGet)
|
2020-05-24 07:38:34 +03:00
|
|
|
r.HandleFunc("/timeline", defaultTimelinePage).Methods(http.MethodGet)
|
2020-01-28 19:51:00 +02:00
|
|
|
r.HandleFunc("/thread/{id}", threadPage).Methods(http.MethodGet)
|
|
|
|
r.HandleFunc("/likedby/{id}", likedByPage).Methods(http.MethodGet)
|
|
|
|
r.HandleFunc("/retweetedby/{id}", retweetedByPage).Methods(http.MethodGet)
|
|
|
|
r.HandleFunc("/notifications", notificationsPage).Methods(http.MethodGet)
|
|
|
|
r.HandleFunc("/user/{id}", userPage).Methods(http.MethodGet)
|
2020-01-31 05:38:49 +02:00
|
|
|
r.HandleFunc("/user/{id}/{type}", userPage).Methods(http.MethodGet)
|
2020-01-30 17:32:37 +02:00
|
|
|
r.HandleFunc("/usersearch/{id}", userSearchPage).Methods(http.MethodGet)
|
2020-01-28 19:51:00 +02:00
|
|
|
r.HandleFunc("/about", aboutPage).Methods(http.MethodGet)
|
|
|
|
r.HandleFunc("/emojis", emojisPage).Methods(http.MethodGet)
|
|
|
|
r.HandleFunc("/search", searchPage).Methods(http.MethodGet)
|
|
|
|
r.HandleFunc("/settings", settingsPage).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)
|
|
|
|
r.HandleFunc("/like/{id}", like).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/unlike/{id}", unlike).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/retweet/{id}", retweet).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/unretweet/{id}", unretweet).Methods(http.MethodPost)
|
2020-02-09 15:42:16 +02:00
|
|
|
r.HandleFunc("/vote/{id}", vote).Methods(http.MethodPost)
|
2020-01-28 19:51:00 +02:00
|
|
|
r.HandleFunc("/follow/{id}", follow).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/unfollow/{id}", unfollow).Methods(http.MethodPost)
|
2020-02-08 12:49:06 +02:00
|
|
|
r.HandleFunc("/mute/{id}", mute).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/unmute/{id}", unMute).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/block/{id}", block).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/unblock/{id}", unBlock).Methods(http.MethodPost)
|
2020-04-17 20:19:11 +03:00
|
|
|
r.HandleFunc("/subscribe/{id}", subscribe).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/unsubscribe/{id}", unSubscribe).Methods(http.MethodPost)
|
2020-01-28 19:51:00 +02:00
|
|
|
r.HandleFunc("/settings", settings).Methods(http.MethodPost)
|
2020-02-02 09:24:06 +02:00
|
|
|
r.HandleFunc("/muteconv/{id}", muteConversation).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/unmuteconv/{id}", unMuteConversation).Methods(http.MethodPost)
|
2020-02-02 10:30:40 +02:00
|
|
|
r.HandleFunc("/delete/{id}", delete).Methods(http.MethodPost)
|
2020-02-19 00:15:37 +02:00
|
|
|
r.HandleFunc("/notifications/read", readNotifications).Methods(http.MethodPost)
|
2020-09-27 12:29:17 +03:00
|
|
|
r.HandleFunc("/bookmark/{id}", bookmark).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/unbookmark/{id}", unBookmark).Methods(http.MethodPost)
|
2020-03-04 17:59:59 +02:00
|
|
|
r.HandleFunc("/signout", signout).Methods(http.MethodPost)
|
2020-01-28 19:51:00 +02:00
|
|
|
r.HandleFunc("/fluoride/like/{id}", fLike).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/fluoride/unlike/{id}", fUnlike).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/fluoride/retweet/{id}", fRetweet).Methods(http.MethodPost)
|
|
|
|
r.HandleFunc("/fluoride/unretweet/{id}", fUnretweet).Methods(http.MethodPost)
|
|
|
|
r.PathPrefix("/static").Handler(http.StripPrefix("/static",
|
2020-01-31 20:18:31 +02:00
|
|
|
http.FileServer(http.Dir(staticDir))))
|
2020-01-28 19:51:00 +02:00
|
|
|
|
|
|
|
return r
|
2020-01-08 20:16:06 +02:00
|
|
|
}
|