support full DC NTE credentials
This commit is contained in:
@@ -18,3 +18,26 @@ void forward_to_event_thread(std::shared_ptr<struct event_base> base, std::funct
|
||||
std::function<void()>* new_fn = new std::function<void()>(std::move(fn));
|
||||
event_base_once(base.get(), -1, EV_TIMEOUT, dispatch_forward_to_event_thread, new_fn, &tv);
|
||||
}
|
||||
|
||||
template <>
|
||||
void call_on_event_thread<void>(std::shared_ptr<struct event_base> base, std::function<void()>&& compute) {
|
||||
bool succeeded = false;
|
||||
std::string exc_what;
|
||||
std::mutex ret_lock;
|
||||
std::condition_variable ret_cv;
|
||||
std::unique_lock<std::mutex> g(ret_lock);
|
||||
forward_to_event_thread(base, [&]() -> void {
|
||||
std::lock_guard<std::mutex> g(ret_lock);
|
||||
try {
|
||||
compute();
|
||||
succeeded = true;
|
||||
} catch (const std::exception& e) {
|
||||
exc_what = e.what();
|
||||
}
|
||||
ret_cv.notify_one();
|
||||
});
|
||||
ret_cv.wait(g);
|
||||
if (!succeeded) {
|
||||
throw std::runtime_error(exc_what);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,3 +33,6 @@ T call_on_event_thread(std::shared_ptr<struct event_base> base, std::function<T(
|
||||
}
|
||||
return ret.value();
|
||||
}
|
||||
|
||||
template <>
|
||||
void call_on_event_thread<void>(std::shared_ptr<struct event_base> base, std::function<void()>&& compute);
|
||||
|
||||
+38
-4
@@ -19,6 +19,8 @@ License::License(const JSON& json)
|
||||
bb_team_id(0) {
|
||||
this->serial_number = json.get_int("SerialNumber");
|
||||
this->access_key = json.get_string("AccessKey", "");
|
||||
this->dc_nte_serial_number = json.get_string("DCNTESerialNumber", "");
|
||||
this->dc_nte_access_key = json.get_string("DCNTEAccessKey", "");
|
||||
this->gc_password = json.get_string("GCPassword", "");
|
||||
this->xb_gamertag = json.get_string("XBGamerTag", "");
|
||||
this->xb_user_id = json.get_int("XBUserID", 0);
|
||||
@@ -38,6 +40,8 @@ JSON License::json() const {
|
||||
return JSON::dict({
|
||||
{"SerialNumber", this->serial_number},
|
||||
{"AccessKey", this->access_key},
|
||||
{"DCNTESerialNumber", this->dc_nte_serial_number},
|
||||
{"DCNTEAccessKey", this->dc_nte_access_key},
|
||||
{"GCPassword", this->gc_password},
|
||||
{"XBGamerTag", this->xb_gamertag},
|
||||
{"XBUserID", this->xb_user_id},
|
||||
@@ -63,6 +67,12 @@ string License::str() const {
|
||||
if (!this->access_key.empty()) {
|
||||
tokens.emplace_back("access_key=" + this->access_key);
|
||||
}
|
||||
if (!this->dc_nte_serial_number.empty()) {
|
||||
tokens.emplace_back("dc_nte_serial_number=" + this->dc_nte_serial_number);
|
||||
}
|
||||
if (!this->dc_nte_access_key.empty()) {
|
||||
tokens.emplace_back("dc_nte_access_key=" + this->dc_nte_access_key);
|
||||
}
|
||||
if (!this->gc_password.empty()) {
|
||||
tokens.emplace_back("gc_password=" + this->gc_password);
|
||||
}
|
||||
@@ -147,23 +157,47 @@ vector<shared_ptr<License>> LicenseIndex::all() const {
|
||||
|
||||
void LicenseIndex::add(shared_ptr<License> l) {
|
||||
this->serial_number_to_license[l->serial_number] = l;
|
||||
if (!l->bb_username.empty()) {
|
||||
this->bb_username_to_license[l->bb_username] = l;
|
||||
if (!l->dc_nte_serial_number.empty()) {
|
||||
this->dc_nte_serial_number_to_license[l->dc_nte_serial_number] = l;
|
||||
}
|
||||
if (!l->xb_gamertag.empty()) {
|
||||
this->xb_gamertag_to_license[l->xb_gamertag] = l;
|
||||
}
|
||||
if (!l->bb_username.empty()) {
|
||||
this->bb_username_to_license[l->bb_username] = l;
|
||||
}
|
||||
}
|
||||
|
||||
void LicenseIndex::remove(uint32_t serial_number) {
|
||||
auto l = this->serial_number_to_license.at(serial_number);
|
||||
this->serial_number_to_license.erase(l->serial_number);
|
||||
if (!l->bb_username.empty()) {
|
||||
this->bb_username_to_license.erase(l->bb_username);
|
||||
if (!l->dc_nte_serial_number.empty()) {
|
||||
this->dc_nte_serial_number_to_license.erase(l->dc_nte_serial_number);
|
||||
}
|
||||
if (!l->xb_gamertag.empty()) {
|
||||
this->xb_gamertag_to_license.erase(l->xb_gamertag);
|
||||
}
|
||||
if (!l->bb_username.empty()) {
|
||||
this->bb_username_to_license.erase(l->bb_username);
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<License> LicenseIndex::verify_dc_nte(const string& serial_number, const string& access_key) const {
|
||||
if (serial_number.empty()) {
|
||||
throw no_username();
|
||||
}
|
||||
try {
|
||||
auto& license = this->dc_nte_serial_number_to_license.at(serial_number);
|
||||
if (license->ban_end_time && (license->ban_end_time >= now())) {
|
||||
throw invalid_argument("user is banned");
|
||||
}
|
||||
if (license->dc_nte_access_key != access_key) {
|
||||
throw incorrect_access_key();
|
||||
}
|
||||
return license;
|
||||
} catch (const out_of_range&) {
|
||||
throw missing_license();
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<License> LicenseIndex::verify_v1_v2(
|
||||
|
||||
+5
-1
@@ -35,6 +35,8 @@ public:
|
||||
};
|
||||
|
||||
uint32_t serial_number = 0;
|
||||
std::string dc_nte_serial_number;
|
||||
std::string dc_nte_access_key;
|
||||
std::string access_key;
|
||||
std::string gc_password;
|
||||
std::string xb_gamertag;
|
||||
@@ -123,6 +125,7 @@ public:
|
||||
void add(std::shared_ptr<License> l);
|
||||
void remove(uint32_t serial_number);
|
||||
|
||||
std::shared_ptr<License> verify_dc_nte(const std::string& serial_number, const std::string& access_key) const;
|
||||
std::shared_ptr<License> verify_v1_v2(
|
||||
uint32_t serial_number,
|
||||
const std::string& access_key,
|
||||
@@ -140,8 +143,9 @@ public:
|
||||
std::shared_ptr<License> verify_bb(const std::string& username, const std::string& password) const;
|
||||
|
||||
protected:
|
||||
std::unordered_map<std::string, std::shared_ptr<License>> bb_username_to_license;
|
||||
std::unordered_map<std::string, std::shared_ptr<License>> dc_nte_serial_number_to_license;
|
||||
std::unordered_map<std::string, std::shared_ptr<License>> xb_gamertag_to_license;
|
||||
std::unordered_map<std::string, std::shared_ptr<License>> bb_username_to_license;
|
||||
std::unordered_map<uint32_t, std::shared_ptr<License>> serial_number_to_license;
|
||||
|
||||
std::shared_ptr<License> create_temporary_license_for_shared_license(
|
||||
|
||||
@@ -465,9 +465,8 @@ static void on_88_DCNTE(shared_ptr<Client> c, uint16_t, uint32_t, string& data)
|
||||
c->config.set_flags_for_version(c->version(), -1);
|
||||
c->log.info("Game version changed to DC_NTE");
|
||||
|
||||
uint32_t serial_number = stoul(cmd.serial_number.decode(), nullptr, 16);
|
||||
try {
|
||||
shared_ptr<License> l = s->license_index->verify_v1_v2(serial_number, cmd.access_key.decode(), "");
|
||||
shared_ptr<License> l = s->license_index->verify_dc_nte(cmd.serial_number.decode(), cmd.access_key.decode());
|
||||
c->set_license(l);
|
||||
send_command(c, 0x88, 0x00);
|
||||
|
||||
@@ -487,8 +486,9 @@ static void on_88_DCNTE(shared_ptr<Client> c, uint16_t, uint32_t, string& data)
|
||||
} else {
|
||||
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
|
||||
auto l = s->license_index->create_license();
|
||||
l->serial_number = serial_number;
|
||||
l->access_key = cmd.access_key.decode();
|
||||
l->dc_nte_serial_number = cmd.serial_number.decode();
|
||||
l->dc_nte_access_key = cmd.access_key.decode();
|
||||
l->serial_number = fnv1a32(l->dc_nte_serial_number) & 0x7FFFFFFF;
|
||||
s->license_index->add(l);
|
||||
if (!s->is_replay) {
|
||||
l->save();
|
||||
@@ -510,9 +510,8 @@ static void on_8B_DCNTE(shared_ptr<Client> c, uint16_t, uint32_t, string& data)
|
||||
c->config.set_flags_for_version(c->version(), -1);
|
||||
c->log.info("Game version changed to DC_NTE");
|
||||
|
||||
uint32_t serial_number = stoul(cmd.serial_number.decode(), nullptr, 16);
|
||||
try {
|
||||
shared_ptr<License> l = s->license_index->verify_v1_v2(serial_number, cmd.access_key.decode(), cmd.name.decode());
|
||||
shared_ptr<License> l = s->license_index->verify_dc_nte(cmd.serial_number.decode(), cmd.access_key.decode());
|
||||
c->set_license(l);
|
||||
|
||||
} catch (const LicenseIndex::no_username& e) {
|
||||
@@ -531,8 +530,9 @@ static void on_8B_DCNTE(shared_ptr<Client> c, uint16_t, uint32_t, string& data)
|
||||
} else {
|
||||
c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED);
|
||||
auto l = s->license_index->create_license();
|
||||
l->serial_number = serial_number;
|
||||
l->access_key = cmd.access_key.decode();
|
||||
l->dc_nte_serial_number = cmd.serial_number.decode();
|
||||
l->dc_nte_access_key = cmd.access_key.decode();
|
||||
l->serial_number = fnv1a32(l->dc_nte_serial_number) & 0x7FFFFFFF;
|
||||
s->license_index->add(l);
|
||||
if (!s->is_replay) {
|
||||
l->save();
|
||||
|
||||
+11
-1
@@ -52,7 +52,7 @@ struct CommandDefinition {
|
||||
if (!def) {
|
||||
fprintf(stderr, "FAILED: no such command; try 'help'\n");
|
||||
} else if (def->run_on_event_thread) {
|
||||
args.s->forward_to_event_thread([def, args]() {
|
||||
args.s->call_on_event_thread<void>([def, args]() {
|
||||
CommandArgs local_args = args;
|
||||
try {
|
||||
def->run(local_args);
|
||||
@@ -282,6 +282,8 @@ CommandDefinition c_add_license(
|
||||
xb-user-id=<user-id> (Xbox user ID)\n\
|
||||
xb-account-id=<account-id> (Xbox account ID)\n\
|
||||
gc-password=<password> (GC password)\n\
|
||||
dc-nte-serial-number=<serial-number> (DC NTE serial number)\n\
|
||||
dc-nte-access-key=<access-key> (DC NTE access key)\n\
|
||||
access-key=<access-key> (DC/GC/PC access key)\n\
|
||||
serial=<serial-number> (decimal serial number; required for all licenses)\n\
|
||||
flags=<privilege-mask> (see below)\n\
|
||||
@@ -318,6 +320,10 @@ CommandDefinition c_add_license(
|
||||
l->xb_account_id = stoull(token.substr(14), nullptr, 16);
|
||||
} else if (starts_with(token, "gc-password=")) {
|
||||
l->gc_password = token.substr(12);
|
||||
} else if (starts_with(token, "dc-nte-serial-number=")) {
|
||||
l->dc_nte_serial_number = token.substr(21);
|
||||
} else if (starts_with(token, "dc-nte-access-key=")) {
|
||||
l->dc_nte_access_key = token.substr(18);
|
||||
} else if (starts_with(token, "access-key=")) {
|
||||
l->access_key = token.substr(11);
|
||||
} else if (starts_with(token, "serial=")) {
|
||||
@@ -383,6 +389,10 @@ CommandDefinition c_update_license(
|
||||
l->xb_account_id = stoull(token.substr(14), nullptr, 16);
|
||||
} else if (starts_with(token, "gc-password=")) {
|
||||
l->gc_password = token.substr(12);
|
||||
} else if (starts_with(token, "dc-nte-serial-number=")) {
|
||||
l->dc_nte_serial_number = token.substr(21);
|
||||
} else if (starts_with(token, "dc-nte-access-key=")) {
|
||||
l->dc_nte_access_key = token.substr(18);
|
||||
} else if (starts_with(token, "access-key=")) {
|
||||
l->access_key = token.substr(11);
|
||||
} else if (starts_with(token, "serial=")) {
|
||||
|
||||
@@ -309,6 +309,10 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
std::pair<std::string, uint16_t> parse_port_spec(const JSON& json) const;
|
||||
std::vector<PortConfiguration> parse_port_configuration(const JSON& json) const;
|
||||
|
||||
template <typename T>
|
||||
inline void call_on_event_thread(std::function<T()>&& fn) {
|
||||
return ::call_on_event_thread<T>(this->base, std::move(fn));
|
||||
}
|
||||
inline void forward_to_event_thread(std::function<void()>&& fn) {
|
||||
::forward_to_event_thread(this->base, std::move(fn));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user