class NetWorker(QObject): ifcAddrChanged = pyqtSignal(str, name='ifcAddrChanged', arguments=['ip']) currentIfcAddrChanged = pyqtSignal() wifiStatus = pyqtSignal(str, str, int, int, name='wifiStatus', arguments=['essid', 'freq', 'quality', 'level']) wifiStatusChanged = pyqtSignal() @pyqtProperty(str, notify=currentIfcAddrChanged) def currentIfcAddr(self): return self.ifcAddr.toString() @pyqtProperty(str, notify=wifiStatusChanged) def currentWifiESSID(self): return self.essid @pyqtProperty(str, notify=wifiStatusChanged) def currentWifiFreq(self): return self.freq @pyqtProperty(int, notify=wifiStatusChanged) def currentWifiQuality(self): return self.quality @pyqtProperty(int, notify=wifiStatusChanged) def currentWifiLevel(self): return self.level def __init__(self, loglevel='WARNING', ifcName='wlan0'): QObject.__init__(self) self.logger = Logger(name='ratt.networker') self.logger.setLogLevelStr(loglevel) self.debug = self.logger.isDebug() self.mgr = QNetworkAccessManager() self.sslConfig = QSslConfiguration() self.sslSupported = QSslSocket.supportsSsl() self.setAuth() self.setSSLCertConfig() self.mgr.authenticationRequired.connect( self.handleAuthenticationRequired) self.ifcName = ifcName self.ifcAddr = QHostAddress() self.statusTimer = QTimer() self.statusTimer.setSingleShot(False) self.statusTimer.timeout.connect(self.slotStatusTimer) self.statusTimer.start(5000) self.essid = '' self.freq = '' self.quality = 0 self.level = 0 def slotStatusTimer(self): ip = self.getIfcAddress(ifc=self.ifcName) if ip != self.ifcAddr: self.ifcAddr = ip self.ifcAddrChanged.emit(ip.toString()) self.currentIfcAddrChanged.emit() results = {} if self.getWifiStatus(results): self.essid = results['essid'] self.freq = results['freq'] self.quality = results['quality'] self.level = results['level'] self.wifiStatus.emit(self.essid, self.freq, self.quality, self.level) self.wifiStatusChanged.emit() # ['wlan0', 'IEEE', '802.11', 'ESSID:"FooBar"', 'Mode:Managed', 'Frequency:2.412', # 'GHz', 'Access', 'Point:', '00:11:22:33:44:55', 'Bit', 'Rate=65', 'Mb/s', 'Tx-Power=31', # 'dBm', 'Retry', 'short', 'limit:7', 'RTS', 'thr:off', 'Fragment', 'thr:off', 'Power', # 'Management:on', 'Link', 'Quality=43/70', 'Signal', 'level=-67', 'dBm', 'Rx', 'invalid', # 'nwid:0', 'Rx', 'invalid', 'crypt:0', 'Rx', 'invalid', 'frag:0', 'Tx', 'excessive', 'retries:113', # 'Invalid', 'misc:0', 'Missed', 'beacon:0'] def getWifiStatus(self, res): try: iw = getoutput('/sbin/iwconfig %s' % self.ifcName) fields = iw.split() for field in fields: if field.find('ESSID') != -1: res['essid'] = field.split('"')[1] elif field.find('Frequency') != -1: res['freq'] = field.split(':')[1] elif field.find('Quality') != -1: frac = field.split('=')[1] (n, d) = frac.split('/') q = int(n) * 100 / int(d) res['quality'] = q elif field.find('level') != -1: res['level'] = int(field.split('=')[1]) except: return False return True def getIfcAddress(self, ifc): myIfc = QNetworkInterface.interfaceFromName(ifc) addrList = myIfc.addressEntries() for addr in addrList: if addr.ip().protocol() == QAbstractSocket.IPv4Protocol: return addr.ip() return QHostAddress() def setAuth(self, user='', password=''): self.user = user self.password = password def setSSLCertConfig(self, enabled=False, caCertFile='', clientCertFile='', clientKeyFile=''): self.sslEnabled = enabled if self.sslSupported and self.sslEnabled: self.caCertFile = caCertFile self.clientCertFile = clientCertFile self.clientKeyFile = clientKeyFile self.configureCerts() def get(self, url): self.logger.debug('get url=%s' % url.toString()) request = QNetworkRequest(QUrl(url)) request.setRawHeader("User-Agent", "RATT") if self.sslSupported and self.sslEnabled: request.setSslConfiguration(self.sslConfig) reply = self.mgr.get(request) if self.sslSupported and self.sslEnabled: reply.sslErrors.connect(self.handleSSLErrors) return reply def buildRequest(self, url): request = QNetworkRequest(QUrl(url)) request.setHeader(QNetworkRequest.ContentTypeHeader, "application/x-www-form-urlencoded") return request def buildQuery(self, vars): query = str() for key in vars: value = vars[key] sep = '&' if query != '' else '' query = query + '%s%s=%s' % (sep, key, value) return query def post(self, request, query): self.logger.debug('post url=%s query=%s' % (request.url().toString(), query)) if self.sslSupported and self.sslEnabled: request.setSslConfiguration(self.sslConfig) bytearray = QByteArray() bytearray.append(query) reply = self.mgr.post(request, bytearray) if self.sslSupported and self.sslEnabled: self.mgr.sslErrors.connect(self.handleSSLErrors) return reply def handleSSLErrors(self, reply, errors): for err in errors: self.logger.error('SSL errors:' + err.errorString()) def handleAuthenticationRequired(self, reply, authenticator): if self.user == '' and self.password == '': self.logger.warning( 'authentication required and no user/password set') authenticator.setUser(self.user) authenticator.setPassword(self.password) def configureCerts(self): ## import the private client key privateKeyFile = QFile(self.clientKeyFile) privateKeyFile.open(QIODevice.ReadOnly) privateKey = QSslKey(privateKeyFile, QSsl.Rsa) if privateKey.isNull(): self.logger.warning('SSL private key is null') else: self.sslConfig.setPrivateKey(privateKey) ## import the client certificate certFile = QFile(self.clientCertFile) certFile.open(QIODevice.ReadOnly) cert = QSslCertificate(certFile) self.sslConfig.setLocalCertificate(cert) ## import the self-signed CA certificate caCertFile = QFile(self.caCertFile) caCertFile.open(QIODevice.ReadOnly) caCert = QSslCertificate(caCertFile) ## add self-signed CA cert to the other CA certs caCertList = self.sslConfig.caCertificates() caCertList.append(caCert) self.sslConfig.setCaCertificates(caCertList)
class SSLConfig(_SSLConfig): """Qt-based implementation of SSLConfig. This implementation does a few things to help: * Automate QSslConfiguration.set* calls and ensure that they happen up front, which is important when some may have no effect later. * Hide the dance of creating a QSslKey. * Makes it easier to set SSL options, and sets defaults marked in Qt docs as more secure, so that less secure options must be explicitly specified. """ default_options = _SSLConfig.default_options.copy() default_options.update({ # Prevent injection of plaintext into SSL sessions. # This option isn't available for other backends. "legacy renegotiation": False, # Prevents BEAST, but "causes problems with a large number of servers". # Yet it works with BCS, so we should use it when it's available. "empty_fragments": False, }) def __init__( self, protocol=None, key=None, options=None, ): super(SSLConfig, self).__init__( protocol=protocol, key=key, options=options, ) # Set up implementation-specific state... # QSslConfiguration is a bag of data we need to talk to Qt. Its # attributes must be set using its various setWhatever methods. self._q_ssl_config = QSslConfiguration() # Get a protocol constant Qt understands, or cry to the user. q_ssl_protocol = _PROTOCOL_CHOICES.get(self.protocol) if q_ssl_protocol is None: raise InvalidSSLConfig("unknown protocol for Qt: {0!r}".format( self.protocol)) # Hang on to it just in case we possibly need it, e.g. debugger self._q_ssl_protocol = q_ssl_protocol # Otherwise, tell Qt about the protocol. # n.b.: setting this after connection starts has no effect, so we # definitely want to do it here instead of deferring this. self._q_ssl_config.setProtocol(q_ssl_protocol) # If we have an SSLKey, have it make a QSslKey and tell Qt about it. if self.key: q_ssl_key = self.key.to_q_ssl_key() self._q_ssl_config.setPrivateKey(q_ssl_key) else: q_ssl_key = None self._q_ssl_key = q_ssl_key # Process self.options self._set_options() def _set_options(self): """Internal: convert options to set QSSLConfiguration option flags. """ for key, value in self.options.items(): # Get the constant used by PyQt option = _PROTOCOL_OPTIONS.get(key.lower().replace("_", " ")) # Make sure we don't fail silently with unrecognized options if option is None: raise InvalidSSLConfig( "unknown option for Qt: {0!r}".format(key)) # All the Qt options are "Disable*", inverting the bools. self._q_ssl_config.setSslOption(option, not value)