1 Commits

Author SHA1 Message Date
orangix
b78ed44730 allow external origin to access media files 2026-01-25 07:23:08 +01:00
8 changed files with 29 additions and 42 deletions

View File

@@ -36,8 +36,6 @@ func (client *Client) FetchTrending(section, sort, page string) ([]Submission, e
case "best": case "best":
q.Add("filter[window]", "all") q.Add("filter[window]", "all")
q.Add("sort", "-top") q.Add("sort", "-top")
case "random":
q.Add("sort", "random")
case "popular": case "popular":
fallthrough fallthrough
default: default:
@@ -53,8 +51,6 @@ func (client *Client) FetchTrending(section, sort, page string) ([]Submission, e
case "top": case "top":
q.Add("filter[section]", "eq:top") q.Add("filter[section]", "eq:top")
q.Add("filter[window]", "day") q.Add("filter[window]", "day")
case "random":
q.Add("filter[section]", "eq:random")
default: default:
q.Add("filter[section]", "eq:hot") q.Add("filter[section]", "eq:hot")
section = "hot" section = "hot"

13
main.go
View File

@@ -87,7 +87,7 @@ func main() {
app.Handle("GET /t/{tag}", wrapHandler(func(w http.ResponseWriter, r *http.Request) error { app.Handle("GET /t/{tag}", wrapHandler(func(w http.ResponseWriter, r *http.Request) error {
name, ext := utils.SplitNameExt(r.PathValue("tag")) name, ext := utils.SplitNameExt(r.PathValue("tag"))
if ext != "" { if ext != "" {
r.SetPathValue("tag", name) r.SetPathValue("tag", name[0:len(name)-1])
r.SetPathValue("type", ext) r.SetPathValue("type", ext)
return pages.HandleTagRSS(w, r) return pages.HandleTagRSS(w, r)
} }
@@ -98,7 +98,7 @@ func main() {
app.Handle("GET /user/{userID}", wrapHandler(func(w http.ResponseWriter, r *http.Request) error { app.Handle("GET /user/{userID}", wrapHandler(func(w http.ResponseWriter, r *http.Request) error {
name, ext := utils.SplitNameExt(r.PathValue("userID")) name, ext := utils.SplitNameExt(r.PathValue("userID"))
if ext != "" { if ext != "" {
r.SetPathValue("userID", name) r.SetPathValue("userID", name[0:len(name)-1])
r.SetPathValue("type", ext) r.SetPathValue("type", ext)
return pages.HandleUserRSS(w, r) return pages.HandleUserRSS(w, r)
} }
@@ -129,14 +129,7 @@ func main() {
r.SetPathValue("postID", component) r.SetPathValue("postID", component)
return pages.HandleGifv(w, r) return pages.HandleGifv(w, r)
case strings.Contains(component, "."): case strings.Contains(component, "."):
baseName, extension := utils.SplitNameExt(r.PathValue("component")) return pages.HandleMedia(w, r)
r.SetPathValue("baseName", baseName)
r.SetPathValue("extension", extension)
switch extension {
case ".png", ".gif", ".jpg", ".jpeg", ".webp", ".mp4", ".webm":
return pages.HandleMedia(w, r)
}
fallthrough
default: default:
r.SetPathValue("postID", component) r.SetPathValue("postID", component)
return pages.HandlePost(w, r) return pages.HandlePost(w, r)

View File

@@ -12,11 +12,12 @@ import (
func HandleMedia(w http.ResponseWriter, r *http.Request) error { func HandleMedia(w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Cache-Control", "public,max-age=31557600") w.Header().Set("Cache-Control", "public,max-age=31557600")
w.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'self'; img-src 'self'") w.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'self'; img-src 'self'")
baseName, extension := r.PathValue("baseName"), r.PathValue("extension") splitName := strings.SplitN(r.PathValue("component"), ".", 2)
baseName, extension := splitName[0], splitName[1]
if strings.HasPrefix(r.URL.Path, "/stack") { if strings.HasPrefix(r.URL.Path, "/stack") {
return handleMedia(w, r, "https://i.stack.imgur.com/"+baseName+extension) return handleMedia(w, r, "https://i.stack.imgur.com/"+strings.ReplaceAll(baseName, "stack/", "")+"."+extension)
} else { } else {
return handleMedia(w, r, "https://i.imgur.com/"+baseName+extension) return handleMedia(w, r, "https://i.imgur.com/"+baseName+"."+extension)
} }
} }
@@ -34,6 +35,9 @@ func HandleUserAvatar(w http.ResponseWriter, r *http.Request) error {
func handleMedia(w http.ResponseWriter, r *http.Request, url string) error { func handleMedia(w http.ResponseWriter, r *http.Request, url string) error {
utils.SetHeaders(w) utils.SetHeaders(w)
if !utils.Config.RestrictiveCORS {
w.Header().Set("Access-Control-Allow-Origin", "*")
}
path := r.URL.Path path := r.URL.Path
if utils.Config.ForceWebp && if utils.Config.ForceWebp &&

View File

@@ -114,21 +114,21 @@ func handleFeed(w http.ResponseWriter, r *http.Request, instance string, feed *f
feed.Items = append(feed.Items, item) feed.Items = append(feed.Items, item)
} }
w.Header().Set("Content-Type", mime.TypeByExtension(r.PathValue("type"))) w.Header().Set("Content-Type", mime.TypeByExtension("."+r.PathValue("type")))
switch r.PathValue("type") { switch r.PathValue("type") {
case ".atom": case "atom":
body, err := feed.ToAtom() body, err := feed.ToAtom()
if err != nil { if err != nil {
return err return err
} }
w.Write([]byte(body)) w.Write([]byte(body))
case ".json": case "json":
body, err := feed.ToJSON() body, err := feed.ToJSON()
if err != nil { if err != nil {
return err return err
} }
w.Write([]byte(body)) w.Write([]byte(body))
case ".rss": case "rss":
body, err := feed.ToRss() body, err := feed.ToRss()
if err != nil { if err != nil {
return err return err

View File

@@ -26,7 +26,7 @@ func HandleTrending(w http.ResponseWriter, r *http.Request) error {
section := r.URL.Query().Get("section") section := r.URL.Query().Get("section")
switch section { switch section {
case "hot", "new", "top", "random": case "hot", "new", "top":
default: default:
section = "hot" section = "hot"
} }

View File

@@ -12,6 +12,7 @@ type config struct {
ProtocolDetection bool ProtocolDetection bool
Secure bool Secure bool
ForceWebp bool ForceWebp bool
RestrictiveCORS bool
ImageCache bool ImageCache bool
CleanupInterval time.Duration CleanupInterval time.Duration
CacheDir string CacheDir string
@@ -39,6 +40,7 @@ func LoadConfig() {
ProtocolDetection: envBool("PROTOCOL_DETECTION"), ProtocolDetection: envBool("PROTOCOL_DETECTION"),
Secure: envBool("SECURE"), Secure: envBool("SECURE"),
ForceWebp: envBool("FORCE_WEBP"), ForceWebp: envBool("FORCE_WEBP"),
RestrictiveCORS: envBool("RESTRICTIVE_CORS"),
Privacy: map[string]interface{}{ Privacy: map[string]interface{}{
"set": os.Getenv("PRIVACY_NOT_COLLECTED") != "", "set": os.Getenv("PRIVACY_NOT_COLLECTED") != "",
"policy": os.Getenv("PRIVACY_POLICY"), "policy": os.Getenv("PRIVACY_POLICY"),

View File

@@ -1,8 +1,16 @@
package utils package utils
import "path/filepath"
func SplitNameExt(path string) (name, ext string) { func SplitNameExt(path string) (name, ext string) {
ext = filepath.Ext(path) name, ext = path, ""
return path[:len(path)-len(ext)], ext for range 5 {
if len(name) == 0 || name[len(name)-1] == '.' || name[len(name)-1] == '/' {
break
}
name = name[:len(name)-1]
ext = path[len(name):]
}
if len(name) == 0 || name[len(name)-1] != '.' {
return path, ""
}
return
} }

View File

@@ -30,35 +30,20 @@
<a href="?section=hot&sort={{sort}}"><b>Hot</b></a> <a href="?section=hot&sort={{sort}}"><b>Hot</b></a>
<a href="?section=new&sort={{sort}}">New</a> <a href="?section=new&sort={{sort}}">New</a>
<a href="?section=top&sort={{sort}}">Top</a> <a href="?section=top&sort={{sort}}">Top</a>
<a href="?section=random&sort=random">Random</a>
{{/equal}} {{/equal}}
{{#equal section "new"}} {{#equal section "new"}}
<a href="?section=hot&sort={{sort}}">Hot</a> <a href="?section=hot&sort={{sort}}">Hot</a>
<a href="?section=new&sort={{sort}}"><b>New</b></a> <a href="?section=new&sort={{sort}}"><b>New</b></a>
<a href="?section=top&sort={{sort}}">Top</a> <a href="?section=top&sort={{sort}}">Top</a>
<a href="?section=random&sort=random">Random</a>
{{/equal}} {{/equal}}
{{#equal section "top"}} {{#equal section "top"}}
<a href="?section=hot&sort={{sort}}">Hot</a> <a href="?section=hot&sort={{sort}}">Hot</a>
<a href="?section=new&sort={{sort}}">New</a> <a href="?section=new&sort={{sort}}">New</a>
<a href="?section=top&sort={{sort}}"><b>Top</b></a> <a href="?section=top&sort={{sort}}"><b>Top</b></a>
<a href="?section=random&sort=random">Random</a>
{{/equal}}
{{#equal section "random"}}
<a href="?section=hot&sort={{sort}}">Hot</a>
<a href="?section=new&sort={{sort}}">New</a>
<a href="?section=top&sort={{sort}}">Top</a>
<a href="?section=random&sort=random"><b>Random</b></a>
{{/equal}} {{/equal}}
</div> </div>
<hr class="sm:hidden my-2" /> <hr class="sm:hidden my-2" />
<div class="flex flex-col sm:items-end"> <div class="flex flex-col sm:items-end">
{{#equal section "random"}}
<a href="?section=hot&sort=popular">Popular</a>
<a href="?section=hot&sort=newest">Newest</a>
<a href="?section=hot&sort=best">Best</a>
{{/equal}}
{{#noteq section "random"}}
{{#equal sort "popular"}} {{#equal sort "popular"}}
<a href="?section={{section}}&sort=popular"><b>Popular</b></a> <a href="?section={{section}}&sort=popular"><b>Popular</b></a>
<a href="?section={{section}}&sort=newest">Newest</a> <a href="?section={{section}}&sort=newest">Newest</a>
@@ -74,7 +59,6 @@
<a href="?section={{section}}&sort=newest">Newest</a> <a href="?section={{section}}&sort=newest">Newest</a>
<a href="?section={{section}}&sort=best"><b>Best</b></a> <a href="?section={{section}}&sort=best"><b>Best</b></a>
{{/equal}} {{/equal}}
{{/noteq}}
</div> </div>
</div> </div>
</header> </header>