Drop NickServ identification
Not registering clod with NickServ, so remove the IDENTIFY-on-connect code, the nickserv_password_file setting and its .gitignore entry. The periodic attempt to reclaim clod from clod_ stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
fc973790fb
commit
6a62ce1758
@@ -1,4 +1,3 @@
|
|||||||
.venv/
|
.venv/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
nickserv_password.txt
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
A small MCP server that gives Claude Code an IRC connection.
|
A small MCP server that gives Claude Code an IRC connection.
|
||||||
|
|
||||||
- Connects to `irc.rizon.net:6697` over TLS as `clod`. If that nick is taken it uses `clod_` and tries to switch back every `nick_retry_seconds` (default 180)
|
- Connects to `irc.rizon.net:6697` over TLS as `clod`. If that nick is taken it uses `clod_` and tries to switch back every `nick_retry_seconds` (default 180)
|
||||||
- Identifies to NickServ whenever it holds `clod`, using the password in `nickserv_password.txt` (gitignored, set by `nickserv_password_file`)
|
|
||||||
- Answers server PINGs, sends its own keepalive PING, and reconnects automatically
|
- Answers server PINGs, sends its own keepalive PING, and reconnects automatically
|
||||||
- Can only join channels listed in `allowed_channels` in `config.json` (re-read on every call, so edits apply right away)
|
- Can only join channels listed in `allowed_channels` in `config.json` (re-read on every call, so edits apply right away)
|
||||||
- Keeps a rolling buffer of recent messages per joined channel (`buffer_size`, default 200)
|
- Keeps a rolling buffer of recent messages per joined channel (`buffer_size`, default 200)
|
||||||
|
|||||||
@@ -8,6 +8,5 @@
|
|||||||
"realname": "Claude Code IRC MCP",
|
"realname": "Claude Code IRC MCP",
|
||||||
"allowed_channels": ["#blog", "#/g/tv"],
|
"allowed_channels": ["#blog", "#/g/tv"],
|
||||||
"buffer_size": 200,
|
"buffer_size": 200,
|
||||||
"nickserv_password_file": "nickserv_password.txt",
|
|
||||||
"nick_retry_seconds": 180
|
"nick_retry_seconds": 180
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ messages, and exposes tools to join/leave/send/read/list users.
|
|||||||
|
|
||||||
It never sends chat text on its own: the only things it writes to the server
|
It never sends chat text on its own: the only things it writes to the server
|
||||||
unprompted are protocol traffic (NICK/USER registration, PONG replies,
|
unprompted are protocol traffic (NICK/USER registration, PONG replies,
|
||||||
keepalive PINGs, NickServ IDENTIFY, periodic NICK attempts to reclaim the
|
keepalive PINGs, periodic NICK attempts to reclaim the configured nick, and
|
||||||
configured nick, and re-joining channels you already joined after a reconnect).
|
re-joining channels you already joined after a reconnect).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
@@ -47,24 +47,10 @@ def load_config() -> dict:
|
|||||||
cfg.setdefault("realname", cfg["nick"])
|
cfg.setdefault("realname", cfg["nick"])
|
||||||
cfg.setdefault("allowed_channels", [])
|
cfg.setdefault("allowed_channels", [])
|
||||||
cfg.setdefault("buffer_size", 200)
|
cfg.setdefault("buffer_size", 200)
|
||||||
cfg.setdefault("nickserv_password_file", "")
|
|
||||||
cfg.setdefault("nick_retry_seconds", 180)
|
cfg.setdefault("nick_retry_seconds", 180)
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
def nickserv_password(cfg: dict) -> str:
|
|
||||||
"""Read the NickServ password from its (gitignored) file, relative to the config."""
|
|
||||||
name = cfg["nickserv_password_file"]
|
|
||||||
if not name:
|
|
||||||
return ""
|
|
||||||
path = CONFIG_PATH.parent / name
|
|
||||||
try:
|
|
||||||
return path.read_text(encoding="utf-8").strip()
|
|
||||||
except FileNotFoundError:
|
|
||||||
log.warning("NickServ password file %s not found; not identifying", path)
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
def irc_lower(s: str) -> str:
|
def irc_lower(s: str) -> str:
|
||||||
"""RFC 1459 case folding, used for channel and nick comparison."""
|
"""RFC 1459 case folding, used for channel and nick comparison."""
|
||||||
return s.lower().translate(str.maketrans("[]\\~", "{}|^"))
|
return s.lower().translate(str.maketrans("[]\\~", "{}|^"))
|
||||||
@@ -214,14 +200,6 @@ class IRCClient:
|
|||||||
log.info("trying to reclaim nick %s", cfg["nick"])
|
log.info("trying to reclaim nick %s", cfg["nick"])
|
||||||
await self.send_raw(f"NICK {cfg['nick']}")
|
await self.send_raw(f"NICK {cfg['nick']}")
|
||||||
|
|
||||||
async def _identify(self):
|
|
||||||
"""Identify to NickServ, but only while holding the configured (registered) nick."""
|
|
||||||
cfg = load_config()
|
|
||||||
password = nickserv_password(cfg)
|
|
||||||
if password and self._is_me(cfg["nick"]):
|
|
||||||
log.info("identifying to NickServ as %s", self.nick)
|
|
||||||
await self.send_raw(f"PRIVMSG NickServ :IDENTIFY {password}")
|
|
||||||
|
|
||||||
async def _quit(self):
|
async def _quit(self):
|
||||||
if self.writer:
|
if self.writer:
|
||||||
try:
|
try:
|
||||||
@@ -261,7 +239,6 @@ class IRCClient:
|
|||||||
self.registered.set()
|
self.registered.set()
|
||||||
self.status = f"connected as {self.nick}"
|
self.status = f"connected as {self.nick}"
|
||||||
log.info(self.status)
|
log.info(self.status)
|
||||||
await self._identify()
|
|
||||||
for ch in list(self.wanted):
|
for ch in list(self.wanted):
|
||||||
await self.send_raw(f"JOIN {self.display.get(ch, ch)}")
|
await self.send_raw(f"JOIN {self.display.get(ch, ch)}")
|
||||||
elif cmd in ("432", "433", "436") and not self.registered.is_set():
|
elif cmd in ("432", "433", "436") and not self.registered.is_set():
|
||||||
@@ -310,7 +287,6 @@ class IRCClient:
|
|||||||
if self._is_me(src):
|
if self._is_me(src):
|
||||||
self.nick = p[0]
|
self.nick = p[0]
|
||||||
self.status = f"connected as {self.nick}"
|
self.status = f"connected as {self.nick}"
|
||||||
await self._identify()
|
|
||||||
for ch, nicks in self.joined.items():
|
for ch, nicks in self.joined.items():
|
||||||
if src in nicks:
|
if src in nicks:
|
||||||
nicks.discard(src)
|
nicks.discard(src)
|
||||||
|
|||||||
Reference in New Issue
Block a user