You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
3.7 KiB
Go
158 lines
3.7 KiB
Go
package fuckgoogle
|
|
|
|
import (
|
|
"math/rand"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/caddyserver/caddy/v2"
|
|
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
|
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
|
|
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
|
)
|
|
|
|
func init() {
|
|
caddy.RegisterModule(FckGgl{})
|
|
httpcaddyfile.RegisterHandlerDirective("fuck-google", parseFuckuppery)
|
|
}
|
|
|
|
type FckGgl struct {
|
|
Level FuckupLevel `json:"level,omitempty"`
|
|
clientMatcher GoogleMatcher
|
|
serverMatcher GoogleMatcher
|
|
}
|
|
|
|
type FuckupLevel string
|
|
|
|
const (
|
|
FuckupLevel1 FuckupLevel = "a teeny tiny bit"
|
|
FuckupLevel2 FuckupLevel = "fuck them"
|
|
FuckupLevel3 FuckupLevel = "for real"
|
|
FuckupLevel4 FuckupLevel = "all the way"
|
|
)
|
|
|
|
func (l FuckupLevel) isValid() bool {
|
|
return l == FuckupLevel1 || l == FuckupLevel2 || l == FuckupLevel3 || l == FuckupLevel4
|
|
}
|
|
|
|
// CaddyModule returns the Caddy module information.
|
|
func (FckGgl) CaddyModule() caddy.ModuleInfo {
|
|
return caddy.ModuleInfo{
|
|
ID: "http.handlers.fuck_google",
|
|
New: func() caddy.Module { return new(FckGgl) },
|
|
}
|
|
}
|
|
|
|
// Provision sets up the module defaults.
|
|
func (m *FckGgl) Provision(ctx caddy.Context) error {
|
|
if m.Level == "" {
|
|
m.Level = FuckupLevel4
|
|
}
|
|
|
|
m.clientMatcher = GoogleMatcher{
|
|
UAChrome: true,
|
|
UAChromeish: m.Level == FuckupLevel4,
|
|
Referer: true,
|
|
RefererExt: m.Level == FuckupLevel3 || m.Level == FuckupLevel4,
|
|
}
|
|
m.serverMatcher = GoogleMatcher{
|
|
Bot: m.Level != FuckupLevel1,
|
|
IPranges: m.Level == FuckupLevel3 || m.Level == FuckupLevel4,
|
|
}
|
|
|
|
if err := m.clientMatcher.Provision(ctx); err != nil {
|
|
return err
|
|
}
|
|
if err := m.serverMatcher.Provision(ctx); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m FckGgl) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
|
|
isGoogleSrv := m.serverMatcher.Match(r)
|
|
isGoogleClient := m.clientMatcher.Match(r)
|
|
|
|
if isGoogleClient {
|
|
w.Header().Add("Permissions-Policy", "interest-cohort=()")
|
|
}
|
|
|
|
if isGoogleClient || isGoogleSrv {
|
|
var competitiveAdvantage float32
|
|
switch m.Level {
|
|
case FuckupLevel1:
|
|
competitiveAdvantage = 50
|
|
case FuckupLevel2:
|
|
competitiveAdvantage = 150
|
|
case FuckupLevel3:
|
|
competitiveAdvantage = 700
|
|
case FuckupLevel4:
|
|
competitiveAdvantage = 1400
|
|
}
|
|
// ±10% random jitter, cuz why not.
|
|
competitiveAdvantage *= 1 + float32(rand.Intn(20)-10)/100.0
|
|
time.Sleep(time.Millisecond * time.Duration(competitiveAdvantage))
|
|
}
|
|
|
|
if isGoogleSrv {
|
|
w.WriteHeader(http.StatusUnavailableForLegalReasons)
|
|
return nil
|
|
}
|
|
|
|
return next.ServeHTTP(w, r)
|
|
}
|
|
|
|
func parseFuckuppery(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
|
|
m := new(FckGgl)
|
|
err := m.UnmarshalCaddyfile(h.Dispenser)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
// UnmarshalCaddyfile sets up the handler from Caddyfile tokens.
|
|
//
|
|
// fuck-google [<matcher>] [<level>] [{
|
|
// level <level>
|
|
// }]
|
|
//
|
|
func (m *FckGgl) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
|
for d.Next() {
|
|
args := d.RemainingArgs()
|
|
if len(args) > 0 {
|
|
m.Level = FuckupLevel(strings.Join(args, " "))
|
|
if !m.Level.isValid() {
|
|
return d.Err("invalid value for level")
|
|
}
|
|
}
|
|
for d.NextBlock(0) {
|
|
switch d.Val() {
|
|
case "level":
|
|
if m.Level != "" {
|
|
return d.Err("level already specified")
|
|
}
|
|
if !d.NextArg() {
|
|
return d.ArgErr()
|
|
}
|
|
m.Level = FuckupLevel(d.Val())
|
|
if !m.Level.isValid() {
|
|
return d.Err("invalid value for level")
|
|
}
|
|
default:
|
|
return d.Errf("unrecognized subdirective: %s", d.Val())
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Interface guards
|
|
var (
|
|
_ caddy.Module = (*FckGgl)(nil)
|
|
_ caddyhttp.MiddlewareHandler = (*FckGgl)(nil)
|
|
_ caddyfile.Unmarshaler = (*FckGgl)(nil)
|
|
)
|