mirror of https://github.com/jlelse/GoBlog
Small things
This commit is contained in:
parent
e74afac829
commit
243d695bf4
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
|
@ -12,12 +13,14 @@ import (
|
|||
|
||||
var asContext = []string{"https://www.w3.org/ns/activitystreams"}
|
||||
|
||||
const asRequestKey requestContextKey = "asRequest"
|
||||
|
||||
func manipulateAsPath(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
if ap := appConfig.ActivityPub; ap != nil && ap.Enabled {
|
||||
if lowerAccept := strings.ToLower(r.Header.Get("Accept")); (strings.Contains(lowerAccept, contentTypeAS) || strings.Contains(lowerAccept, "application/ld+json")) && !strings.Contains(lowerAccept, contentTypeHTML) {
|
||||
// Is ActivityStream, add ".as" to differentiate cache and also trigger as function
|
||||
r.URL.Path += ".as"
|
||||
next.ServeHTTP(rw, r.WithContext(context.WithValue(r.Context(), asRequestKey, true)))
|
||||
return
|
||||
}
|
||||
}
|
||||
next.ServeHTTP(rw, r)
|
||||
|
|
|
@ -96,36 +96,40 @@ func checkIsLogin(next http.Handler) http.Handler {
|
|||
}
|
||||
|
||||
func checkLogin(w http.ResponseWriter, r *http.Request) bool {
|
||||
if r.Method == http.MethodPost &&
|
||||
r.Header.Get(contentType) == contentTypeWWWForm &&
|
||||
r.FormValue("loginaction") == "login" {
|
||||
// Do original request
|
||||
loginbody, _ := base64.StdEncoding.DecodeString(r.FormValue("loginbody"))
|
||||
req, _ := http.NewRequest(r.FormValue("loginmethod"), r.RequestURI, bytes.NewReader(loginbody))
|
||||
// Copy original headers
|
||||
loginheaders, _ := base64.StdEncoding.DecodeString(r.FormValue("loginheaders"))
|
||||
var headers http.Header
|
||||
_ = json.Unmarshal(loginheaders, &headers)
|
||||
for k, v := range headers {
|
||||
req.Header[k] = v
|
||||
}
|
||||
// Check credential
|
||||
if checkCredentials(r.FormValue("username"), r.FormValue("password")) {
|
||||
tokenCookie, err := createTokenCookie(r.FormValue("username"))
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return true
|
||||
}
|
||||
// Add cookie to original request
|
||||
req.AddCookie(tokenCookie)
|
||||
// Send cookie
|
||||
http.SetCookie(w, tokenCookie)
|
||||
}
|
||||
// Serve original request
|
||||
d.ServeHTTP(w, req)
|
||||
return true
|
||||
if r.Method != http.MethodPost {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
if r.Header.Get(contentType) != contentTypeWWWForm {
|
||||
return false
|
||||
}
|
||||
if r.FormValue("loginaction") != "login" {
|
||||
return false
|
||||
}
|
||||
// Do original request
|
||||
loginbody, _ := base64.StdEncoding.DecodeString(r.FormValue("loginbody"))
|
||||
req, _ := http.NewRequest(r.FormValue("loginmethod"), r.RequestURI, bytes.NewReader(loginbody))
|
||||
// Copy original headers
|
||||
loginheaders, _ := base64.StdEncoding.DecodeString(r.FormValue("loginheaders"))
|
||||
var headers http.Header
|
||||
_ = json.Unmarshal(loginheaders, &headers)
|
||||
for k, v := range headers {
|
||||
req.Header[k] = v
|
||||
}
|
||||
// Check credential
|
||||
if checkCredentials(r.FormValue("username"), r.FormValue("password")) {
|
||||
tokenCookie, err := createTokenCookie(r.FormValue("username"))
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return true
|
||||
}
|
||||
// Add cookie to original request
|
||||
req.AddCookie(tokenCookie)
|
||||
// Send cookie
|
||||
http.SetCookie(w, tokenCookie)
|
||||
}
|
||||
// Serve original request
|
||||
d.ServeHTTP(w, req)
|
||||
return true
|
||||
}
|
||||
|
||||
type authClaims struct {
|
||||
|
|
20
cache.go
20
cache.go
|
@ -7,7 +7,9 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/araddon/dateparse"
|
||||
|
@ -81,7 +83,23 @@ func cacheMiddleware(next http.Handler) http.Handler {
|
|||
}
|
||||
|
||||
func cacheKey(r *http.Request) string {
|
||||
return r.URL.String()
|
||||
def := cacheURLString(r.URL)
|
||||
// Special cases
|
||||
if asRequest, ok := r.Context().Value(asRequestKey).(bool); ok && asRequest {
|
||||
return "as-" + def
|
||||
}
|
||||
// Default
|
||||
return def
|
||||
}
|
||||
|
||||
func cacheURLString(u *url.URL) string {
|
||||
var buf strings.Builder
|
||||
_, _ = buf.WriteString(u.EscapedPath())
|
||||
if u.RawQuery != "" {
|
||||
_ = buf.WriteByte('?')
|
||||
_, _ = buf.WriteString(u.RawQuery)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func setCacheHeaders(w http.ResponseWriter, cache *cacheItem) {
|
||||
|
|
|
@ -25,7 +25,6 @@ type config struct {
|
|||
type configServer struct {
|
||||
Logging bool `mapstructure:"logging"`
|
||||
LogFile string `mapstructure:"logFile"`
|
||||
Debug bool `mapstructure:"Debug"`
|
||||
Port int `mapstructure:"port"`
|
||||
PublicAddress string `mapstructure:"publicAddress"`
|
||||
ShortPublicAddress string `mapstructure:"shortPublicAddress"`
|
||||
|
@ -204,7 +203,6 @@ func initConfig() error {
|
|||
// Defaults
|
||||
viper.SetDefault("server.logging", false)
|
||||
viper.SetDefault("server.logFile", "data/access.log")
|
||||
viper.SetDefault("server.debug", false)
|
||||
viper.SetDefault("server.port", 8080)
|
||||
viper.SetDefault("server.publicAddress", "http://localhost:8080")
|
||||
viper.SetDefault("server.publicHttps", false)
|
||||
|
|
8
go.mod
8
go.mod
|
@ -10,7 +10,7 @@ require (
|
|||
github.com/caddyserver/certmagic v0.12.0
|
||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/go-chi/chi v1.5.2
|
||||
github.com/go-chi/chi v1.5.3
|
||||
github.com/go-fed/httpsig v1.1.0
|
||||
github.com/go-sql-driver/mysql v1.5.0 // indirect
|
||||
github.com/gofrs/flock v0.8.0 // indirect
|
||||
|
@ -33,7 +33,7 @@ require (
|
|||
github.com/mattn/go-sqlite3 v1.14.6
|
||||
github.com/mholt/acmez v0.1.3 // indirect
|
||||
github.com/microcosm-cc/bluemonday v1.0.4
|
||||
github.com/miekg/dns v1.1.38 // indirect
|
||||
github.com/miekg/dns v1.1.39 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||
github.com/pelletier/go-toml v1.8.1 // indirect
|
||||
github.com/smartystreets/assertions v1.2.0 // indirect
|
||||
|
@ -53,9 +53,9 @@ require (
|
|||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect
|
||||
golang.org/x/mod v0.4.1 // indirect
|
||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d // indirect
|
||||
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43 // indirect
|
||||
golang.org/x/sys v0.0.0-20210223212115-eede4237b368 // indirect
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
|
||||
golang.org/x/text v0.3.5 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
|
|
16
go.sum
16
go.sum
|
@ -66,8 +66,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
|||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-chi/chi v1.5.2 h1:YcLIBANL4OTaAOcTdp//sskGa0yGACQMCtbnr7YEn0Q=
|
||||
github.com/go-chi/chi v1.5.2/go.mod h1:REp24E+25iKvxgeTfHmdUoL5x15kBiDBlnIl5bCwe2k=
|
||||
github.com/go-chi/chi v1.5.3 h1:+DVDS9/D3MTbEu3WrrH3oz9oP6PlSPSNj8LLw3X17yU=
|
||||
github.com/go-chi/chi v1.5.3/go.mod h1:Q8xfe6s3fjZyMr8ZTv5jL+vxhVaFyCq2s+RvSfzTD0E=
|
||||
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
|
||||
github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
|
@ -205,8 +205,8 @@ github.com/microcosm-cc/bluemonday v1.0.4 h1:p0L+CTpo/PLFdkoPcJemLXG+fpMD7pYOoDE
|
|||
github.com/microcosm-cc/bluemonday v1.0.4/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.38 h1:MtIY+fmHUVVgv1AXzmKMWcwdCYxTRPG1EDjpqF4RCEw=
|
||||
github.com/miekg/dns v1.1.38/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.39 h1:6dRfDGnHiXOMmTZkwWANy7bBXXlKls5Qu+pn+Ue0TLo=
|
||||
github.com/miekg/dns v1.1.39/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
|
@ -371,8 +371,8 @@ golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d h1:1aflnvSoWWLI2k/dMUAl5lvU1YO4Mb4hz0gh+1rjcxU=
|
||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM=
|
||||
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -405,8 +405,8 @@ golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43 h1:SgQ6LNaYJU0JIuEHv9+s6EbhSCwYeAf5Yvj6lpYlqAE=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210223212115-eede4237b368 h1:fDE3p0qf2V1co1vfj3/o87Ps8Hq6QTGNxJ5Xe7xSp80=
|
||||
golang.org/x/sys v0.0.0-20210223212115-eede4237b368/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=
|
||||
|
|
5
http.go
5
http.go
|
@ -100,11 +100,6 @@ func buildHandler() (http.Handler, error) {
|
|||
r.Use(checkIsCaptcha)
|
||||
r.Use(checkLoggedIn)
|
||||
|
||||
// Profiler
|
||||
if appConfig.Server.Debug {
|
||||
r.Mount("/debug", middleware.Profiler())
|
||||
}
|
||||
|
||||
// Micropub
|
||||
r.Route(micropubPath, func(mpRouter chi.Router) {
|
||||
mpRouter.Use(checkIndieAuth)
|
||||
|
|
31
main.go
31
main.go
|
@ -1,13 +1,31 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime/pprof"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
|
||||
var memprofile = flag.String("memprofile", "", "write memory profile to `file`")
|
||||
|
||||
func main() {
|
||||
// Init CPU profiling
|
||||
flag.Parse()
|
||||
if *cpuprofile != "" {
|
||||
f, err := os.Create(*cpuprofile)
|
||||
if err != nil {
|
||||
log.Fatal("could not create CPU profile: ", err)
|
||||
}
|
||||
defer f.Close()
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
log.Fatal("could not start CPU profile: ", err)
|
||||
}
|
||||
defer pprof.StopCPUProfile()
|
||||
}
|
||||
// Initialize config
|
||||
log.Println("Initialize configuration...")
|
||||
err := initConfig()
|
||||
|
@ -90,6 +108,19 @@ func main() {
|
|||
<-quit
|
||||
log.Println("Stopping...")
|
||||
|
||||
// Write memory profile
|
||||
if *memprofile != "" {
|
||||
f, err := os.Create(*memprofile)
|
||||
if err != nil {
|
||||
log.Fatal("could not create memory profile: ", err)
|
||||
}
|
||||
defer f.Close()
|
||||
// runtime.GC() // get up-to-date statistics
|
||||
if err := pprof.WriteHeapProfile(f); err != nil {
|
||||
log.Fatal("could not write memory profile: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Close DB
|
||||
err = closeDb()
|
||||
if err != nil {
|
||||
|
|
9
posts.go
9
posts.go
|
@ -41,10 +41,6 @@ const (
|
|||
)
|
||||
|
||||
func servePost(w http.ResponseWriter, r *http.Request) {
|
||||
as := strings.HasSuffix(r.URL.Path, ".as")
|
||||
if as {
|
||||
r.URL.Path = strings.TrimSuffix(r.URL.Path, ".as")
|
||||
}
|
||||
p, err := getPost(r.URL.Path)
|
||||
if err == errPostNotFound {
|
||||
serve404(w, r)
|
||||
|
@ -53,7 +49,7 @@ func servePost(w http.ResponseWriter, r *http.Request) {
|
|||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if as {
|
||||
if asRequest, ok := r.Context().Value(asRequestKey).(bool); ok && asRequest {
|
||||
p.serveActivityStreams(w)
|
||||
return
|
||||
}
|
||||
|
@ -109,8 +105,7 @@ func (p *postPaginationAdapter) Slice(offset, length int, data interface{}) erro
|
|||
|
||||
func serveHome(blog string, path string) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
as := strings.HasSuffix(r.URL.Path, ".as")
|
||||
if as {
|
||||
if asRequest, ok := r.Context().Value(asRequestKey).(bool); ok && asRequest {
|
||||
appConfig.Blogs[blog].serveActivityStreams(blog, w, r)
|
||||
return
|
||||
}
|
||||
|
|
21
utils.go
21
utils.go
|
@ -16,15 +16,15 @@ import (
|
|||
type requestContextKey string
|
||||
|
||||
func urlize(str string) string {
|
||||
newStr := ""
|
||||
for _, c := range strings.Split(strings.ToLower(str), "") {
|
||||
if c >= "a" && c <= "z" || c >= "A" && c <= "Z" || c >= "0" && c <= "9" {
|
||||
newStr += c
|
||||
} else if c == " " {
|
||||
newStr += "-"
|
||||
var sb strings.Builder
|
||||
for _, c := range strings.ToLower(str) {
|
||||
if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' {
|
||||
_, _ = sb.WriteRune(c)
|
||||
} else if c == ' ' {
|
||||
_, _ = sb.WriteRune('-')
|
||||
}
|
||||
}
|
||||
return newStr
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func sortedStrings(s []string) []string {
|
||||
|
@ -105,11 +105,10 @@ func resolveURLReferences(base string, refs ...string) ([]string, error) {
|
|||
}
|
||||
|
||||
func unescapedPath(p string) string {
|
||||
u, err := url.PathUnescape(p)
|
||||
if err != nil {
|
||||
return p
|
||||
if u, err := url.PathUnescape(p); err == nil {
|
||||
return u
|
||||
}
|
||||
return u
|
||||
return p
|
||||
}
|
||||
|
||||
func slashIfEmpty(s string) string {
|
||||
|
|
Loading…
Reference in New Issue