feat: add validation rules for CGI extensions, folder existence, and host validation
This commit is contained in:
parent
c74bebd75b
commit
1994de27af
@ -1,12 +1,15 @@
|
|||||||
|
#include "webserv/config/validation/directive_rules/CgiExtValidationRule.hpp"
|
||||||
#include <webserv/config/validation/ConfigValidator.hpp>
|
#include <webserv/config/validation/ConfigValidator.hpp>
|
||||||
|
|
||||||
#include <webserv/config/validation/ValidationEngine.hpp> // for ValidationEngine
|
#include <webserv/config/validation/ValidationEngine.hpp> // for ValidationEngine
|
||||||
#include <webserv/config/validation/directive_rules/AValidationRule.hpp> // for AValidationRule
|
#include <webserv/config/validation/directive_rules/AValidationRule.hpp> // for AValidationRule
|
||||||
#include <webserv/config/validation/directive_rules/AllowedValuesRule.hpp> // for AllowedValuesRule
|
#include <webserv/config/validation/directive_rules/AllowedValuesRule.hpp> // for AllowedValuesRule
|
||||||
|
#include <webserv/config/validation/directive_rules/FolderExistsRule.hpp>
|
||||||
|
#include <webserv/config/validation/directive_rules/HostValidationRule.hpp>
|
||||||
#include <webserv/config/validation/directive_rules/PortValidationRule.hpp> // for PortValidationRule
|
#include <webserv/config/validation/directive_rules/PortValidationRule.hpp> // for PortValidationRule
|
||||||
#include <webserv/config/validation/structural_rules/StructuralRules.hpp> // for structural rules
|
#include <webserv/config/validation/structural_rules/StructuralRules.hpp> // for structural rules
|
||||||
#include <webserv/log/Log.hpp> // for LOCATION, Log
|
#include <webserv/log/Log.hpp> // for LOCATION, Log
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string> // for basic_string, string
|
#include <string> // for basic_string, string
|
||||||
|
|
||||||
ConfigValidator::ConfigValidator(const GlobalConfig *config) : engine_(std::make_unique<ValidationEngine>(config))
|
ConfigValidator::ConfigValidator(const GlobalConfig *config) : engine_(std::make_unique<ValidationEngine>(config))
|
||||||
@ -22,10 +25,14 @@ ConfigValidator::ConfigValidator(const GlobalConfig *config) : engine_(std::make
|
|||||||
|
|
||||||
/*Server Directive Rules*/
|
/*Server Directive Rules*/
|
||||||
engine_->addServerRule("listen", std::make_unique<PortValidationRule>());
|
engine_->addServerRule("listen", std::make_unique<PortValidationRule>());
|
||||||
|
engine_->addServerRule("host", std::make_unique<HostValidationRule>());
|
||||||
|
engine_->addServerRule("root", std::make_unique<FolderExistsRule>(true));
|
||||||
|
|
||||||
/*Location Directive Rules*/
|
/*Location Directive Rules*/
|
||||||
engine_->addLocationRule("allowed_methods",
|
engine_->addLocationRule("allowed_methods",
|
||||||
std::make_unique<AllowedValuesRule>(std::vector<std::string>{"GET", "POST", "DELETE"}));
|
std::make_unique<AllowedValuesRule>(std::vector<std::string>{"GET", "POST", "DELETE"}));
|
||||||
|
engine_->addLocationRule("root", std::make_unique<FolderExistsRule>(true));
|
||||||
|
engine_->addLocationRule("cgi_ext", std::make_unique<CgiExtValidationRule>(true));
|
||||||
|
|
||||||
engine_->validate();
|
engine_->validate();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,52 @@
|
|||||||
|
#include "webserv/config/AConfig.hpp"
|
||||||
|
#include "webserv/config/validation/ValidationResult.hpp"
|
||||||
|
#include "webserv/utils/FileUtils.hpp"
|
||||||
|
|
||||||
|
#include <webserv/config/validation/directive_rules/CgiExtValidationRule.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
CgiExtValidationRule::CgiExtValidationRule(bool requiresValue)
|
||||||
|
: AValidationRule("CgiExt", "Ensure CGI extension is valid", requiresValue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isAllowedCGIExtension(const std::string &extension)
|
||||||
|
{
|
||||||
|
static const std::vector<std::string> allowedExtensions = {".php", ".py"};
|
||||||
|
return std::ranges::any_of(allowedExtensions, [&extension](const auto &it) { return extension == it; });
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidationResult CgiExtValidationRule::validateValue(const AConfig *config, const std::string &directiveName) const
|
||||||
|
{
|
||||||
|
const ADirective *directive = config->getDirective(directiveName);
|
||||||
|
if (!directive->getValue().holds<std::vector<std::string>>())
|
||||||
|
{
|
||||||
|
return ValidationResult::error("Directive '" + directive->getName() + "' does not hold a string value");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cgiExt = directive->getValue().get<std::vector<std::string>>();
|
||||||
|
if (cgiExt.size() != 2)
|
||||||
|
{
|
||||||
|
return ValidationResult::error("Directive '" + directive->getName() +
|
||||||
|
"' has invalid format, expected extension and path");
|
||||||
|
}
|
||||||
|
auto extension = std::string(cgiExt[0]);
|
||||||
|
auto path = std::string(cgiExt[1]);
|
||||||
|
if (extension.empty() || extension[0] != '.')
|
||||||
|
{
|
||||||
|
return ValidationResult::error("Directive '" + directive->getName() + "' has invalid extension '" + extension +
|
||||||
|
"'");
|
||||||
|
}
|
||||||
|
if (!isAllowedCGIExtension(extension))
|
||||||
|
{
|
||||||
|
return ValidationResult::error("Directive '" + directive->getName() + "' has unsupported extension '" +
|
||||||
|
extension + "'");
|
||||||
|
}
|
||||||
|
if (!FileUtils::isFile(path))
|
||||||
|
{
|
||||||
|
return ValidationResult::error("Directive '" + directive->getName() + "' has invalid path '" + path + "'");
|
||||||
|
}
|
||||||
|
return ValidationResult::success();
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "webserv/config/validation/directive_rules/AValidationRule.hpp"
|
||||||
|
#include <webserv/config/validation/ValidationResult.hpp> // for ValidationResult
|
||||||
|
|
||||||
|
class CgiExtValidationRule : public AValidationRule
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CgiExtValidationRule(bool requiresValue);
|
||||||
|
|
||||||
|
ValidationResult validateValue(const AConfig *config, const std::string &directiveName) const override;
|
||||||
|
};
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
#include "webserv/config/directive/ADirective.hpp"
|
||||||
|
#include "webserv/config/validation/ValidationResult.hpp"
|
||||||
|
#include "webserv/log/Log.hpp"
|
||||||
|
#include "webserv/utils/FileUtils.hpp"
|
||||||
|
|
||||||
|
#include <webserv/config/validation/directive_rules/FolderExistsRule.hpp>
|
||||||
|
|
||||||
|
FolderExistsRule::FolderExistsRule(bool requiresValue)
|
||||||
|
: AValidationRule("FolderExists", "Ensures the specified folder exists", requiresValue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidationResult FolderExistsRule::validateValue(const AConfig *config, const std::string &directiveName) const
|
||||||
|
{
|
||||||
|
const ADirective *directive = config->getDirective(directiveName);
|
||||||
|
if (!directive->getValue().holds<std::string>())
|
||||||
|
{
|
||||||
|
return ValidationResult::error("Directive '" + directive->getName() + "' does not hold a string value");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto folderPath = directive->getValue().get<std::string>();
|
||||||
|
Log::debug("Validating folder exists: " + folderPath);
|
||||||
|
if (!FileUtils::isDirectory(folderPath))
|
||||||
|
{
|
||||||
|
return ValidationResult::error(folderPath + " is not a valid directory");
|
||||||
|
}
|
||||||
|
return ValidationResult::success();
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "webserv/config/AConfig.hpp"
|
||||||
|
#include "webserv/config/validation/ValidationResult.hpp"
|
||||||
|
#include "webserv/config/validation/directive_rules/AValidationRule.hpp"
|
||||||
|
|
||||||
|
class FolderExistsRule : public AValidationRule
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FolderExistsRule(bool requiresValue);
|
||||||
|
|
||||||
|
ValidationResult validateValue(const AConfig *config, const std::string &directiveName) const override;
|
||||||
|
};
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
#include "webserv/config/AConfig.hpp"
|
||||||
|
#include "webserv/config/directive/ADirective.hpp"
|
||||||
|
#include "webserv/config/validation/ValidationResult.hpp"
|
||||||
|
#include "webserv/utils/utils.hpp"
|
||||||
|
|
||||||
|
#include <webserv/config/validation/directive_rules/HostValidationRule.hpp>
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
HostValidationRule::HostValidationRule(bool requiresValue)
|
||||||
|
: AValidationRule("HostValidationRule", "Validates that the host is a valid domain name", requiresValue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValidIPv4(const std::string &ip)
|
||||||
|
{
|
||||||
|
std::vector<std::string> parts = utils::split(ip, '.');
|
||||||
|
if (parts.size() != 4)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const std::string &part : parts)
|
||||||
|
{
|
||||||
|
if (part.empty() || part.size() > 3)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (char c : part)
|
||||||
|
{
|
||||||
|
if (std::isdigit(c) < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int num = std::stoi(part);
|
||||||
|
if (num < 0 || num > 255)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (part.size() > 1 && part[0] == '0')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidationResult HostValidationRule::validateValue(const AConfig *config, const std::string &directiveName) const
|
||||||
|
{
|
||||||
|
const ADirective *directive = config->getDirective(directiveName);
|
||||||
|
|
||||||
|
if (!directive->getValue().holds<std::string>())
|
||||||
|
{
|
||||||
|
return ValidationResult::error("Directive '" + directive->getName() + "' does not hold a string value");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto host = directive->getValue().get<std::string>();
|
||||||
|
|
||||||
|
if (!isValidIPv4(host))
|
||||||
|
{
|
||||||
|
return ValidationResult::error("Host '" + host + "' is not a valid IPv4 address");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ValidationResult::success();
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <webserv/config/validation/directive_rules/AValidationRule.hpp> // for AValidationRule
|
||||||
|
|
||||||
|
#include <string> // for string
|
||||||
|
|
||||||
|
class AConfig;
|
||||||
|
|
||||||
|
class HostValidationRule : public AValidationRule
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HostValidationRule(bool requiresValue = true);
|
||||||
|
|
||||||
|
private:
|
||||||
|
[[nodiscard]] ValidationResult validateValue(const AConfig *config,
|
||||||
|
const std::string &directiveName) const override;
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user