Geo-gating on signup
This commit is contained in:
parent
45cb4d260e
commit
c172565a56
4
go.mod
4
go.mod
|
@ -35,6 +35,8 @@ require (
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.14 // indirect
|
github.com/mattn/go-sqlite3 v1.14.14 // indirect
|
||||||
github.com/microcosm-cc/bluemonday v1.0.19 // indirect
|
github.com/microcosm-cc/bluemonday v1.0.19 // indirect
|
||||||
|
github.com/oschwald/geoip2-golang v1.9.0 // indirect
|
||||||
|
github.com/oschwald/maxminddb-golang v1.11.0 // indirect
|
||||||
github.com/russross/blackfriday v1.5.2 // indirect
|
github.com/russross/blackfriday v1.5.2 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect
|
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect
|
||||||
|
@ -50,7 +52,7 @@ require (
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||||
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 // indirect
|
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 // indirect
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
|
golang.org/x/sys v0.9.0 // indirect
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/tools v0.1.12 // indirect
|
golang.org/x/tools v0.1.12 // indirect
|
||||||
|
|
6
go.sum
6
go.sum
|
@ -109,6 +109,10 @@ github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLv
|
||||||
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.19 h1:OI7hoF5FY4pFz2VA//RN8TfM0YJ2dJcl4P4APrCWy6c=
|
github.com/microcosm-cc/bluemonday v1.0.19 h1:OI7hoF5FY4pFz2VA//RN8TfM0YJ2dJcl4P4APrCWy6c=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.19/go.mod h1:QNzV2UbLK2/53oIIwTOyLUSABMkjZ4tqiyC1g/DyqxE=
|
github.com/microcosm-cc/bluemonday v1.0.19/go.mod h1:QNzV2UbLK2/53oIIwTOyLUSABMkjZ4tqiyC1g/DyqxE=
|
||||||
|
github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc=
|
||||||
|
github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y=
|
||||||
|
github.com/oschwald/maxminddb-golang v1.11.0 h1:aSXMqYR/EPNjGE8epgqwDay+P30hCBZIveY0WZbAWh0=
|
||||||
|
github.com/oschwald/maxminddb-golang v1.11.0/go.mod h1:YmVI+H0zh3ySFR3w+oz8PCfglAFj3PuCmui13+P9zDg=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
@ -214,6 +218,8 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+R
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||||
|
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
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 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||||
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=
|
||||||
|
|
20
pkg/config/geo_gate.go
Normal file
20
pkg/config/geo_gate.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
// GeoIP gating rules. TODO: make dynamically configurable.
|
||||||
|
|
||||||
|
// GeoIP database path (standard location on Fedora/Debian)
|
||||||
|
const GeoIPPath = "/usr/share/GeoIP/GeoLite2-City.mmdb"
|
||||||
|
|
||||||
|
// US states to block.
|
||||||
|
var BlockUSStates = map[string]interface{}{
|
||||||
|
"UT": nil, // Utah
|
||||||
|
"LA": nil, // Louisiana
|
||||||
|
"MS": nil, // Mississippi
|
||||||
|
"AR": nil, // Arkansas
|
||||||
|
"MT": nil, // Montana
|
||||||
|
}
|
||||||
|
|
||||||
|
// Countries to block.
|
||||||
|
var BlockCountries = map[string]interface{}{
|
||||||
|
// "DE": nil,
|
||||||
|
}
|
88
pkg/middleware/geo_gate.go
Normal file
88
pkg/middleware/geo_gate.go
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.nonshy.com/nonshy/website/pkg/config"
|
||||||
|
"code.nonshy.com/nonshy/website/pkg/controller/index"
|
||||||
|
"code.nonshy.com/nonshy/website/pkg/log"
|
||||||
|
"code.nonshy.com/nonshy/website/pkg/session"
|
||||||
|
"code.nonshy.com/nonshy/website/pkg/utility"
|
||||||
|
"github.com/oschwald/geoip2-golang"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GeoGate: block access to the site based on the user's location (due to local laws or regulations).
|
||||||
|
func GeoGate(handler http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
// Flash errors to admins.
|
||||||
|
onError := func(err error) {
|
||||||
|
session.FlashError(w, r, "GeoIP: %s", err)
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// See where they're coming from.
|
||||||
|
db, err := geoip2.Open(config.GeoIPPath)
|
||||||
|
if err != nil {
|
||||||
|
onError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// If you are using strings that may be invalid, check that ip is not nil
|
||||||
|
addr := strings.SplitN(utility.IPAddress(r), ":", 2)[0]
|
||||||
|
ip := net.ParseIP(utility.IPAddress(r))
|
||||||
|
log.Info("IP addr: %s (raw: %s)", ip, addr)
|
||||||
|
if ip != nil {
|
||||||
|
record, err := db.City(ip)
|
||||||
|
if err != nil {
|
||||||
|
onError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Raw: %+v", record)
|
||||||
|
|
||||||
|
// Blocked by US states
|
||||||
|
if record.Country.IsoCode == "US" {
|
||||||
|
for _, sub := range record.Subdivisions {
|
||||||
|
if _, ok := config.BlockUSStates[sub.IsoCode]; ok {
|
||||||
|
session.LogoutUser(w, r)
|
||||||
|
page := index.StaticTemplate("errors/geo_gate.html")()
|
||||||
|
page(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blocked by country code
|
||||||
|
if _, ok := config.BlockCountries[record.Country.IsoCode]; ok {
|
||||||
|
session.LogoutUser(w, r)
|
||||||
|
page := index.StaticTemplate("errors/geo_gate.html")()
|
||||||
|
page(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug info
|
||||||
|
fmt.Printf("Portuguese (BR) city name: %v\n", record.City.Names["pt-BR"])
|
||||||
|
if len(record.Subdivisions) > 0 {
|
||||||
|
fmt.Printf("English subdivision name: %v\n", record.Subdivisions[0].Names["en"])
|
||||||
|
}
|
||||||
|
fmt.Printf("Russian country name: %v\n", record.Country.Names["ru"])
|
||||||
|
fmt.Printf("ISO country code: %v\n", record.Country.IsoCode)
|
||||||
|
fmt.Printf("Time zone: %v\n", record.Location.TimeZone)
|
||||||
|
fmt.Printf("Coordinates: %v, %v\n", record.Location.Latitude, record.Location.Longitude)
|
||||||
|
// Output:
|
||||||
|
// Portuguese (BR) city name: Londres
|
||||||
|
// English subdivision name: England
|
||||||
|
// Russian country name: Великобритания
|
||||||
|
// ISO country code: GB
|
||||||
|
// Time zone: Europe/London
|
||||||
|
// Coordinates: 51.5142, -0.0931
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
|
@ -33,10 +33,11 @@ func New() http.Handler {
|
||||||
mux.HandleFunc("/contact", index.Contact())
|
mux.HandleFunc("/contact", index.Contact())
|
||||||
mux.HandleFunc("/login", account.Login())
|
mux.HandleFunc("/login", account.Login())
|
||||||
mux.HandleFunc("/logout", account.Logout())
|
mux.HandleFunc("/logout", account.Logout())
|
||||||
mux.HandleFunc("/signup", account.Signup())
|
mux.Handle("/signup", middleware.GeoGate(account.Signup()))
|
||||||
mux.HandleFunc("/forgot-password", account.ForgotPassword())
|
mux.HandleFunc("/forgot-password", account.ForgotPassword())
|
||||||
mux.HandleFunc("/settings/confirm-email", account.ConfirmEmailChange())
|
mux.HandleFunc("/settings/confirm-email", account.ConfirmEmailChange())
|
||||||
mux.HandleFunc("/markdown", index.StaticTemplate("markdown.html")())
|
mux.HandleFunc("/markdown", index.StaticTemplate("markdown.html")())
|
||||||
|
mux.HandleFunc("/test/geo-gate", index.StaticTemplate("errors/geo_gate.html")())
|
||||||
|
|
||||||
// Login Required. Pages that non-certified users can access.
|
// Login Required. Pages that non-certified users can access.
|
||||||
mux.Handle("/me", middleware.LoginRequired(account.Dashboard()))
|
mux.Handle("/me", middleware.LoginRequired(account.Dashboard()))
|
||||||
|
|
23
pkg/utility/ip_address.go
Normal file
23
pkg/utility/ip_address.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package utility
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.nonshy.com/nonshy/website/pkg/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
IPAddress returns the best guess at the user's IP address, as a string for logging.
|
||||||
|
*/
|
||||||
|
func IPAddress(r *http.Request) string {
|
||||||
|
if config.Current.UseXForwardedFor {
|
||||||
|
if realIP := r.Header.Get("X-Real-IP"); realIP != "" {
|
||||||
|
return realIP
|
||||||
|
}
|
||||||
|
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
|
||||||
|
return strings.SplitN(xff, " ", 1)[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r.RemoteAddr
|
||||||
|
}
|
28
web/templates/errors/geo_gate.html
Normal file
28
web/templates/errors/geo_gate.html
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{{define "content"}}
|
||||||
|
<div class="container">
|
||||||
|
<section class="hero block is-warning is-bold">
|
||||||
|
<div class="hero-body">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="title">Not Available</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="block content p-4 mb-0">
|
||||||
|
<h1>{{PrettyTitle}} is not available in your area</h1>
|
||||||
|
<p>
|
||||||
|
We regret to inform you that {{PrettyTitle}} will not be available in your area.
|
||||||
|
This may likely be due to local laws and regulations in your country or state of
|
||||||
|
origin regarding 'adult sites' and whether they are required to ask for your
|
||||||
|
photo ID to be on file. We do not, at this time, wish to handle such sensitive
|
||||||
|
information from our users (so that we don't risk such information being hacked
|
||||||
|
or leaked, which you can probably agree is a good call).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you already have an account with us, please <a href="/contact">contact support</a>
|
||||||
|
for next steps (e.g., in case you would like us to delete your account).
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
Loading…
Reference in New Issue
Block a user