irkerd: Extract username and password from submitted URLs
authorW. Trevor King <wking@tremily.us>
Fri, 7 Mar 2014 04:21:24 +0000 (20:21 -0800)
committerEric S. Raymond <esr@thyrsus.com>
Tue, 11 Mar 2014 04:55:54 +0000 (00:55 -0400)
And use them (when present) as the USER username [1] and server PASS
[2] respectively.  The previous implementation gave no way to set
PASS, which will vary on a per-target-server level.  There's unlikely
to be much need to set per-server usernames, except collision
avoidance (e.g. network X already has an 'irker' user).

I changed the existing IRCServerConnection.connect argument from
'ircname' to 'realname' to match the USER specs and our
IRCServerConnection.user implementation.  The 'realname' and
'username' arguments are currently unset, but you could add command
line options to set irker-wide defaults, and use the kwargs chain to
pass them down to the connect method.  The fallback logic is:

* Prefer the setting listed in the URL (although you'd need to add a
  parser to extract 'realname').  If that's empty or missing, fall
  back to
* The irker-wide default passed down the kwargs chain.  If that's
  empty or missing, fall back to
* Local defaults ('irker' and 'irker relaying client').

I also tweaked the servername and port extraction in
Target.__init__(), because they are already parsed out of the netloc
(along with the username and password) by urlparse().

[1]: https://tools.ietf.org/html/rfc2812#section-3.1.3
[2]: https://tools.ietf.org/html/rfc2812#section-3.1.1

NEWS
irkerd
irkerd.xml

diff --git a/NEWS b/NEWS
index 18c6859d155112f8666b4d9ccb2b6541c44494ca..7959d5bbb0fbc8fa1d67bb067002fb5b693a6abf 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@
 
 2.7 @ unreleased
   Add support for ircs:// and SSL/TLS connections to IRC servers.
+  Add support for per-URL usernames and passwords.
 
 2.6 @ 2014-02-04
    Fix for an infinite loop on failing to connect to IRC
diff --git a/irkerd b/irkerd
index adcde8bad0ca5f52a1e87c52a2d00e18a74d5f22..e2c338d7957aa42bec66baad91d71694f905c8d6 100755 (executable)
--- a/irkerd
+++ b/irkerd
@@ -263,8 +263,8 @@ class IRCServerConnection():
             LOG.warning(
                 'cannot check SSL/TLS hostname with Python %s' % sys.version)
 
-    def connect(self, target, nickname,
-                password=None, username=None, ircname=None, **kwargs):
+    def connect(self, target, nickname, username=None, realname=None,
+                **kwargs):
         LOG.debug("connect(server=%r, port=%r, nickname=%r, ...)" % (
             target.servername, target.port, nickname))
         if self.socket is not None:
@@ -287,10 +287,12 @@ class IRCServerConnection():
 
         if target.ssl:
             self._check_hostname(target=target)
-        if password:
-            self.ship("PASS " + password)
+        if target.password:
+            self.ship("PASS " + target.password)
         self.nick(self.nickname)
-        self.user(username=username or ircname, realname=ircname or nickname)
+        self.user(
+            username=target.username or username or 'irker',
+            realname=realname or 'irker relaying client')
         return self
 
     def close(self):
@@ -567,8 +569,6 @@ class Connection:
                             self.connection.connect(
                                 target=self.target,
                                 nickname=self.nickname(),
-                                username="irker",
-                                ircname="irker relaying client",
                                 **self.kwargs)
                             self.status = "handshaking"
                             LOG.info("XMIT_TTL bump (%s connection) at %s" % (
@@ -675,10 +675,10 @@ class Target():
             default_ircport = 6697
         else:
             default_ircport = 6667
-        irchost, _, ircport = parsed.netloc.partition(':')
-        if not ircport:
-            ircport = default_ircport
-        self.servername = irchost
+        self.username = parsed.username
+        self.password = parsed.password
+        self.servername = parsed.hostname
+        self.port = parsed.port or default_ircport
         # IRC channel names are case-insensitive.  If we don't smash
         # case here we may run into problems later. There was a bug
         # observed on irc.rizon.net where an irkerd user specified #Channel,
@@ -697,7 +697,6 @@ class Target():
         self.key = ""
         if parsed.query:
             self.key = re.sub("^key=", "", parsed.query)
-        self.port = int(ircport)
 
     def __str__(self):
         "Represent this instance as a string"
index 729c4f4178f4c272435b28bab657e348a519ba75..c14a950f0c0947cb2a46be1f70d908e166b2ba6a 100644 (file)
@@ -54,6 +54,7 @@ Examples:
 {"to":["irc://chat.freenode.net/#git-ciabot","irc://chat.freenode.net/#gpsd"],"privmsg":"Multichannel test"}
 {"to":"irc://chat.hypothetical.net:6668/git-ciabot", "privmsg":"Hello, world!"}
 {"to":"ircs://chat.hypothetical.net/git-private?key=topsecret", "privmsg":"Keyed channel test"}
+{"to":"ircs://:topsecret@chat.example.net/git-private", "privmsg":"Password-protected server test"}
 </programlisting></para>
 
 <para>If the channel part of the URL does not have one of the prefix
@@ -67,6 +68,11 @@ colon, as shown in the third example; otherwise
 <application>irkerd</application> sends plaintext messages to the default
 6667 IRC port of each server, and SSL/TLS messages to 6697.</para>
 
+<para>The password for password-protected servers can be set using the
+usual <quote>[{username}:{password}@]{host}:{port}</quote> defined in
+RFC 3986, as shown in the fifth example.  Non-empty URL usernames
+override the default <quote>irker</quote> username.</para>
+
 <para>When the <quote>to</quote> URL uses the <quote>ircs</quote>
 scheme (as shown in the fourth and fifth examples), the connection to
 the server is made via SSL/TLS (vs. a plaintext connection with the