1
0
mirror of https://github.com/krislamo/Flea synced 2024-09-19 18:20:34 +00:00

Added Control Plugin

Added Control Plugin: authentication and basic control of IRC
commands; Move settings and packet info into the IRC class; Minor
fix of irclib's Whois function
This commit is contained in:
Kris Lamoureux 2016-02-03 18:14:45 -05:00
parent ec0e9a3485
commit 80e6787d50
6 changed files with 256 additions and 32 deletions

View File

@ -1,11 +1,11 @@
# Flea # Flea
Flea aims to be a modular Python IRC bot. This software was inspired from older Flea aims to be a modular Python IRC bot. This software was inspired from older
IRC bots I wrote. IRC bots I wrote.
## License ## License
Flea is released under the Flea is released under the
[GNU AGPLv3](https://www.gnu.org/licenses/why-affero-gpl.html), please **direct [GNU AGPLv3](https://www.gnu.org/licenses/why-affero-gpl.html), please **direct
your attention to the LICENSE file in the root of the repository** before your attention to the LICENSE file in the root of the repository** before
continuing. continuing.
## Requirements ## Requirements
@ -14,7 +14,7 @@ Flea was written in [Python 2.7](http://www.python.org/download/releases/2.7/)
## Quick Start ## Quick Start
1. Edit the *settings.conf* file to appropriate settings on the server you would 1. Edit the *settings.conf* file to appropriate settings on the server you would
like to use like to use
2. Run the terminal/console in the root of the project and type: 2. Run the terminal/console in the root of the project and type:
*python Flea.py* *python Flea.py*

View File

@ -14,10 +14,14 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/> # along with this program. If not, see <http://www.gnu.org/licenses/>
# Built-in to Python 2.7
import socket import socket
class irc: class irc:
debug = False debug = False
config = {}
pack = {}
sock = socket.socket() sock = socket.socket()
# IRC Parser. Parses by line # IRC Parser. Parses by line
@ -114,7 +118,7 @@ class irc:
self.msg("NOTICE "+user+" :\001VERSION "+version+"\001") self.msg("NOTICE "+user+" :\001VERSION "+version+"\001")
def Whois(self, query): def Whois(self, query):
self.msg("WHOIS "+query+"\r\n") self.msg("WHOIS "+query)
def SetMode(self, channel, nick, mode): def SetMode(self, channel, nick, mode):
self.msg("MODE "+channel+" "+mode+" "+nick) self.msg("MODE "+channel+" "+mode+" "+nick)

View File

@ -23,6 +23,7 @@ import socket
import ssl import ssl
import sys import sys
import os import os
import re
# Allows reimporting modules # Allows reimporting modules
@ -63,6 +64,9 @@ def PluginsImport():
# Path to /plugins/ under /Flea/ # Path to /plugins/ under /Flea/
plugins = current+"/plugins/" plugins = current+"/plugins/"
# List of plugins
plugin_list = []
# If /plugins/ exists change directory to it # If /plugins/ exists change directory to it
if os.path.exists(plugins): if os.path.exists(plugins):
os.chdir(plugins) os.chdir(plugins)
@ -73,33 +77,36 @@ def PluginsImport():
# Only import directory plugins (no single files) # Only import directory plugins (no single files)
if os.path.isdir(plugins+item): if os.path.isdir(plugins+item):
print "[Plugins] Initializing "+item print "[Plugins] Initializing "+item
__import__(item+".main") plugin = __import__(item+".main")
plugin_list.append(plugin)
else: else:
return False return False
os.chdir(current) os.chdir(current)
return True return plugin_list
def main(): def main():
# Create irclib irc object
irc = irclib.irc()
# Parse main settings.conf file # Parse main settings.conf file
config = cfgParser("settings.conf") irc.config = cfgParser("settings.conf")
# Keep track of modules for a rollback # Keep track of modules for a rollback
importctrl = ImportRollback() importctrl = ImportRollback()
# Import /plugins/ # Import /plugins/
if config["plugins"]: if irc.config["plugins"]:
if not PluginsImport(): plugins = PluginsImport()
if not plugins:
print "[Plugins] Failed to load." print "[Plugins] Failed to load."
# Create irclib irc object
irc = irclib.irc()
# Set debug to true/false inside irc() object # Set debug to true/false inside irc() object
irc.debug = config["debug"] irc.debug = irc.config["debug"]
# Create socket object # Create socket object
irc.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) irc.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@ -108,8 +115,8 @@ def main():
irc.sock = ssl.wrap_socket(irc.sock) irc.sock = ssl.wrap_socket(irc.sock)
# Connect to IRC server # Connect to IRC server
irc.sock.connect((config["host"], config["port"])) irc.sock.connect((irc.config["host"], irc.config["port"]))
print "Connecting to "+config["host"]+':'+str(config["port"]) print "Connecting to "+irc.config["host"]+':'+str(irc.config["port"])
# Display SSL information to the user # Display SSL information to the user
ssl_info = irc.sock.cipher() ssl_info = irc.sock.cipher()
@ -119,10 +126,10 @@ def main():
print "[SSL] Bits: "+str(ssl_info[2]) print "[SSL] Bits: "+str(ssl_info[2])
# Send User/Nick message to establish user on the server # Send User/Nick message to establish user on the server
irc.User(config["ident"], config["mode"], irc.User(irc.config["ident"], irc.config["mode"],
config["unused"], config["realname"]) irc.config["unused"], irc.config["realname"])
irc.Nick(config["nick"]) irc.Nick(irc.config["nick"])
while True: while True:
# Buffer to store data from server # Buffer to store data from server
@ -152,24 +159,29 @@ def main():
# Print line, parse it and respond # Print line, parse it and respond
print line print line
pack = irc.Parser(line) irc.pack = irc.Parser(line)
# Run all plugins main() function
if irc.config["plugins"]:
for plugin in plugins:
plugin.main.main(irc)
# Ping Pong, keep the connection alive. # Ping Pong, keep the connection alive.
if pack["cmd"] == "PING": if irc.pack["cmd"] == "PING":
irc.Pong(pack["text"]) irc.Pong(irc.pack["text"])
# Send user mode message after command 001 # Send user mode message after command 001
elif pack["cmd"] == "001": elif irc.pack["cmd"] == "001":
irc.Mode(config["nick"], config["mode"]) irc.Mode(irc.config["nick"], irc.config["mode"])
elif pack["cmd"] == "NOTICE": elif irc.pack["cmd"] == "NOTICE":
if pack["ident"] == "NickServ": if irc.pack["ident"] == "NickServ":
# Send password after NickServ informs you # Send password after NickServ informs you
# that your nick is registered # that your nick is registered
pattern = r"[Tt]his nickname is registered" pattern = r"[Tt]his nickname is registered"
if re.search(pattern, pack["text"]): if re.search(pattern, irc.pack["text"]):
irc.Identify(config["password"]) irc.Identify(irc.config["password"])
irc.Join("#Flea") irc.Join(irc.config["channel"])
main() main()

View File

206
plugins/Control/main.py Normal file
View File

@ -0,0 +1,206 @@
import re
# Init
controlchan = ''
chans = {}
access = []
queue = []
def chkcontrol(irc):
global access
global queue
nick = irc.pack["nick"]
for person in access:
if nick == person:
return True
if queue.count(nick) == 0:
queue.append(nick)
irc.Whois(nick)
def noaccess(irc):
msg = "You don't have access to that."
irc.Notice(msg, irc.pack["nick"])
def main(irc):
global controlchan
global access
global chans
global queue
# Set control channel
controlchan = irc.config["channel"]
# NOTICEs are used to "control" Flea
if irc.pack["cmd"] == "NOTICE":
# Nick must match the nick in settings
# e.g. control = Kris
if irc.pack["nick"] == irc.config["control"]:
# Split message by spaces, for functions with
# required parameters. e.g. "<cmd> <param1> <param2>"
if irc.pack["text"].find(' ') != -1:
command = irc.pack["text"].lower().split(' ')
# Command Flea to join a channel
if command[0] == "join":
if chkcontrol(irc):
irc.Join(command[1])
else:
noaccess(irc)
# Command Flea to part
elif command[0] == "part":
if chkcontrol(irc):
irc.Part(command[1],
"Fleabot https://github.com/Kris619/Flea")
else:
noaccess(irc)
# Single word commands
else:
if irc.pack["text"] == "acc":
if chkcontrol(irc):
irc.Notice("You already have access to Control.",
irc.pack["nick"])
else:
noaccess(irc)
if irc.pack["text"] == "quit":
if chkcontrol(irc):
irc.Quit("Fleabot https://github.com/Kris619/Flea")
quit()
else:
noaccess(irc)
# Check if commanding Nick is identified
elif irc.pack["cmd"] == "307":
if irc.pack["text"] == "is identified for this nick":
# Check if Nick is in the queue for access list
if queue.count(irc.pack["params"][1]) == 1:
# Remove Nick from queue
queue.remove(irc.pack["params"][1])
# Check if user is set to control in settings
# e.g. control = Kris
if irc.pack["params"][1] == irc.config["control"]:
# Is control user inside the control channel?
if chans[controlchan].count(irc.pack["params"][1]) == 1:
# Grant access
access.append(irc.pack["params"][1])
print irc.pack["params"][1]+" added to Access"
irc.Notice(
"You have been given access to Control.",
irc.pack["params"][1])
else:
irc.Notice(
"You are not in the Control channel: "+controlchan,
irc.pack["params"][1])
# Keep track of users in every channel
# "353" lists users to a channel
elif irc.pack["cmd"] == "353":
# If channel is in dictionary of channels
if chans.keys().count(irc.pack["params"][2]) == 1:
# Split list of channel users by space
# "+Kris @Flea" > ["+Kris", "@Flea"]
if irc.pack["text"].find(' ') != -1:
chan_nicks = irc.pack["text"].split(' ')
for aNick in chan_nicks:
if aNick != '':
# Remove prefix; e.g. "+Kris" > "Kris"
if re.search("^[~&@%+]", aNick):
aNick = aNick[1:]
# Add nick to it's channel
chans[irc.pack["params"][2]].append(aNick)
# Track users joining channels
elif irc.pack["cmd"] == "JOIN":
# Check to see if it is the bot that joined
if irc.pack["nick"] == irc.config["nick"]:
# Create channel user list if it doesn't exist
if chans.keys().count(irc.pack["text"]) == 0:
chans[irc.pack["text"]] = []
# Another user joined
else:
# Add user to channel; chans["#Channel"].append("Kris")
chans[irc.pack["text"]].append(irc.pack["nick"])
# Track users parting from the channel
elif irc.pack["cmd"] == "PART":
# Remove nick from channel they parted from
chans[irc.pack["params"][0]].remove(irc.pack["nick"])
# If someone parted the control channel
# check if it was someone on the access list
if irc.pack["params"][0] == controlchan:
for usr in access:
if usr == irc.pack["nick"]:
# Someone on the access list left.
access.remove(irc.pack["nick"])
print irc.pack["nick"]+" removed from Access"
# Track users parting from the channel
elif irc.pack["cmd"] == "QUIT":
# Remove user from channels
for channel in chans.keys():
if chans[channel].count(irc.pack["nick"]) == 1:
chans[channel].remove(irc.pack["nick"])
# Remove access if user quitting had it
for usr in access:
if usr == irc.pack["nick"]:
access.remove(irc.pack["nick"])
print irc.pack["nick"]+" removed from Access"
# Track users being kicked from the channel
elif irc.pack["cmd"] == "KICK":
# Remove nick from channel they were kicked from
chans[irc.pack["params"][0]].remove(irc.pack["params"][1])
# If someone was kicked from the control channel
# check if it was someone on the access list
if irc.pack["params"][0] == controlchan:
if irc.pack["params"][1] == irc.config["nick"]:
print "Access list is erased, control channel is gone"
access = []
else:
for usr in access:
if usr == irc.pack["params"][1]:
# Someone on the access list was kicked.
access.remove(irc.pack["params"][1])
print irc.pack["params"][1]+" removed from Access"
# Track users changing their nick
elif irc.pack["cmd"] == "NICK":
for channel in chans.keys():
if channel.count(irc.pack["nick"]) == 1:
channel.remove(irc.pack["nick"])
channel.append(irc.pack["text"])
# Remove access to users changing their nick
for usr in access:
if access.count(irc.pack["nick"]) == 1:
access.remove(irc.pack["nick"])
print irc.pack["nick"]+" removed from Access"

View File

@ -1,5 +1,5 @@
debug = true debug = true
plugins = false plugins = true
host = irc.example.net host = irc.example.net
port = 7001 port = 7001
@ -11,3 +11,5 @@ mode = +B
unused = * unused = *
realname = your_name realname = your_name
control = your_nick
channel = #MyChannel