From 9e94bf87a1470e0a4aecddc22a84f0af7899982f Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Mon, 4 Aug 2025 23:01:10 +0200 Subject: [PATCH] Add port configuration, and wrap into SSL context if standard SSL port. --- ircplom/client.py | 11 +++++++++-- ircplom/client_tui.py | 19 +++++++++++++++---- ircplom/irc_conn.py | 11 ++++++++--- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/ircplom/client.py b/ircplom/client.py index 2b543a4..caafc20 100644 --- a/ircplom/client.py +++ b/ircplom/client.py @@ -11,7 +11,7 @@ from uuid import UUID, uuid4 from ircplom.events import (AffectiveEvent, ExceptionEvent, Logger, PayloadMixin, QueueMixin) from ircplom.irc_conn import (BaseIrcConnection, IrcConnAbortException, - IrcMessage) + IrcMessage, PORT_SSL) ClientsDb = dict[UUID, 'Client'] CHAT_GLOB = '*' @@ -167,6 +167,7 @@ class _CapsManager: class IrcConnSetup: 'All we need to know to set up a new Client connection.' hostname: str + port: int nickname: str realname: str password: str @@ -181,10 +182,13 @@ class Client(ABC, ClientQueueMixin): super().__init__(**kwargs) self._caps = _CapsManager(self.send) self.conn_setup = conn_setup + if self.conn_setup.port <= 0: + self.conn_setup.port = PORT_SSL self.id_ = uuid4() self.log = Logger(self._log) self.update_login(nick_confirmed=False, nickname=self.conn_setup.nickname) + self.log.add(f'connecting {self.conn_setup}') self.start_connecting() def start_connecting(self) -> None: @@ -193,6 +197,7 @@ class Client(ABC, ClientQueueMixin): def connect(self) -> None: try: self.conn = _IrcConnection(hostname=self.conn_setup.hostname, + port=self.conn_setup.port, q_out=self.q_out, client_id=self.id_) self._cput(ClientEvent.make_subtype('on_connect')) @@ -205,7 +210,9 @@ class Client(ABC, ClientQueueMixin): def on_connect(self) -> None: 'Steps to perform right after connection.' - self.log.add(msg='connected to server', chat=CHAT_GLOB) + assert self.conn is not None + self.log.add('connected to server (SSL: ' + f'{"yes" if self.conn.ssl else "no"})', chat=CHAT_GLOB) self._caps.challenge('LS', '302') self.send(IrcMessage(verb='USER', params=(getuser(), '0', '*', diff --git a/ircplom/client_tui.py b/ircplom/client_tui.py index ab24508..c7e60c2 100644 --- a/ircplom/client_tui.py +++ b/ircplom/client_tui.py @@ -99,16 +99,27 @@ class ClientTui(BaseTui): client_wins[0].prompt.prefix_copy_to(win.prompt) return win - def cmd__connect(self, hostname: str, nickname_and_pw: str, realname: str + def cmd__connect(self, host_port: str, nickname_pw: str, realname: str ) -> None: 'Create Client and pass it via NewClientEvent.' - split = nickname_and_pw.split(':', maxsplit=1) + split = host_port.split(':', maxsplit=1) + hostname = split[0] + port = -1 + if len(split) > 1: + to_int = split[1] + if to_int.isdigit(): + port = int(split[1]) + else: + self.log.alert(f'invalid port number: {to_int}') + return + split = nickname_pw.split(':', maxsplit=1) nickname = split[0] - pw = split[1] if len(split) > 1 else '' + password = split[1] if len(split) > 1 else '' self._put(NewClientEvent( _ClientKnowingTui( q_out=self.q_out, - conn_setup=IrcConnSetup(hostname, nickname, realname, pw)))) + conn_setup=IrcConnSetup( + hostname, port, nickname, realname, password)))) @dataclass diff --git a/ircplom/irc_conn.py b/ircplom/irc_conn.py index f7f5455..45ebc47 100644 --- a/ircplom/irc_conn.py +++ b/ircplom/irc_conn.py @@ -2,15 +2,16 @@ # built-ins from abc import ABC, abstractmethod from socket import socket, gaierror as socket_gaierror +from ssl import create_default_context as create_ssl_context from typing import Callable, Iterator, NamedTuple, Optional, Self # ourselves from ircplom.events import Event, Loop, QueueMixin +PORT_SSL = 6697 _TIMEOUT_RECV_LOOP = 0.1 _TIMEOUT_CONNECT = 5 _CONN_RECV_BUFSIZE = 1024 -_PORT = 6667 _IRCSPEC_LINE_SEPARATOR = b'\r\n' _IRCSPEC_TAG_ESCAPES = ((r'\:', ';'), @@ -127,12 +128,16 @@ class IrcConnAbortException(Exception): class BaseIrcConnection(QueueMixin, ABC): 'Collects low-level server-client connection management.' - def __init__(self, hostname: str, **kwargs) -> None: + def __init__(self, hostname: str, port: int, **kwargs) -> None: super().__init__(**kwargs) self._socket = socket() + self.ssl = port == PORT_SSL + if self.ssl: + self._socket = create_ssl_context().wrap_socket( + self._socket, server_hostname=hostname) self._socket.settimeout(_TIMEOUT_CONNECT) try: - self._socket.connect((hostname, _PORT)) + self._socket.connect((hostname, port)) except (TimeoutError, socket_gaierror) as e: raise IrcConnAbortException(e) from e self._socket.settimeout(_TIMEOUT_RECV_LOOP) -- 2.30.2