Validate certificates when using SSL/TLS
This commit is contained in:
parent
a3d047350b
commit
a906b6a98e
5 changed files with 49 additions and 10 deletions
|
@ -5,6 +5,11 @@
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Support for color via IRCv3 metadata draft.
|
- Support for color via IRCv3 metadata draft.
|
||||||
|
- Prompt for connecting anyway when certificate validation fails.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Reenabled server certificate validation when using SSL.
|
||||||
|
- Uses the system's local certificates, so might fail on some installations.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Error when setting quirk with PyQt5.
|
- Error when setting quirk with PyQt5.
|
||||||
|
|
2
TODO.md
2
TODO.md
|
@ -14,4 +14,4 @@
|
||||||
- Console is hopelessly broken, it'd be easier to make a list of what commands *don't* cause it to crash. Does anyone use this?
|
- Console is hopelessly broken, it'd be easier to make a list of what commands *don't* cause it to crash. Does anyone use this?
|
||||||
|
|
||||||
## CHANGE
|
## CHANGE
|
||||||
- When everything has been tested and more people have compatible versions, switch Pesterchum over to using metadata and message tags by default instead of wraping its protocol in PRIVMSG. The current method should stay availible for compatibility.
|
- When everything has been tested and more people have compatible versions, switch Pesterchum over to using metadata and message tags by default instead of wrapping its protocol in PRIVMSG. The current method should stay available for compatibility.
|
||||||
|
|
12
irc.py
12
irc.py
|
@ -4,6 +4,7 @@ import socket
|
||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
|
import ssl
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PyQt6 import QtCore, QtGui
|
from PyQt6 import QtCore, QtGui
|
||||||
|
@ -40,12 +41,13 @@ QString = str
|
||||||
# logging.basicConfig(level=logging.WARNING)
|
# logging.basicConfig(level=logging.WARNING)
|
||||||
|
|
||||||
class PesterIRC(QtCore.QThread):
|
class PesterIRC(QtCore.QThread):
|
||||||
def __init__(self, config, window):
|
def __init__(self, config, window, verify_hostname=True):
|
||||||
QtCore.QThread.__init__(self)
|
QtCore.QThread.__init__(self)
|
||||||
self.mainwindow = window
|
self.mainwindow = window
|
||||||
self.config = config
|
self.config = config
|
||||||
self.unresponsive = False
|
self.unresponsive = False
|
||||||
self.registeredIRC = False
|
self.registeredIRC = False
|
||||||
|
self.verify_hostname = verify_hostname
|
||||||
self.metadata_supported = False
|
self.metadata_supported = False
|
||||||
self.stopIRC = None
|
self.stopIRC = None
|
||||||
self.NickServ = services.NickServ()
|
self.NickServ = services.NickServ()
|
||||||
|
@ -61,7 +63,12 @@ class PesterIRC(QtCore.QThread):
|
||||||
timeout=120)
|
timeout=120)
|
||||||
self.cli.command_handler.parent = self
|
self.cli.command_handler.parent = self
|
||||||
self.cli.command_handler.mainwindow = self.mainwindow
|
self.cli.command_handler.mainwindow = self.mainwindow
|
||||||
self.cli.connect()
|
try:
|
||||||
|
self.cli.connect(self.verify_hostname)
|
||||||
|
except ssl.SSLCertVerificationError as e:
|
||||||
|
# Ask if users wants to connect anyway
|
||||||
|
self.askToConnect.emit(e)
|
||||||
|
raise e
|
||||||
self.conn = self.cli.conn()
|
self.conn = self.cli.conn()
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
|
@ -395,6 +402,7 @@ class PesterIRC(QtCore.QThread):
|
||||||
chanInviteOnly = QtCore.pyqtSignal('QString')
|
chanInviteOnly = QtCore.pyqtSignal('QString')
|
||||||
modesUpdated = QtCore.pyqtSignal('QString', 'QString')
|
modesUpdated = QtCore.pyqtSignal('QString', 'QString')
|
||||||
connected = QtCore.pyqtSignal()
|
connected = QtCore.pyqtSignal()
|
||||||
|
askToConnect = QtCore.pyqtSignal(Exception)
|
||||||
userPresentUpdate = QtCore.pyqtSignal('QString', 'QString',
|
userPresentUpdate = QtCore.pyqtSignal('QString', 'QString',
|
||||||
'QString')
|
'QString')
|
||||||
cannotSendToChan = QtCore.pyqtSignal('QString', 'QString')
|
cannotSendToChan = QtCore.pyqtSignal('QString', 'QString')
|
||||||
|
|
|
@ -185,17 +185,17 @@ class IRCClient:
|
||||||
#raise se
|
#raise se
|
||||||
self._end = True # This ok?
|
self._end = True # This ok?
|
||||||
|
|
||||||
def connect(self):
|
def connect(self, verify_hostname=True):
|
||||||
""" initiates the connection to the server set in self.host:self.port
|
""" initiates the connection to the server set in self.host:self.port
|
||||||
"""
|
"""
|
||||||
PchumLog.info('connecting to %s:%s' % (self.host, self.port))
|
PchumLog.info('connecting to %s:%s' % (self.host, self.port))
|
||||||
|
|
||||||
if self.ssl == True:
|
if self.ssl == True:
|
||||||
context = ssl.create_default_context()
|
context = ssl.create_default_context()
|
||||||
# Checking relies on the system
|
if verify_hostname == False:
|
||||||
context.check_hostname = False
|
context.check_hostname = False
|
||||||
context.verify_mode = ssl.CERT_NONE
|
context.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
bare_sock = socket.create_connection((self.host, self.port))
|
bare_sock = socket.create_connection((self.host, self.port))
|
||||||
self.socket = context.wrap_socket(bare_sock,
|
self.socket = context.wrap_socket(bare_sock,
|
||||||
server_hostname=self.host,
|
server_hostname=self.host,
|
||||||
|
@ -208,6 +208,11 @@ class IRCClient:
|
||||||
select.select([self.socket], [], [])
|
select.select([self.socket], [], [])
|
||||||
except ssl.SSLWantWriteError:
|
except ssl.SSLWantWriteError:
|
||||||
select.select([], [self.socket], [])
|
select.select([], [self.socket], [])
|
||||||
|
except ssl.SSLCertVerificationError as e:
|
||||||
|
# Disconnect for now
|
||||||
|
self.socket.close()
|
||||||
|
bare_sock.close()
|
||||||
|
raise e
|
||||||
|
|
||||||
PchumLog.info("secure sockets version is %s" % self.socket.version())
|
PchumLog.info("secure sockets version is %s" % self.socket.version())
|
||||||
|
|
||||||
|
|
|
@ -3694,6 +3694,26 @@ class PesterWindow(MovingWindow):
|
||||||
self.chooseServerWidged.show()
|
self.chooseServerWidged.show()
|
||||||
self.chooseServerWidged.setFocus()
|
self.chooseServerWidged.setFocus()
|
||||||
|
|
||||||
|
@QtCore.pyqtSlot(Exception)
|
||||||
|
def connectAnyway(self, e):
|
||||||
|
# Prompt user to connect anyway
|
||||||
|
msgbox = QtWidgets.QMessageBox()
|
||||||
|
msgbox.setStyleSheet("QMessageBox{ %s }"
|
||||||
|
% self.theme["main/defaultwindow/style"])
|
||||||
|
msgbox.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
||||||
|
msgbox.setText("Server certificate validation failed")
|
||||||
|
msgbox.setInformativeText("Reason: \"%s (%s)\"" % (e.verify_message, e.verify_code)
|
||||||
|
+ "\n\nConnect anyway?")
|
||||||
|
msgbox.setStandardButtons(QtWidgets.QMessageBox.StandardButton.Yes
|
||||||
|
| QtWidgets.QMessageBox.StandardButton.No)
|
||||||
|
msgbox.setDefaultButton(QtWidgets.QMessageBox.StandardButton.No)
|
||||||
|
ret = msgbox.exec()
|
||||||
|
if ret == QtWidgets.QMessageBox.StandardButton.Yes:
|
||||||
|
self.parent.restartIRC(verify_hostname=False)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
pcUpdate = QtCore.pyqtSignal('QString', 'QString')
|
pcUpdate = QtCore.pyqtSignal('QString', 'QString')
|
||||||
closeToTraySignal = QtCore.pyqtSignal()
|
closeToTraySignal = QtCore.pyqtSignal()
|
||||||
newConvoStarted = QtCore.pyqtSignal('QString', bool, name="newConvoStarted")
|
newConvoStarted = QtCore.pyqtSignal('QString', bool, name="newConvoStarted")
|
||||||
|
@ -3982,6 +4002,7 @@ class MainProgram(QtCore.QObject):
|
||||||
(widget.disconnectIRC, irc.disconnectIRC),
|
(widget.disconnectIRC, irc.disconnectIRC),
|
||||||
# Main window --> IRC
|
# Main window --> IRC
|
||||||
(irc.connected, widget.connected),
|
(irc.connected, widget.connected),
|
||||||
|
(irc.askToConnect, widget.connectAnyway),
|
||||||
(irc.moodUpdated, widget.updateMoodSlot),
|
(irc.moodUpdated, widget.updateMoodSlot),
|
||||||
(irc.colorUpdated, widget.updateColorSlot),
|
(irc.colorUpdated, widget.updateColorSlot),
|
||||||
(irc.messageReceived, widget.deliverMessage),
|
(irc.messageReceived, widget.deliverMessage),
|
||||||
|
@ -4069,7 +4090,7 @@ class MainProgram(QtCore.QObject):
|
||||||
else:
|
else:
|
||||||
self.restartIRC()
|
self.restartIRC()
|
||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def restartIRC(self):
|
def restartIRC(self, verify_hostname=True):
|
||||||
if hasattr(self, 'irc') and self.irc:
|
if hasattr(self, 'irc') and self.irc:
|
||||||
self.disconnectWidgets(self.irc, self.widget)
|
self.disconnectWidgets(self.irc, self.widget)
|
||||||
stop = self.irc.stopIRC
|
stop = self.irc.stopIRC
|
||||||
|
@ -4077,7 +4098,7 @@ class MainProgram(QtCore.QObject):
|
||||||
else:
|
else:
|
||||||
stop = None
|
stop = None
|
||||||
if stop is None:
|
if stop is None:
|
||||||
self.irc = PesterIRC(self.widget.config, self.widget)
|
self.irc = PesterIRC(self.widget.config, self.widget, verify_hostname=verify_hostname)
|
||||||
self.connectWidgets(self.irc, self.widget)
|
self.connectWidgets(self.irc, self.widget)
|
||||||
self.irc.start()
|
self.irc.start()
|
||||||
if self.attempts == 1:
|
if self.attempts == 1:
|
||||||
|
|
Loading…
Reference in a new issue