diff --git a/web/handler/handler.go b/web/handler/handler.go index f8ba2e4..aa5214d 100644 --- a/web/handler/handler.go +++ b/web/handler/handler.go @@ -1,13 +1,16 @@ package handler import ( + "errors" "fmt" "github.com/gorilla/mux" "log" "net/http" + "net/url" "status/config" "status/storage" "status/web/session" + "strings" ) func serverError(w http.ResponseWriter, err error) { @@ -30,28 +33,24 @@ type Handler struct { sess *session.Session } -//func (h *Handler) getUser(r *http.Request) (string, error) { -// user, err := h.sess.Get(r) -// if err != nil { -// return "", err -// } -// if h.cfg.Env != "PROD" { -// return user, err -// } -// // Removes "https://" from referer before checking. -// // Thank you crussel for this fix! -// if !strings.HasPrefix(r.Referer()[8:], h.cfg.Host) && !strings.HasPrefix(r.Referer()[8:], user+h.cfg.Host) { -// err = errors.New("wrong referer") -// } -// return user, err -//} +func protectClickJacking(w http.ResponseWriter) { + w.Header().Set("X-Frame-Options", "DENY") + w.Header().Set("Content-Security-Policy", "frame-ancestors 'none'") +} func (h *Handler) getUser(r *http.Request) (string, error) { user, err := h.sess.Get(r) if err != nil { return "", err } - return user, nil + u, err := url.Parse(r.Referer()) + if err != nil { + return "", err + } + if strings.HasPrefix(u.Path, "/users") { + err = errors.New("forbidden access") + } + return user, err } func New(cfg *config.Config, sess *session.Session, data *storage.Storage) (http.Handler, error) { @@ -84,9 +83,11 @@ func New(cfg *config.Config, sess *session.Session, data *storage.Storage) (http router.HandleFunc("/about/status-updater", h.showStatusUpdaterView).Methods(http.MethodGet) router.HandleFunc("/users/{user}.atom", h.showAtomView).Methods(http.MethodGet) router.HandleFunc("/users/{user}", h.showUserView).Methods(http.MethodGet) - router.HandleFunc("/users/{user}/status.json", h.showUserStatusView).Methods(http.MethodGet) + router.HandleFunc("/users/{user}/status", h.showUserStatusView).Methods(http.MethodGet) + router.HandleFunc("/users/{user}/status.json", h.showUserStatusJSONView).Methods(http.MethodGet) router.HandleFunc("/users/{user}/status.png", h.showUserStatusImageView).Methods(http.MethodGet) + router.HandleFunc("/users/{user}/badge.png", h.showUserStatusBadgeView).Methods(http.MethodGet) router.PathPrefix("/assets/").Handler( http.StripPrefix("/assets/", http.FileServer( diff --git a/web/handler/html.go b/web/handler/html.go index 7baa4fa..5b4a295 100644 --- a/web/handler/html.go +++ b/web/handler/html.go @@ -297,6 +297,21 @@ var TplMap = map[string]string{ {{ end }}`, + "status": ` + + + + + status cafe + + + + +{{ if .status.Content }} +{{ template "status" .status }} +{{ end }} + +`, "status-updater": `{{ define "content" }}

Status Updater

@@ -314,7 +329,7 @@ var TplMap = map[string]string{ Drag the following link to your bookmarks toolbar:

- status updater + status updater

That's it! From now on, whenever you want to update your status, click the status updater button from your bookmarks and a pop-up window will launch to let you update it.

diff --git a/web/handler/html/status-updater.html b/web/handler/html/status-updater.html index 6d4c0e4..b859dca 100644 --- a/web/handler/html/status-updater.html +++ b/web/handler/html/status-updater.html @@ -15,7 +15,7 @@ Drag the following link to your bookmarks toolbar:

- status updater + status updater

That's it! From now on, whenever you want to update your status, click the status updater button from your bookmarks and a pop-up window will launch to let you update it.

diff --git a/web/handler/html/status.html b/web/handler/html/status.html new file mode 100644 index 0000000..0f11011 --- /dev/null +++ b/web/handler/html/status.html @@ -0,0 +1,15 @@ + + + + + + status cafe + + + + +{{ if .status.Content }} +{{ template "status" .status }} +{{ end }} + + \ No newline at end of file diff --git a/web/handler/index_show.go b/web/handler/index_show.go index a8cee64..2b6133e 100644 --- a/web/handler/index_show.go +++ b/web/handler/index_show.go @@ -11,6 +11,7 @@ type Update struct { } func (h *Handler) showIndexView(w http.ResponseWriter, r *http.Request) { + protectClickJacking(w) user, _ := h.sess.Get(r) statuses, err := h.storage.LatestStatuses() if err != nil { diff --git a/web/handler/settings_show.go b/web/handler/settings_show.go index 957ab86..b578c05 100644 --- a/web/handler/settings_show.go +++ b/web/handler/settings_show.go @@ -3,6 +3,7 @@ package handler import "net/http" func (h *Handler) showSettingsView(w http.ResponseWriter, r *http.Request) { + protectClickJacking(w) username, err := h.getUser(r) if err != nil { unauthorized(w) diff --git a/web/handler/status_create.go b/web/handler/status_create.go index 0484bfa..281f3f7 100644 --- a/web/handler/status_create.go +++ b/web/handler/status_create.go @@ -6,6 +6,7 @@ import ( ) func (h *Handler) showNewStatusView(w http.ResponseWriter, r *http.Request) { + protectClickJacking(w) _, err := h.getUser(r) if err != nil { unauthorized(w) diff --git a/web/handler/status_edit.go b/web/handler/status_edit.go index c5a2ed3..7a70eff 100644 --- a/web/handler/status_edit.go +++ b/web/handler/status_edit.go @@ -19,6 +19,7 @@ func RouteInt64Param(r *http.Request, param string) int64 { } func (h *Handler) showEditStatusView(w http.ResponseWriter, r *http.Request) { + protectClickJacking(w) user, err := h.getUser(r) if err != nil { unauthorized(w) diff --git a/web/handler/status_remove.go b/web/handler/status_remove.go index cf19731..5c498a1 100644 --- a/web/handler/status_remove.go +++ b/web/handler/status_remove.go @@ -6,6 +6,7 @@ import ( ) func (h *Handler) handleRemoveStatus(w http.ResponseWriter, r *http.Request) { + protectClickJacking(w) user, err := h.getUser(r) if err != nil { unauthorized(w) diff --git a/web/handler/tpl.go b/web/handler/tpl.go index 3793067..8cb7856 100644 --- a/web/handler/tpl.go +++ b/web/handler/tpl.go @@ -16,7 +16,7 @@ func (h *Handler) initTpl() { for name, content := range TplMap { views[name] = template.Must(template.New("main").Funcs(template.FuncMap{ "faces": func() []string { - return []string{"🙂", "😎", "😛", "🥰", "👽", "😱", "🤔", "😯", "🤒", "😡", "🥺", "🥳", "🤖", "💀", "😴", "😭", "☕", "🍺"} + return []string{"🙂", "😎", "😛", "🥰", "👽", "😱", "🤔", "😯", "🤒", "😡", "🥺", "🥳", "🤖", "💀", "😴", "😭", "☕", "🍺", "📖", "🔥", "❄️", "✨", "💡", "🎼"} }}).Parse(commonTemplates + content)) } } diff --git a/web/handler/user_show.go b/web/handler/user_show.go index 414c56d..e254bb7 100644 --- a/web/handler/user_show.go +++ b/web/handler/user_show.go @@ -15,6 +15,7 @@ import ( "image" "image/color" "image/draw" + "status/model" "strconv" "time" @@ -96,7 +97,7 @@ type statusjson struct { TimeAgo string `json:"timeAgo"` } -func (h *Handler) showUserStatusView(w http.ResponseWriter, r *http.Request) { +func (h *Handler) showUserStatusJSONView(w http.ResponseWriter, r *http.Request) { user := mux.Vars(r)["user"] if !h.storage.UserExists(user) { notFound(w) @@ -119,6 +120,19 @@ func (h *Handler) showUserStatusView(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(res) } +func (h *Handler) showUserStatusView(w http.ResponseWriter, r *http.Request) { + statuses, _, err := h.storage.StatusByUsername(mux.Vars(r)["user"], 1, 0) + if err != nil { + serverError(w, err) + return + } + var status model.Status + if len(statuses) > 0 { + status = statuses[0] + } + h.view("status").Execute(w, map[string]interface{}{"status": status}) +} + func drawText(canvas *image.RGBA, text string) error { var ( fgColor image.Image @@ -162,6 +176,46 @@ func createAvatar(text string) *image.RGBA { return background } +func (h *Handler) showUserStatusBadgeView(w http.ResponseWriter, r *http.Request) { + user := mux.Vars(r)["user"] + if !h.storage.UserExists(user) { + notFound(w) + return + } + statuses, _, err := h.storage.StatusByUsername(mux.Vars(r)["user"], 1, 0) + if err != nil { + serverError(w, err) + return + } + + var username string + if len(statuses) > 0 { + username = statuses[0].User + } + + background := "#f0ffff" + + dc := gg.NewContext(88, 31) + dc.SetHexColor(background) + dc.Clear() + dc.SetHexColor("#191970") + font, err := truetype.Parse(goregular.TTF) + if err != nil { + panic("") + } + face := truetype.NewFace(font, &truetype.Options{ + Size: 12, + }) + dc.SetFontFace(face) + if err != nil { + fmt.Println(err) + } + //dc.DrawString(username, 10, 14) + dc.DrawStringAnchored(username, 88/2, 8, 0.5, 0.5) + dc.DrawStringAnchored("status.cafe", 88/2, 20, 0.5, 0.5) + dc.EncodePNG(w) +} + func (h *Handler) showUserStatusImageView(w http.ResponseWriter, r *http.Request) { user := mux.Vars(r)["user"] if !h.storage.UserExists(user) { diff --git a/web/handler/widget_show.go b/web/handler/widget_show.go index 5bdbd26..38581b8 100644 --- a/web/handler/widget_show.go +++ b/web/handler/widget_show.go @@ -15,7 +15,7 @@ fetch("https://status.cafe/users/` + name + `/status.json") document.getElementById("statuscafe-content").innerHTML = "No status yet." return } - document.getElementById("statuscafe-username").innerHTML = '' + r.author + ' ' + r.face + ' ' + r.timeAgo + document.getElementById("statuscafe-username").innerHTML = '' + r.author + ' ' + r.face + ' ' + r.timeAgo document.getElementById("statuscafe-content").innerHTML = r.content }) `)) diff --git a/web/session/session.go b/web/session/session.go index a78a624..579e661 100644 --- a/web/session/session.go +++ b/web/session/session.go @@ -18,6 +18,7 @@ func New(key string, storage *storage.Storage) *Session { store := sessions.NewCookieStore([]byte(key)) store.Options = &sessions.Options{ HttpOnly: true, + Secure: true, MaxAge: 86400 * 30, } return &Session{