def __init__(self, hostControlBackend, hostId, address, username, password, method, params=[], hostPort=0): KillableThread.__init__(self) self.hostControlBackend = hostControlBackend self.hostId = forceHostId(hostId) self.address = forceIpAddress(address) self.username = forceUnicode(username) self.password = forceUnicode(password) self.method = forceUnicode(method) self.params = forceList(params) self.error = None self.result = None self.started = 0 self.ended = 0 if hostPort: self.hostPort = forceInt(hostPort) else: self.hostPort = self.hostControlBackend._opsiclientdPort
def blowfishEncrypt(key, cleartext): """ Takes `cleartext` string, returns hex-encoded, blowfish-encrypted string. :raises BlowfishError: In case things go wrong. :rtype: unicode """ cleartext = forceUnicode(cleartext).encode('utf-8') key = forceUnicode(key) while len(cleartext) % 8 != 0: # Fill up with \0 until length is a mutiple of 8 cleartext += chr(0) try: key = key.decode("hex") except TypeError: raise BlowfishError(u"Failed to hex decode key '%s'" % key) blowfish = Blowfish.new(key, Blowfish.MODE_CBC, BLOWFISH_IV) try: crypt = blowfish.encrypt(cleartext) except Exception as encryptError: logger.logException(encryptError, LOG_DEBUG) raise BlowfishError(u"Failed to encrypt") return unicode(crypt.encode("hex"))
def blowfishDecrypt(key, crypt): """ Takes hex-encoded, blowfish-encrypted string, returns cleartext string. :raises BlowfishError: In case things go wrong. :rtype: unicode """ key = forceUnicode(key) crypt = forceUnicode(crypt) try: key = key.decode("hex") except TypeError as e: raise BlowfishError(u"Failed to hex decode key '%s'" % key) crypt = crypt.decode("hex") blowfish = Blowfish.new(key, Blowfish.MODE_CBC, BLOWFISH_IV) try: cleartext = blowfish.decrypt(crypt) except Exception as decryptError: logger.logException(decryptError, LOG_DEBUG) raise BlowfishError(u"Failed to decrypt") # Remove possible \0-chars if cleartext.find('\0') != -1: cleartext = cleartext[:cleartext.find('\0')] try: return unicode(cleartext, 'utf-8') except Exception as e: logger.error(e) raise BlowfishError(u"Failed to convert decrypted text to unicode.")
def showMessage(self, text, title=_(u'Message'), okLabel=_(u'OK'), width=-1, height=-1, seconds=0): try: text = forceUnicode(text) title = forceUnicode(title) okLabel = forceUnicode(okLabel) width = forceInt(width) height = forceInt(height) seconds = forceInt(seconds) for string in self.confidentialStrings: text = text.replace(string, u'*** confidential ***') if width <= 0: width = self.getScreen().width - 15 if height <= 0: height = len(text.split(u'\n')) + 2 textBox = Textbox(width=width, height=height, text=text.encode(encoding, 'replace'), scroll=1, wrap=1) button = Button(okLabel.encode(encoding, 'replace')) rows = 2 if seconds: rows = 1 gridForm = GridForm(self._screen, title.encode(encoding, 'replace'), 1, rows) gridForm.add(textBox, 0, 0) if seconds: gridForm.draw() self.refresh() time.sleep(seconds) self._screen.popWindow() else: gridForm.add(button, 0, 1) helpLine = _( u"<F12> %s | <Space> select | <Up/Down> scroll text" ) % okLabel self.getScreen().pushHelpLine( forceUnicode(helpLine).encode(encoding, 'replace')) return gridForm.runOnce() except Exception as e: self.exit() logger.logException(e) raise
def getResponse(self): response = {} if self.type == 'rpc': response['tid'] = self.tid response['action'] = self.action response['method'] = self.method if self.exception: response['type'] = 'exception' response['message'] = { 'class': self.exception.__class__.__name__, 'message': forceUnicode(self.exception) } response['where'] = self.traceback else: response['type'] = 'rpc' response['result'] = self.result else: response['id'] = self.tid if self.rpcVersion == '2.0': response['jsonrpc'] = '2.0' if self.exception: if self.rpcVersion == '2.0': try: code = int(getattr(self.exception, 'errno')) except Exception: code = 0 response['error'] = { 'code': code, 'message': forceUnicode(self.exception), 'data': { 'class': self.exception.__class__.__name__ } } else: response['error'] = { 'class': self.exception.__class__.__name__, 'message': forceUnicode(self.exception) } if self.rpcVersion != '2.0': # TODO: das macht keinen Sinn! response['result'] = None else: if self.rpcVersion != '2.0': response['error'] = None response['result'] = self.result return response
def testCircularDependenciesExceptionNamesConflictingProducts( productSequenceAlgorithm): ''' A circular dependency exception should inform the user what \ products are currently conflicting. ''' dependencies, products = getCircularDepedencies() try: productSequenceAlgorithm(products, dependencies) pytest.fail("Should not get here.") except OpsiProductOrderingError as error: assert 'firefox' in forceUnicode(error) assert 'javavm' in forceUnicode(error) assert 'ultravnc' in forceUnicode(error)
def setText(self, text): try: self._text = forceUnicode(text) for string in self._ui.confidentialStrings: self._text = self._text.replace(string, u'*** confidential ***') lines = self._text.split(u"\n") for i in range(len(lines)): pos = lines[i].find(u"\r") if (pos != -1): parts = lines[i].split(u"\r") for j in range(len(parts) - 1, -1, -1): if parts[j]: lines[i] = parts[j] + u"\r" break if (lines > self._textHeight): self._text = u"\n".join(lines[(-1) * self._textHeight:]) try: self._textbox.setText(self._text.encode(encoding, 'replace')) except Exception as e: logger.logException(e) self.show() except Exception as e: self._ui.exit() logger.logException(e) raise
def non_blocking_connect_http(self, connectTimeout=0): ''' Non blocking connect, needed for KillableThread ''' sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(3.0) started = time.time() lastError = None while True: try: if connectTimeout > 0 and ( (time.time() - started) >= connectTimeout): raise OpsiTimeoutError( u"Timed out after {0:d} seconds (last error: {1})".format( connectTimeout, forceUnicode(lastError))) sock.connect((self.host, self.port)) break except socket.error as error: logger.logException(error, LOG_DEBUG) logger.debug(error) if error[0] in (106, 10056): # Transport endpoint is already connected break if error[0] not in (114, ) or not lastError: lastError = error time.sleep(0.5) sock.settimeout(None) self.sock = sock
def urlsplit(url): url = forceUnicode(url) scheme = None baseurl = u'/' port = None username = None password = None if url.find('://') != -1: (scheme, url) = url.split('://', 1) scheme = scheme.lower() parts = url.split('/', 1) host = parts[0] if len(parts) > 1: baseurl += parts[1] if '@' in host: username, host = host.split('@', 1) if ':' in username: username, password = username.split(':', 1) if ':' in host: host, port = host.split(':', 1) port = int(port) return (scheme, host, port, baseurl, username, password)
def sendCommand(self, cmd): with createUnixSocket(self.port, timeout=self.timeout) as unixSocket: unixSocket.send(forceUnicode(cmd).encode('utf-8')) result = '' try: for part in iter(lambda: unixSocket.recv(4096), ''): logger.debug2("Received {!r}", part) result += forceUnicode(part) except Exception as error: raise RuntimeError(u"Failed to receive: %s" % error) if result.startswith(ERROR_MARKER): raise RuntimeError(u"Command '%s' failed: %s" % (cmd, result)) return result
def addText(self, text): try: self.setText(self._text + forceUnicode(text)) except Exception as e: self._ui.exit() logger.logException(e) raise
def createMessageBox(self, width=-1, height=-1, title=_(u'Text'), text=u''): width = forceInt(width) height = forceInt(height) title = forceUnicode(title) text = forceUnicode(text) self.messageBox = SnackMessageBox(ui=self, width=width, height=height, title=title, text=text) return self.messageBox
def ask(question=WARNING_DIFF): """ Ask for a yes or no. Returns ``True`` if the answer is ``Yes``, false otherwise. """ fd = sys.stdin.fileno() oldterm = termios.tcgetattr(fd) newattr = termios.tcgetattr(fd) newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO termios.tcsetattr(fd, termios.TCSANOW, newattr) oldflags = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK) self.stdout.write(question) try: while True: try: firstCharacter = sys.stdin.read(1) return forceUnicode(firstCharacter) in (u"y", u"Y") except IOError: pass finally: termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm) fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
def librsyncPatchFile(oldfile, deltafile, newfile): logger.debug( u"Librsync patch: old file {!r}, delta file {!r}, new file {!r}", oldfile, deltafile, newfile) oldfile = forceFilename(oldfile) newfile = forceFilename(newfile) deltafile = forceFilename(deltafile) if oldfile == newfile: raise ValueError(u"Oldfile and newfile are the same file") if deltafile == newfile: raise ValueError(u"deltafile and newfile are the same file") if deltafile == oldfile: raise ValueError(u"oldfile and deltafile are the same file") bufsize = 1024 * 1024 try: with open(oldfile, "rb") as of: with open(deltafile, "rb") as df: with open(newfile, "wb") as nf: with closing(librsync.PatchedFile(of, df)) as pf: data = True while data: data = pf.read(bufsize) nf.write(data) except Exception as patchError: logger.debug("Patching {!r} with delta {!r} into {!r} failed: {}", oldfile, deltafile, newfile, patchError) raise RuntimeError(u"Failed to patch file %s: %s" % (oldfile, forceUnicode(patchError)))
def hostControl_fireEvent(self, event, hostIds=[]): event = forceUnicode(event) hostIds = self._context.host_getIdents(id=hostIds, returnType='unicode') # pylint: disable=maybe-no-member return self._opsiclientdRpc(hostIds=hostIds, method='fireEvent', params=[event])
def hostControl_showPopup(self, message, hostIds=[]): message = forceUnicode(message) hostIds = self._context.host_getIdents(id=hostIds, returnType='unicode') # pylint: disable=maybe-no-member return self._opsiclientdRpc(hostIds=hostIds, method='showPopup', params=[message])
def addConfidentialString(self, string): string = forceUnicode(string) if not string: raise ValueError(u"Cannot use empty string as confidential string") if string in self.confidentialStrings: return self.confidentialStrings.append(string)
def randomString(length, characters=_ACCEPTED_CHARACTERS): """ Generates a random string for a given length. :param characters: The characters to choose from. This defaults to 0-9a-Z. """ return forceUnicode(u''.join( random.choice(characters) for _ in range(length)))
def __unicode__(self): if self._message: if self.problematicRequirements: return u"{0}: {1} ({2})".format(self.ExceptionShortDescription, self._message, self.problematicRequirements) else: return u"{0}: {1}".format(self.ExceptionShortDescription, self._message) else: return forceUnicode(self.ExceptionShortDescription)
def __init__(self, ui, width=0, height=0, total=100, title=_(u'Title'), text=u''): ProgressObserver.__init__(self) self._ui = ui width = forceInt(width) height = forceInt(height) total = forceInt(total) title = forceUnicode(title) text = forceUnicode(text) if (width <= 0): width = self._ui.getScreen().width - 7 if (height <= 0): height = self._ui.getScreen().height - 7 SnackMessageBox.__init__(self, ui, width, height - 4, title, text) self._overallTotal = total self._overallState = -1 self._overallFactor = 1 self._overallProgressSubject = None self._currentTotal = 100 self._currentState = -1 self._currentFactor = 1 self._currentProgressSubject = None self._width = width self._height = height self._gridForm = GridForm(self._ui.getScreen(), title.encode(encoding, 'replace'), 1, 3) self._currentScale = Scale(self._width, self._currentTotal) self._overallScale = Scale(self._width, self._overallTotal) self._gridForm.add(self._textbox, 0, 0) self._gridForm.add(self._currentScale, 0, 1) self._gridForm.add(self._overallScale, 0, 2) self._ui.getScreen().pushHelpLine("")
def hostControlSafe_fireEvent(self, event, hostIds=[]): if not hostIds: raise BackendMissingDataError(u"No matching host ids found") event = forceUnicode(event) hostIds = self._context.host_getIdents(id=hostIds, returnType='unicode') # pylint: disable=maybe-no-member return self._opsiclientdRpc(hostIds=hostIds, method='fireEvent', params=[event])
def __init__(self, smtphost=u'localhost', smtpport=25, subject=u'opsi product updater', sender=u'', receivers=[]): super(EmailNotifier, self).__init__() self.receivers = forceUnicodeList(receivers) if not self.receivers: raise ValueError(u"List of mail recipients empty") self.smtphost = forceUnicode(smtphost) self.smtpport = forceInt(smtpport) self.sender = forceUnicode(sender) self.subject = forceUnicode(subject) self.username = None self.password = None self.useStarttls = False
def hostControlSafe_showPopup(self, message, hostIds=[]): if not hostIds: raise BackendMissingDataError(u"No matching host ids found") message = forceUnicode(message) hostIds = self._context.host_getIdents(id=hostIds, returnType='unicode') # pylint: disable=maybe-no-member return self._opsiclientdRpc(hostIds=hostIds, method='showPopup', params=[message])
def addEvent(self, title, description='', isError=False, category=None, durationEvent=False, start=None, end=None): # pylint: disable=too-many-arguments if self._stopped: return -1 with self._db_lock, self._sql.session() as session: try: if category: category = forceUnicode(category) if not start: start = timestamp() start = forceOpsiTimestamp(start) if end: end = forceOpsiTimestamp(end) durationEvent = True event = { 'title': forceUnicode(title), 'category': category, 'description': forceUnicode(description), 'isError': forceBool(isError), 'durationEvent': forceBool(durationEvent), 'start': start, 'end': end, } try: return self._sql.insert(session, 'EVENT', event) except sqlite3.DatabaseError as db_error: logger.error( "Failed to add event '%s': %s, recreating database", title, db_error) self._sql.delete_db() self._createDatabase(delete_existing=True) return self._sql.insert(session, 'EVENT', event) except Exception as add_error: # pylint: disable=broad-except logger.error("Failed to add event '%s': %s", title, add_error) return -1
def __init__(self, sessionName=u'OPSISID', sessionMaxInactiveInterval=120, maxSessionsPerIp=0, sessionDeletionTimeout=60): self.sessionName = forceUnicode(sessionName) self.sessionMaxInactiveInterval = forceInt(sessionMaxInactiveInterval) self.maxSessionsPerIp = forceInt(maxSessionsPerIp) self.sessionDeletionTimeout = forceInt(sessionDeletionTimeout) self.sessions = {}
def run(self): self.started = time.time() timeout = self.hostControlBackend._hostRpcTimeout if timeout < 0: timeout = 0 try: query = toJson({ 'id': 1, 'method': self.method, 'params': self.params }).encode('utf-8') connection = HTTPSConnection(host=self.address, port=self.hostPort, timeout=timeout) with closingConnection(connection) as connection: non_blocking_connect_https(connection, timeout) connection.putrequest('POST', '/opsiclientd') connection.putheader('User-Agent', self._USER_AGENT) connection.putheader('content-type', 'application/json') connection.putheader('content-length', str(len(query))) auth = u'{0}:{1}'.format(self.username, self.password) connection.putheader( 'Authorization', 'Basic ' + base64.b64encode(auth.encode('latin-1'))) connection.endheaders() connection.send(query) response = connection.getresponse() response = response.read() response = fromJson(unicode(response, 'utf-8')) if response and isinstance(response, dict): self.error = response.get('error') self.result = response.get('result') else: self.error = u"Bad response from client: %s" % forceUnicode( response) except Exception as e: self.error = forceUnicode(e) finally: self.ended = time.time()
def productOnClient_deleteObjects(self, productOnClients): errors = [] for productOnClient in productOnClients: try: self._updateByProductOnClient(productOnClient) except Exception as error: errors.append(forceUnicode(error)) if errors: raise RuntimeError(u', '.join(errors))
def _parseConfig(filename): config = {} with codecs.open(filename, mode='r', encoding='utf-8') as opsircfile: for line in opsircfile: line = line.strip() if line.startswith(('#', ';')) or not line: continue try: key, value = line.split('=', 1) except ValueError: logger.debug2(u"Unable to split line {!r}".format(line)) continue key = key.strip() value = value.strip() if not value: logger.warning( "There is no value for {} in opsirc file {!r}, skipping.", key, filename) continue if key == 'address': config[key] = forceUrl(value) elif key == 'username': config[key] = forceUnicode(value) elif key == 'password': value = forceUnicode(value) logger.addConfidentialString(value) config[key] = value elif key == 'password file': passwordFilePath = os.path.expanduser(value) value = _readPasswordFile(passwordFilePath) logger.addConfidentialString(value) config['password'] = value else: logger.debug(u"Ignoring unknown key {}", key) logger.debug("Found the following usable keys in {!r}: {}", filename, ", ".join(config.keys())) return config
def __init__(self, ui, width=0, height=0, title=_(u'Title'), text=u''): MessageObserver.__init__(self) try: self._ui = ui width = forceInt(width) height = forceInt(height) title = forceUnicode(title) text = forceUnicode(text) self._visible = False self._title = title self._text = text for string in self._ui.confidentialStrings: self._text = self._text.replace(string, u'*** confidential ***') if (width <= 0): width = self._ui.getScreen().width - 7 if (height <= 0): height = self._ui.getScreen().height - 7 self._width = width self._height = self._textHeight = height self._gridForm = GridForm(self._ui.getScreen(), title.encode(encoding, 'replace'), 1, 1) self._textbox = Textbox(self._width, self._height, self._text.encode(encoding, 'replace'), scroll=0, wrap=1) self._gridForm.add(self._textbox, 0, 0) # help line self._ui.getScreen().pushHelpLine(u"") except Exception as e: self._ui.exit() logger.logException(e) raise
def replaceSpecialHTMLCharacters(text): return forceUnicode(text)\ .replace(u'\r', u'')\ .replace(u'\t', u' ')\ .replace(u'&', u'&')\ .replace(u'"', u'"')\ .replace(u"'", u''')\ .replace(u' ', u' ')\ .replace(u'<', u'<')\ .replace(u'>', u'>')\ .replace(u'\n', u'<br />\n')
def __init__(self, **kwargs): self._address = u'localhost' self._username = u'opsi' self._password = u'opsi' self._database = u'opsi' self._databaseCharset = 'utf8' self._connectionPoolSize = 20 self._connectionPoolMaxOverflow = 10 self._connectionPoolTimeout = 30 # Parse arguments for (option, value) in kwargs.items(): option = option.lower() if option == 'address': self._address = forceUnicode(value) elif option == 'username': self._username = forceUnicode(value) elif option == 'password': self._password = forceUnicode(value) elif option == 'database': self._database = forceUnicode(value) elif option == 'databasecharset': self._databaseCharset = str(value) elif option == 'connectionpoolsize': self._connectionPoolSize = forceInt(value) elif option == 'connectionpoolmaxoverflow': self._connectionPoolMaxOverflow = forceInt(value) elif option == 'connectionpooltimeout': self._connectionPoolTimeout = forceInt(value) self._transactionLock = threading.Lock() self._pool = None self._createConnectionPool() logger.debug(u'PgSQL created: %s' % self)
def execute(self, query, conn=None, cursor=None): query = query.replace(' GROUP ',' "GROUP" ') res = None needClose = False if not conn or not cursor: (conn, cursor) = self.connect() needClose = True try: query = forceUnicode(query) logger.debug2(u"SQL query: %s" % query) res = cursor.execute(query) if self.doCommit: conn.commit() finally: if needClose: self.close(conn, cursor) return res