This commit is contained in:
m15o 2021-12-06 07:14:20 +01:00
parent 3dd8ca4c27
commit ae71abda0b
13 changed files with 113 additions and 22 deletions

View file

@ -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(

View file

@ -297,6 +297,21 @@ var TplMap = map[string]string{
<input type="submit" value="Submit">
</form>
{{ end }}`,
"status": `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>status cafe</title>
<link rel="stylesheet" href="/assets/style.css"/>
<meta name="description" content="your friends' updates">
</head>
<body>
{{ if .status.Content }}
{{ template "status" .status }}
{{ end }}
</body>
</html>`,
"status-updater": `{{ define "content" }}
<section>
<h1>Status Updater</h1>
@ -314,7 +329,7 @@ var TplMap = map[string]string{
Drag the following link to your bookmarks toolbar:
</p>
<p>
<a href="javascript:void(open('https://status.cafe/add','status.cafe','resizable,scrollbars,width=350,height=250'))">status updater</a>
<a href="javascript:void(open('https://status.cafe/add','status.cafe','resizable,scrollbars,width=350,height=290'))">status updater</a>
</p>
<p>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.</p>
</section>

View file

@ -15,7 +15,7 @@
Drag the following link to your bookmarks toolbar:
</p>
<p>
<a href="javascript:void(open('https://status.cafe/add','status.cafe','resizable,scrollbars,width=350,height=250'))">status updater</a>
<a href="javascript:void(open('https://status.cafe/add','status.cafe','resizable,scrollbars,width=350,height=290'))">status updater</a>
</p>
<p>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.</p>
</section>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>status cafe</title>
<link rel="stylesheet" href="/assets/style.css"/>
<meta name="description" content="your friends' updates">
</head>
<body>
{{ if .status.Content }}
{{ template "status" .status }}
{{ end }}
</body>
</html>

View file

@ -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 {

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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))
}
}

View file

@ -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) {

View file

@ -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 = '<a href="https://status.cafe/users/` + name + `">' + r.author + '</a> ' + r.face + ' ' + r.timeAgo
document.getElementById("statuscafe-username").innerHTML = '<a href="https://status.cafe/users/` + name + `" target="_blank">' + r.author + '</a> ' + r.face + ' ' + r.timeAgo
document.getElementById("statuscafe-content").innerHTML = r.content
})
`))

View file

@ -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{