irc-socket-sasl
v4.0.0
Published
Simple IRC Socket with SSL and SASL support, for usage with IRC libraries. Forked from irc-socket.
Downloads
9
Readme
IRC Socket SASL
Socket wrapper to emit IRC messages and handle server startup. Supports SSL and SASL authentication.
We provide for you the following benefits:
- One "data" event per IRC message.
- Pings are automatically ponged too..
- The startup handshake (before the RPL_WELCOME) message is handled.
- A
raw
method to send raw messages to the server. - NetSocket with SSL support
- SASL authentication support
Maintainer
Originally written and maintained by Havvy. Forked and now maintained by Nick Jennings to add SSL and SASL support.
Installation
npm install irc-socket --save
Instantiation
const net = require("net");
const IrcSocket = require("irc-socket");
const ircSocket = IrcSocket({
socket: net,
port: 6667,
server: "irc.someircnetwork.net",
nicknames: ["freddy", "freddy_"],
username: "freddy",
realname: "Freddy",
password: "server-password",
// For transparent proxies using
// the webirc protocol.
proxy: {
password: "shared-webirc-password",
username: "users-username",
hostname: "users-hostname",
ip: "users-ip"
},
// For anybody wanting IRC3 capabilities.
capabilities: {
requires: ["multi-prefix", "userhost-in-names"],
wants: ["account-notify"]
},
// Passed as the options parameter to socket's
// connect method.
// Shown here are example options.
connectOptions: {
localAddress: "a-local-address",
localPort: "a-local-port",
family: 6, // for ipv6 with net.Socket
},
// optional number of milliseconds with no
// response before timeout is fired
timeout: 5 * 60 * 1000
});
IrcSocket(config, socket)
The IrcSocket constructor is overloaded to provide a convenience form that takes the socket separately. This is provided so that if the config is created apart from the Socket, you don't need to modify the config object, especially since the rest of the configuration values can be serialized as JSON.
const net = require("net");
const IrcSocket = require("irc-socket");
const fs = require("fs");
const config = fs.readFileSync("config.json");
const ircSocket = IrcSocket(config, net);
Configuration
The configuration options are as follows.
socket
: [required] A net.Socket that IrcSocket wraps around.server
: [required] The server/host to connect to. e.g. "irc.mibbit.net"port
: [required] Which port to connect to. Normally 6667, or 6697 for TLS.nicknames
: [required] Array of nicknames to try to use in order.username
: [required] Username part of the hostmask.realname
: [required] "Real name" to send with the USER command.password
: Password used to connect to the network. Most networks don't have one.saslPassword
: Will be used for SASL authentication if the sasl property is also true.saslUsername
: Will be used for SASL authentication. (Defaults to username if not set).proxy
: WEBIRC details if your connection is acting as a (probably web-based) proxy.capabilities
: See the Capabilities section below..connectOptions
: Options passed to the wrapped socket's connect method. Optionshost
andport
are overwritten. See io.js's net.Socket.prototype.connect for options when usingnet.Socket
in either Node.js or io.js. (Node.js's documentation is incomplete.)
Capabilities
Capabilities are a feature added in IRCv3 to extend IRC while still keeping IRCv2 compatibility. You can see the specification and well-known capabilities at the IRCv3 website.
Should you want to use IRCv3 features, pass an object with the requires
property listing which features you absolutely require and wants
for
features that you can handle not being there. Both properties are optional.
Proxy
The proxy object has the following four fields, all required:
password
: Shared secret password between you and the network you are connecting with.username
: User or client requesting spoof.hostname
: Hostname of user connecting to your proxy.ip
: IP Address of user connecting to your proxy.
Starting and Closing the Socket
You start and end the socket like a normal net.Socket with the connect
and
end
methods. You shouldn't call end
yourself though. Instead, you should
write a QUIT message to the server (see tnext section).
The connect
method returns a
Promise<Result<{capabilities, nickname}, ConnectFailure>, Error>
.
You can either use the "ready" event or use the promises returned by the connect method.
const client = IrcSocket(options);
client.once('ready', function () {
client.end();
});
client.connect();
const client = IrcSocket(options);
client.connect().then(function (res) {
// If connect failed, it already closed itself (or was force killed).
// Otherwise, it succeeded, and we want to end it ourself.
if (res.isOk()) {
client.end();
}
});
SASL
Supporting SASL authentication.
const client = IrcSocket({
capabilities: {
requires: ["sasl"]
},
saslUsername: 'exampleuser', // will default to `username` if not specified
saslPassword: 'foo bar'
});
Writing to the Server
To send messages to the server, use socket.raw(). It accepts either a string or an array of Strings. The message '''must''' follow the [IRC protocol](https://irc-wiki.org/RFC 1459).
const details = {...};
const client = Ircsocket(details);
mySocket.connect().then(function (res) {
if (res.isFail()) {
return;
}
// Using a string.
mySocket.raw("JOIN #biscuits");
});
mySocket.on('data', function (message) {
message = message.split(" ");
// Numeric 333 is sent when a user joins a channel.
if (message[1] === "333" &&
message[2] === details.nick &&
message[3] === "#biscuits")
{
// Using an array instead of a string.
mySocket.raw(["PRIVMSG", "#biscuits", ":Hello world."])
}
});
mySocket.on('data', function (message) {
// This is sent when you send QUIT too.
if (message.slice(0, 5) === "ERROR") {
mySocket.end();
}
});
The raw method does not allow the usage of newline characters.
If an array is passed to raw
, the message will be joined with a space.
Reading from the Server
All messages are emitted via a 'data' event. Receiving callbacks to this event will receive the message as the first parameter.
Examples of reading messages are in the previous example. Messages generally look like the following:
:irc.uk.mibbit.net 376 Havvy :End of /MOTD command.
:[email protected] QUIT :Quit: http://www.mibbit.com ajax IRC Client
ERROR :Closing Link: Havvy[127-00-00-00.redacted.com] (Quit: Custom quit message.)
All PING messages sent from the server are automatically PONGed too. You do not need to handle them yourself, but you still receive them, should you wish to log them.
Timeouts
The IRC socket will listen to ping messages and respond to them appropriately, so you do not need to handle this yourself.
Furthermore, if no message from the server is sent within five
minutes, the IrcSocket will ping the server. If no response is
thenn sent in five more minutes, the socket will close and emit
a "timeout"
event.
Should that not be good enough, you can always use
setTimeout(number, optionalCallback)
to use the implementing
socket's (usually a net.Socket) timeout mechanisms.
You can listen to the "timeout"
event for when this occurs.
Utility Methods
isStarted()
This method will return true if the socket was ever started.
isConnected()
This method will return true when the socket is started, but not ended. It will otherwise return false.
isReady()
This method will return true if the RPL_WELCOME message has been sent and the socket is still open. It will otherwise return false.
getRealname()
This method returns the realname (sometimes called gecos) of the connection.
Events
The irc-socket is an event emitter. It emits five events.
- ready(): Once the first 001 message has been acknowledged.
- data(message: String): Every message (including the 001) from the sender (inclusive) the the newline (exclusive).
- close(): Once the implementing socket has been closed.
- timeout(): When either this or the implenting socket time out.
- end(): Once the implementing socket emits an 'end' event.
Testing
We install mocha
as a developer dependency, and run tests with that.
npm install
npm test
Upgrading from v.2.0.0
All of the legacy compatibility has been removed.
A lot of things have changed/been added.
- Changed: "nickname" property is now "nicknames" and takes an array.
- Changed: You cannot restart an irc-socket Socket.
- Changed: you must pass in your own Socket under the "socket" property. All socket related configuration has been removed.
- Changed: Real support for IRC3 capabilities. "capab" property changed to "capabilities", takes an object now.
- Added: Support for the (Webirc)[http://wiki.mibbit.com/index.php/WebIRC] protocol.
- Added:
isStarted
,isReady
methods. for more fine grained status tracking. - Added:
connect
method returns a (Bluebird) Promise that either resolves to a Result of Ok([capabilities]) or Fail(FailReason). - Removed: Auto-addition of colons in .raw(Array) are gone. Put them in yourself as needed.
- Added
debug
property which takes a function likeconsole.log
.
Configuration
You must rename the nickname
property to nicknames
and change it to an array.
This was done so that we can have multiple nicknames. Should all of them be not
accepted, the socket will close itself.
If you were using the (practically useless) capab
property, you probably want to
use the capabilities
property which takes an object now.
If you were using ipv6
you now want to pass family: 6
to the connectOptions
property object now. Likewise, other Socket connect options should go there.
If you were using secure
, you now want to create a net.Socket
and then upgrade
it to a tls.Socket
and finally upgrade that to an irc-socket
. See the next
section for details.
Initialization
We now upgrade your socket into an irc-socket instead of instatiating it ourself.
This means that you need to instantiate the socket you want. Once you upgrade the socket, you give up ownership of it, but gain ownership of the upgraded socket.
const net = require("net");
const IrcSocket = require("irc-socket");
const ircSocket = IrcSocket({
port: 6667,
server: "irc.someircnetwork.net",
nicknames: ["freddy", "freddy_"],
username: "freddy",
realname: "Freddy"
}, net);
Even though port
and server
are part of the Socket connect options, you
must pass them to the IrcSocket options object. For every other connect
option that was supported, you should instead pass the option in the
connectOptions object.
const net = require("net");
const IrcSocket = require("irc-socket");
const ircSocket = IrcSocket({
socket: net,
port: 6667,
server: "irc.someircnetwork.net",
nicknames: ["freddy", "freddy_"],
username: "freddy",
realname: "Freddy",
connectOptions: {
localAddress: aLocalAddress,
family: 6 // was `ipv6` option in old version, is `family` in net.Socket.
}
});
For what was a secure
socket, you must instead pass in the
TLS socket object.
const tls = require("tls");
const IrcSocket = require("irc-socket");
const IrcSocket = IrcSocket({
socket: tls,
...
connectionOptions: {rejectUnauthorized: false}
});
raw([String]) breaking change
If you were using the raw
method with an array and relying on it to put in colons
for you, you must go back and add those colons in yourself. Just grep for raw([
and you should find all of them.
connect() returns a Promise
Instead of listening to the ready
event and doing your own startup handling there,
the connect
method return a Promise. The promise resolves to a
r-result result (mostly equivalent to Rust's
Result type) where it is either Ok({capabilities, nickname}) or Fail(ConnectFailureReason).
The connect failure reasons are located at IrcSocket.connectFailures.
See Also
The irc-message package will quickly parse the strings you pass into objects.
The new version also merges with irc-message-stream
to provide a stream.
For a full IRC Bot framework, take a look at Tennu.
For long-running IRC Clients, take a look at IRC Factory.