#include "collection_permissions.hpp" #include "logging/logger.hpp" namespace smartbotic::runner { // System collections that are always protected - no workflow access allowed const std::unordered_set CollectionPermissions::SYSTEM_COLLECTIONS = { "users", "sessions", "api_keys", "credentials", "collection_permissions" }; std::string collectionAccessToString(CollectionAccess access) { switch (access) { case CollectionAccess::None: return "none"; case CollectionAccess::ReadOnly: return "read-only"; case CollectionAccess::ReadWrite: return "read-write"; default: return "none"; } } CollectionAccess collectionAccessFromString(const std::string& str) { if (str == "read-only") return CollectionAccess::ReadOnly; if (str == "read-write") return CollectionAccess::ReadWrite; return CollectionAccess::None; } CollectionPermissions::CollectionPermissions(storage::StorageClient& storage) : storage_(storage) { } void CollectionPermissions::loadPermissions() { std::lock_guard lock(mutex_); permissions_.clear(); // Set default permissions for known collections // These can be overridden by database settings permissions_["workflows"] = CollectionAccess::ReadWrite; permissions_["workflow_groups"] = CollectionAccess::ReadWrite; permissions_["executions"] = CollectionAccess::ReadOnly; permissions_["runners"] = CollectionAccess::ReadOnly; permissions_["nodes"] = CollectionAccess::ReadOnly; // Load permissions from database auto result = storage_.get("collection_permissions", "settings"); if (result.ok()) { const auto& data = result.value(); // Load default access if (data.contains("defaultAccess")) { default_access_ = collectionAccessFromString(data["defaultAccess"].get()); } // Load per-collection permissions if (data.contains("permissions") && data["permissions"].is_object()) { for (auto& [collection, config] : data["permissions"].items()) { if (config.is_object() && config.contains("access")) { auto access = collectionAccessFromString(config["access"].get()); permissions_[collection] = access; } } } LOG_INFO("Loaded collection permissions for {} collections", permissions_.size()); } else { LOG_INFO("No collection permissions found in database, using defaults"); } } bool CollectionPermissions::canRead(const std::string& collection) const { // System collections are never accessible if (isSystemCollection(collection)) { return false; } std::lock_guard lock(mutex_); auto it = permissions_.find(collection); if (it != permissions_.end()) { return it->second == CollectionAccess::ReadOnly || it->second == CollectionAccess::ReadWrite; } // Use default access for unlisted collections return default_access_ == CollectionAccess::ReadOnly || default_access_ == CollectionAccess::ReadWrite; } bool CollectionPermissions::canWrite(const std::string& collection) const { // System collections are never accessible if (isSystemCollection(collection)) { return false; } std::lock_guard lock(mutex_); auto it = permissions_.find(collection); if (it != permissions_.end()) { return it->second == CollectionAccess::ReadWrite; } // Use default access for unlisted collections return default_access_ == CollectionAccess::ReadWrite; } CollectionAccess CollectionPermissions::getAccess(const std::string& collection) const { // System collections are never accessible if (isSystemCollection(collection)) { return CollectionAccess::None; } std::lock_guard lock(mutex_); auto it = permissions_.find(collection); if (it != permissions_.end()) { return it->second; } return default_access_; } bool CollectionPermissions::isSystemCollection(const std::string& collection) const { return SYSTEM_COLLECTIONS.contains(collection); } std::unordered_map CollectionPermissions::getPermissions() const { std::lock_guard lock(mutex_); return permissions_; } CollectionAccess CollectionPermissions::getDefaultAccess() const { std::lock_guard lock(mutex_); return default_access_; } void CollectionPermissions::setPermission(const std::string& collection, CollectionAccess access) { std::lock_guard lock(mutex_); permissions_[collection] = access; } void CollectionPermissions::setDefaultAccess(CollectionAccess access) { std::lock_guard lock(mutex_); default_access_ = access; } } // namespace smartbotic::runner