User:a proofreader/Anti-phish script/kickbot.py

From the RuneScape Wiki, the wiki for all things RuneScape
Jump to: navigation, search


This is a bot written in Python, using the Twisted library. If it has operator status, it will kick anyone who posts RuneScape phishing links.

The following would run the bot under the nickname KickBot in the channels #wikia-runescape, and #cvn-wikia-runescape, with all channel messages logged into logfile.txt.

 $ python kickbot.py --nickname KickBot --user KickBotIdent --password KickBotPassword --realname KickBot --channels #wikia-runescape,#cvn-wikia-runescape --filename logfile.txt
from twisted.words.protocols import irc
from twisted.internet import reactor, protocol

import time
import sys
import re

phishing_regex = re.compile(r"(http://|www.)[^/ ]*\.?runescape\.com\.(?!au(?!\.))" # unexpected dot after .com, exception for .com.au, [[wikipedia:.au#Second-level domains]]
  + "|(http://|www\.)[^/ ]*(?!runescape)r[-\.]?u[-\.]?n[-\.]?e[-\.]?s[-\.]?c[-\.]?a[-\.]?p[-\.]?e[-\.]" # not runescape (matched above), but something containing a dash or dot (more aggressive)
  + "|(http://|www\.)runescape\.co\.(?!uk(?!\.))" # runescape.co.tld, excluding runescape.co.uk (legit)
  + "|(http://|www\.)[^/ ]*(?!runescape-wiki)(-runescape|runescape-)[^/ ]*/" # dashes instead of dots at expected places
  , re.IGNORECASE)

class MessageLogger:
  def __init__(self, file):
    self.file = file

  def log(self, message):
    timestamp = time.strftime("[%H:%M:%S]", time.localtime(time.time()))
    self.file.write('%s %s\n' % (timestamp, message))
    self.file.flush()

  def close(self):
    self.file.close()


class KickBot(irc.IRCClient):
  def __init__(self, nickname,
        password=None, realname=None, username=None):
    self.nickname = nickname
    self.password = password
    self.realname = realname
    self.username = username

  def connectionMade(self):
    irc.IRCClient.connectionMade(self)
    self.logger = MessageLogger(open(self.factory.filename, "a"))
    self.logger.log("[connected at %s]" %
                    time.asctime(time.localtime(time.time())))

  def connectionLost(self, reason):
    irc.IRCClient.connectionLost(self, reason)
    self.logger.log("[disconnected at %s]" %
                    time.asctime(time.localtime(time.time())))
    self.logger.close()

  def signedOn(self):
    self.join(self.reactor.channels)

  def joined(self, channel):
    self.logger.log("[I have joined %s]" % channel)

  def privmsg(self, user, channel, msg):
    nick = user.split("!", 1)[0]
    lnick = nick.lower()

    self.logger.log("<%s> %s" % (nick, msg))

    #Is it in a query?
    if channel == self.nickname:
      self.msg(nick, "hi")

    if (lnick !== "bullbot" and
        lnick !== "evilbot" and lnick !== "runescript" and
        phishing_regex.search(msg)):

      self.kick("#wikia-runescape", nick, "Phishing link detected")
      self.logger.log("[I have kicked %s from %s (Phishing link detected)]" % (nick, channel))

  action = privmsg


class KickBotFactory(protocol.ClientFactory):
  def __init__(self, nickname, password=None, realname=None, username=None,
                     channels="#wikia-runescape", filename=None):
    self.nickname = nickname
    self.password = password
    self.realname = realname
    self.username = username
    self.channels = channels
    self.filename = filename

  def buildProtocol(self, addr):
    p = KickBot(self.nickname, self.password, self.realname, self.username)
    p.factory = self
    return p

  def clientConnectionLost(self, connector, reason):
    connector.connect()

  def clientConnectionFailed(self, connector, reason):
    print "connection failed:", reason
    reactor.stop()


if __name__ == "__main__":
  try:
    import argparse
  except ImportError:
    print "Python 2.7 is required for this script to work."
    sys.exit(2)

  parser = argparse.ArgumentParser()

  parser.add_argument("--nickname", help="Nickname for the bot to use")
  parser.add_argument("--realname", help="Realname for the bot to use")
  parser.add_argument("--password", help="Password for the bot to use")
  parser.add_argument("--username", help="Username for the bot to use")
  parser.add_argument("--channels", help="Channel(s) the bot should join")
  parser.add_argument("--filename", help="Filename for the bot to log under")

  args = parser.parse_args()

  factory = KickBotFactory(args.nickname, args.password, args.realname,
                          args.username, args.channels, args.filename)

  reactor.connectTCP("irc.freenode.net", 6667, factory)
  reactor.run()