diff --git a/handler.cpp b/handler.cpp index eeded02..c3a2c76 100644 --- a/handler.cpp +++ b/handler.cpp @@ -1,27 +1,69 @@ #include "handler.hpp" +#include +#include +#include -std::string process(const std::string &username){ - try{ - // Check for directory traversal patterns - if (username.find("../") != std::string::npos || - username.find("..\\") != std::string::npos || - username.find("%2e%2e%2f") != std::string::npos || - username.find("%2e%2e%5c") != std::string::npos || - username.find("%2E%2E%2F") != std::string::npos || - username.find("%2E%2E%5C") != std::string::npos || - username.find("..%2f") != std::string::npos || - username.find("..%5c") != std::string::npos || - username.find("..%2F") != std::string::npos || - username.find("..%5C") != std::string::npos) { - throw InvalidInput("Directory traversal detected in username"); - } +const std::filesystem::path kPATH{"/var/finger/users/"}; - if (username.find("/") != std::string::npos){ - throw InvalidInput("Path detected in username"); - } +std::string process(const std::string &username) { + try { + // Check for directory traversal patterns + if (username.find("../") != std::string::npos || + username.find("..\\") != std::string::npos || + username.find("%2e%2e%2f") != std::string::npos || + username.find("%2e%2e%5c") != std::string::npos || + username.find("%2E%2E%2F") != std::string::npos || + username.find("%2E%2E%5C") != std::string::npos || + username.find("..%2f") != std::string::npos || + username.find("..%5c") != std::string::npos || + username.find("..%2F") != std::string::npos || + username.find("..%5C") != std::string::npos) { + throw InvalidInput("Directory traversal detected in username"); } - catch(InvalidInput&e){ - return std::string("InvalidInput: ") + e.what() + std::string("\r\n"); + + if (username.find("/") != std::string::npos) { + throw InvalidInput("Path detected in username"); } + } catch (InvalidInput &e) { + return std::string("InvalidInput: ") + e.what() + std::string("\r\n"); + } + + // Attempt to open the plan file (if any) and return the contents as a string + std::filesystem::path planPath = kPATH / username; + + // Check if the plan file exists + if (!std::filesystem::exists(planPath)) { + // If no plan file exists, return just the username return username; + } + + // Try to read the plan file + try { + std::ifstream planFile(planPath); + if (!planFile.is_open()) { + return username; + } + + std::string content; + std::string line; + while (std::getline(planFile, line)) { + content += line + "\n"; + } + + // Return the plan content with proper line endings + if (!content.empty() && content.back() == '\n') { + content.pop_back(); // Remove the last newline + content += "\r\n"; + return content; + } else if (!content.empty()) { + content += "\r\n"; + return content; + } else { + // If file exists but is empty, return just the username + return username; + } + } catch (...) { + // If there's any error reading the file, just return the username + return username; + } } diff --git a/main.cpp b/main.cpp index 927e217..2f208da 100644 --- a/main.cpp +++ b/main.cpp @@ -22,18 +22,33 @@ namespace this_coro = boost::asio::this_coro; awaitable dofinger(const std::string &username) { co_return process(username); - //co_return std::string("this is some finger information for ") + username + std::string("\r\n"); + // co_return std::string("this is some finger information for ") + username + + // std::string("\r\n"); } awaitable echo(tcp::socket socket) { try { char data[1024]; - co_await socket.async_read_some(boost::asio::buffer(data), deferred); - auto response = co_await dofinger(std::string(data)); + auto bytes_read = + co_await socket.async_read_some(boost::asio::buffer(data), deferred); + // strip \r\n from data + std::string username(data, bytes_read); + // Remove trailing \r\n characters + while (!username.empty() && + (username.back() == '\r' || username.back() == '\n')) { + username.pop_back(); + } + auto response = co_await dofinger(username); + if (response.compare(std::string(username)) == 0) { + // No plan found + co_await async_write( + socket, boost::asio::buffer(std::string("No plan found\r\n")), + deferred); + co_return; + } co_await async_write(socket, boost::asio::buffer(response), deferred); co_return; - } - catch (std::exception &e) { + } catch (std::exception &e) { std::printf("echo Exception: %s\n", e.what()); } } diff --git a/test_handler.cpp b/test_handler.cpp index 8178825..f06b326 100644 --- a/test_handler.cpp +++ b/test_handler.cpp @@ -4,138 +4,138 @@ // Test fixture for process function tests class ProcessTest : public ::testing::Test { protected: - void SetUp() override {} - void TearDown() override {} + void SetUp() override {} + void TearDown() override {} }; // Valid username tests TEST_F(ProcessTest, ValidUsernameSimple) { - std::string result = process("john"); - EXPECT_EQ(result, "john"); + std::string result = process("john"); + EXPECT_EQ(result, "john"); } TEST_F(ProcessTest, ValidUsernameWithNumbers) { - std::string result = process("user123"); - EXPECT_EQ(result, "user123"); + std::string result = process("user123"); + EXPECT_EQ(result, "user123"); } TEST_F(ProcessTest, ValidUsernameWithUnderscore) { - std::string result = process("user_name"); - EXPECT_EQ(result, "user_name"); + std::string result = process("user_name"); + EXPECT_EQ(result, "user_name"); } TEST_F(ProcessTest, ValidUsernameWithHyphen) { - std::string result = process("user-name"); - EXPECT_EQ(result, "user-name"); + std::string result = process("user-name"); + EXPECT_EQ(result, "user-name"); } TEST_F(ProcessTest, ValidUsernameEmptyString) { - std::string result = process(""); - EXPECT_EQ(result, ""); + std::string result = process(""); + EXPECT_EQ(result, ""); } // Directory traversal tests TEST_F(ProcessTest, DirectoryTraversalBasicDotDotSlash) { - std::string result = process("user../file"); - EXPECT_TRUE(result.find("InvalidInput:") == 0); - EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); + std::string result = process("user../file"); + EXPECT_TRUE(result.find("InvalidInput:") == 0); + EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); } TEST_F(ProcessTest, DirectoryTraversalBasicDotDotBackslash) { - std::string result = process("user..\\file"); - EXPECT_TRUE(result.find("InvalidInput:") == 0); - EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); + std::string result = process("user..\\file"); + EXPECT_TRUE(result.find("InvalidInput:") == 0); + EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); } TEST_F(ProcessTest, DirectoryTraversalURLEncodedLowercase2e2e2f) { - std::string result = process("user%2e%2e%2ffile"); - EXPECT_TRUE(result.find("InvalidInput:") == 0); - EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); + std::string result = process("user%2e%2e%2ffile"); + EXPECT_TRUE(result.find("InvalidInput:") == 0); + EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); } TEST_F(ProcessTest, DirectoryTraversalURLEncodedLowercase2e2e5c) { - std::string result = process("user%2e%2e%5cfile"); - EXPECT_TRUE(result.find("InvalidInput:") == 0); - EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); + std::string result = process("user%2e%2e%5cfile"); + EXPECT_TRUE(result.find("InvalidInput:") == 0); + EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); } TEST_F(ProcessTest, DirectoryTraversalURLEncodedUppercase2E2E2F) { - std::string result = process("user%2E%2E%2Ffile"); - EXPECT_TRUE(result.find("InvalidInput:") == 0); - EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); + std::string result = process("user%2E%2E%2Ffile"); + EXPECT_TRUE(result.find("InvalidInput:") == 0); + EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); } TEST_F(ProcessTest, DirectoryTraversalURLEncodedUppercase2E2E5C) { - std::string result = process("user%2E%2E%5Cfile"); - EXPECT_TRUE(result.find("InvalidInput:") == 0); - EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); + std::string result = process("user%2E%2E%5Cfile"); + EXPECT_TRUE(result.find("InvalidInput:") == 0); + EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); } TEST_F(ProcessTest, DirectoryTraversalMixedDotDot2f) { - std::string result = process("user..%2ffile"); - EXPECT_TRUE(result.find("InvalidInput:") == 0); - EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); + std::string result = process("user..%2ffile"); + EXPECT_TRUE(result.find("InvalidInput:") == 0); + EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); } TEST_F(ProcessTest, DirectoryTraversalMixedDotDot5c) { - std::string result = process("user..%5cfile"); - EXPECT_TRUE(result.find("InvalidInput:") == 0); - EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); + std::string result = process("user..%5cfile"); + EXPECT_TRUE(result.find("InvalidInput:") == 0); + EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); } TEST_F(ProcessTest, DirectoryTraversalMixedDotDot2F) { - std::string result = process("user..%2Ffile"); - EXPECT_TRUE(result.find("InvalidInput:") == 0); - EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); + std::string result = process("user..%2Ffile"); + EXPECT_TRUE(result.find("InvalidInput:") == 0); + EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); } TEST_F(ProcessTest, DirectoryTraversalMixedDotDot5C) { - std::string result = process("user..%5Cfile"); - EXPECT_TRUE(result.find("InvalidInput:") == 0); - EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); + std::string result = process("user..%5Cfile"); + EXPECT_TRUE(result.find("InvalidInput:") == 0); + EXPECT_TRUE(result.find("Directory traversal detected") != std::string::npos); } // Path detection tests TEST_F(ProcessTest, PathDetectionForwardSlash) { - std::string result = process("user/name"); - EXPECT_TRUE(result.find("InvalidInput:") == 0); - EXPECT_TRUE(result.find("Path detected") != std::string::npos); + std::string result = process("user/name"); + EXPECT_TRUE(result.find("InvalidInput:") == 0); + EXPECT_TRUE(result.find("Path detected") != std::string::npos); } TEST_F(ProcessTest, PathDetectionForwardSlashAtStart) { - std::string result = process("/username"); - EXPECT_TRUE(result.find("InvalidInput:") == 0); - EXPECT_TRUE(result.find("Path detected") != std::string::npos); + std::string result = process("/username"); + EXPECT_TRUE(result.find("InvalidInput:") == 0); + EXPECT_TRUE(result.find("Path detected") != std::string::npos); } TEST_F(ProcessTest, PathDetectionForwardSlashAtEnd) { - std::string result = process("username/"); - EXPECT_TRUE(result.find("InvalidInput:") == 0); - EXPECT_TRUE(result.find("Path detected") != std::string::npos); + std::string result = process("username/"); + EXPECT_TRUE(result.find("InvalidInput:") == 0); + EXPECT_TRUE(result.find("Path detected") != std::string::npos); } // Edge cases TEST_F(ProcessTest, SingleDot) { - std::string result = process("."); - EXPECT_EQ(result, "."); + std::string result = process("."); + EXPECT_EQ(result, "."); } TEST_F(ProcessTest, DoubleDotWithoutSlash) { - std::string result = process(".."); - EXPECT_EQ(result, ".."); + std::string result = process(".."); + EXPECT_EQ(result, ".."); } TEST_F(ProcessTest, ContainsDotButNotTraversal) { - std::string result = process("user.name"); - EXPECT_EQ(result, "user.name"); + std::string result = process("user.name"); + EXPECT_EQ(result, "user.name"); } TEST_F(ProcessTest, BackslashWithoutDots) { - std::string result = process("user\\name"); - EXPECT_EQ(result, "user\\name"); + std::string result = process("user\\name"); + EXPECT_EQ(result, "user\\name"); } int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); }