Private mode

This commit is contained in:
Jan-Lukas Else 2021-02-27 08:31:06 +01:00
parent 98e81875d4
commit e25199b2a3
9 changed files with 118 additions and 56 deletions

View File

@ -15,7 +15,7 @@ var asContext = []string{"https://www.w3.org/ns/activitystreams"}
const asRequestKey requestContextKey = "asRequest" const asRequestKey requestContextKey = "asRequest"
func manipulateAsPath(next http.Handler) http.Handler { func checkActivityStreamsRequest(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if ap := appConfig.ActivityPub; ap != nil && ap.Enabled { 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) { if lowerAccept := strings.ToLower(r.Header.Get("Accept")); (strings.Contains(lowerAccept, contentTypeAS) || strings.Contains(lowerAccept, "application/ld+json")) && !strings.Contains(lowerAccept, contentTypeHTML) {

View File

@ -20,6 +20,7 @@ type config struct {
PathRedirects []*configRegexRedirect `mapstructure:"pathRedirects"` PathRedirects []*configRegexRedirect `mapstructure:"pathRedirects"`
ActivityPub *configActivityPub `mapstructure:"activityPub"` ActivityPub *configActivityPub `mapstructure:"activityPub"`
Notifications *configNotifications `mapstructure:"notifications"` Notifications *configNotifications `mapstructure:"notifications"`
PrivateMode *configPrivateMode `mapstructure:"privateMode"`
} }
type configServer struct { type configServer struct {
@ -190,6 +191,10 @@ type configTelegram struct {
InstantViewHash string `mapstructure:"instantViewHash"` InstantViewHash string `mapstructure:"instantViewHash"`
} }
type configPrivateMode struct {
Enabled bool `mapstructure:"enabled"`
}
var appConfig = &config{} var appConfig = &config{}
func initConfig() error { func initConfig() error {
@ -255,6 +260,9 @@ func initConfig() error {
} }
appConfig.Micropub.MediaStorage.MediaURL = strings.TrimSuffix(appConfig.Micropub.MediaStorage.MediaURL, "/") appConfig.Micropub.MediaStorage.MediaURL = strings.TrimSuffix(appConfig.Micropub.MediaStorage.MediaURL, "/")
} }
if pm := appConfig.PrivateMode; pm != nil && pm.Enabled {
appConfig.ActivityPub = &configActivityPub{Enabled: false}
}
return nil return nil
} }

5
go.mod
View File

@ -44,6 +44,7 @@ require (
github.com/spf13/viper v1.7.1 github.com/spf13/viper v1.7.1
github.com/tdewolff/minify/v2 v2.9.13 github.com/tdewolff/minify/v2 v2.9.13
github.com/tdewolff/parse/v2 v2.5.11 // indirect github.com/tdewolff/parse/v2 v2.5.11 // indirect
github.com/thoas/go-funk v0.7.1-0.20201128100912-5035611e402b
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2 github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2
github.com/yuin/goldmark v1.3.2 github.com/yuin/goldmark v1.3.2
@ -53,9 +54,9 @@ require (
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect
golang.org/x/mod v0.4.1 // indirect golang.org/x/mod v0.4.1 // indirect
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 // indirect golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 // indirect golang.org/x/sys v0.0.0-20210227040730-b0d1d43c014d // indirect
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
golang.org/x/text v0.3.5 // indirect golang.org/x/text v0.3.5 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect

10
go.sum
View File

@ -288,6 +288,8 @@ github.com/tdewolff/parse/v2 v2.5.11 h1:Wq0x026IKZh9GPUB5Fp+v5bki/SNmpIkdltcnm6H
github.com/tdewolff/parse/v2 v2.5.11/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho= github.com/tdewolff/parse/v2 v2.5.11/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4= github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/thoas/go-funk v0.7.1-0.20201128100912-5035611e402b h1:EBnJBNE7sw2Z7dg2inKlTQNO2se7PvDejZQjNaPAjg8=
github.com/thoas/go-funk v0.7.1-0.20201128100912-5035611e402b/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
@ -370,8 +372,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-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-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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/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-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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -404,8 +406,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-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-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-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 h1:8qxJSnu+7dRq6upnbntrmriWByIakBuct5OM/MdQC1M= golang.org/x/sys v0.0.0-20210227040730-b0d1d43c014d h1:9fH9JvLNoSpsDWcXJ4dSE3lZW99Z3OCUZLr07g60U6o=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210227040730-b0d1d43c014d/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-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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=

128
http.go
View File

@ -77,13 +77,21 @@ func reloadRouter() error {
return nil return nil
} }
const paginationPath = "/page/{page:[0-9-]+}"
const feedPath = ".{feed:rss|json|atom}"
func buildHandler() (http.Handler, error) { func buildHandler() (http.Handler, error) {
paginationPath := "/page/{page:[0-9-]+}"
feedPath := ".{feed:rss|json|atom}"
r := chi.NewRouter() r := chi.NewRouter()
// Private mode
privateMode := false
privateModeHandler := []func(http.Handler) http.Handler{}
if pm := appConfig.PrivateMode; pm != nil && pm.Enabled {
privateMode = true
privateModeHandler = append(privateModeHandler, authMiddleware)
}
// Basic middleware
if appConfig.Server.Logging { if appConfig.Server.Logging {
r.Use(logMiddleware) r.Use(logMiddleware)
} }
@ -96,29 +104,37 @@ func buildHandler() (http.Handler, error) {
if !appConfig.Cache.Enable { if !appConfig.Cache.Enable {
r.Use(middleware.NoCache) r.Use(middleware.NoCache)
} }
// No Index Header
if privateMode {
r.Use(noIndexHeader)
}
// Login middleware etc.
r.Use(checkIsLogin) r.Use(checkIsLogin)
r.Use(checkIsCaptcha) r.Use(checkIsCaptcha)
r.Use(checkLoggedIn) r.Use(checkLoggedIn)
r.Use(checkActivityStreamsRequest)
// Logout // Logout
r.With(authMiddleware).Get("/login", serveLogin) r.With(authMiddleware).Get("/login", serveLogin)
r.With(authMiddleware).Get("/logout", serveLogout) r.With(authMiddleware).Get("/logout", serveLogout)
// Micropub // Micropub
r.Route(micropubPath, func(mpRouter chi.Router) { r.Route(micropubPath, func(r chi.Router) {
mpRouter.Use(checkIndieAuth) r.Use(checkIndieAuth)
mpRouter.Get("/", serveMicropubQuery) r.Get("/", serveMicropubQuery)
mpRouter.Post("/", serveMicropubPost) r.Post("/", serveMicropubPost)
mpRouter.Post(micropubMediaSubPath, serveMicropubMedia) r.Post(micropubMediaSubPath, serveMicropubMedia)
}) })
// IndieAuth // IndieAuth
r.Route("/indieauth", func(indieauthRouter chi.Router) { r.Route("/indieauth", func(r chi.Router) {
indieauthRouter.Get("/", indieAuthRequest) r.Get("/", indieAuthRequest)
indieauthRouter.With(authMiddleware).Post("/accept", indieAuthAccept) r.With(authMiddleware).Post("/accept", indieAuthAccept)
indieauthRouter.Post("/", indieAuthVerification) r.Post("/", indieAuthVerification)
indieauthRouter.Get("/token", indieAuthToken) r.Get("/token", indieAuthToken)
indieauthRouter.Post("/token", indieAuthToken) r.Post("/token", indieAuthToken)
}) })
// ActivityPub and stuff // ActivityPub and stuff
@ -132,9 +148,9 @@ func buildHandler() (http.Handler, error) {
} }
// Webmentions // Webmentions
r.Route(webmentionPath, func(webmentionRouter chi.Router) { r.Route(webmentionPath, func(r chi.Router) {
webmentionRouter.Post("/", handleWebmention) r.Post("/", handleWebmention)
webmentionRouter.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
// Authenticated routes // Authenticated routes
r.Use(authMiddleware) r.Use(authMiddleware)
r.Get("/", webmentionAdmin) r.Get("/", webmentionAdmin)
@ -159,7 +175,8 @@ func buildHandler() (http.Handler, error) {
return nil, err return nil, err
} }
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(manipulateAsPath, cacheMiddleware) r.Use(privateModeHandler...)
r.Use(cacheMiddleware)
for _, path := range pp { for _, path := range pp {
r.Get(path, servePost) r.Get(path, servePost)
} }
@ -171,7 +188,7 @@ func buildHandler() (http.Handler, error) {
return nil, err return nil, err
} }
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(authMiddleware, cacheMiddleware) r.Use(authMiddleware)
for _, path := range dp { for _, path := range dp {
r.Get(path, servePost) r.Get(path, servePost)
} }
@ -183,6 +200,7 @@ func buildHandler() (http.Handler, error) {
return nil, err return nil, err
} }
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(privateModeHandler...)
r.Use(cacheMiddleware) r.Use(cacheMiddleware)
for _, path := range allPostAliases { for _, path := range allPostAliases {
r.Get(path, servePostAlias) r.Get(path, servePostAlias)
@ -200,13 +218,13 @@ func buildHandler() (http.Handler, error) {
} }
// Media files // Media files
r.Get(`/m/{file:[0-9a-fA-F]+(\.[0-9a-zA-Z]+)?}`, serveMediaFile) r.With(privateModeHandler...).Get(`/m/{file:[0-9a-fA-F]+(\.[0-9a-zA-Z]+)?}`, serveMediaFile)
// Captcha // Captcha
r.Handle("/captcha/*", captcha.Server(500, 250)) r.Handle("/captcha/*", captcha.Server(500, 250))
// Short paths // Short paths
r.With(cacheMiddleware).Get("/s/{id:[0-9a-fA-F]+}", redirectToLongPath) r.With(privateModeHandler...).With(cacheMiddleware).Get("/s/{id:[0-9a-fA-F]+}", redirectToLongPath)
for blog, blogConfig := range appConfig.Blogs { for blog, blogConfig := range appConfig.Blogs {
@ -216,12 +234,9 @@ func buildHandler() (http.Handler, error) {
blogPath = "" blogPath = ""
} }
r.Group(func(r chi.Router) {
})
// Sections // Sections
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(privateModeHandler...)
r.Use(cacheMiddleware) r.Use(cacheMiddleware)
for _, section := range blogConfig.Sections { for _, section := range blogConfig.Sections {
if section.Name != "" { if section.Name != "" {
@ -243,6 +258,7 @@ func buildHandler() (http.Handler, error) {
return nil, err return nil, err
} }
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(privateModeHandler...)
r.Use(cacheMiddleware) r.Use(cacheMiddleware)
r.Get(taxPath, serveTaxonomy(blog, taxonomy)) r.Get(taxPath, serveTaxonomy(blog, taxonomy))
for _, tv := range taxValues { for _, tv := range taxValues {
@ -253,13 +269,13 @@ func buildHandler() (http.Handler, error) {
r.Get(vPath+paginationPath, handler) r.Get(vPath+paginationPath, handler)
} }
}) })
} }
} }
// Photos // Photos
if blogConfig.Photos != nil && blogConfig.Photos.Enabled { if blogConfig.Photos != nil && blogConfig.Photos.Enabled {
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(privateModeHandler...)
r.Use(cacheMiddleware) r.Use(cacheMiddleware)
photoPath := blogPath + blogConfig.Photos.Path photoPath := blogPath + blogConfig.Photos.Path
handler := servePhotos(blog, photoPath) handler := servePhotos(blog, photoPath)
@ -272,6 +288,7 @@ func buildHandler() (http.Handler, error) {
// Search // Search
if blogConfig.Search != nil && blogConfig.Search.Enabled { if blogConfig.Search != nil && blogConfig.Search.Enabled {
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(privateModeHandler...)
r.Use(cacheMiddleware) r.Use(cacheMiddleware)
searchPath := blogPath + blogConfig.Search.Path searchPath := blogPath + blogConfig.Search.Path
handler := serveSearch(blog, searchPath) handler := serveSearch(blog, searchPath)
@ -288,7 +305,7 @@ func buildHandler() (http.Handler, error) {
// Stats // Stats
if blogConfig.BlogStats != nil && blogConfig.BlogStats.Enabled { if blogConfig.BlogStats != nil && blogConfig.BlogStats.Enabled {
statsPath := blogPath + blogConfig.BlogStats.Path statsPath := blogPath + blogConfig.BlogStats.Path
r.With(cacheMiddleware).Get(statsPath, serveBlogStats(blog, statsPath)) r.With(privateModeHandler...).With(cacheMiddleware).Get(statsPath, serveBlogStats(blog, statsPath))
} }
// Year / month archives // Year / month archives
@ -297,6 +314,7 @@ func buildHandler() (http.Handler, error) {
return nil, err return nil, err
} }
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(privateModeHandler...)
r.Use(cacheMiddleware) r.Use(cacheMiddleware)
for _, d := range dates { for _, d := range dates {
// Year // Year
@ -334,19 +352,23 @@ func buildHandler() (http.Handler, error) {
// Blog // Blog
if !blogConfig.PostAsHome { if !blogConfig.PostAsHome {
handler := serveHome(blog, blogPath) r.Group(func(r chi.Router) {
r.With(manipulateAsPath, cacheMiddleware).Get(fullBlogPath, handler) r.Use(privateModeHandler...)
r.With(cacheMiddleware).Get(fullBlogPath+feedPath, handler) r.Use(cacheMiddleware)
r.With(cacheMiddleware).Get(blogPath+paginationPath, handler) handler := serveHome(blog, blogPath)
r.Get(fullBlogPath, handler)
r.Get(fullBlogPath+feedPath, handler)
r.Get(blogPath+paginationPath, handler)
})
} }
// Custom pages // Custom pages
for _, cp := range blogConfig.CustomPages { for _, cp := range blogConfig.CustomPages {
handler := serveCustomPage(blogConfig, cp) handler := serveCustomPage(blogConfig, cp)
if cp.Cache { if cp.Cache {
r.With(cacheMiddleware).Get(cp.Path, handler) r.With(privateModeHandler...).With(cacheMiddleware).Get(cp.Path, handler)
} else { } else {
r.Get(cp.Path, handler) r.With(privateModeHandler...).Get(cp.Path, handler)
} }
} }
@ -356,20 +378,21 @@ func buildHandler() (http.Handler, error) {
if randomPath == "" { if randomPath == "" {
randomPath = "/random" randomPath = "/random"
} }
r.Get(blogPath+randomPath, redirectToRandomPost(blog)) r.With(privateModeHandler...).Get(blogPath+randomPath, redirectToRandomPost(blog))
} }
// Editor // Editor
r.Route(blogPath+"/editor", func(mpRouter chi.Router) { r.Route(blogPath+"/editor", func(r chi.Router) {
mpRouter.Use(authMiddleware) r.Use(authMiddleware)
mpRouter.Get("/", serveEditor(blog)) r.Get("/", serveEditor(blog))
mpRouter.Post("/", serveEditorPost(blog)) r.Post("/", serveEditorPost(blog))
}) })
// Comments // Comments
if commentsConfig := blogConfig.Comments; commentsConfig != nil && commentsConfig.Enabled { if commentsConfig := blogConfig.Comments; commentsConfig != nil && commentsConfig.Enabled {
commentsPath := blogPath + "/comment" commentsPath := blogPath + "/comment"
r.Route(commentsPath, func(cr chi.Router) { r.Route(commentsPath, func(cr chi.Router) {
cr.Use(privateModeHandler...)
cr.With(cacheMiddleware).Get("/{id:[0-9]+}", serveComment(blog)) cr.With(cacheMiddleware).Get("/{id:[0-9]+}", serveComment(blog))
cr.With(captchaMiddleware).Post("/", createComment(blog, commentsPath)) cr.With(captchaMiddleware).Post("/", createComment(blog, commentsPath))
// Admin // Admin
@ -385,10 +408,14 @@ func buildHandler() (http.Handler, error) {
} }
// Sitemap // Sitemap
r.With(cacheMiddleware).Get(sitemapPath, serveSitemap) r.With(privateModeHandler...).With(cacheMiddleware).Get(sitemapPath, serveSitemap)
// Robots.txt - doesn't need cache, because it's too simple // Robots.txt - doesn't need cache, because it's too simple
r.Get("/robots.txt", serveRobotsTXT) if !privateMode {
r.Get("/robots.txt", serveRobotsTXT)
} else {
r.Get("/robots.txt", servePrivateRobotsTXT)
}
// Check redirects, then serve 404 // Check redirects, then serve 404
r.With(cacheMiddleware, checkRegexRedirects).NotFound(serve404) r.With(cacheMiddleware, checkRegexRedirects).NotFound(serve404)
@ -411,12 +438,19 @@ func securityHeaders(next http.Handler) http.Handler {
extraCSPDomains += " " + strings.Join(appConfig.Server.CSPDomains, " ") extraCSPDomains += " " + strings.Join(appConfig.Server.CSPDomains, " ")
} }
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Strict-Transport-Security", "max-age=31536000;") w.Header().Set("Strict-Transport-Security", "max-age=31536000;")
w.Header().Add("Referrer-Policy", "no-referrer") w.Header().Set("Referrer-Policy", "no-referrer")
w.Header().Add("X-Content-Type-Options", "nosniff") w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Add("X-Frame-Options", "SAMEORIGIN") w.Header().Set("X-Frame-Options", "SAMEORIGIN")
w.Header().Add("X-Xss-Protection", "1; mode=block") w.Header().Set("X-Xss-Protection", "1; mode=block")
w.Header().Add("Content-Security-Policy", "default-src 'self'"+extraCSPDomains) w.Header().Set("Content-Security-Policy", "default-src 'self'"+extraCSPDomains)
next.ServeHTTP(w, r)
})
}
func noIndexHeader(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Robots-Tag", "noindex")
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
}) })
} }

View File

@ -8,3 +8,7 @@ import (
func serveRobotsTXT(w http.ResponseWriter, r *http.Request) { func serveRobotsTXT(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte(fmt.Sprintf("User-agent: *\nSitemap: %v", appConfig.Server.PublicAddress+sitemapPath))) _, _ = w.Write([]byte(fmt.Sprintf("User-agent: *\nSitemap: %v", appConfig.Server.PublicAddress+sitemapPath)))
} }
func servePrivateRobotsTXT(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("User-agent: *\nDisallow: /"))
}

View File

@ -14,6 +14,7 @@
<input type="password" name="password" placeholder="{{ string .Blog.Lang "password" }}"> <input type="password" name="password" placeholder="{{ string .Blog.Lang "password" }}">
<input class="fw" type="submit" value="{{ string .Blog.Lang "login" }}"> <input class="fw" type="submit" value="{{ string .Blog.Lang "login" }}">
</form> </form>
{{ include "author" . }}
</main> </main>
{{ end }} {{ end }}

View File

@ -9,6 +9,7 @@ import (
"strings" "strings"
"github.com/PuerkitoBio/goquery" "github.com/PuerkitoBio/goquery"
"github.com/thoas/go-funk"
"github.com/tomnomnom/linkheader" "github.com/tomnomnom/linkheader"
) )
@ -19,11 +20,12 @@ func (p *post) sendWebmentions() error {
return err return err
} }
links = append(links, contentLinks...) links = append(links, contentLinks...)
links = append(links, p.firstParameter(appConfig.Micropub.LikeParam), p.firstParameter(appConfig.Micropub.ReplyParam), p.firstParameter(appConfig.Micropub.BookmarkParam)) links = append(links, p.firstParameter("link"), p.firstParameter(appConfig.Micropub.LikeParam), p.firstParameter(appConfig.Micropub.ReplyParam), p.firstParameter(appConfig.Micropub.BookmarkParam))
for _, link := range links { for _, link := range funk.UniqString(links) {
if link == "" { if link == "" {
continue continue
} }
// Internal mention
if strings.HasPrefix(link, appConfig.Server.PublicAddress) { if strings.HasPrefix(link, appConfig.Server.PublicAddress) {
// Save mention directly // Save mention directly
if err := createWebmention(p.fullURL(), link); err != nil { if err := createWebmention(p.fullURL(), link); err != nil {
@ -31,6 +33,11 @@ func (p *post) sendWebmentions() error {
} }
continue continue
} }
// External mention
if pm := appConfig.PrivateMode; pm != nil && pm.Enabled {
// Private mode, don't send external mentions
continue
}
endpoint := discoverEndpoint(link) endpoint := discoverEndpoint(link)
if endpoint == "" { if endpoint == "" {
continue continue

View File

@ -10,6 +10,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"strings"
"github.com/PuerkitoBio/goquery" "github.com/PuerkitoBio/goquery"
"github.com/joncrlsn/dque" "github.com/joncrlsn/dque"
@ -73,6 +74,10 @@ func (m *mention) verifyMention() error {
return err return err
} }
req.Header.Set(userAgent, appUserAgent) req.Header.Set(userAgent, appUserAgent)
if strings.HasPrefix(m.Source, appConfig.Server.PublicAddress) {
// Set authentication
req.SetBasicAuth(appConfig.User.Nick, appConfig.User.Password)
}
resp, err := http.DefaultClient.Do(req) resp, err := http.DefaultClient.Do(req)
if err != nil { if err != nil {
return err return err