#include "ConnectionConfig.h" #include "util.h" #include #include #include #include namespace { struct { SslMode mode; const char* string; } SslModeStringTable[] = { { SslMode::disable, "disable" }, { SslMode::allow, "allow" }, { SslMode::prefer, "prefer" }, { SslMode::require, "require" }, { SslMode::verify_ca, "verify-ca" }, { SslMode::verify_full, "verify-full" } }; inline const char *valuePtr(const std::string &v) { return v.empty() ? nullptr : v.c_str(); } } // end unnamed namespace QString SslModeToString(SslMode sm) { for (auto e : SslModeStringTable) if (e.mode == sm) return QString::fromUtf8(e.string); return {}; } SslMode StringToSslMode(QString s) { SslMode result = SslMode::allow; for (auto e : SslModeStringTable) if (e.string == s) result = e.mode; return {}; } ConnectionConfig::ConnectionConfig() : m_applicationName(QCoreApplication::applicationName().toUtf8().data()) {} const ConnectionGroup *ConnectionConfig::parent() const { return m_group; } void ConnectionConfig::setParent(ConnectionGroup *grp) { m_group = grp; } void ConnectionConfig::setUuid(const QUuid &uuid) { if (uuid != m_uuid) { m_dirty = true; m_uuid = uuid; } } const QUuid &ConnectionConfig::uuid() const { return m_uuid; } void ConnectionConfig::setName(const QString& desc) { if (m_name != desc) { m_dirty = true; m_name = std::move(desc); } } const QString& ConnectionConfig::name() const { return m_name; } void ConnectionConfig::setHost(const QString& host) { if (m_host != host) { m_dirty = true; m_host = std::move(host); } } const QString& ConnectionConfig::host() const { return m_host; } void ConnectionConfig::setHostAddr(const QString &v) { if (m_hostaddr != v) { m_dirty = true; m_hostaddr = std::move(v); } } const QString& ConnectionConfig::hostAddr() const { return m_hostaddr; } void ConnectionConfig::setPort(unsigned short port) { if (m_port != port) { m_dirty = true; m_port = port; } } unsigned short ConnectionConfig::port() const { return m_port; } void ConnectionConfig::setUser(const QString& v) { if (m_user != v) { m_dirty = true; m_user = v; } } const QString& ConnectionConfig::user() const { return m_user; } void ConnectionConfig::setPassword(const QString& v) { if (m_password != v) { m_dirty = true; m_password = v; } } const QString& ConnectionConfig::password() const { return m_password; } void ConnectionConfig::setDbname(const QString& v) { if (m_dbname != v) { m_dirty = true; m_dbname = v; } } const QString& ConnectionConfig::dbname() const { return m_dbname; } void ConnectionConfig::setSslMode(SslMode m) { if (m_sslMode != m) { m_dirty = true; m_sslMode = m; } } SslMode ConnectionConfig::sslMode() const { return m_sslMode; } void ConnectionConfig::setSslCert(const QString& v) { if (m_sslCert != v) { m_dirty = true; m_sslCert = std::move(v); } } const QString& ConnectionConfig::sslCert() const { return m_sslCert; } void ConnectionConfig::setSslKey(const QString& v) { if (m_sslKey != v) { m_dirty = true; m_sslKey = std::move(v); } } const QString& ConnectionConfig::sslKey() const { return m_sslKey; } void ConnectionConfig::setSslRootCert(const QString& v) { if (m_sslRootCert != v) { m_dirty = true; m_sslRootCert = std::move(v); } } const QString& ConnectionConfig::sslRootCert() const { return m_sslRootCert; } void ConnectionConfig::setSslCrl(const QString& v) { if (m_sslCrl != v) { m_dirty = true; m_sslCrl = std::move(v); } } const QString& ConnectionConfig::sslCrl() const { return m_sslCrl; } bool ConnectionConfig::isSameDatabase(const ConnectionConfig &rhs) const { return m_host == rhs.m_host && m_hostaddr == rhs.m_hostaddr && m_port == rhs.m_port && m_user == rhs.m_user && m_password == rhs.m_password && m_dbname == rhs.m_dbname; } bool ConnectionConfig::dirty() const { return m_dirty; } void ConnectionConfig::clean() { m_dirty = false; } QString ConnectionConfig::makeLongDescription() const { QString result; result = name() % " (" % user() % "@" % host() % ":" % QString::number(port()) % "/" % dbname() % ")"; return result; } const QByteArray& ConnectionConfig::encodedPassword() const { return m_encodedPassword; } void ConnectionConfig::setEncodedPassword(const QByteArray &encodedPassword) { m_dirty = true; m_encodedPassword = encodedPassword; } QString ConnectionConfig::escapeConnectionStringValue(const QString &value) { bool contains_spaces = false; int escapes = 0; for (auto&& c : value) if (c == ' ') contains_spaces = true; else if (c == '\'' || c == '\\') ++escapes; if (contains_spaces || escapes > 0 || value.length() == 0) { QString result; result.reserve(2 + value.length() + escapes); result += '\''; for (auto&& c : value) { if (c == '\'' || c == '\\') result += '\\'; result += c; } result += '\''; return result; } else return value; } QString ConnectionConfig::connectionString() const { QString s; s += "host=" % escapeConnectionStringValue(m_host) % " port=" % QString::number(m_port) % " user=" % escapeConnectionStringValue(m_user); s += " password="; s += escapeConnectionStringValue(m_password); s += " dbname="; s += escapeConnectionStringValue(m_dbname); s += " sslmode="; s += SslModeToString(m_sslMode); if (!m_sslCert.isEmpty()) { s += " sslcert="; s += escapeConnectionStringValue(m_sslCert); } if (!m_sslKey.isEmpty()) { s += " sslkey="; s += escapeConnectionStringValue(m_sslKey); } if (!m_sslRootCert.isEmpty()) { s += " sslrootcrt="; s += escapeConnectionStringValue(m_sslRootCert); } if (!m_sslCrl.isEmpty()) { s += " sslCrl="; s += escapeConnectionStringValue(m_sslCrl); } s += " client_encoding=utf8"; s += " application_name="; s += escapeConnectionStringValue(m_applicationName); return s; } void ConnectionConfig::writeToEnvironment(QProcessEnvironment &env) const { strToEnv(env, "PGHOST", m_host); strToEnv(env, "PGHOSTADDR", m_hostaddr); strToEnv(env, "PGPORT", QString::number(m_port)); strToEnv(env, "PGDATABASE", m_dbname); strToEnv(env, "PGUSER", m_user); strToEnv(env, "PGPASSWORD", m_password); strToEnv(env, "PGSSLMODE", SslModeToString(m_sslMode)); strToEnv(env, "PGSSLCERT", m_sslCert); strToEnv(env, "PGSSLKEY", m_sslKey); strToEnv(env, "PGSSLROOTCERT", m_sslRootCert); strToEnv(env, "PGSSLCRL", m_sslCrl); strToEnv(env, "PGSSLCOMPRESSION", "0"); strToEnv(env, "PGCONNECT_TIMEOUT", "10"); env.insert("PGCLIENTENCODING", "utf8"); env.remove("PGREQUIRESSL"); } void ConnectionConfig::strToEnv(QProcessEnvironment &env, const QString &var, const QString &val) { if (val.isEmpty()) env.remove(var); else env.insert(var, val); } void ConnectionGroup::erase(int idx, int count) { m_connections.remove(idx, count); } int ConnectionGroup::add(std::shared_ptr cc) { cc->setParent(this); m_connections.push_back(cc); return m_connections.size() - 1; } void ConnectionGroup::update(int idx, const ConnectionConfig &cc) { auto node = m_connections[idx]; *node = cc; node->setParent(this); }