changeset 175:a23758dda37d

Server: implement authentication, closes #869 While here, cleanup client class to match new conventions.
author David Demelier <markand@malikania.fr>
date Mon, 20 Aug 2018 22:21:11 +0200
parents 80b1638aa154
children e7f3f477a896
files libserver/malikania/server/client.cpp libserver/malikania/server/client.hpp libserver/malikania/server/net/auth_handler.cpp libserver/malikania/server/net/auth_handler.hpp libserver/malikania/server/net/handler.hpp libserver/malikania/server/server.cpp libserver/malikania/server/server.hpp server/main.cpp
diffstat 8 files changed, 138 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/libserver/malikania/server/client.cpp	Mon Aug 20 13:25:18 2018 +0200
+++ b/libserver/malikania/server/client.cpp	Mon Aug 20 22:21:11 2018 +0200
@@ -24,12 +24,12 @@
 
 namespace mlk::server {
 
-void client::handle_read(boost::system::error_code code, std::size_t xfer)
+void client::handle_read(std::error_code code, std::size_t xfer)
 {
     // TODO: use fixed size stream + verify exceed.
-    if (code) {
+    if (code)
         server_.handle_disconnect(shared_from_this());
-    } else {
+    else {
         std::string message(
             boost::asio::buffers_begin(input_.data()),
             boost::asio::buffers_begin(input_.data()) + xfer - 4
@@ -48,7 +48,7 @@
     }
 }
 
-void client::handle_write(boost::system::error_code code, std::size_t)
+void client::handle_write(std::error_code code, std::size_t)
 {
     if (code) {
         server_.handle_disconnect(shared_from_this());
@@ -65,7 +65,7 @@
 
 void client::do_read()
 {
-    auto self = shared_from_this();
+    const auto self = shared_from_this();
 
     boost::asio::async_read_until(socket_, input_, "\r\n\r\n", [self] (auto code, auto xfer) {
         self->handle_read(code, xfer);
@@ -76,22 +76,16 @@
 {
     assert(!output_.empty());
 
-    auto self = shared_from_this();
+    const auto self = shared_from_this();
 
     boost::asio::async_write(socket_, boost::asio::buffer(output_[0]), [self] (auto code, auto xfer) {
         self->handle_write(code, xfer);
     });
 }
 
-client::client(server& server, boost::asio::io_service& service, boost::asio::ssl::context& context)
-    : server_(server)
-    , socket_(service, context)
-{
-}
-
 void client::handshake()
 {
-    auto self = shared_from_this();
+    const auto self = shared_from_this();
 
     socket_.async_handshake(boost::asio::ssl::stream_base::server, [self] (auto code) {
         if (code) {
@@ -107,6 +101,41 @@
     do_read();
 }
 
+client::client(server& server, boost::asio::io_service& service, boost::asio::ssl::context& context)
+    : server_(server)
+    , socket_(service, context)
+{
+}
+
+auto client::get_state() const noexcept -> state
+{
+    return state_;
+}
+
+void client::set_state(state state) noexcept
+{
+    state_ = state;
+}
+
+auto client::get_account() const noexcept -> const db::account&
+{
+    assert(state_ == state::ready);
+
+    return *account_;
+}
+
+auto client::get_account() noexcept -> db::account&
+{
+    assert(state_ == state::ready);
+
+    return *account_;
+}
+
+void client::set_account(db::account account) noexcept
+{
+    account_ = std::move(account);
+}
+
 void client::send(nlohmann::json message)
 {
     assert(message.is_object());
@@ -115,7 +144,7 @@
         return;
     }
 
-    auto in_progress = !output_.empty();
+    const auto in_progress = !output_.empty();
 
     output_.push_back(message.dump() + "\r\n\r\n");
 
--- a/libserver/malikania/server/client.hpp	Mon Aug 20 13:25:18 2018 +0200
+++ b/libserver/malikania/server/client.hpp	Mon Aug 20 22:21:11 2018 +0200
@@ -27,8 +27,9 @@
 #include <cstdint>
 #include <deque>
 #include <memory>
+#include <optional>
+#include <sstream>
 #include <string>
-#include <sstream>
 
 #include <boost/asio.hpp>
 #include <boost/asio/ssl.hpp>
@@ -78,10 +79,10 @@
     boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
     boost::asio::streambuf input_;
     std::deque<std::string> output_;
-    std::shared_ptr<class account> account_;
+    std::optional<db::account> account_;
 
-    void handle_read(boost::system::error_code, std::size_t);
-    void handle_write(boost::system::error_code, std::size_t);
+    void handle_read(std::error_code, std::size_t);
+    void handle_write(std::error_code, std::size_t);
 
     void do_read();
     void do_write();
@@ -104,30 +105,37 @@
      *
      * \return the state
      */
-    inline enum state state() const noexcept
-    {
-        return state_;
-    }
+    auto get_state() const noexcept -> state;
 
     /**
      * Set the client state.
      *
      * \param new_state the state
      */
-    inline void set_state(enum state new_state) noexcept
-    {
-        state_ = new_state;
-    }
+    void set_state(state state) noexcept;
+
+    /**
+     * Get the underlying account database object.
+     *
+     * \pre get_state() == ready
+     * \return the account
+     */
+    auto get_account() const noexcept -> const db::account&;
+
+    /**
+     * Overloaded function.
+     *
+     * \pre get_state() == ready
+     * \return the account
+     */
+    auto get_account() noexcept -> db::account&;
 
     /**
      * Set the client account.
      *
      * \param account the account
      */
-    inline void set_account(std::shared_ptr<class account> account) noexcept
-    {
-        account_ = std::move(account);
-    }
+    void set_account(db::account account) noexcept;
 
     /**
      * Send a command and its arguments.
--- a/libserver/malikania/server/net/auth_handler.cpp	Mon Aug 20 13:25:18 2018 +0200
+++ b/libserver/malikania/server/net/auth_handler.cpp	Mon Aug 20 22:21:11 2018 +0200
@@ -18,7 +18,6 @@
 
 #include <util.hpp>
 
-#include "db/database.hpp"
 #include "db/account.hpp"
 
 #include "auth_handler.hpp"
@@ -27,29 +26,39 @@
 
 namespace mlk::server {
 
-void auth_handler::exec(server& server, std::shared_ptr<client> clt, nlohmann::json object) noexcept
+namespace {
+
+auto is_connected(const server& server, const db::account& account) noexcept -> bool
 {
-    (void)server;
-    (void)clt;
-    (void)object;
-#if 0
-    try {
-        // TODO: VERIFY ALREADY LOGGED IN!
-        auto ac = server.database().accounts().authenticate(
-            util::json::require_string(object, "/login"_json_pointer),
-            util::json::require_string(object, "/password"_json_pointer)
-        );
+    const auto& clients = server.get_clients();
+    const auto it = std::find_if(clients.begin(), clients.end(), [&] (const auto& c) {
+        if (c->get_state() != client::state::ready)
+            return false;
+
+        return c->get_account().get_login() == account.get_login();
+    });
+
+    return it != clients.end();
+}
+
+} // !namespace
 
-        if (ac)
-            clt->error("auth", "invalid credentials");
-        else {
-            clt->set_state(client::state::ready);
-            clt->ok("auth");
-        }
-    } catch (const std::exception& ex) {
-        clt->error("auth", ex.what());
+void auth_handler::exec(server& server, client& clt, nlohmann::json object) noexcept
+{
+    auto ac = db::account::authenticate(
+        util::json::require_string(object, "/login"_json_pointer),
+        util::json::require_string(object, "/password"_json_pointer)
+    );
+
+    if (!ac)
+        clt.error("auth", "invalid credentials");
+    else if (is_connected(server, *ac))
+        clt.error("auth", "already connected");
+    else {
+        clt.set_account(std::move(*ac));
+        clt.set_state(client::state::ready);
+        clt.ok("auth");
     }
-#endif
 }
 
 } // !mlk::server
--- a/libserver/malikania/server/net/auth_handler.hpp	Mon Aug 20 13:25:18 2018 +0200
+++ b/libserver/malikania/server/net/auth_handler.hpp	Mon Aug 20 22:21:11 2018 +0200
@@ -36,7 +36,7 @@
     /**
      * \copydoc handler::exec
      */
-    void exec(server &server, std::shared_ptr<client> clt, nlohmann::json object) noexcept override;
+    void exec(server& server, client& clt, nlohmann::json object) noexcept override;
 };
 
 } // !mlk::server
--- a/libserver/malikania/server/net/handler.hpp	Mon Aug 20 13:25:18 2018 +0200
+++ b/libserver/malikania/server/net/handler.hpp	Mon Aug 20 22:21:11 2018 +0200
@@ -55,9 +55,7 @@
      * \param client the client
      * \param message the network message
      */
-    virtual void exec(server& server,
-                      std::shared_ptr<client> client,
-                      nlohmann::json message) noexcept = 0;
+    virtual void exec(server& server, client& client, nlohmann::json message) noexcept = 0;
 };
 
 } // !mlk::server
--- a/libserver/malikania/server/server.cpp	Mon Aug 20 13:25:18 2018 +0200
+++ b/libserver/malikania/server/server.cpp	Mon Aug 20 22:21:11 2018 +0200
@@ -60,12 +60,22 @@
     start();
 }
 
+auto server::get_clients() const noexcept -> const clients&
+{
+    return clients_;
+}
+
+auto server::get_clients() noexcept -> clients&
+{
+    return clients_;
+}
+
 void server::handle(std::string name, std::unique_ptr<handler> handler)
 {
     assert(!name.empty());
     assert(handler);
 
-    handlers_.emplace(std::move(name), std::move(handler));
+    commands_.emplace(std::move(name), std::move(handler));
 }
 
 void server::handle_disconnect(std::shared_ptr<client> clt)
@@ -84,15 +94,15 @@
         return;
     }
 
-    const auto it = handlers_.find(*cmd);
+    const auto it = commands_.find(*cmd);
 
-    if (it == handlers_.end()) {
+    if (it == commands_.end()) {
         // TODO: log error.
         return;
     }
 
     try {
-        it->second->exec(*this, std::move(clt), std::move(message));
+        it->second->exec(*this, *clt, std::move(message));
     } catch (const std::exception&) {
         // TODO: log error.
     }
--- a/libserver/malikania/server/server.hpp	Mon Aug 20 13:25:18 2018 +0200
+++ b/libserver/malikania/server/server.hpp	Mon Aug 20 22:21:11 2018 +0200
@@ -57,13 +57,17 @@
  * \brief Malikania basic server.
  */
 class server {
+public:
+    using clients = std::unordered_set<std::shared_ptr<client>>;
+    using commands = std::unordered_map<std::string, std::unique_ptr<handler>>;
+
 private:
     boost::asio::io_service& service_;
     boost::asio::ip::tcp::acceptor acceptor_;
     boost::asio::ssl::context context_;
 
-    std::unordered_set<std::shared_ptr<client>> clients_;
-    std::unordered_map<std::string, std::unique_ptr<handler>> handlers_;
+    clients clients_;
+    commands commands_;
 
     void load();
     void start();
@@ -78,6 +82,20 @@
     server(boost::asio::io_service& service, const settings& settings);
 
     /**
+     * Get the set of connected clients.
+     *
+     * \return the clients
+     */
+    auto get_clients() const noexcept -> const clients&;
+
+    /**
+     * Overloaded function.
+     *
+     * \return the clients
+     */
+    auto get_clients() noexcept -> clients&;
+
+    /**
      * Add network handler.
      *
      * If a handler is already present, it will be replaced with the new one.
--- a/server/main.cpp	Mon Aug 20 13:25:18 2018 +0200
+++ b/server/main.cpp	Mon Aug 20 22:21:11 2018 +0200
@@ -32,11 +32,14 @@
     try {
         server::settings settings;
 
-        settings.key = "";
-        settings.certificate = "";
+        settings.key = "/home/markand/server.key";
+        settings.certificate = "/home/markand/server.crt";
         settings.port = 3320;
         
         server::server sv(ctx, settings);
+
+        server::db::open("", "", "markand", "malikaniadb", "");
+        server::db::init();
         
         ctx.run();
     } catch (const std::exception& ex) {