More config settings and age gating
This commit is contained in:
parent
532135094c
commit
aca9734b14
1
blog.go
1
blog.go
|
@ -133,6 +133,7 @@ func (b *Blog) SetupHTTP() {
|
|||
negroni.HandlerFunc(sessions.Middleware),
|
||||
negroni.HandlerFunc(middleware.CSRF(responses.Forbidden)),
|
||||
negroni.HandlerFunc(auth.Middleware),
|
||||
negroni.HandlerFunc(middleware.AgeGate(authctl.AgeGate)),
|
||||
)
|
||||
n.UseHandler(r)
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/kirsle/blog/internal/forms"
|
||||
"github.com/kirsle/blog/models/settings"
|
||||
"github.com/kirsle/blog/internal/render"
|
||||
"github.com/kirsle/blog/internal/responses"
|
||||
"github.com/kirsle/blog/models/settings"
|
||||
)
|
||||
|
||||
func settingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -21,11 +21,16 @@ func settingsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
redisPort, _ := strconv.Atoi(r.FormValue("redis-port"))
|
||||
redisDB, _ := strconv.Atoi(r.FormValue("redis-db"))
|
||||
mailPort, _ := strconv.Atoi(r.FormValue("mail-port"))
|
||||
ppp, _ := strconv.Atoi(r.FormValue("posts-per-page"))
|
||||
ppf, _ := strconv.Atoi(r.FormValue("posts-per-feed"))
|
||||
form := &forms.Settings{
|
||||
Title: r.FormValue("title"),
|
||||
Description: r.FormValue("description"),
|
||||
AdminEmail: r.FormValue("admin-email"),
|
||||
URL: r.FormValue("url"),
|
||||
NSFW: r.FormValue("nsfw") == "true",
|
||||
PostsPerPage: ppp,
|
||||
PostsPerFeed: ppf,
|
||||
RedisEnabled: len(r.FormValue("redis-enabled")) > 0,
|
||||
RedisHost: r.FormValue("redis-host"),
|
||||
RedisPort: redisPort,
|
||||
|
@ -45,6 +50,9 @@ func settingsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
settings.Site.Description = form.Description
|
||||
settings.Site.AdminEmail = form.AdminEmail
|
||||
settings.Site.URL = form.URL
|
||||
settings.Site.NSFW = form.NSFW
|
||||
settings.Blog.PostsPerPage = form.PostsPerPage
|
||||
settings.Blog.PostsPerFeed = form.PostsPerFeed
|
||||
settings.Redis.Enabled = form.RedisEnabled
|
||||
settings.Redis.Host = form.RedisHost
|
||||
settings.Redis.Port = form.RedisPort
|
||||
|
|
35
internal/controllers/authctl/age-gate.go
Normal file
35
internal/controllers/authctl/age-gate.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
package authctl
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/kirsle/blog/internal/log"
|
||||
"github.com/kirsle/blog/internal/render"
|
||||
"github.com/kirsle/blog/internal/responses"
|
||||
"github.com/kirsle/blog/internal/sessions"
|
||||
)
|
||||
|
||||
// AgeGate handles age verification for NSFW blogs.
|
||||
func AgeGate(w http.ResponseWriter, r *http.Request) {
|
||||
next := r.FormValue("next")
|
||||
if next == "" {
|
||||
next = "/"
|
||||
}
|
||||
v := map[string]interface{}{
|
||||
"Next": next,
|
||||
}
|
||||
|
||||
if r.Method == http.MethodPost {
|
||||
confirm := r.FormValue("confirm")
|
||||
log.Info("confirm: %s", confirm)
|
||||
if r.FormValue("confirm") == "true" {
|
||||
session := sessions.Get(r)
|
||||
session.Values["age-ok"] = true
|
||||
session.Save(r, w)
|
||||
responses.Redirect(w, next)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
render.Template(w, r, ".age-gate.gohtml", v)
|
||||
}
|
|
@ -11,6 +11,9 @@ type Settings struct {
|
|||
Description string
|
||||
AdminEmail string
|
||||
URL string
|
||||
NSFW bool
|
||||
PostsPerPage int
|
||||
PostsPerFeed int
|
||||
RedisEnabled bool
|
||||
RedisHost string
|
||||
RedisPort int
|
||||
|
|
59
internal/middleware/age-gate.go
Normal file
59
internal/middleware/age-gate.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/kirsle/blog/internal/responses"
|
||||
"github.com/kirsle/blog/internal/sessions"
|
||||
"github.com/kirsle/blog/models/settings"
|
||||
"github.com/urfave/negroni"
|
||||
)
|
||||
|
||||
var ageGateSuffixes = []string{
|
||||
".js",
|
||||
".css",
|
||||
".txt",
|
||||
".ico",
|
||||
".png",
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".gif",
|
||||
}
|
||||
|
||||
// AgeGate is a middleware generator that does age verification for NSFW sites.
|
||||
func AgeGate(verifyHandler func(http.ResponseWriter, *http.Request)) negroni.HandlerFunc {
|
||||
middleware := func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
s, _ := settings.Load()
|
||||
if !s.Site.NSFW {
|
||||
next(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
path := r.URL.Path
|
||||
if strings.HasPrefix(path, "/age-verify") {
|
||||
verifyHandler(w, r) // defer to the age gate handler itself.
|
||||
return
|
||||
}
|
||||
|
||||
// Allow static files and things through.
|
||||
for _, prefix := range ageGateSuffixes {
|
||||
if strings.HasSuffix(path, prefix) {
|
||||
next(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// See if they've been cleared.
|
||||
session := sessions.Get(r)
|
||||
if val, _ := session.Values["age-ok"].(bool); !val {
|
||||
// They haven't been verified.
|
||||
responses.Redirect(w, "/age-verify?next="+r.URL.Path)
|
||||
return
|
||||
}
|
||||
|
||||
next(w, r)
|
||||
}
|
||||
|
||||
return middleware
|
||||
}
|
|
@ -20,6 +20,7 @@ type Settings struct {
|
|||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
AdminEmail string `json:"adminEmail"`
|
||||
NSFW bool `json:"nsfw"`
|
||||
URL string `json:"url"`
|
||||
} `json:"site"`
|
||||
|
||||
|
@ -29,6 +30,12 @@ type Settings struct {
|
|||
HashCost int `json:"hashCost"` // Bcrypt hash cost for passwords
|
||||
} `json:"security"`
|
||||
|
||||
// Blog settings.
|
||||
Blog struct {
|
||||
PostsPerPage int `json:"postsPerPage"`
|
||||
PostsPerFeed int `json:"postsPerFeed"`
|
||||
} `json:"blog"`
|
||||
|
||||
// Redis settings for caching in JsonDB.
|
||||
Redis struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
|
@ -58,6 +65,8 @@ func Defaults() *Settings {
|
|||
s.Site.Title = "Untitled Site"
|
||||
s.Security.HashCost = 14
|
||||
s.Security.SecretKey = RandomKey()
|
||||
s.Blog.PostsPerPage = 10
|
||||
s.Blog.PostsPerFeed = 10
|
||||
s.Redis.Host = "localhost"
|
||||
s.Redis.Port = 6379
|
||||
s.Redis.DB = 0
|
||||
|
|
34
root/.age-gate.gohtml
Normal file
34
root/.age-gate.gohtml
Normal file
|
@ -0,0 +1,34 @@
|
|||
{{ define "title" }}Age Verification{{ end }}
|
||||
{{ define "content" }}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form action="/age-verify" method="POST">
|
||||
<input type="hidden" name="_csrf" value="{{ .CSRF }}">
|
||||
<input type="hidden" name="next" value="{{ .Data.Next }}">
|
||||
<input type="hidden" name="confirm" value="true">
|
||||
|
||||
<h1>Restricted Content</h1>
|
||||
|
||||
<p>
|
||||
This website has been marked <abbr title="Not Safe For Work">NSFW</abbr>
|
||||
by its owner. It may contain nudity or content not suited for users
|
||||
under the age of 18.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To proceed, you must verify you are at least 18 years or older.
|
||||
</p>
|
||||
|
||||
<button type="submit"
|
||||
class="btn btn-danger">
|
||||
I am 18 years or older
|
||||
</button>
|
||||
<a class="btn btn-primary"
|
||||
href="https://duckduckgo.com/">
|
||||
Get me out of here!
|
||||
</a>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
|
@ -50,6 +50,38 @@
|
|||
placeholder="https://www.example.com/">
|
||||
</div>
|
||||
|
||||
<strong>NSFW Website</strong>
|
||||
<div class="form-check mb-4">
|
||||
<label class="form-check-label">
|
||||
<input type="checkbox"
|
||||
class="form-check-input"
|
||||
name="nsfw"
|
||||
value="true"
|
||||
{{ if .Site.NSFW }}checked{{ end }}>
|
||||
Website is NSFW. Requires an age verification to enter.
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<h3>Blog Settings</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="admin-email">Posts Per Page</label>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
name="posts-per-page"
|
||||
value="{{ .Blog.PostsPerPage }}"
|
||||
placeholder="https://www.example.com/">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="admin-email">Posts Per (RSS) Feed</label>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
name="posts-per-page"
|
||||
value="{{ .Blog.PostsPerFeed }}"
|
||||
placeholder="https://www.example.com/">
|
||||
</div>
|
||||
|
||||
<h3>Redis Cache</h3>
|
||||
|
||||
<p>
|
||||
|
|
Loading…
Reference in New Issue
Block a user