Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 91 additions & 1 deletion auth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,97 @@ namespace auth
namespace core
{

// TODO: добавьте определения классов/функций
AuthManager::AuthManager() = default;

void AuthManager::AddAdmin(std::string username, std::string password)
{
users_.emplace(std::move(username), User{std::move(password), true});
}

std::optional<uint64_t> AuthManager::Login(const std::string& username, const std::string& password)
{
const auto it = users_.find(username);
if (it == users_.end() ||
it->second.password != password)
return std::nullopt;

const uint64_t id = AcquireSessionId();

sessions_[id] = username;
return id;
}

bool AuthManager::Logout(uint64_t sessionId)
{
const auto erased = sessions_.erase(sessionId);
if (erased == 0) return false;

ReleaseSessionId(sessionId);
return true;
}

bool AuthManager::AddUser(uint64_t sessionId, const std::string& username, const std::string& password)
{
if (!SessionIsAdmin(sessionId) || users_.count(username) != 0) return false;

users_.emplace(username, User{password, false});
return true;
}

bool AuthManager::DelUser(uint64_t sessionId, const std::string& username)
{
if (!SessionIsAdmin(sessionId)) return false;

const auto erased = users_.erase(username);
if (erased == 0) return false;

for (auto it = sessions_.begin(); it != sessions_.end(); )
{
if (it->second == username)
{
ReleaseSessionId(it->first);
it = sessions_.erase(it);
}
else
{
++it;
}
}

return true;
}

bool AuthManager::SessionExists(uint64_t sessionId)
{
return sessions_.count(sessionId) != 0;
}

bool AuthManager::SessionIsAdmin(uint64_t sessionId)
{
auto sit = sessions_.find(sessionId);
if (sit == sessions_.end()) return false;

auto uit = users_.find(sit->second);
if (uit == users_.end()) return false;

return uit->second.isAdmin;
}

uint64_t AuthManager::AcquireSessionId()
{
if (!freeSessions_.empty())
{
const uint64_t id = freeSessions_.top();
freeSessions_.pop();
return id;
}

return nextSessionId_++;
}

void AuthManager::ReleaseSessionId(uint64_t id)
{
freeSessions_.push(id);
}
} // namespace core
} // namespace auth
37 changes: 36 additions & 1 deletion auth.hpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,46 @@
#pragma once
#include <cstdint>
#include <string>
#include <unordered_map>
#include <optional>
#include <stack>

namespace auth
{
namespace core
{
struct User
{
std::string password;
bool isAdmin = false;
};

// TODO: добавьте объявления классов/функций
class AuthManager
{
public:
AuthManager();

void AddAdmin(std::string username, std::string password);

std::optional<uint64_t> Login(const std::string& username, const std::string& password);

bool Logout(uint64_t sessionId);

bool AddUser(uint64_t sessionId, const std::string& username, const std::string& password);

bool DelUser(uint64_t sessionId, const std::string& username);

bool SessionExists(uint64_t sessionId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

У многих параметров не хватает константности

bool SessionIsAdmin(uint64_t sessionId);
private:
uint64_t AcquireSessionId();
void ReleaseSessionId(uint64_t id);

std::unordered_map<std::string, User> users_;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Так немного нарушается простота воспроиятия данных. У вас есть структура User, но имени в ней нет. Как можно было бы пользоваться ассоциативным контейнером с поиском по имени и хранить все данные пользователя в одной структуре?

std::unordered_map<uint64_t, std::string> sessions_;

std::stack<uint64_t> freeSessions_;
uint64_t nextSessionId_ = 1;
};
} // namespace core
} // namespace auth
44 changes: 34 additions & 10 deletions server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@
#include "udp_session.hpp"
#include "udp_socket.hpp"
#include "command.hpp"
#include "auth.hpp"

namespace auth
{
namespace server
{

static auth::core::AuthManager authManager;


namespace
{

Expand Down Expand Up @@ -50,23 +54,43 @@ std::string process_command(std::string_view income)
const auto vargs = command.GetArgs();
if (std::holds_alternative<args::Login>(vargs))
{
// TODO: обработайте команду login
[[maybe_unused]] const auto args = std::get<args::Login>(vargs);
const auto args = std::get<args::Login>(vargs);
const auto session = authManager.Login(std::string(args.username), std::string(args.password));

if (!session)
return "error: invalud username or password\n";

return "session_id=" + std::to_string(*session) + "\n";
}
else if (std::holds_alternative<args::Logout>(vargs))
{
// TODO: обработайте команду logout
[[maybe_unused]] const auto args = std::get<args::Logout>(vargs);
const auto args = std::get<args::Logout>(vargs);

if (!authManager.Logout(std::stoull(std::string(args.sessionId))))
return "error: invalid session\n";

return "ok\n";
}
else if (std::holds_alternative<args::Adduser>(vargs))
{
// TODO: обработайте команду adduser
[[maybe_unused]] const auto args = std::get<args::Adduser>(vargs);
const auto args = std::get<args::Adduser>(vargs);

if (!authManager.AddUser(std::stoull(std::string(args.sessionId)),
std::string(args.username),
std::string(args.password)))
return "error: access denied or user exists\n";

return "ok\n";
}
else if (std::holds_alternative<args::Deluser>(vargs))
{
// TODO: обработайте команда deluser
[[maybe_unused]] const auto args = std::get<args::Deluser>(vargs);
const auto args = std::get<args::Deluser>(vargs);

if (!authManager.DelUser(std::stoull(std::string(args.sessionId)),
std::string(args.username)))
return "error: access denied or user not found\n";

return "ok\n";
}
}
catch (const std::exception& err)
Expand All @@ -83,8 +107,8 @@ Server::Server(std::string_view adminUsername,
const std::atomic<bool>& running)
: running_(running), socket_(port), session_(socket_)
{
// TODO: добавьте администратора с именем и паролем
// из параметров конструктора
authManager.AddAdmin(std::string(adminUsername), std::string(adminPassword));

std::cout << "Add administrator user '" << adminUsername << "/***'\n";
std::cout << "Listening on port " << port << '\n';
}
Expand Down