summaryrefslogtreecommitdiff
path: root/files
diff options
context:
space:
mode:
authorSilvio Rhatto <rhatto@riseup.net>2012-01-28 14:09:30 -0200
committerSilvio Rhatto <rhatto@riseup.net>2012-01-28 14:09:30 -0200
commitafade3b215bc5c10fdbf30a5d8b6d97e87302aaa (patch)
treea25deb96cf1616cda6278929a5408e31edf428e7 /files
downloadpuppet-qwebirc-afade3b215bc5c10fdbf30a5d8b6d97e87302aaa.tar.gz
puppet-qwebirc-afade3b215bc5c10fdbf30a5d8b6d97e87302aaa.tar.bz2
Initial import
Diffstat (limited to 'files')
-rw-r--r--files/ircclient-ssl.py173
-rw-r--r--files/qwebirc-init.d.sh154
-rw-r--r--files/qwebirc-ssl.patch38
-rw-r--r--files/qwebirc-ssl.patch.orig38
4 files changed, 403 insertions, 0 deletions
diff --git a/files/ircclient-ssl.py b/files/ircclient-ssl.py
new file mode 100644
index 0000000..2fd09c0
--- /dev/null
+++ b/files/ircclient-ssl.py
@@ -0,0 +1,173 @@
+import twisted, sys, codecs, traceback
+from twisted.words.protocols import irc
+from twisted.internet import reactor, protocol, abstract, ssl
+from twisted.web import resource, server
+from twisted.protocols import basic
+from twisted.names.client import Resolver
+import hmac, time, config, random, qwebirc.config_options as config_options
+from config import HMACTEMPORAL
+
+if config.get("CONNECTION_RESOLVER"):
+ CONNECTION_RESOLVER = Resolver(servers=config.get("CONNECTION_RESOLVER"))
+else:
+ CONNECTION_RESOLVER = None
+
+if hasattr(config, "WEBIRC_MODE") and config.WEBIRC_MODE == "hmac":
+ HMACKEY = hmac.HMAC(key=config.HMACKEY)
+
+def hmacfn(*args):
+ h = HMACKEY.copy()
+ h.update("%d %s" % (int(time.time() / HMACTEMPORAL), " ".join(args)))
+ return h.hexdigest()
+
+def utf8_iso8859_1(data, table=dict((x, x.decode("iso-8859-1")) for x in map(chr, range(0, 256)))):
+ return (table.get(data.object[data.start]), data.start+1)
+
+codecs.register_error("mixed-iso-8859-1", utf8_iso8859_1)
+
+def irc_decode(x):
+ try:
+ return x.decode("utf-8", "mixed-iso-8859-1")
+ except UnicodeDecodeError:
+ return x.decode("iso-8859-1", "ignore")
+
+class QWebIRCClient(basic.LineReceiver):
+ delimiter = "\n"
+ def __init__(self, *args, **kwargs):
+ self.__nickname = "(unregistered)"
+
+ def dataReceived(self, data):
+ basic.LineReceiver.dataReceived(self, data.replace("\r", ""))
+
+ def lineReceived(self, line):
+ line = irc_decode(irc.lowDequote(line))
+
+ try:
+ prefix, command, params = irc.parsemsg(line)
+ self.handleCommand(command, prefix, params)
+ except irc.IRCBadMessage:
+ # emit and ignore
+ traceback.print_exc()
+ return
+
+ if command == "001":
+ self.__nickname = params[0]
+
+ if self.__perform is not None:
+ for x in self.__perform:
+ self.write(x)
+ self.__perform = None
+ elif command == "NICK":
+ nick = prefix.split("!", 1)[0]
+ if nick == self.__nickname:
+ self.__nickname = params[0]
+
+ def handleCommand(self, command, prefix, params):
+ self("c", command, prefix, params)
+
+ def __call__(self, *args):
+ self.factory.publisher.event(args)
+
+ def write(self, data):
+ self.transport.write("%s\r\n" % irc.lowQuote(data.encode("utf-8")))
+
+ def connectionMade(self):
+ basic.LineReceiver.connectionMade(self)
+
+ self.lastError = None
+ f = self.factory.ircinit
+ nick, ident, ip, realname, hostname, pass_ = f["nick"], f["ident"], f["ip"], f["realname"], f["hostname"], f.get("password")
+ self.__nickname = nick
+ self.__perform = f.get("perform")
+
+ if not hasattr(config, "WEBIRC_MODE"):
+ self.write("USER %s bleh bleh %s :%s" % (ident, ip, realname))
+ elif config.WEBIRC_MODE == "hmac":
+ hmac = hmacfn(ident, ip)
+ self.write("USER %s bleh bleh %s %s :%s" % (ident, ip, hmac, realname))
+ elif config.WEBIRC_MODE == "webirc":
+ self.write("WEBIRC %s qwebirc %s %s" % (config.WEBIRC_PASSWORD, hostname, ip))
+ self.write("USER %s bleh %s :%s" % (ident, ip, realname))
+ elif config.WEBIRC_MODE == "cgiirc":
+ self.write("PASS %s_%s_%s" % (config.CGIIRC_STRING, ip, hostname))
+ self.write("USER %s bleh %s :%s" % (ident, ip, realname))
+ elif config.WEBIRC_MODE == config_options.WEBIRC_REALNAME or config.WEBIRC_MODE is None: # last bit is legacy
+ if ip == hostname:
+ dispip = ip
+ else:
+ dispip = "%s/%s" % (hostname, ip)
+
+ self.write("USER %s bleh bleh :%s - %s" % (ident, dispip, realname))
+
+ if pass_ is not None:
+ self.write("PASS :%s" % pass_)
+ self.write("NICK %s" % nick)
+
+ self.factory.client = self
+ self("connect")
+
+ def __str__(self):
+ return "<QWebIRCClient: %s!%s@%s>" % (self.__nickname, self.factory.ircinit["ident"], self.factory.ircinit["ip"])
+
+ def connectionLost(self, reason):
+ if self.lastError:
+ self.disconnect("Connection to IRC server lost: %s" % self.lastError)
+ else:
+ self.disconnect("Connection to IRC server lost.")
+ self.factory.client = None
+ basic.LineReceiver.connectionLost(self, reason)
+
+ def error(self, message):
+ self.lastError = message
+ self.write("QUIT :qwebirc exception: %s" % message)
+ self.transport.loseConnection()
+
+ def disconnect(self, reason):
+ self("disconnect", reason)
+ self.factory.publisher.disconnect()
+
+class QWebIRCFactory(protocol.ClientFactory):
+ protocol = QWebIRCClient
+ def __init__(self, publisher, **kwargs):
+ self.client = None
+ self.publisher = publisher
+ self.ircinit = kwargs
+
+ def write(self, data):
+ self.client.write(data)
+
+ def error(self, reason):
+ self.client.error(reason)
+
+ def clientConnectionFailed(self, connector, reason):
+ protocol.ClientFactory.clientConnectionFailed(self, connector, reason)
+ self.publisher.event(["disconnect", "Connection to IRC server failed."])
+ self.publisher.disconnect()
+
+def createIRC(*args, **kwargs):
+ f = QWebIRCFactory(*args, **kwargs)
+
+ tcpkwargs = {}
+ if hasattr(config, "OUTGOING_IP"):
+ tcpkwargs["bindAddress"] = (config.OUTGOING_IP, 0)
+
+ if CONNECTION_RESOLVER is None:
+ if hasattr(config, "SSLPORT"):
+ reactor.connectSSL(config.IRCSERVER, config.SSLPORT, f, ssl.ClientContextFactory(), **tcpkwargs)
+ else:
+ reactor.connectTCP(config.IRCSERVER, config.IRCPORT, f, **tcpkwargs)
+ return f
+
+ def callback(result):
+ name, port = random.choice(sorted((str(x.payload.target), x.payload.port) for x in result[0]))
+ reactor.connectTCP(name, port, f, **tcpkwargs)
+ def errback(err):
+ f.clientConnectionFailed(None, err) # None?!
+
+ d = CONNECTION_RESOLVER.lookupService(config.IRCSERVER, (1, 3, 11))
+ d.addCallbacks(callback, errback)
+ return f
+
+if __name__ == "__main__":
+ e = createIRC(lambda x: 2, nick="slug__moo", ident="mooslug", ip="1.2.3.6", realname="mooooo", hostname="1.2.3.4")
+ reactor.run()
diff --git a/files/qwebirc-init.d.sh b/files/qwebirc-init.d.sh
new file mode 100644
index 0000000..c0cea70
--- /dev/null
+++ b/files/qwebirc-init.d.sh
@@ -0,0 +1,154 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides: qwebirc
+# Required-Start: $remote_fs $syslog
+# Required-Stop: $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: QwebIRC web interface
+# Description: This script launches the QWebIRC daemon.
+### END INIT INFO
+
+# Author: Antoine Beaupre <anarcat@koumbit.org>
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+DESC="Description of the service"
+NAME=qwebirc
+HOME=/var/lib/qwebirc
+DAEMON=$HOME/run.py
+DAEMON_ARGS=""
+PIDFILE=$HOME/twistd.pid
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+. /lib/init/vars.sh
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
+# and status_of_proc is working.
+. /lib/lsb/init-functions
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+ # Return
+ # 0 if daemon has been started
+ # 1 if daemon was already running
+ # 2 if daemon could not be started
+ start-stop-daemon --start --quiet --pidfile $PIDFILE --startas $DAEMON --test > /dev/null \
+ || return 1
+ start-stop-daemon --chdir $HOME --chuid $NAME --start --quiet --pidfile $PIDFILE --startas $DAEMON -- \
+ $DAEMON_ARGS \
+ || return 2
+ # Add code here, if necessary, that waits for the process to be ready
+ # to handle requests from services started subsequently which depend
+ # on this one. As a last resort, sleep for some time.
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+ # Return
+ # 0 if daemon has been stopped
+ # 1 if daemon was already stopped
+ # 2 if daemon could not be stopped
+ # other if a failure occurred
+ start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE
+ RETVAL="$?"
+ [ "$RETVAL" = 2 ] && return 2
+ # Wait for children to finish too if this is a daemon that forks
+ # and if the daemon is only ever run from this initscript.
+ # If the above conditions are not satisfied then add some other code
+ # that waits for the process to drop all resources that could be
+ # needed by services started subsequently. A last resort is to
+ # sleep for some time.
+ start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --user $NAME --name python
+ [ "$?" = 2 ] && return 2
+ # Many daemons don't delete their pidfiles when they exit.
+ rm -f $PIDFILE
+ return "$RETVAL"
+}
+
+#
+# Function that sends a SIGHUP to the daemon/service
+#
+do_reload() {
+ #
+ # If the daemon can reload its configuration without
+ # restarting (for example, when it is sent a SIGHUP),
+ # then implement that here.
+ #
+ start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
+ return 0
+}
+
+case "$1" in
+ start)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+ do_start
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ stop)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ status)
+ status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
+ ;;
+ #reload|force-reload)
+ #
+ # If do_reload() is not implemented then leave this commented out
+ # and leave 'force-reload' as an alias for 'restart'.
+ #
+ #log_daemon_msg "Reloading $DESC" "$NAME"
+ #do_reload
+ #log_end_msg $?
+ #;;
+ restart|force-reload)
+ #
+ # If the "reload" option is implemented then remove the
+ # 'force-reload' alias
+ #
+ log_daemon_msg "Restarting $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1)
+ do_start
+ case "$?" in
+ 0) log_end_msg 0 ;;
+ 1) log_end_msg 1 ;; # Old process is still running
+ *) log_end_msg 1 ;; # Failed to start
+ esac
+ ;;
+ *)
+ # Failed to stop
+ log_end_msg 1
+ ;;
+ esac
+ ;;
+ *)
+ #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
+ echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
+ exit 3
+ ;;
+esac
+
+:
diff --git a/files/qwebirc-ssl.patch b/files/qwebirc-ssl.patch
new file mode 100644
index 0000000..9c9e921
--- /dev/null
+++ b/files/qwebirc-ssl.patch
@@ -0,0 +1,38 @@
+diff -r 19d6068a1aa6 config.py.example
+--- a/config.py.example Sun Apr 03 23:58:29 2011 +0100
++++ b/config.py.example Sat Jan 28 13:31:49 2012 -0200
+@@ -20,6 +20,11 @@
+ # Port of IRC server to connect to.
+ IRCSERVER, IRCPORT = "irc.myserver.com", 6667
+
++# OPTION: SSLPORT
++# SSL port of IRC server to connect to.
++# If this option is uncommented it will override IRCPORT.
++#SSLPORT = 6697
++
+ # OPTION: REALNAME
+ # The realname field of IRC clients will be set to this value.
+ REALNAME = "http://moo.com/"
+diff -r 19d6068a1aa6 qwebirc/ircclient.py
+--- a/qwebirc/ircclient.py Sun Apr 03 23:58:29 2011 +0100
++++ b/qwebirc/ircclient.py Sat Jan 28 13:31:49 2012 -0200
+@@ -1,6 +1,6 @@
+ import twisted, sys, codecs, traceback
+ from twisted.words.protocols import irc
+-from twisted.internet import reactor, protocol, abstract
++from twisted.internet import reactor, protocol, abstract, ssl
+ from twisted.web import resource, server
+ from twisted.protocols import basic
+ from twisted.names.client import Resolver
+@@ -152,7 +152,10 @@
+ tcpkwargs["bindAddress"] = (config.OUTGOING_IP, 0)
+
+ if CONNECTION_RESOLVER is None:
+- reactor.connectTCP(config.IRCSERVER, config.IRCPORT, f, **tcpkwargs)
++ if hasattr(config, "SSLPORT"):
++ reactor.connectSSL(config.IRCSERVER, config.SSLPORT, f, ssl.ClientContextFactory(), **tcpkwargs)
++ else:
++ reactor.connectTCP(config.IRCSERVER, config.IRCPORT, f, **tcpkwargs)
+ return f
+
+ def callback(result):
diff --git a/files/qwebirc-ssl.patch.orig b/files/qwebirc-ssl.patch.orig
new file mode 100644
index 0000000..f0626f9
--- /dev/null
+++ b/files/qwebirc-ssl.patch.orig
@@ -0,0 +1,38 @@
+diff -r 19d6068a1aa6 config.py.example
+--- a/config.py.example Sun Apr 03 23:58:29 2011 +0100
++++ b/config.py.example Wed Oct 12 17:43:46 2011 -0400
+@@ -19,6 +19,11 @@
+ # OPTION: IRCPORT
+ # Port of IRC server to connect to.
+ IRCSERVER, IRCPORT = "irc.myserver.com", 6667
++
++# OPTION: SSLPORT
++# SSL port of IRC server to connect to.
++# If this option is uncommented it will override IRCPORT.
++#SSLPORT = 6697
+
+ # OPTION: REALNAME
+ # The realname field of IRC clients will be set to this value.
+diff -r 19d6068a1aa6 qwebirc/ircclient.py
+--- a/qwebirc/ircclient.py Sun Apr 03 23:58:29 2011 +0100
++++ b/qwebirc/ircclient.py Wed Oct 12 17:43:46 2011 -0400
+@@ -1,6 +1,6 @@
+ import twisted, sys, codecs, traceback
+ from twisted.words.protocols import irc
+-from twisted.internet import reactor, protocol, abstract
++from twisted.internet import reactor, protocol, abstract, ssl
+ from twisted.web import resource, server
+ from twisted.protocols import basic
+ from twisted.names.client import Resolver
+@@ -152,7 +152,10 @@
+ tcpkwargs["bindAddress"] = (config.OUTGOING_IP, 0)
+
+ if CONNECTION_RESOLVER is None:
+- reactor.connectTCP(config.IRCSERVER, config.IRCPORT, f, **tcpkwargs)
++ if hasattr(config, "SSLPORT"):
++ reactor.connectSSL(config.IRCSERVER, config.SSLPORT, f, ssl.ClientContextFactory(), **tcpkwargs)
++ else:
++ reactor.connectTCP(config.IRCSERVER, config.IRCPORT, f, **tcpkwargs)
+ return f
+
+ def callback(result):