Skip to content

Instantly share code, notes, and snippets.

@madmongo1
Created April 25, 2020 21:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save madmongo1/460177bd94f3447c69cbf927ad6c80dd to your computer and use it in GitHub Desktop.
Save madmongo1/460177bd94f3447c69cbf927ad6c80dd to your computer and use it in GitHub Desktop.
template < class NextLayer >
struct server_accept_op : server_accept_op_base
{
using stream_type = stream< NextLayer >;
server_accept_op(stream_type &stream, server_accept_state &state)
: server_accept_op_base(state)
, stream(stream)
{
}
template < class Self >
void operator()(Self &self, error_code ec, boost::webclient::unique_http_response response)
{
state.auth_response.emplace(std::move(response));
spdlog::info("response: \n{}\n", state.auth_response->body());
spdlog::info("log: \n{}\n", state.auth_response->log());
(*this)(self, ec);
}
template < class Self >
void operator()(Self &self, error_code ec = {}, std::size_t bytes_transferred = 0)
{
boost::ignore_unused(bytes_transferred);
#include <boost/asio/yield.hpp>
if (log_fail(ec).failed())
return self.complete(ec);
reenter(coro)
{
yield
{
auto &pkt = state.client_packet.emplace< packets::client::login_start >();
async_expect_frame(stream, pkt, std::move(self));
}
{
auto &logstart = std::get< packets::client::login_start >(state.client_packet);
if (verify(logstart, ec).failed())
return self.complete(log_fail(ec));
stream.player_name(logstart.name);
}
if (state.server_key.has_value())
{
context = "encryption request";
yield
{
auto &pkt = state.server_packet.emplace< packets::server::encryption_request >();
prepare(pkt, state.server_id, *state.server_key);
state.server_public_key_der = pkt.public_key;
stream.async_write_packet(pkt, std::move(self));
}
//
// receive encryption response
//
yield
{
context = "encryption response";
auto &pkt = state.client_packet.emplace< packets::client::encryption_response >();
async_expect_frame(stream, pkt, std::move(self));
}
//
// decode shared secret
//
yield
{
context = "verify with mojang";
using net::buffer;
auto &request = std::get< packets::server::encryption_request >(state.server_packet);
auto &response = std::get< packets::client::encryption_response >(state.client_packet);
auto secret = response.decrypt_secret(*state.server_key, request.verify_token, ec);
if (log_fail(ec).failed())
return self.complete(ec);
stream.set_encryption(secret);
daft_hash_impl hasher;
hasher.update(buffer(state.server_id));
hasher.update(buffer(secret));
hasher.update(buffer(state.server_public_key_der));
auto hash = hasher.finalise();
auto url = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" +
stream.player_name() + "&serverId=" + hash; // + "&ip=ip";
spdlog::info("url [{}]", url);
boost::webclient::async_get(stream.inet_session(), url, std::move(self));
}
{
this->context = "parse mojang response";
auto v = boost::json::parse(state.auth_response->body(), ec);
if (log_fail(ec).failed())
return self.complete(ec);
}
}
yield
{
context = "set compression";
auto &pkt = state.server_packet.emplace< packets::server::set_compression >();
pkt.threshold = state.compression_threshold;
stream.async_write_packet(pkt, std::move(self));
}
// note: set threshold after writing packet
stream.compression_threshold(state.compression_threshold);
//
// send login success
//
yield
{
context = "success";
auto &pkt = state.server_packet.emplace< packets::server::login_success >();
if (state.mojang_data)
{
pkt.username.assign(state.mojang_data->name.begin(), state.mojang_data->name.end());
pkt.uuid = insert_dashes(state.mojang_data->id);
}
else
{
pkt.username = stream.player_name();
pkt.uuid = to_string(server_accept_op_base::generate_uuid());
}
stream.async_write_packet(pkt, std::move(self));
}
return self.complete(log_fail(ec));
}
#include <boost/asio/unyield.hpp>
}
private:
stream_type &stream;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment