Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
kcenon::logger::security::path_validator Class Reference

Validates file paths to prevent security vulnerabilities. More...

#include <path_validator.h>

Collaboration diagram for kcenon::logger::security::path_validator:
Collaboration graph

Public Member Functions

 path_validator (std::filesystem::path allowed_base)
 Construct with allowed base directory.
 
common::VoidResult validate (const std::filesystem::path &path, bool allow_symlinks=false, bool strict_filename=true) const
 Validate a file path.
 
const std::filesystem::path & allowed_base () const
 Get the allowed base directory.
 

Static Public Member Functions

static bool is_safe_filename (const std::string &name)
 Check if a filename is safe (contains only allowed characters)
 
static std::string sanitize_filename (const std::string &name, char replacement='_')
 Sanitize a filename by removing/replacing invalid characters.
 
static result< std::filesystem::path > safe_join (const std::filesystem::path &base, const std::filesystem::path &relative)
 Create a safe path by joining base and relative path.
 

Private Attributes

std::filesystem::path allowed_base_
 

Detailed Description

Validates file paths to prevent security vulnerabilities.

Security features:

  • Path traversal prevention (../ attacks)
  • Symbolic link validation
  • Filename character restrictions
  • Base directory enforcement

Definition at line 30 of file path_validator.h.

Constructor & Destructor Documentation

◆ path_validator()

kcenon::logger::security::path_validator::path_validator ( std::filesystem::path allowed_base)
inlineexplicit

Construct with allowed base directory.

Parameters
allowed_baseAll paths must be within this directory

Definition at line 36 of file path_validator.h.

37 : allowed_base_(std::move(allowed_base)) {
38
39 // Convert to canonical path if it exists
40 try {
41 if (std::filesystem::exists(allowed_base_)) {
42 allowed_base_ = std::filesystem::canonical(allowed_base_);
43 } else {
44 // Use weakly_canonical for non-existent paths
45 allowed_base_ = std::filesystem::weakly_canonical(allowed_base_);
46 }
47 } catch (const std::filesystem::filesystem_error&) {
48 // If canonicalization fails, use as-is
49 // Validation will catch issues later
50 }
51 }
const std::filesystem::path & allowed_base() const
Get the allowed base directory.

References allowed_base_.

Member Function Documentation

◆ allowed_base()

const std::filesystem::path & kcenon::logger::security::path_validator::allowed_base ( ) const
inline

Get the allowed base directory.

Definition at line 122 of file path_validator.h.

122 {
123 return allowed_base_;
124 }

References allowed_base_.

◆ is_safe_filename()

static bool kcenon::logger::security::path_validator::is_safe_filename ( const std::string & name)
inlinestatic

Check if a filename is safe (contains only allowed characters)

Parameters
nameFilename to check
Returns
true if safe, false otherwise

Allowed characters:

  • Alphanumeric (a-z, A-Z, 0-9)
  • Hyphen (-)
  • Underscore (_)
  • Period (.)

Definition at line 137 of file path_validator.h.

137 {
138 // Empty or special names are not allowed
139 if (name.empty() || name == "." || name == "..") {
140 return false;
141 }
142
143 // Check each character
144 for (char c : name) {
145 if (!std::isalnum(static_cast<unsigned char>(c)) &&
146 c != '-' && c != '_' && c != '.') {
147 return false;
148 }
149 }
150
151 return true;
152 }

Referenced by validate().

Here is the caller graph for this function:

◆ safe_join()

static result< std::filesystem::path > kcenon::logger::security::path_validator::safe_join ( const std::filesystem::path & base,
const std::filesystem::path & relative )
inlinestatic

Create a safe path by joining base and relative path.

Parameters
baseBase directory
relativeRelative path to join
Returns
Validated absolute path or error

Definition at line 196 of file path_validator.h.

199 {
200 try {
201 // Ensure relative path doesn't contain absolute components
202 if (relative.is_absolute()) {
203 return result<std::filesystem::path>{
205 "Cannot join with absolute path"};
206 }
207
208 // Join paths
209 auto joined = base / relative;
210
211 // Validate the result
212 path_validator validator(base);
213 auto validation = validator.validate(joined);
214
215 if (validation.is_err()) {
216 return result<std::filesystem::path>{
217 get_logger_error_code(validation),
218 get_logger_error_message(validation)};
219 }
220
221 return result<std::filesystem::path>(joined);
222
223 } catch (const std::filesystem::filesystem_error& e) {
224 return result<std::filesystem::path>{
226 std::string("Path join failed: ") + e.what()};
227 }
228 }
path_validator(std::filesystem::path allowed_base)
Construct with allowed base directory.
std::string get_logger_error_message(const common::VoidResult &result)
Get error message from a VoidResult.
logger_error_code get_logger_error_code(const common::VoidResult &result)

References kcenon::logger::get_logger_error_code(), kcenon::logger::get_logger_error_message(), kcenon::logger::path_traversal_detected, and validate().

Here is the call graph for this function:

◆ sanitize_filename()

static std::string kcenon::logger::security::path_validator::sanitize_filename ( const std::string & name,
char replacement = '_' )
inlinestatic

Sanitize a filename by removing/replacing invalid characters.

Parameters
nameFilename to sanitize
replacementCharacter to use for invalid characters (default: '_')
Returns
Sanitized filename

Definition at line 160 of file path_validator.h.

163 {
164 // Handle special cases
165 if (name.empty()) {
166 return "unnamed";
167 }
168 if (name == ".") {
169 return std::string(1, replacement) + name;
170 }
171 if (name == "..") {
172 return std::string(1, replacement) + '.';
173 }
174
175 std::string result;
176 result.reserve(name.size());
177
178 for (char c : name) {
179 if (std::isalnum(static_cast<unsigned char>(c)) ||
180 c == '-' || c == '_' || c == '.') {
181 result += c;
182 } else {
183 result += replacement;
184 }
185 }
186
187 return result;
188 }

◆ validate()

common::VoidResult kcenon::logger::security::path_validator::validate ( const std::filesystem::path & path,
bool allow_symlinks = false,
bool strict_filename = true ) const
inline

Validate a file path.

Parameters
pathPath to validate
allow_symlinksWhether symbolic links are allowed (default: false)
strict_filenameWhether to enforce strict filename rules (default: true)
Returns
Success or error describing the security issue

Definition at line 60 of file path_validator.h.

64 {
65 try {
66 // 1. Convert to absolute path and resolve relative components
67 std::filesystem::path canonical;
68 if (std::filesystem::exists(path)) {
69 canonical = std::filesystem::canonical(path);
70 } else {
71 canonical = std::filesystem::weakly_canonical(path);
72 }
73
74 // 2. Check for symbolic links (if not allowed)
75 if (!allow_symlinks && std::filesystem::exists(path)) {
76 if (std::filesystem::is_symlink(path)) {
79 "Symbolic links are not allowed for security reasons"
80 );
81 }
82 }
83
84 // 3. Verify path is within allowed base directory
85 auto [base_end, path_end] = std::mismatch(
86 allowed_base_.begin(), allowed_base_.end(),
87 canonical.begin(), canonical.end()
88 );
89
90 if (base_end != allowed_base_.end()) {
93 "Path must be within allowed directory: " + allowed_base_.string()
94 );
95 }
96
97 // 4. Validate filename (if strict mode enabled)
98 if (strict_filename && path.has_filename()) {
99 auto filename = path.filename().string();
100
101 if (!is_safe_filename(filename)) {
104 "Filename contains invalid or potentially dangerous characters"
105 );
106 }
107 }
108
109 return common::ok();
110
111 } catch (const std::filesystem::filesystem_error& e) {
114 std::string("Path validation failed: ") + e.what()
115 );
116 }
117 }
static bool is_safe_filename(const std::string &name)
Check if a filename is safe (contains only allowed characters)
VoidResult ok()
common::VoidResult make_logger_void_result(logger_error_code code, const std::string &message="")

References allowed_base_, kcenon::logger::invalid_filename, is_safe_filename(), kcenon::logger::make_logger_void_result(), kcenon::common::ok(), and kcenon::logger::path_traversal_detected.

Referenced by safe_join().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ allowed_base_

std::filesystem::path kcenon::logger::security::path_validator::allowed_base_
private

Definition at line 231 of file path_validator.h.

Referenced by allowed_base(), path_validator(), and validate().


The documentation for this class was generated from the following file: