···40404141# IRC Configuration
4242IRC_NICK=slackbridge
4343+NICKSERV_PASSWORD=your-nickserv-password-here
4444+NICKSERV_EMAIL=your-email@example.com
43454446# Admin users (comma-separated Slack user IDs)
4547ADMINS=U1234567890,U0987654321
···90929193The bridge connects to `irc.hackclub.com:6667` (no TLS) and forwards messages bidirectionally based on channel mappings:
92949595+- **NickServ Authentication**: If `NICKSERV_PASSWORD` is configured, the bridge authenticates on connect
9696+ - Waits for NickServ confirmation before joining channels
9797+ - Auto-registers the nick if not registered (requires `NICKSERV_EMAIL`)
9898+ - Prevents "No external channel messages" errors by ensuring proper authentication
9399- **IRC → Slack**: Messages from mapped IRC channels appear in their corresponding Slack channels
94100 - Image URLs are automatically displayed as inline attachments
95101 - IRC mentions (`@nick` or `nick:`) are converted to Slack mentions for mapped users
96102 - IRC formatting codes are converted to Slack markdown
97103- **Slack → IRC**: Messages from mapped Slack channels are sent to their corresponding IRC channels
9898- - Slack mentions are converted to `@displayName` format using Cachet
104104+ - Slack mentions are converted to mapped IRC nicks, or the display name from `<@U123|name>` format
99105 - Slack markdown is converted to IRC formatting codes
100106 - File attachments are uploaded to Hack Club CDN and URLs are shared
101107- **User mappings** allow custom IRC nicknames for specific Slack users and enable proper mentions both ways
+49-3
src/index.ts
···8484// Register slash commands
8585registerCommands();
86868787+// Track NickServ authentication state
8888+let nickServAuthAttempted = false;
8989+let isAuthenticated = false;
9090+8791// Join all mapped IRC channels on connect
8892ircClient.addListener("registered", async () => {
8993 console.log("Connected to IRC server");
9090- const mappings = channelMappings.getAll();
9191- for (const mapping of mappings) {
9292- ircClient.join(mapping.irc_channel);
9494+9595+ // Authenticate with NickServ if password is provided
9696+ if (process.env.NICKSERV_PASSWORD && !nickServAuthAttempted) {
9797+ nickServAuthAttempted = true;
9898+ console.log("Authenticating with NickServ...");
9999+ ircClient.say("NickServ", `IDENTIFY ${process.env.NICKSERV_PASSWORD}`);
100100+ // Don't join channels yet - wait for NickServ response
101101+ } else if (!process.env.NICKSERV_PASSWORD) {
102102+ // No auth needed, join immediately
103103+ const mappings = channelMappings.getAll();
104104+ for (const mapping of mappings) {
105105+ ircClient.join(mapping.irc_channel);
106106+ }
93107 }
94108});
9510996110ircClient.addListener("join", (channel: string, nick: string) => {
97111 if (nick === process.env.IRC_NICK) {
98112 console.log(`Joined IRC channel: ${channel}`);
113113+ }
114114+});
115115+116116+// Handle NickServ notices
117117+ircClient.addListener("notice", async (nick: string, to: string, text: string) => {
118118+ if (nick !== "NickServ") return;
119119+120120+ console.log(`NickServ: ${text}`);
121121+122122+ // Check for successful authentication
123123+ if (text.includes("You are now identified") || text.includes("Password accepted")) {
124124+ console.log("✓ Successfully authenticated with NickServ");
125125+ isAuthenticated = true;
126126+127127+ // Join channels after successful auth
128128+ const mappings = channelMappings.getAll();
129129+ for (const mapping of mappings) {
130130+ ircClient.join(mapping.irc_channel);
131131+ }
132132+ }
133133+ // Check if nick is not registered
134134+ else if (text.includes("isn't registered") || text.includes("not registered")) {
135135+ console.log("Nick not registered, registering with NickServ...");
136136+ if (process.env.NICKSERV_PASSWORD && process.env.NICKSERV_EMAIL) {
137137+ ircClient.say("NickServ", `REGISTER ${process.env.NICKSERV_PASSWORD} ${process.env.NICKSERV_EMAIL}`);
138138+ } else {
139139+ console.error("Cannot register: NICKSERV_EMAIL not configured");
140140+ }
141141+ }
142142+ // Check for failed authentication
143143+ else if (text.includes("Invalid password") || text.includes("Access denied")) {
144144+ console.error("✗ NickServ authentication failed: Invalid password");
99145 }
100146});
101147