32#include <boost/format.hpp>
33#include <boost/algorithm/string.hpp>
45#undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
46#define ELECTRONEUM_DEFAULT_LOG_CATEGORY "wallet.mms"
55 m_next_message_id = 1;
56 m_num_authorized_signers = 0;
57 m_num_required_signers = 0;
82 const std::string &own_transport_address,
uint32_t num_authorized_signers,
uint32_t num_required_signers)
84 m_num_authorized_signers = num_authorized_signers;
85 m_num_required_signers = num_required_signers;
88 m_next_message_id = 1;
94 for (
uint32_t i = 0; i < m_num_authorized_signers; ++i)
97 m_signers.push_back(signer);
103 m_nettype =
state.nettype;
105 m_filename =
state.mms_file;
111 const options opts{};
119 m_transporter.set_options(bitmessage_address, bitmessage_login);
124 const boost::optional<std::string> &label,
125 const boost::optional<std::string> &transport_address,
126 const boost::optional<cryptonote::account_public_address> etn_address)
132 m.
label = label.get();
134 if (transport_address)
150 return m_signers[index];
155 for (
uint32_t i = 0; i < m_num_authorized_signers; ++i)
170 for (
uint32_t i = 0; i < m_num_authorized_signers; ++i)
183 std::stringstream oss;
190 std::vector<authorized_signer> &signers)
194 std::stringstream iss;
219 std::vector<authorized_signer> signers;
223 for (
uint32_t i = 0; i < m_num_authorized_signers; ++i)
238 take_index = new_index;
239 if ((new_index + 1) < m_num_authorized_signers)
261 for (
uint32_t i = 0; i < m_num_authorized_signers; ++i)
266 setup_signer_for_auto_config(i, create_auto_config_token(),
true);
277 std::string &adjusted_token)
const
281 uint32_t full_length = num_hex_digits + prefix.length();
282 uint32_t raw_length = raw_token.length();
283 std::string hex_digits;
285 if (raw_length == full_length)
288 std::string raw_prefix(raw_token.substr(0, 3));
289 boost::algorithm::to_lower(raw_prefix);
290 if (raw_prefix != prefix)
294 hex_digits = raw_token.substr(3);
296 else if (raw_length == num_hex_digits)
299 hex_digits = raw_token;
307 boost::algorithm::to_lower(hex_digits);
308 std::replace(hex_digits.begin(), hex_digits.end(),
'o',
'0');
309 std::replace(hex_digits.begin(), hex_digits.end(),
'i',
'1');
310 std::replace(hex_digits.begin(), hex_digits.end(),
'l',
'1');
313 std::string token_bytes;
323 adjusted_token = prefix + hex_digits;
328std::string message_store::create_auto_config_token()
332 std::string token_bytes;
338 token_bytes += hash.data[0];
346 const std::string &auto_config_token)
350 setup_signer_for_auto_config(0, auto_config_token,
false);
358 std::stringstream oss;
372 const message &m = get_message_ref_by_id(
id);
377 std::stringstream iss;
397 for (
uint32_t i = 0; i < m_num_authorized_signers; ++i)
414void message_store::setup_signer_for_auto_config(
uint32_t index,
const std::string token,
bool receiving)
444 for (
uint32_t i = 0; i < m_num_authorized_signers; ++i)
453 MWARNING(
"No authorized signer with Electroneum address " << account_address_to_string(etn_address));
459 for (
uint32_t i = 0; i < m_num_authorized_signers; ++i)
462 if (m.
label == label)
468 MWARNING(
"No authorized signer with label " << label);
485 for (
uint32_t i = 1; i < m_num_authorized_signers; ++i)
495 if (m_num_required_signers == 1)
516 const std::string &content)
519 m.
id = m_next_message_id++;
545 m.
hash = crypto::null_hash;
546 m_messages.push_back(m);
551 MINFO(boost::format(
"Added %s message %s for signer %s of type %s")
553 return m_messages.size() - 1;
557bool message_store::get_message_index_by_id(
uint32_t id,
size_t &index)
const
559 for (
size_t i = 0; i < m_messages.size(); ++i)
561 if (m_messages[i].
id ==
id)
567 MWARNING(
"No message found with an id of " <<
id);
572size_t message_store::get_message_index_by_id(
uint32_t id)
const
575 bool found = get_message_index_by_id(
id, index);
583 return m_messages[get_message_index_by_id(
id)];
591 bool found = get_message_index_by_id(
id, index);
594 m = m_messages[index];
610 for (
size_t i = 0; i < m_messages.size(); ++i)
612 if ((m_messages[i].type == type) && (m_messages[i].direction == direction))
620bool message_store::any_message_with_hash(
const crypto::hash &hash)
const
622 for (
size_t i = 0; i < m_messages.size(); ++i)
624 if (m_messages[i].hash == hash)
637size_t message_store::get_other_signers_id_count(
const std::vector<uint32_t> &ids)
const
640 for (
size_t i = 1 ; i < ids.size(); ++i)
651bool message_store::message_ids_complete(
const std::vector<uint32_t> &ids)
const
653 return get_other_signers_id_count(ids) == (ids.size() - 1);
658 delete_transport_message(
id);
659 size_t index = get_message_index_by_id(
id);
660 m_messages.erase(m_messages.begin() + index);
665 for (
size_t i = 0; i < m_messages.size(); ++i)
667 delete_transport_message(m_messages[i].
id);
676 sanitized_text.clear();
679 size_t length = std::min(m.
content.length(), (
size_t)1000);
681 for (
size_t i = 0; i < length; ++i)
690 else if ((c ==
'<') || (c ==
'>'))
702 std::stringstream oss;
705 std::string
buf = oss.str();
707 crypto::chacha_key
key;
710 file_data write_file_data = boost::value_initialized<file_data>();
714 std::string encrypted_data;
715 encrypted_data.resize(
buf.size());
716 crypto::chacha20(
buf.data(),
buf.size(),
key, write_file_data.
iv, &encrypted_data[0]);
719 std::stringstream file_oss;
721 file_ar << write_file_data;
729 boost::system::error_code ignored_ec;
730 bool file_exists = boost::filesystem::exists(filename, ignored_ec);
735 MERROR(
"No message store file found: " << filename);
746 std::stringstream iss;
749 ar >> read_file_data;
751 catch (
const std::exception &e)
753 MERROR(
"MMS file " << filename <<
" has bad structure <iv,encrypted_data>: " << e.what());
757 crypto::chacha_key
key;
759 std::string decrypted_data;
765 std::stringstream iss;
766 iss << decrypted_data;
770 catch (
const std::exception &e)
772 MERROR(
"MMS file " << filename <<
" has bad structure: " << e.what());
776 m_filename = filename;
784 if (!m_filename.empty())
791 bool force_sync, std::vector<processing_data> &data_list, std::string &wait_reason)
801 std::vector<uint32_t> auto_config_messages(m_num_authorized_signers, 0);
802 bool any_auto_config =
false;
804 for (
size_t i = 0; i < m_messages.size(); ++i)
812 any_auto_config =
true;
820 bool auto_config_complete = message_ids_complete(auto_config_messages);
821 if (auto_config_complete)
827 data_list.push_back(data);
832 wait_reason =
tr(
"Auto-config cannot proceed because auto config data from other signers is not complete");
841 for (
size_t i = 0; i < m_messages.size(); ++i)
849 data_list.push_back(data);
857 wait_reason =
tr(
"The signer config is not complete.");
871 data_list.push_back(data);
880 std::vector<uint32_t> key_set_messages(m_num_authorized_signers, 0);
882 for (
size_t i = 0; i < m_messages.size(); ++i)
896 bool key_sets_complete = message_ids_complete(key_set_messages);
897 if (key_sets_complete)
904 data_list.push_back(data);
909 wait_reason =
tr(
"Wallet can't go multisig because key sets from other signers are missing or not complete.");
914 if (
state.multisig && !
state.multisig_is_ready)
923 std::vector<uint32_t> additional_key_set_messages(m_num_authorized_signers, 0);
925 for (
size_t i = 0; i < m_messages.size(); ++i)
939 bool key_sets_complete = message_ids_complete(additional_key_set_messages);
940 if (key_sets_complete)
946 data_list.push_back(data);
951 wait_reason =
tr(
"Wallet can't start another key exchange round because key sets from other signers are missing or not complete.");
968 if (
state.has_multisig_partial_key_images || force_sync)
974 bool own_sync_data_created =
false;
975 std::vector<uint32_t> sync_messages(m_num_authorized_signers, 0);
976 for (
size_t i = 0; i < m_messages.size(); ++i)
985 own_sync_data_created =
true;
998 if (!own_sync_data_created)
1004 data_list.push_back(data);
1009 bool all_sync_data = id_count == (m_num_authorized_signers - 1);
1013 bool enough_sync_data = id_count >= (m_num_required_signers - 1);
1015 wait_reason =
tr(
"Syncing not done because multisig sync data from other signers are missing or not complete.");
1020 else if (enough_sync_data)
1029 wait_reason += (boost::format(
"\nUse \"mms next sync\" if you want to sync with just %s out of %s authorized signers and transact just with them")
1030 % (m_num_required_signers - 1) % (m_num_authorized_signers - 1)).str();
1037 for (
size_t i = 0; i < sync_messages.size(); ++i)
1045 data_list.push_back(data);
1055 bool waiting_found =
false;
1056 bool note_found =
false;
1057 bool sync_data_found =
false;
1058 for (
size_t i = 0; i < m_messages.size(); ++i)
1063 waiting_found =
true;
1072 data_list.push_back(data);
1075 for (
uint32_t j = 1; j < m_num_authorized_signers; ++j)
1078 data_list.push_back(data);
1095 for (
uint32_t j = 1; j < m_num_authorized_signers; ++j)
1098 data_list.push_back(data);
1109 data_list.push_back(data);
1119 sync_data_found =
true;
1129 wait_reason =
tr(
"There are waiting messages, but nothing is ready to process under normal circumstances");
1130 if (sync_data_found)
1132 wait_reason +=
tr(
"\nUse \"mms next sync\" if you want to force processing of the waiting sync data");
1136 wait_reason +=
tr(
"\nUse \"mms note\" to display the waiting notes");
1141 wait_reason =
tr(
"There are no messages waiting to be processed.");
1149 for (
size_t i = 0; i < data.
message_ids.size(); ++i)
1157 message &m = get_message_ref_by_id(
id);
1163 delete_transport_message(
id);
1173void message_store::encrypt(
crypto::public_key public_key,
const std::string &plaintext,
1174 std::string &ciphertext,
crypto::public_key &encryption_public_key, crypto::chacha_iv &iv)
1183 crypto::chacha_key chacha_key;
1184 crypto::generate_chacha_key(&derivation,
sizeof(derivation), chacha_key, 1);
1186 ciphertext.resize(plaintext.size());
1187 crypto::chacha20(plaintext.data(), plaintext.size(), chacha_key, iv, &ciphertext[0]);
1190void message_store::decrypt(
const std::string &ciphertext,
const crypto::public_key &encryption_public_key,
const crypto::chacha_iv &iv,
1196 crypto::chacha_key chacha_key;
1197 crypto::generate_chacha_key(&derivation,
sizeof(derivation), chacha_key, 1);
1198 plaintext.resize(ciphertext.size());
1199 crypto::chacha20(ciphertext.data(), ciphertext.size(), chacha_key, iv, &plaintext[0]);
1204 message &m = get_message_ref_by_id(
id);
1228 dm.destination_etn_address = receiver.
etn_address;
1231 encrypt(public_key, m.
content, dm.content, dm.encryption_public_key, dm.iv);
1238 m_transporter.send_message(dm);
1246 m_run.store(
true, std::memory_order_relaxed);
1248 std::vector<std::string> destinations;
1250 for (
uint32_t i = 1; i < m_num_authorized_signers; ++i)
1258 std::vector<transport_message> transport_messages;
1259 bool r = m_transporter.receive_messages(destinations, transport_messages);
1260 if (!m_run.load(std::memory_order_relaxed))
1267 bool new_messages =
false;
1268 for (
size_t i = 0; i < transport_messages.size(); ++i)
1271 if (any_message_with_hash(rm.hash))
1285 for (
uint32_t i = 1; i < m_num_authorized_signers; ++i)
1313 take = rm.destination_etn_address == me.
etn_address;
1320 bool signature_valid =
crypto::check_signature(actual_hash, rm.source_etn_address.m_view_public_key, rm.signature);
1323 std::string plaintext;
1324 decrypt(rm.content, rm.encryption_public_key, rm.iv, decrypt_key, plaintext);
1326 message &m = m_messages[index];
1329 m.
sent = rm.timestamp;
1332 messages.push_back(m);
1333 new_messages =
true;
1337 return new_messages;
1340void message_store::delete_transport_message(
uint32_t id)
1349std::string message_store::account_address_to_string(
const cryptonote::account_public_address &account_address)
const
1359 return tr(
"key set");
1361 return tr(
"additional key set");
1363 return tr(
"multisig sync data");
1365 return tr(
"partially signed tx");
1367 return tr(
"fully signed tx");
1371 return tr(
"signer config");
1373 return tr(
"auto-config data");
1375 return tr(
"unknown message type");
1388 return tr(
"unknown message direction");
1397 return tr(
"ready to send");
1401 return tr(
"waiting");
1403 return tr(
"processed");
1405 return tr(
"cancelled");
1407 return tr(
"unknown message state");
1416 s.reserve(max_width);
1419 if (label_len > avail)
1421 s.append(signer.
label.substr(0, avail - 2));
1425 s.append(signer.
label);
1428 if ((transport_addr_len > 0) && (avail > 10))
1432 if (transport_addr_len <= avail)
void init(const multisig_wallet_state &state, const std::string &own_label, const std::string &own_transport_address, uint32_t num_authorized_signers, uint32_t num_required_signers)
static const char * tr(const char *str)
void process_signer_config(const multisig_wallet_state &state, const std::string &signer_config)
bool get_signer_index_by_label(const std::string label, uint32_t &index) const
void process_auto_config_data_message(uint32_t id)
void set_active(bool active)
bool check_for_messages(const multisig_wallet_state &state, std::vector< message > &messages)
static const char * message_direction_to_string(message_direction direction)
bool get_processable_messages(const multisig_wallet_state &state, bool force_sync, std::vector< processing_data > &data_list, std::string &wait_reason)
bool get_signer_index_by_etn_address(const cryptonote::account_public_address &etn_address, uint32_t &index) const
void send_message(const multisig_wallet_state &state, uint32_t id)
bool check_auto_config_token(const std::string &raw_token, std::string &adjusted_token) const
size_t add_message(const multisig_wallet_state &state, uint32_t signer_index, message_type type, message_direction direction, const std::string &content)
void delete_all_messages()
bool signer_labels_complete() const
size_t add_auto_config_data_message(const multisig_wallet_state &state, const std::string &auto_config_token)
void set_message_processed_or_sent(uint32_t id)
void get_signer_config(std::string &signer_config)
std::string signer_to_string(const authorized_signer &signer, uint32_t max_width)
void write_to_file(const multisig_wallet_state &state, const std::string &filename)
void process_wallet_created_data(const multisig_wallet_state &state, message_type type, const std::string &content)
void set_options(const boost::program_options::variables_map &vm)
static void init_options(boost::program_options::options_description &desc_params)
void start_auto_config(const multisig_wallet_state &state)
static const char * message_state_to_string(message_state state)
void set_signer(const multisig_wallet_state &state, uint32_t index, const boost::optional< std::string > &label, const boost::optional< std::string > &transport_address, const boost::optional< cryptonote::account_public_address > etn_address)
void read_from_file(const multisig_wallet_state &state, const std::string &filename)
bool signer_config_complete() const
const authorized_signer & get_signer(uint32_t index) const
void delete_message(uint32_t id)
void unpack_signer_config(const multisig_wallet_state &state, const std::string &signer_config, std::vector< authorized_signer > &signers)
void get_sanitized_message_text(const message &m, std::string &sanitized_text) const
static const char * message_type_to_string(message_type type)
bool get_message_by_id(uint32_t id, message &m) const
void set_messages_processed(const processing_data &data)
bool delete_message(const std::string &transport_id)
std::string derive_and_receive_transport_address(const std::string &seed)
std::string derive_transport_address(const std::string &seed)
#define AUTO_CONFIG_TOKEN_BYTES
#define AUTO_CONFIG_TOKEN_PREFIX
void add_arg(boost::program_options::options_description &description, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg, bool unique=true)
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
const crypto::public_key null_pkey
void generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig)
std::enable_if< std::is_pod< T >::value, T >::type rand()
const crypto::secret_key null_skey
epee::mlocked< tools::scrubbed< ec_scalar > > secret_key
void cn_fast_hash(const void *data, size_t length, char *hash)
secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key &recovery_key=secret_key(), bool recover=false)
bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation)
bool check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig)
bool secret_key_to_public_key(const secret_key &sec, public_key &pub)
void hash_to_scalar(const void *data, size_t length, ec_scalar &res)
std::string get_account_address_as_str(network_type nettype, bool subaddress, account_public_address const &adr)
bool load_file_to_string(const std::string &path_to_file, std::string &target_str, size_t max_size=1000000000)
bool save_string_to_file(const std::string &path_to_file, const std::string &str)
mdb_size_t count(MDB_cursor *cur)
epee::misc_utils::struct_init< transport_message_t > transport_message
@ process_auto_config_data
unsigned __int64 uint64_t
crypto::public_key m_view_public_key
crypto::secret_key auto_config_secret_key
std::string transport_address
std::string auto_config_token
cryptonote::account_public_address etn_address
crypto::public_key auto_config_public_key
std::string auto_config_transport_address
cryptonote::account_public_address etn_address
std::string transport_address
std::string encrypted_data
message_direction direction
std::vector< uint32_t > message_ids
uint32_t receiving_signer_index
message_processing processing
uint64_t random(const uint64_t max_value)
#define THROW_WALLET_EXCEPTION_IF(cond, err_type,...)
#define THROW_WALLET_EXCEPTION(err_type,...)