this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

automod interaction rule tweaks (anti-spam) (#588)

still very human-in-the-loop

authored by

bnewbold and committed by
GitHub
d6ed4eb6 6d15380c

+75 -15
+43
automod/rules/helpers.go
··· 197 197 val := murmur3.Sum64([]byte(s)) 198 198 return fmt.Sprintf("%016x", val) 199 199 } 200 + 201 + func ParentOrRootIsFollower(c *automod.RecordContext, post *appbsky.FeedPost) bool { 202 + if post.Reply == nil || IsSelfThread(c, post) { 203 + return false 204 + } 205 + 206 + parentURI, err := syntax.ParseATURI(post.Reply.Parent.Uri) 207 + if err != nil { 208 + c.Logger.Warn("failed to parse reply AT-URI", "uri", post.Reply.Parent.Uri) 209 + return false 210 + } 211 + parentDID, err := parentURI.Authority().AsDID() 212 + if err != nil { 213 + c.Logger.Warn("reply AT-URI authority not a DID", "uri", post.Reply.Parent.Uri) 214 + return false 215 + } 216 + 217 + rel := c.GetAccountRelationship(parentDID) 218 + if rel.FollowedBy { 219 + return true 220 + } 221 + 222 + rootURI, err := syntax.ParseATURI(post.Reply.Root.Uri) 223 + if err != nil { 224 + c.Logger.Warn("failed to parse reply AT-URI", "uri", post.Reply.Root.Uri) 225 + return false 226 + } 227 + rootDID, err := rootURI.Authority().AsDID() 228 + if err != nil { 229 + c.Logger.Warn("reply AT-URI authority not a DID", "uri", post.Reply.Root.Uri) 230 + return false 231 + } 232 + 233 + if rootDID == parentDID { 234 + return false 235 + } 236 + 237 + rel = c.GetAccountRelationship(rootDID) 238 + if rel.FollowedBy { 239 + return true 240 + } 241 + return false 242 + }
+9
automod/rules/interaction.go
··· 13 13 14 14 // looks for accounts which do frequent interaction churn, such as follow-unfollow. 15 15 func InteractionChurnRule(c *automod.RecordContext) error { 16 + 16 17 did := c.Account.Identity.DID.String() 17 18 switch c.RecordOp.Collection { 18 19 case "app.bsky.feed.like": ··· 35 36 c.Logger.Info("high-follow-churn", "created-today", created, "deleted-today", deleted) 36 37 c.AddAccountFlag("high-follow-churn") 37 38 c.ReportAccount(automod.ReportReasonSpam, fmt.Sprintf("interaction churn: %d follows, %d unfollows today (so far)", created, deleted)) 39 + c.Notify("slack") 40 + } 41 + // just generic bulk following 42 + followRatio := float64(c.Account.FollowersCount) / float64(c.Account.FollowsCount) 43 + if created > interactionDailyThreshold && c.Account.FollowsCount > 2000 && followRatio < 0.1 { 44 + c.Logger.Info("bulk-follower", "created-today", created) 45 + c.AddAccountFlag("bulk-follower") 46 + //c.ReportAccount(automod.ReportReasonSpam, fmt.Sprintf("many follows: %d follows today (so far)", created)) 38 47 c.Notify("slack") 39 48 } 40 49 }
+3 -2
automod/rules/mentions.go
··· 1 1 package rules 2 2 3 3 import ( 4 + "fmt" 4 5 "time" 5 6 6 7 appbsky "github.com/bluesky-social/indigo/api/bsky" ··· 42 43 return nil 43 44 } 44 45 45 - var youngMentionAccountLimit = 6 46 + var youngMentionAccountLimit = 12 46 47 var _ automod.PostRuleFunc = YoungAccountDistinctMentionsRule 47 48 48 49 func YoungAccountDistinctMentionsRule(c *automod.RecordContext, post *appbsky.FeedPost) error { ··· 90 91 count := c.GetCountDistinct("young-mention", did, countstore.PeriodHour) + newMentions 91 92 if count >= youngMentionAccountLimit { 92 93 c.AddAccountFlag("young-distinct-account-mention") 93 - //c.ReportAccount(automod.ReportReasonRude, fmt.Sprintf("possible spam (young account, mentioned %d distinct accounts in past hour)", count)) 94 + c.ReportAccount(automod.ReportReasonRude, fmt.Sprintf("possible spam (young account, mentioned %d distinct accounts in past hour)", count)) 94 95 c.Notify("slack") 95 96 } 96 97
+3 -1
automod/rules/promo.go
··· 4 4 "net/url" 5 5 "strings" 6 6 "time" 7 + "fmt" 7 8 8 9 appbsky "github.com/bluesky-social/indigo/api/bsky" 9 10 "github.com/bluesky-social/indigo/automod" ··· 55 56 56 57 did := c.Account.Identity.DID.String() 57 58 uniqueReplies := c.GetCountDistinct("reply-to", did, countstore.PeriodDay) 58 - if uniqueReplies >= 5 { 59 + if uniqueReplies >= 10 { 59 60 c.AddAccountFlag("promo-multi-reply") 61 + c.ReportAccount(automod.ReportReasonSpam, fmt.Sprintf("possible aggressive self-promotion")) 60 62 c.Notify("slack") 61 63 } 62 64
+17 -12
automod/rules/replies.go
··· 3 3 import ( 4 4 "time" 5 5 "unicode/utf8" 6 + "fmt" 6 7 7 8 appbsky "github.com/bluesky-social/indigo/api/bsky" 8 9 "github.com/bluesky-social/indigo/atproto/syntax" ··· 34 35 return nil 35 36 } 36 37 37 - // triggers on the N+1 post, so 6th identical reply 38 - var identicalReplyLimit = 5 38 + // triggers on the N+1 post 39 + var identicalReplyLimit = 6 39 40 40 41 var _ automod.PostRuleFunc = IdenticalReplyPostRule 41 42 ··· 58 59 } 59 60 } 60 61 62 + // don't count if there is a follow-back relationship 63 + if ParentOrRootIsFollower(c, post) { 64 + return nil 65 + } 66 + 61 67 // increment before read. use a specific period (IncrementPeriod()) to reduce the number of counters (one per unique post text) 62 68 period := countstore.PeriodDay 63 69 bucket := c.Account.Identity.DID.String() + "/" + HashOfString(post.Text) ··· 66 72 count := c.GetCount("reply-text", bucket, period) 67 73 if count >= identicalReplyLimit { 68 74 c.AddAccountFlag("multi-identical-reply") 69 - //c.ReportAccount(automod.ReportReasonRude, fmt.Sprintf("possible spam (young account, %d identical reply-posts today)", tag)) 75 + c.ReportAccount(automod.ReportReasonRude, fmt.Sprintf("possible spam (young account, %d identical reply-posts today)", count)) 70 76 c.Notify("slack") 71 77 } 72 78 ··· 93 99 } 94 100 } 95 101 96 - did := c.Account.Identity.DID.String() 102 + // don't count if there is a follow-back relationship 103 + if ParentOrRootIsFollower(c, post) { 104 + return nil 105 + } 97 106 98 107 parentURI, err := syntax.ParseATURI(post.Reply.Parent.Uri) 99 108 if err != nil { 100 109 c.Logger.Warn("failed to parse reply AT-URI", "uri", post.Reply.Parent.Uri) 101 110 return nil 102 111 } 103 - otherDID, err := parentURI.Authority().AsDID() 112 + parentDID, err := parentURI.Authority().AsDID() 104 113 if err != nil { 105 114 c.Logger.Warn("reply AT-URI authority not a DID", "uri", post.Reply.Parent.Uri) 106 115 return nil 107 116 } 108 117 109 - // don't count if there is a follow-back relationship 110 - rel := c.GetAccountRelationship(otherDID) 111 - if rel.FollowedBy { 112 - return nil 113 - } 118 + did := c.Account.Identity.DID.String() 114 119 115 - c.IncrementDistinct("young-reply-to", did, otherDID.String()) 120 + c.IncrementDistinct("young-reply-to", did, parentDID.String()) 116 121 // NOTE: won't include the increment from this event 117 122 count := c.GetCountDistinct("young-reply-to", did, countstore.PeriodHour) 118 123 if count >= youngReplyAccountLimit { 119 124 c.AddAccountFlag("young-distinct-account-reply") 120 - //c.ReportAccount(automod.ReportReasonRude, fmt.Sprintf("possible spam (young account, reply-posts to %d distinct accounts in past hour)", count)) 125 + c.ReportAccount(automod.ReportReasonRude, fmt.Sprintf("possible spam (young account, reply-posts to %d distinct accounts in past hour)", count)) 121 126 c.Notify("slack") 122 127 } 123 128