#include #include #include #include #include #include #include #include #include using namespace ::qtprotobuf::examples; class MessageListHandler; class UserListHandler; class SimpleChatService final : public SimpleChat::WithAsyncMethod_messageList> { public: Users m_usersOnline; Users m_usersDatabase; ChatMessages m_messages; SimpleChatService() { User *newUser = m_usersDatabase.add_users(); newUser->set_name("user1"); newUser->set_password("d8578edf8458ce06fbc5bb76a58c5ca4"); newUser = m_usersDatabase.add_users(); newUser->set_name("user2"); newUser->set_password("d8578edf8458ce06fbc5bb76a58c5ca4"); newUser = m_usersDatabase.add_users(); newUser->set_name("user3"); newUser->set_password("d8578edf8458ce06fbc5bb76a58c5ca4"); newUser = m_usersDatabase.add_users(); newUser->set_name("user4"); newUser->set_password("d8578edf8458ce06fbc5bb76a58c5ca4"); newUser = m_usersDatabase.add_users(); newUser->set_name("user5"); newUser->set_password("d8578edf8458ce06fbc5bb76a58c5ca4"); } void loginUser(MessageListHandler *userHandler); void updateActiveUsers() { for (unsigned int i = 0; i < (m_activeUserListClients.size() - 1); i++) { m_activeUserListClients[i]->Write(m_usersOnline, nullptr); } } void updateMessages() { for (unsigned int i = 0; i < (m_activeClients.size() - 1); i++) { m_activeClients[i]->Write(m_messages, nullptr); } } bool checkUserCredentials(const std::string &name, const std::string &password) { for (int i = 0; i < m_usersDatabase.users_size(); i++) { if (m_usersDatabase.users(i).name() == name && m_usersDatabase.users(i).password() == password) { return true; } } return false; } std::tuple extractCredentials(grpc::ServerContext *context) { std::string name{}; std::string password{}; for (auto it = context->client_metadata().begin(); it != context->client_metadata().end(); ++it) { if ((*it).first == std::string("user-name")) { name = std::string((*it).second.data()); } if ((*it).first == std::string("user-password")) { password = std::string((*it).second.data()); password.resize(32); } } return std::make_tuple(name, password); } ::grpc::Status sendMessage(grpc::ServerContext *context, const ChatMessage *request, None *) override { std::string name{}; std::string password{}; std::tie(name, password) = extractCredentials(context); if (!checkUserCredentials(name, password)) { return ::grpc::Status(::grpc::StatusCode::UNAUTHENTICATED, "User or login are invalid"); } ChatMessage *msg = m_messages.add_messages(); *msg = *request; msg->set_from(name); updateMessages(); return ::grpc::Status(); } std::vector<::grpc::ServerAsyncWriter *> m_activeClients; std::vector<::grpc::ServerAsyncWriter *> m_activeUserListClients; }; class MessageListHandler { public: MessageListHandler(SimpleChatService *service, ::grpc::ServerCompletionQueue *cq) : tag_(0xdeadbeef) , writer_(&ctx_) , cq_(cq) { service->RequestmessageList(&ctx_, &request_, &writer_, cq_, cq_, &tag_); service->loginUser(this); } int tag_; grpc::ServerContext ctx_; None request_; ::grpc::ServerAsyncWriter< ::qtprotobuf::examples::ChatMessages> writer_; ::grpc::ServerCompletionQueue *cq_; }; void SimpleChatService::loginUser(MessageListHandler *handler) { m_activeClients.push_back(&(handler->writer_)); //TODO: update online if required here } int main(int argc, char *argv[]) { std::string server_address("localhost:65002"); SimpleChatService service; std::ifstream tfile("cert.pem"); std::stringstream cert; cert << tfile.rdbuf(); tfile.close(); tfile.open("key.pem"); std::stringstream key; key << tfile.rdbuf(); tfile.close(); grpc::ServerBuilder builder; grpc::SslServerCredentialsOptions opts(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE); opts.pem_key_cert_pairs.push_back({key.str(), cert.str()}); builder.AddListeningPort(server_address, grpc::SslServerCredentials(opts)); builder.RegisterService(&service); std::unique_ptr cq = builder.AddCompletionQueue(); std::unique_ptr server(builder.BuildAndStart()); std::cout << "Server listening on " << server_address << std::endl; MessageListHandler *last = new MessageListHandler(&service, cq.get()); while (true) { unsigned int *tag; bool ok; cq->Next((void**)&tag, &ok); if (tag == nullptr) { continue; } if ((*tag) == 0xdeadbeef) { std::string name{}; std::string password{}; std::tie(name, password) = service.extractCredentials(&(last->ctx_)); if (!service.checkUserCredentials(name, password)) { std::cout << "Authentication failed" << std::endl; last->writer_.Finish(::grpc::Status(::grpc::StatusCode::UNAUTHENTICATED, "User or login are invalid"), nullptr); last = new MessageListHandler(&service, cq.get()); continue; } std::cout << "Authentication ok update user chat" << std::endl; last->writer_.Write(service.m_messages, nullptr); last = new MessageListHandler(&service, cq.get()); } } }