all repos — honk @ fa6917a048b9c40caa63396291e74da2ca144da8

my fork of honk

hfcs.go (view raw)

  1//
  2// Copyright (c) 2019 Ted Unangst <tedu@tedunangst.com>
  3//
  4// Permission to use, copy, modify, and distribute this software for any
  5// purpose with or without fee is hereby granted, provided that the above
  6// copyright notice and this permission notice appear in all copies.
  7//
  8// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15
 16package main
 17
 18import (
 19	"log"
 20	"net/http"
 21	"regexp"
 22)
 23
 24type Filter struct {
 25	ID              int64
 26	Actor           string
 27	IncludeAudience bool
 28	Text            string
 29	IsAnnounce      bool
 30	Reject          bool
 31	SkipMedia       bool
 32	Hide            bool
 33	Collapse        bool
 34	Rewrite         string
 35	re_rewrite      *regexp.Regexp
 36	Replace         string
 37}
 38
 39type filtType uint
 40
 41const (
 42	filtNone filtType = iota
 43	filtAny
 44	filtReject
 45	filtSkipMedia
 46	filtHide
 47	filtCollapse
 48	filtRewrite
 49)
 50
 51var filtNames = []string{"None", "Any", "Reject", "SkipMedia", "Hide", "Collapse", "Rewrite"}
 52
 53func (ft filtType) String() string {
 54	return filtNames[ft]
 55}
 56
 57type afiltermap map[filtType][]*Filter
 58
 59var filtcache = cacheNew(func(userid int64) (afiltermap, bool) {
 60	rows, err := stmtGetFilters.Query(userid)
 61	if err != nil {
 62		log.Printf("error querying filters: %s", err)
 63		return nil, false
 64	}
 65	defer rows.Close()
 66
 67	filtmap := make(afiltermap)
 68	for rows.Next() {
 69		filt := new(Filter)
 70		var j string
 71		var filterid int64
 72		err = rows.Scan(&filterid, &j)
 73		if err == nil {
 74			err = unjsonify(j, filt)
 75		}
 76		if err != nil {
 77			log.Printf("error scanning filter: %s", err)
 78			continue
 79		}
 80		filt.ID = filterid
 81		if filt.Reject {
 82			filtmap[filtReject] = append(filtmap[filtReject], filt)
 83		}
 84		if filt.SkipMedia {
 85			filtmap[filtSkipMedia] = append(filtmap[filtSkipMedia], filt)
 86		}
 87		if filt.Hide {
 88			filtmap[filtHide] = append(filtmap[filtHide], filt)
 89		}
 90		if filt.Collapse {
 91			filtmap[filtCollapse] = append(filtmap[filtCollapse], filt)
 92		}
 93		if filt.Rewrite != "" {
 94			filtmap[filtRewrite] = append(filtmap[filtRewrite], filt)
 95		}
 96	}
 97	return filtmap, true
 98})
 99
100func getfilters(userid int64, scope filtType) []*Filter {
101	var filtmap afiltermap
102	ok := filtcache.Get(userid, &filtmap)
103	if ok {
104		return filtmap[scope]
105	}
106	return nil
107}
108
109func rejectorigin(userid int64, origin string) bool {
110	if o := originate(origin); o != "" {
111		origin = o
112	}
113	filts := getfilters(userid, filtReject)
114	for _, f := range filts {
115		if f.Actor == origin {
116			log.Printf("rejecting origin: %s", origin)
117			return true
118		}
119	}
120	return false
121}
122
123func rejectactor(userid int64, actor string) bool {
124	origin := originate(actor)
125	filts := getfilters(userid, filtReject)
126	for _, f := range filts {
127		if f.Actor == actor || (origin != "" && f.Actor == origin) {
128			log.Printf("rejecting actor: %s", actor)
129			return true
130		}
131	}
132	return false
133}
134
135func stealthmode(userid int64, r *http.Request) bool {
136	agent := r.UserAgent()
137	agent = originate(agent)
138	if agent != "" {
139		fake := rejectorigin(userid, agent)
140		if fake {
141			log.Printf("faking 404 for %s", agent)
142			return fake
143		}
144	}
145	return false
146}
147
148func matchfilter(h *Honk, filts []*Filter) bool {
149	origin := originate(h.XID)
150	for _, f := range filts {
151		if f.Actor == origin || f.Actor == h.Honker {
152			return true
153		}
154		if f.Text != "" {
155			for _, d := range h.Donks {
156				if d.Desc == f.Text {
157					return true
158				}
159			}
160		}
161	}
162	return false
163}
164
165func rejectnote(xonk *Honk) bool {
166	filts := getfilters(xonk.UserID, filtReject)
167	return matchfilter(xonk, filts)
168}
169
170func skipMedia(xonk *Honk) bool {
171	filts := getfilters(xonk.UserID, filtSkipMedia)
172	return matchfilter(xonk, filts)
173}
174
175func unsee(filts []*Filter, h *Honk) string {
176	return ""
177}
178
179func osmosis(honks []*Honk, userid int64) []*Honk {
180	filts := getfilters(userid, filtHide)
181	j := 0
182outer:
183	for _, h := range honks {
184		if matchfilter(h, filts) {
185			continue outer
186		}
187		honks[j] = h
188		j++
189	}
190	honks = honks[0:j]
191	return honks
192}