#include "./tox_client.hpp" // meh, change this #include #include #include #include #include #include #include #include static void eee(std::string& mod) { for (char& c : mod) { c ^= 0x59; } } ToxClient::ToxClient(std::string_view save_path, std::string_view save_password) : _tox_profile_path(save_path), _tox_profile_password(save_password) { TOX_ERR_OPTIONS_NEW err_opt_new; Tox_Options* options = tox_options_new(&err_opt_new); assert(err_opt_new == TOX_ERR_OPTIONS_NEW::TOX_ERR_OPTIONS_NEW_OK); std::vector profile_data{}; if (!_tox_profile_path.empty()) { std::ifstream ifile{_tox_profile_path, std::ios::binary}; if (ifile.is_open()) { std::cout << "TOX loading save " << _tox_profile_path << "\n"; // fill savedata while (ifile.good()) { auto ch = ifile.get(); if (ch == EOF) { break; } else { profile_data.push_back(ch); } } if (profile_data.empty()) { std::cerr << "empty tox save\n"; } else { // set options if (!save_password.empty()) { std::vector encrypted_copy(profile_data.begin(), profile_data.end()); //profile_data.clear(); profile_data.resize(encrypted_copy.size() - TOX_PASS_ENCRYPTION_EXTRA_LENGTH); if (!tox_pass_decrypt( encrypted_copy.data(), encrypted_copy.size(), reinterpret_cast(save_password.data()), save_password.size(), profile_data.data(), nullptr // TODO: error checking )) { throw std::runtime_error("FAILED to decrypt save file!!!!"); } eee(_tox_profile_password); } tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE); tox_options_set_savedata_data(options, profile_data.data(), profile_data.size()); } ifile.close(); // do i need this? } } tox_options_set_experimental_groups_persistence(options, true); TOX_ERR_NEW err_new; _tox = tox_new(options, &err_new); tox_options_free(options); if (err_new != TOX_ERR_NEW_OK) { std::cerr << "tox_new failed with error code " << err_new << "\n"; throw std::runtime_error{"tox failed"}; } // no callbacks, use events tox_events_init(_tox); runBootstrap(); } ToxClient::~ToxClient(void) { if (_tox_profile_dirty) { saveToxProfile(); } tox_kill(_tox); } bool ToxClient::iterate(float time_delta) { Tox_Err_Events_Iterate err_e_it = TOX_ERR_EVENTS_ITERATE_OK; auto* events = tox_events_iterate(_tox, false, &err_e_it); if (err_e_it == TOX_ERR_EVENTS_ITERATE_OK && events != nullptr) { _subscriber_raw(events); // forward events to event handlers dispatchEvents(events); } tox_events_free(events); _save_heat -= time_delta; if (_tox_profile_dirty && _save_heat <= 0.f) { saveToxProfile(); } return true; } void ToxClient::runBootstrap(void) { // TODO: extend and read from json? // TODO: seperate out relays struct DHT_node { const char *ip; uint16_t port; const char key_hex[TOX_PUBLIC_KEY_SIZE*2 + 1]; // 1 for null terminator unsigned char key_bin[TOX_PUBLIC_KEY_SIZE]; }; DHT_node nodes[] { // TODO: more/diff nodes // you can change or add your own bs and tcprelays here, ideally closer to you //{"tox.plastiras.org", 33445, "8E8B63299B3D520FB377FE5100E65E3322F7AE5B20A0ACED2981769FC5B43725", {}}, // LU tha14 {"104.244.74.69", 443, "8E8B63299B3D520FB377FE5100E65E3322F7AE5B20A0ACED2981769FC5B43725", {}}, // LU tha14 {"104.244.74.69", 33445, "8E8B63299B3D520FB377FE5100E65E3322F7AE5B20A0ACED2981769FC5B43725", {}}, // LU tha14 //{"tox2.plastiras.org", 33445, "B6626D386BE7E3ACA107B46F48A5C4D522D29281750D44A0CBA6A2721E79C951", {}}, // DE tha14 //{"tox4.plastiras.org", 33445, "836D1DA2BE12FE0E669334E437BE3FB02806F1528C2B2782113E0910C7711409", {}}, // MD tha14 {"37.221.66.161", 443, "836D1DA2BE12FE0E669334E437BE3FB02806F1528C2B2782113E0910C7711409", {}}, // MD tha14 {"37.221.66.161", 33445, "836D1DA2BE12FE0E669334E437BE3FB02806F1528C2B2782113E0910C7711409", {}}, // MD tha14 }; for (size_t i = 0; i < sizeof(nodes)/sizeof(DHT_node); i++) { sodium_hex2bin( nodes[i].key_bin, sizeof(nodes[i].key_bin), nodes[i].key_hex, sizeof(nodes[i].key_hex)-1, NULL, NULL, NULL ); tox_bootstrap(_tox, nodes[i].ip, nodes[i].port, nodes[i].key_bin, NULL); // TODO: use extra tcp option to avoid error msgs // ... this is hardcore tox_add_tcp_relay(_tox, nodes[i].ip, nodes[i].port, nodes[i].key_bin, NULL); } } void ToxClient::subscribeRaw(std::function fn) { _subscriber_raw = fn; } void ToxClient::saveToxProfile(void) { if (_tox_profile_path.empty()) { return; } std::cout << "TOX saving\n"; std::vector data{}; data.resize(tox_get_savedata_size(_tox)); tox_get_savedata(_tox, data.data()); if (!_tox_profile_password.empty()) { std::vector unencrypted_copy(data.begin(), data.end()); //profile_data.clear(); data.resize(unencrypted_copy.size() + TOX_PASS_ENCRYPTION_EXTRA_LENGTH); eee(_tox_profile_password); if (!tox_pass_encrypt( unencrypted_copy.data(), unencrypted_copy.size(), reinterpret_cast(_tox_profile_password.data()), _tox_profile_password.size(), data.data(), nullptr // TODO: error checking )) { eee(_tox_profile_password); throw std::runtime_error("FAILED to encrypt save file!!!!"); } eee(_tox_profile_password); } std::ofstream ofile{_tox_profile_path, std::ios::binary}; // TODO: improve for (const auto& ch : data) { ofile.put(ch); } _tox_profile_dirty = false; _save_heat = 10.f; }