#include "PgAcl.h" #include namespace { QString privilegeLetterToKeyword(char c) { switch (c) { case 'r': return "SELECT"; case 'w': return "UPDATE"; case 'a': return "INSERT"; case 'd': return "DELETE"; case 'D': return "TRUNCATE"; case 'x': return "REFERENCES"; case 't': return "TRIGGER"; case 'X': return "EXECUTE"; case 'U': return "USAGE"; case 'C': return "CREATE"; case 'c': return "CONNECT"; case 'T': return "TEMPORARY"; } throw std::runtime_error("Unexpected value for c in privilegeLetterToKeyword"); } } char privilegeToChar(Privilege p) { switch (p) { case Privilege::Select: return 'r'; case Privilege::Update: return 'w'; case Privilege::Insert: return 'a'; case Privilege::Delete: return 'd'; case Privilege::Truncate: return 'D'; case Privilege::References: return 'x'; case Privilege::Trigger: return 't'; case Privilege::Execute: return 'X'; case Privilege::Usage: return 'U'; case Privilege::Create: return 'C'; case Privilege::Connect: return 'c'; case Privilege::Temporary: return 'T'; } throw std::runtime_error("Unexpected value for privilege in privilegeToChar"); } PgAcl::PgAcl(const QString &acl) { setFromString(acl); } void PgAcl::setFromString(const QString &acl) { m_grantee = acl.section('=', 0, 0); auto t = acl.section('=', 1); m_privileges = t.section('/', 0, 0); m_grantor = t.section('/', 1); } PrivValue PgAcl::privilege(Privilege priv) const { char c = privilegeToChar(priv); return privilege(c); } PrivValue PgAcl::privilege(char c) const { int pos = m_privileges.indexOf(c); if (pos >= 0) { if ( (pos+1) < m_privileges.length() && m_privileges[pos+1] == '*') return PrivValue::YesWithGrant; return PrivValue::Yes; } return PrivValue::No; } QString PgAcl::singleString() const { return m_grantee % "=" % m_privileges % "/" % m_grantor; } //void operator<<(AclList &s, const Pgsql::Value &v) void operator<<(PgAcl &acl, const Pgsql::Value &v) { acl.setFromString(v); } namespace Pgsql { template <> PgAcl StringToArrayElem(std::string_view sv) { return PgAcl(QString::fromUtf8(sv.data(), static_cast(sv.length()))); } } namespace { void appendColumn(QString &rights, const QString &column) { if (!column.isEmpty()) { rights += "(" % column % ")"; } } QString privilegeGrant(const QString &all_pattern, const QString &acl, const QString &grantOnObject, QString user, const QString &column) { QString rights; if (user.isEmpty()) user = "PUBLIC"; if (all_pattern.length() > 1 && acl == all_pattern) { rights = "ALL"; appendColumn(rights, column); } else { for (auto c : acl) { if (!rights.isEmpty()) rights += ", "; rights += privilegeLetterToKeyword(c.toLatin1()); appendColumn(rights, column); } } QString grant; if (rights.isEmpty()) { grant += "REVOKE ALL"; appendColumn(grant, column); } else grant += "GRANT " + rights; grant += " ON " + grantOnObject; if (rights.isEmpty()) grant += " FROM "; else grant += " TO "; grant += user; return grant; } } QString PgAcl::sql(const QString &all_pattern, const QString &grant_on_object, const QString &column) const { QString acl, acl_with_grant; // Doorloop acl en scheid de rechten met GRANT optie van die zonder for (auto c : all_pattern) { switch(privilege(c.toLatin1())) { case PrivValue::No: break; case PrivValue::Yes: acl += c; break; case PrivValue::YesWithGrant: acl_with_grant += c; break; } } QString sql; // Call when acl is not empty or both are empty // needs to be calledwhen both are empty to generate REVOKE if (!acl.isEmpty() || acl_with_grant.isEmpty()) { sql += privilegeGrant(all_pattern, acl, grant_on_object, m_grantee, column) + ";\n"; } if (!acl_with_grant.isEmpty()) { sql += privilegeGrant(all_pattern, acl_with_grant, grant_on_object, m_grantee, column) + " WITH GRANT OPTION;\n"; } return sql; } bool PgAcl::empty() const { return m_privileges.isEmpty(); }