Electroneum
mms::message_store Class Reference

#include <message_store.h>

Public Member Functions

 message_store ()
 
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)
 
void set_active (bool active)
 
void set_auto_send (bool auto_send)
 
void set_options (const boost::program_options::variables_map &vm)
 
void set_options (const std::string &bitmessage_address, const epee::wipeable_string &bitmessage_login)
 
bool get_active () const
 
bool get_auto_send () const
 
uint32_t get_num_required_signers () const
 
uint32_t get_num_authorized_signers () const
 
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)
 
const authorized_signerget_signer (uint32_t index) const
 
bool get_signer_index_by_etn_address (const cryptonote::account_public_address &etn_address, uint32_t &index) const
 
bool get_signer_index_by_label (const std::string label, uint32_t &index) const
 
const std::vector< authorized_signer > & get_all_signers () const
 
bool signer_config_complete () const
 
bool signer_labels_complete () const
 
void get_signer_config (std::string &signer_config)
 
void unpack_signer_config (const multisig_wallet_state &state, const std::string &signer_config, std::vector< authorized_signer > &signers)
 
void process_signer_config (const multisig_wallet_state &state, const std::string &signer_config)
 
void start_auto_config (const multisig_wallet_state &state)
 
bool check_auto_config_token (const std::string &raw_token, std::string &adjusted_token) const
 
size_t add_auto_config_data_message (const multisig_wallet_state &state, const std::string &auto_config_token)
 
void process_auto_config_data_message (uint32_t id)
 
void stop_auto_config ()
 
void process_wallet_created_data (const multisig_wallet_state &state, message_type type, const std::string &content)
 
bool get_processable_messages (const multisig_wallet_state &state, bool force_sync, std::vector< processing_data > &data_list, std::string &wait_reason)
 
void set_messages_processed (const processing_data &data)
 
size_t add_message (const multisig_wallet_state &state, uint32_t signer_index, message_type type, message_direction direction, const std::string &content)
 
const std::vector< message > & get_all_messages () const
 
bool get_message_by_id (uint32_t id, message &m) const
 
message get_message_by_id (uint32_t id) const
 
void set_message_processed_or_sent (uint32_t id)
 
void delete_message (uint32_t id)
 
void delete_all_messages ()
 
void get_sanitized_message_text (const message &m, std::string &sanitized_text) const
 
void send_message (const multisig_wallet_state &state, uint32_t id)
 
bool check_for_messages (const multisig_wallet_state &state, std::vector< message > &messages)
 
void stop ()
 
void write_to_file (const multisig_wallet_state &state, const std::string &filename)
 
void read_from_file (const multisig_wallet_state &state, const std::string &filename)
 
template<class t_archive >
void serialize (t_archive &a, const unsigned int ver)
 
std::string signer_to_string (const authorized_signer &signer, uint32_t max_width)
 

Static Public Member Functions

static const char * message_type_to_string (message_type type)
 
static const char * message_direction_to_string (message_direction direction)
 
static const char * message_state_to_string (message_state state)
 
static const char * tr (const char *str)
 
static void init_options (boost::program_options::options_description &desc_params)
 

Detailed Description

Definition at line 202 of file message_store.h.

Constructor & Destructor Documentation

◆ message_store()

mms::message_store::message_store ( )

Definition at line 51 of file message_store.cpp.

52 {
53  m_active = false;
54  m_auto_send = false;
55  m_next_message_id = 1;
56  m_num_authorized_signers = 0;
57  m_num_required_signers = 0;
59  m_run = true;
60 }

Member Function Documentation

◆ add_auto_config_data_message()

size_t mms::message_store::add_auto_config_data_message ( const multisig_wallet_state state,
const std::string &  auto_config_token 
)

Definition at line 345 of file message_store.cpp.

347 {
348  authorized_signer &me = m_signers[0];
349  me.auto_config_token = auto_config_token;
350  setup_signer_for_auto_config(0, auto_config_token, false);
351  me.auto_config_running = true;
352 
353  auto_config_data data;
354  data.label = me.label;
355  data.transport_address = me.transport_address;
356  data.etn_address = me.etn_address;
357 
358  std::stringstream oss;
360  ar << data;
361 
363 }
Definition: blake256.h:37
size_t add_message(const multisig_wallet_state &state, uint32_t signer_index, message_type type, message_direction direction, const std::string &content)
Here is the call graph for this function:

◆ add_message()

size_t mms::message_store::add_message ( const multisig_wallet_state state,
uint32_t  signer_index,
message_type  type,
message_direction  direction,
const std::string &  content 
)

Definition at line 514 of file message_store.cpp.

517 {
518  message m;
519  m.id = m_next_message_id++;
520  m.type = type;
521  m.direction = direction;
522  m.content = content;
523  m.created = (uint64_t)time(NULL);
524  m.modified = m.created;
525  m.sent = 0;
526  m.signer_index = signer_index;
527  if (direction == message_direction::out)
528  {
530  }
531  else
532  {
533  m.state = message_state::waiting;
534  };
535  m.wallet_height = (uint32_t)state.num_transfer_details;
537  {
538  m.round = state.multisig_rounds_passed;
539  }
540  else
541  {
542  m.round = 0;
543  }
544  m.signature_count = 0; // Future expansion for signature counting when signing txs
545  m.hash = crypto::null_hash;
546  m_messages.push_back(m);
547 
548  // Save for every new message right away (at least while in beta)
549  save(state);
550 
551  MINFO(boost::format("Added %s message %s for signer %s of type %s")
552  % message_direction_to_string(direction) % m.id % signer_index % message_type_to_string(type));
553  return m_messages.size() - 1;
554 }
#define MINFO(x)
Definition: misc_log_ex.h:75
static const char * message_direction_to_string(message_direction direction)
time_t time
Definition: blockchain.cpp:93
unsigned int uint32_t
Definition: stdint.h:126
unsigned __int64 uint64_t
Definition: stdint.h:136
static const char * message_type_to_string(message_type type)
std::string message("Message requiring signing")
Definition: blake256.h:37
else if(0==res)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_auto_config_token()

bool mms::message_store::check_auto_config_token ( const std::string &  raw_token,
std::string &  adjusted_token 
) const

Definition at line 276 of file message_store.cpp.

278 {
280  uint32_t num_hex_digits = (AUTO_CONFIG_TOKEN_BYTES + 1) * 2;
281  uint32_t full_length = num_hex_digits + prefix.length();
282  uint32_t raw_length = raw_token.length();
283  std::string hex_digits;
284 
285  if (raw_length == full_length)
286  {
287  // Prefix must be there; accept it in any casing
288  std::string raw_prefix(raw_token.substr(0, 3));
289  boost::algorithm::to_lower(raw_prefix);
290  if (raw_prefix != prefix)
291  {
292  return false;
293  }
294  hex_digits = raw_token.substr(3);
295  }
296  else if (raw_length == num_hex_digits)
297  {
298  // Accept the token without the prefix if it's otherwise ok
299  hex_digits = raw_token;
300  }
301  else
302  {
303  return false;
304  }
305 
306  // Convert to strict lowercase and correct any common misspellings
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');
311 
312  // Now it must be correct hex with correct checksum, no further tolerance possible
313  std::string token_bytes;
314  if (!epee::string_tools::parse_hexstr_to_binbuff(hex_digits, token_bytes))
315  {
316  return false;
317  }
318  const crypto::hash &hash = crypto::cn_fast_hash(token_bytes.data(), token_bytes.size() - 1);
319  if (token_bytes[AUTO_CONFIG_TOKEN_BYTES] != hash.data[0])
320  {
321  return false;
322  }
323  adjusted_token = prefix + hex_digits;
324  return true;
325 }
::std::string string
Definition: gtest-port.h:1097
unsigned int uint32_t
Definition: stdint.h:126
void cn_fast_hash(const void *data, size_t length, char *hash)
#define AUTO_CONFIG_TOKEN_PREFIX
Definition: message_store.h:51
#define AUTO_CONFIG_TOKEN_BYTES
Definition: message_store.h:50
POD_CLASS hash
Definition: hash.h:50
bool parse_hexstr_to_binbuff(const epee::span< const char > s, epee::span< char > &res)
Definition: string_tools.h:92

◆ check_for_messages()

bool mms::message_store::check_for_messages ( const multisig_wallet_state state,
std::vector< message > &  messages 
)

Definition at line 1244 of file message_store.cpp.

1245 {
1246  m_run.store(true, std::memory_order_relaxed);
1247  const authorized_signer &me = m_signers[0];
1248  std::vector<std::string> destinations;
1249  destinations.push_back(me.transport_address);
1250  for (uint32_t i = 1; i < m_num_authorized_signers; ++i)
1251  {
1252  const authorized_signer &m = m_signers[i];
1253  if (m.auto_config_running)
1254  {
1255  destinations.push_back(m.auto_config_transport_address);
1256  }
1257  }
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))
1261  {
1262  // Stop was called, don't waste time processing the messages
1263  // (but once started processing them, don't react to stop request anymore, avoid receiving them "partially)"
1264  return false;
1265  }
1266 
1267  bool new_messages = false;
1268  for (size_t i = 0; i < transport_messages.size(); ++i)
1269  {
1270  transport_message &rm = transport_messages[i];
1271  if (any_message_with_hash(rm.hash))
1272  {
1273  // Already seen, do not take again
1274  }
1275  else
1276  {
1277  uint32_t sender_index;
1278  bool take = false;
1279  message_type type = static_cast<message_type>(rm.type);
1280  crypto::secret_key decrypt_key = state.view_secret_key;
1281  if (type == message_type::auto_config_data)
1282  {
1283  // Find out which signer sent it by checking which auto config transport address
1284  // the message was sent to
1285  for (uint32_t i = 1; i < m_num_authorized_signers; ++i)
1286  {
1287  const authorized_signer &m = m_signers[i];
1288  if (m.auto_config_transport_address == rm.destination_transport_address)
1289  {
1290  take = true;
1291  sender_index = i;
1292  decrypt_key = m.auto_config_secret_key;
1293  break;
1294  }
1295  }
1296  }
1297  else if (type == message_type::signer_config)
1298  {
1299  // Typically we can't check yet whether we know the sender, so take from any
1300  // and pretend it's from "me" because we might have nothing else yet
1301  take = true;
1302  sender_index = 0;
1303  }
1304  else
1305  {
1306  // Only accept from senders that are known as signer here, otherwise just ignore
1307  take = get_signer_index_by_etn_address(rm.source_etn_address, sender_index);
1308  }
1309  if (take && (type != message_type::auto_config_data))
1310  {
1311  // If the destination address is known, check it as well; this additional filter
1312  // allows using the same transport address for multiple signers
1313  take = rm.destination_etn_address == me.etn_address;
1314  }
1315  if (take)
1316  {
1317  crypto::hash actual_hash = crypto::cn_fast_hash(rm.content.data(), rm.content.size());
1318  THROW_WALLET_EXCEPTION_IF(actual_hash != rm.hash, tools::error::wallet_internal_error, "Message hash mismatch");
1319 
1320  bool signature_valid = crypto::check_signature(actual_hash, rm.source_etn_address.m_view_public_key, rm.signature);
1321  THROW_WALLET_EXCEPTION_IF(!signature_valid, tools::error::wallet_internal_error, "Message signature not valid");
1322 
1323  std::string plaintext;
1324  decrypt(rm.content, rm.encryption_public_key, rm.iv, decrypt_key, plaintext);
1325  size_t index = add_message(state, sender_index, (message_type)rm.type, message_direction::in, plaintext);
1326  message &m = m_messages[index];
1327  m.hash = rm.hash;
1328  m.transport_id = rm.transport_id;
1329  m.sent = rm.timestamp;
1330  m.round = rm.round;
1331  m.signature_count = rm.signature_count;
1332  messages.push_back(m);
1333  new_messages = true;
1334  }
1335  }
1336  }
1337  return new_messages;
1338 }
message_type
Definition: message_store.h:55
::std::string string
Definition: gtest-port.h:1097
unsigned int uint32_t
Definition: stdint.h:126
bool get_signer_index_by_etn_address(const cryptonote::account_public_address &etn_address, uint32_t &index) const
void cn_fast_hash(const void *data, size_t length, char *hash)
std::string message("Message requiring signing")
Definition: blake256.h:37
#define THROW_WALLET_EXCEPTION_IF(cond, err_type,...)
epee::misc_utils::struct_init< transport_message_t > transport_message
crypto::secret_key decrypt_key(crypto::secret_key key, const epee::wipeable_string &passphrase)
POD_CLASS hash
Definition: hash.h:50
bool receive_messages(const std::vector< std::string > &destination_transport_addresses, std::vector< transport_message > &messages)
size_t add_message(const multisig_wallet_state &state, uint32_t signer_index, message_type type, message_direction direction, const std::string &content)
bool check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig)
Definition: crypto.h:295
Here is the call graph for this function:

◆ delete_all_messages()

void mms::message_store::delete_all_messages ( )

Definition at line 663 of file message_store.cpp.

664 {
665  for (size_t i = 0; i < m_messages.size(); ++i)
666  {
667  delete_transport_message(m_messages[i].id);
668  }
669  m_messages.clear();
670 }

◆ delete_message()

void mms::message_store::delete_message ( uint32_t  id)

Definition at line 656 of file message_store.cpp.

657 {
658  delete_transport_message(id);
659  size_t index = get_message_index_by_id(id);
660  m_messages.erase(m_messages.begin() + index);
661 }

◆ get_active()

bool mms::message_store::get_active ( ) const
inline

Definition at line 215 of file message_store.h.

215 { return m_active; };

◆ get_all_messages()

const std::vector<message>& mms::message_store::get_all_messages ( ) const
inline

Definition at line 270 of file message_store.h.

270 { return m_messages; };

◆ get_all_signers()

const std::vector<authorized_signer>& mms::message_store::get_all_signers ( ) const
inline

Definition at line 229 of file message_store.h.

229 { return m_signers; };

◆ get_auto_send()

bool mms::message_store::get_auto_send ( ) const
inline

Definition at line 216 of file message_store.h.

216 { return m_auto_send; };

◆ get_message_by_id() [1/2]

bool mms::message_store::get_message_by_id ( uint32_t  id,
message m 
) const

Definition at line 588 of file message_store.cpp.

589 {
590  size_t index;
591  bool found = get_message_index_by_id(id, index);
592  if (found)
593  {
594  m = m_messages[index];
595  }
596  return found;
597 }
Here is the caller graph for this function:

◆ get_message_by_id() [2/2]

message mms::message_store::get_message_by_id ( uint32_t  id) const

Definition at line 600 of file message_store.cpp.

601 {
602  message m;
603  bool found = get_message_by_id(id, m);
605  return m;
606 }
std::string message("Message requiring signing")
#define THROW_WALLET_EXCEPTION_IF(cond, err_type,...)
bool get_message_by_id(uint32_t id, message &m) const
std::string to_string(t_connection_type type)
Here is the call graph for this function:

◆ get_num_authorized_signers()

uint32_t mms::message_store::get_num_authorized_signers ( ) const
inline

Definition at line 218 of file message_store.h.

218 { return m_num_authorized_signers; };

◆ get_num_required_signers()

uint32_t mms::message_store::get_num_required_signers ( ) const
inline

Definition at line 217 of file message_store.h.

217 { return m_num_required_signers; };

◆ get_processable_messages()

bool mms::message_store::get_processable_messages ( const multisig_wallet_state state,
bool  force_sync,
std::vector< processing_data > &  data_list,
std::string &  wait_reason 
)

Definition at line 790 of file message_store.cpp.

792 {
793  uint32_t wallet_height = (uint32_t)state.num_transfer_details;
794  data_list.clear();
795  wait_reason.clear();
796  // In all scans over all messages looking for complete sets (1 message for each signer),
797  // if there are duplicates, the OLDEST of them is taken. This may not play a role with
798  // any of the current message types, but may with future ones, and it's probably a good
799  // idea to have a clear and somewhat defensive strategy.
800 
801  std::vector<uint32_t> auto_config_messages(m_num_authorized_signers, 0);
802  bool any_auto_config = false;
803 
804  for (size_t i = 0; i < m_messages.size(); ++i)
805  {
806  message &m = m_messages[i];
807  if ((m.type == message_type::auto_config_data) && (m.state == message_state::waiting))
808  {
809  if (auto_config_messages[m.signer_index] == 0)
810  {
811  auto_config_messages[m.signer_index] = m.id;
812  any_auto_config = true;
813  }
814  // else duplicate auto config data, ignore
815  }
816  }
817 
818  if (any_auto_config)
819  {
820  bool auto_config_complete = message_ids_complete(auto_config_messages);
821  if (auto_config_complete)
822  {
823  processing_data data;
825  data.message_ids = auto_config_messages;
826  data.message_ids.erase(data.message_ids.begin());
827  data_list.push_back(data);
828  return true;
829  }
830  else
831  {
832  wait_reason = tr("Auto-config cannot proceed because auto config data from other signers is not complete");
833  return false;
834  // With ANY auto config data present but not complete refuse to check for any
835  // other processing. Manually delete those messages to abort such an auto config
836  // phase if needed.
837  }
838  }
839 
840  // Any signer config that arrived will be processed right away, regardless of other things that may wait
841  for (size_t i = 0; i < m_messages.size(); ++i)
842  {
843  message &m = m_messages[i];
844  if ((m.type == message_type::signer_config) && (m.state == message_state::waiting))
845  {
846  processing_data data;
848  data.message_ids.push_back(m.id);
849  data_list.push_back(data);
850  return true;
851  }
852  }
853 
854  // ALL of the following processings depend on the signer info being complete
855  if (!signer_config_complete())
856  {
857  wait_reason = tr("The signer config is not complete.");
858  return false;
859  }
860 
861  if (!state.multisig)
862  {
863 
864  if (!any_message_of_type(message_type::key_set, message_direction::out))
865  {
866  // With the own key set not yet ready we must do "prepare_multisig" first;
867  // Key sets from other signers may be here already, but if we process them now
868  // the wallet will go multisig too early: we can't produce our own key set any more!
869  processing_data data;
870  data.processing = message_processing::prepare_multisig;
871  data_list.push_back(data);
872  return true;
873  }
874 
875  // Ids of key set messages per signer index, to check completeness
876  // Naturally, does not care about the order of the messages and is trivial to secure against
877  // key sets that were received more than once
878  // With full M/N multisig now possible consider only key sets of the right round, i.e.
879  // with not yet multisig the only possible round 0
880  std::vector<uint32_t> key_set_messages(m_num_authorized_signers, 0);
881 
882  for (size_t i = 0; i < m_messages.size(); ++i)
883  {
884  message &m = m_messages[i];
885  if ((m.type == message_type::key_set) && (m.state == message_state::waiting)
886  && (m.round == 0))
887  {
888  if (key_set_messages[m.signer_index] == 0)
889  {
890  key_set_messages[m.signer_index] = m.id;
891  }
892  // else duplicate key set, ignore
893  }
894  }
895 
896  bool key_sets_complete = message_ids_complete(key_set_messages);
897  if (key_sets_complete)
898  {
899  // Nothing else can be ready to process earlier than this, ignore everything else and give back
900  processing_data data;
901  data.processing = message_processing::make_multisig;
902  data.message_ids = key_set_messages;
903  data.message_ids.erase(data.message_ids.begin());
904  data_list.push_back(data);
905  return true;
906  }
907  else
908  {
909  wait_reason = tr("Wallet can't go multisig because key sets from other signers are missing or not complete.");
910  return false;
911  }
912  }
913 
914  if (state.multisig && !state.multisig_is_ready)
915  {
916  // In the case of M/N multisig the call 'wallet2::multisig' returns already true
917  // after "make_multisig" but with calls to "exchange_multisig_keys" still needed, and
918  // sets the parameter 'ready' to false to document this particular "in-between" state.
919  // So what may be possible here, with all necessary messages present, is a call to
920  // "exchange_multisig_keys".
921  // Consider only messages belonging to the next round to do, which has the number
922  // "state.multisig_rounds_passed".
923  std::vector<uint32_t> additional_key_set_messages(m_num_authorized_signers, 0);
924 
925  for (size_t i = 0; i < m_messages.size(); ++i)
926  {
927  message &m = m_messages[i];
928  if ((m.type == message_type::additional_key_set) && (m.state == message_state::waiting)
929  && (m.round == state.multisig_rounds_passed))
930  {
931  if (additional_key_set_messages[m.signer_index] == 0)
932  {
933  additional_key_set_messages[m.signer_index] = m.id;
934  }
935  // else duplicate key set, ignore
936  }
937  }
938 
939  bool key_sets_complete = message_ids_complete(additional_key_set_messages);
940  if (key_sets_complete)
941  {
942  processing_data data;
944  data.message_ids = additional_key_set_messages;
945  data.message_ids.erase(data.message_ids.begin());
946  data_list.push_back(data);
947  return true;
948  }
949  else
950  {
951  wait_reason = tr("Wallet can't start another key exchange round because key sets from other signers are missing or not complete.");
952  return false;
953  }
954  }
955 
956  // Properly exchanging multisig sync data is easiest and most transparent
957  // for the user if a wallet sends its own data first and processes any received
958  // sync data afterwards so that's the order that the MMS enforces here.
959  // (Technically, it seems to work also the other way round.)
960  //
961  // To check whether a NEW round of syncing is necessary the MMS works with a
962  // "wallet state": new state means new syncing needed.
963  //
964  // The MMS monitors the "wallet state" by recording "wallet heights" as
965  // numbers of transfers present in a wallet at the time of message creation. While
966  // not watertight, this quite simple scheme should already suffice to trigger
967  // and orchestrate a sensible exchange of sync data.
968  if (state.has_multisig_partial_key_images || force_sync)
969  {
970  // Sync is necessary and not yet completed: Processing of transactions
971  // will only be possible again once properly synced
972  // Check first whether we generated already OUR sync info; take note of
973  // any processable sync info from other signers on the way in case we need it
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)
977  {
978  message &m = m_messages[i];
979  if ((m.type == message_type::multisig_sync_data) && (force_sync || (m.wallet_height == wallet_height)))
980  // It's data for the same "round" of syncing, on the same "wallet height", therefore relevant
981  // With "force_sync" take ANY waiting sync data, maybe it will work out
982  {
983  if (m.direction == message_direction::out)
984  {
985  own_sync_data_created = true;
986  // Ignore whether sent already or not, and assume as complete if several other signers there
987  }
988  else if ((m.direction == message_direction::in) && (m.state == message_state::waiting))
989  {
990  if (sync_messages[m.signer_index] == 0)
991  {
992  sync_messages[m.signer_index] = m.id;
993  }
994  // else duplicate sync message, ignore
995  }
996  }
997  }
998  if (!own_sync_data_created)
999  {
1000  // As explained above, creating sync data BEFORE processing such data from
1001  // other signers reliably works, so insist on that here
1002  processing_data data;
1003  data.processing = message_processing::create_sync_data;
1004  data_list.push_back(data);
1005  return true;
1006  }
1007  uint32_t id_count = (uint32_t)get_other_signers_id_count(sync_messages);
1008  // Do we have sync data from ALL other signers?
1009  bool all_sync_data = id_count == (m_num_authorized_signers - 1);
1010  // Do we have just ENOUGH sync data to have a minimal viable sync set?
1011  // In cases like 2/3 multisig we don't need messages from ALL other signers, only
1012  // from enough of them i.e. num_required_signers minus 1 messages
1013  bool enough_sync_data = id_count >= (m_num_required_signers - 1);
1014  bool sync = false;
1015  wait_reason = tr("Syncing not done because multisig sync data from other signers are missing or not complete.");
1016  if (all_sync_data)
1017  {
1018  sync = true;
1019  }
1020  else if (enough_sync_data)
1021  {
1022  if (force_sync)
1023  {
1024  sync = true;
1025  }
1026  else
1027  {
1028  // Don't sync, but give a hint how this minimal set COULD be synced if really wanted
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();
1031  }
1032  }
1033  if (sync)
1034  {
1035  processing_data data;
1036  data.processing = message_processing::process_sync_data;
1037  for (size_t i = 0; i < sync_messages.size(); ++i)
1038  {
1039  uint32_t id = sync_messages[i];
1040  if (id != 0)
1041  {
1042  data.message_ids.push_back(id);
1043  }
1044  }
1045  data_list.push_back(data);
1046  return true;
1047  }
1048  else
1049  {
1050  // We can't proceed to any transactions until we have synced; "wait_reason" already set above
1051  return false;
1052  }
1053  }
1054 
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)
1059  {
1060  message &m = m_messages[i];
1061  if (m.state == message_state::waiting)
1062  {
1063  waiting_found = true;
1064  switch (m.type)
1065  {
1067  {
1068  // We can either submit it ourselves, or send it to any other signer for submission
1069  processing_data data;
1070  data.processing = message_processing::submit_tx;
1071  data.message_ids.push_back(m.id);
1072  data_list.push_back(data);
1073 
1074  data.processing = message_processing::send_tx;
1075  for (uint32_t j = 1; j < m_num_authorized_signers; ++j)
1076  {
1077  data.receiving_signer_index = j;
1078  data_list.push_back(data);
1079  }
1080  return true;
1081  }
1082 
1084  {
1085  if (m.signer_index == 0)
1086  {
1087  // We started this ourselves, or signed it but with still signatures missing:
1088  // We can send it to any other signer for signing / further signing
1089  // In principle it does not make sense to send it back to somebody who
1090  // already signed, but the MMS does not / not yet keep track of that,
1091  // because that would be somewhat complicated.
1092  processing_data data;
1093  data.processing = message_processing::send_tx;
1094  data.message_ids.push_back(m.id);
1095  for (uint32_t j = 1; j < m_num_authorized_signers; ++j)
1096  {
1097  data.receiving_signer_index = j;
1098  data_list.push_back(data);
1099  }
1100  return true;
1101  }
1102  else
1103  {
1104  // Somebody else sent this to us: We can sign it
1105  // It would be possible to just pass it on, but that's not directly supported here
1106  processing_data data;
1107  data.processing = message_processing::sign_tx;
1108  data.message_ids.push_back(m.id);
1109  data_list.push_back(data);
1110  return true;
1111  }
1112  }
1113 
1114  case message_type::note:
1115  note_found = true;
1116  break;
1117 
1119  sync_data_found = true;
1120  break;
1121 
1122  default:
1123  break;
1124  }
1125  }
1126  }
1127  if (waiting_found)
1128  {
1129  wait_reason = tr("There are waiting messages, but nothing is ready to process under normal circumstances");
1130  if (sync_data_found)
1131  {
1132  wait_reason += tr("\nUse \"mms next sync\" if you want to force processing of the waiting sync data");
1133  }
1134  if (note_found)
1135  {
1136  wait_reason += tr("\nUse \"mms note\" to display the waiting notes");
1137  }
1138  }
1139  else
1140  {
1141  wait_reason = tr("There are no messages waiting to be processed.");
1142  }
1143 
1144  return false;
1145 }
static const char * tr(const char *str)
unsigned int uint32_t
Definition: stdint.h:126
std::string message("Message requiring signing")
Definition: blake256.h:37
bool signer_config_complete() const
Here is the call graph for this function:

◆ get_sanitized_message_text()

void mms::message_store::get_sanitized_message_text ( const message m,
std::string &  sanitized_text 
) const

Definition at line 674 of file message_store.cpp.

675 {
676  sanitized_text.clear();
677 
678  // Restrict the size to fend of DOS-style attacks with heaps of data
679  size_t length = std::min(m.content.length(), (size_t)1000);
680 
681  for (size_t i = 0; i < length; ++i)
682  {
683  char c = m.content[i];
684  if ((int)c < 32)
685  {
686  // Strip out any controls, especially ESC for getting rid of potentially dangerous
687  // ANSI escape sequences that a console window might interpret
688  c = ' ';
689  }
690  else if ((c == '<') || (c == '>'))
691  {
692  // Make XML or HTML impossible that e.g. might contain scripts that Qt might execute
693  // when displayed in the GUI wallet
694  c = ' ';
695  }
696  sanitized_text += c;
697  }
698 }

◆ get_signer()

const authorized_signer & mms::message_store::get_signer ( uint32_t  index) const

Definition at line 147 of file message_store.cpp.

148 {
149  THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + std::to_string(index));
150  return m_signers[index];
151 }
#define THROW_WALLET_EXCEPTION_IF(cond, err_type,...)
std::string to_string(t_connection_type type)
Here is the call graph for this function:

◆ get_signer_config()

void mms::message_store::get_signer_config ( std::string &  signer_config)

Definition at line 181 of file message_store.cpp.

182 {
183  std::stringstream oss;
185  ar << m_signers;
186  signer_config = oss.str();
187 }

◆ get_signer_index_by_etn_address()

bool mms::message_store::get_signer_index_by_etn_address ( const cryptonote::account_public_address etn_address,
uint32_t index 
) const

Definition at line 442 of file message_store.cpp.

443 {
444  for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
445  {
446  const authorized_signer &m = m_signers[i];
447  if (m.etn_address == etn_address)
448  {
449  index = m.index;
450  return true;
451  }
452  }
453  MWARNING("No authorized signer with Electroneum address " << account_address_to_string(etn_address));
454  return false;
455 }
unsigned int uint32_t
Definition: stdint.h:126
#define MWARNING(x)
Definition: misc_log_ex.h:74
Here is the caller graph for this function:

◆ get_signer_index_by_label()

bool mms::message_store::get_signer_index_by_label ( const std::string  label,
uint32_t index 
) const

Definition at line 457 of file message_store.cpp.

458 {
459  for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
460  {
461  const authorized_signer &m = m_signers[i];
462  if (m.label == label)
463  {
464  index = m.index;
465  return true;
466  }
467  }
468  MWARNING("No authorized signer with label " << label);
469  return false;
470 }
unsigned int uint32_t
Definition: stdint.h:126
#define MWARNING(x)
Definition: misc_log_ex.h:74

◆ init()

void mms::message_store::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 
)

Definition at line 81 of file message_store.cpp.

83 {
84  m_num_authorized_signers = num_authorized_signers;
85  m_num_required_signers = num_required_signers;
86  m_signers.clear();
87  m_messages.clear();
88  m_next_message_id = 1;
89 
90  // The vector "m_signers" gets here once the required number of elements, one for each authorized signer,
91  // and is never changed again. The rest of the code relies on "size(m_signers) == m_num_authorized_signers"
92  // without further checks.
93  authorized_signer signer;
94  for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
95  {
96  signer.me = signer.index == 0; // Strict convention: The very first signer is fixed as / must be "me"
97  m_signers.push_back(signer);
98  signer.index++;
99  }
100 
101  set_signer(state, 0, own_label, own_transport_address, state.address);
102 
103  m_nettype = state.nettype;
104  set_active(true);
105  m_filename = state.mms_file;
106  save(state);
107 }
unsigned int uint32_t
Definition: stdint.h:126
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)
Definition: blake256.h:37
void set_active(bool active)
Here is the call graph for this function:

◆ init_options()

void mms::message_store::init_options ( boost::program_options::options_description &  desc_params)
static

Definition at line 74 of file message_store.cpp.

75 {
76  const options opts{};
77  command_line::add_arg(desc_params, opts.bitmessage_address);
78  command_line::add_arg(desc_params, opts.bitmessage_login);
79 }
void add_arg(boost::program_options::options_description &description, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg, bool unique=true)
Definition: command_line.h:188
Here is the call graph for this function:
Here is the caller graph for this function:

◆ message_direction_to_string()

const char * mms::message_store::message_direction_to_string ( message_direction  direction)
static

Definition at line 1379 of file message_store.cpp.

1380 {
1381  switch (direction)
1382  {
1383  case message_direction::in:
1384  return tr("in");
1386  return tr("out");
1387  default:
1388  return tr("unknown message direction");
1389  }
1390 }
static const char * tr(const char *str)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ message_state_to_string()

const char * mms::message_store::message_state_to_string ( message_state  state)
static

Definition at line 1392 of file message_store.cpp.

1393 {
1394  switch (state)
1395  {
1397  return tr("ready to send");
1398  case message_state::sent:
1399  return tr("sent");
1401  return tr("waiting");
1403  return tr("processed");
1405  return tr("cancelled");
1406  default:
1407  return tr("unknown message state");
1408  }
1409 }
static const char * tr(const char *str)
Definition: blake256.h:37
Here is the call graph for this function:

◆ message_type_to_string()

const char * mms::message_store::message_type_to_string ( message_type  type)
static

Definition at line 1354 of file message_store.cpp.

1355 {
1356  switch (type)
1357  {
1358  case message_type::key_set:
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");
1368  case message_type::note:
1369  return tr("note");
1371  return tr("signer config");
1373  return tr("auto-config data");
1374  default:
1375  return tr("unknown message type");
1376  }
1377 }
static const char * tr(const char *str)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_auto_config_data_message()

void mms::message_store::process_auto_config_data_message ( uint32_t  id)

Definition at line 366 of file message_store.cpp.

367 {
368  // "auto_config_data" contains the label that the auto-config data sender uses for "me", but that's
369  // more for completeness' sake, and right now it's not used. In general, the auto-config manager
370  // decides/defines the labels, and right after completing auto-config ALL wallets use the SAME labels.
371 
372  const message &m = get_message_ref_by_id(id);
373 
374  auto_config_data data;
375  try
376  {
377  std::stringstream iss;
378  iss << m.content;
380  ar >> data;
381  }
382  catch (...)
383  {
384  THROW_WALLET_EXCEPTION_IF(true, tools::error::wallet_internal_error, "Invalid structure of auto config data");
385  }
386 
387  authorized_signer &signer = m_signers[m.signer_index];
388  // "signer.label" does NOT change, see comment above
389  signer.transport_address = data.transport_address;
390  signer.etn_address_known = true;
391  signer.etn_address = data.etn_address;
392  signer.auto_config_running = false;
393 }
std::string message("Message requiring signing")
#define THROW_WALLET_EXCEPTION_IF(cond, err_type,...)

◆ process_signer_config()

void mms::message_store::process_signer_config ( const multisig_wallet_state state,
const std::string &  signer_config 
)

Definition at line 207 of file message_store.cpp.

208 {
209  // The signers in "signer_config" and the resident wallet signers are matched not by label, but
210  // by Electroneum address, and ALL labels will be set from "signer_config", even the "me" label.
211  // In the auto-config process as implemented now the auto-config manager is responsible for defining
212  // the labels, and right at the end of the process ALL wallets use the SAME labels. The idea behind this
213  // is preventing problems like duplicate labels and confusion (Bob choosing a label "IamAliceHonest").
214  // (Of course signers are free to re-define any labels they don't like AFTER auto-config.)
215  //
216  // Usually this method will be called with only the "me" signer defined in the wallet, and may
217  // produce unexpected behaviour if that wallet contains additional signers that have nothing to do with
218  // those arriving in "signer_config".
219  std::vector<authorized_signer> signers;
221 
222  uint32_t new_index = 1;
223  for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
224  {
225  const authorized_signer &m = signers[i];
226  uint32_t index;
227  uint32_t take_index;
228  bool found = get_signer_index_by_etn_address(m.etn_address, index);
229  if (found)
230  {
231  // Redefine existing (probably "me", under usual circumstances)
232  take_index = index;
233  }
234  else
235  {
236  // Add new; neglect that we may erroneously overwrite already defined signers
237  // (but protect "me")
238  take_index = new_index;
239  if ((new_index + 1) < m_num_authorized_signers)
240  {
241  new_index++;
242  }
243  }
244  authorized_signer &modify = m_signers[take_index];
245  modify.label = m.label; // ALWAYS set label, see comments above
246  if (!modify.me)
247  {
248  modify.transport_address = m.transport_address;
249  modify.etn_address_known = m.etn_address_known;
250  if (m.etn_address_known)
251  {
252  modify.etn_address = m.etn_address;
253  }
254  }
255  }
256  save(state);
257 }
void unpack_signer_config(const multisig_wallet_state &state, const std::string &signer_config, std::vector< authorized_signer > &signers)
unsigned int uint32_t
Definition: stdint.h:126
bool get_signer_index_by_etn_address(const cryptonote::account_public_address &etn_address, uint32_t &index) const
Definition: blake256.h:37
Here is the call graph for this function:

◆ process_wallet_created_data()

void mms::message_store::process_wallet_created_data ( const multisig_wallet_state state,
message_type  type,
const std::string &  content 
)

Definition at line 472 of file message_store.cpp.

473 {
474  switch(type)
475  {
477  // Result of a "prepare_multisig" command in the wallet
478  // Send the key set to all other signers
480  // Result of a "make_multisig" command or a "exchange_multisig_keys" in the wallet in case of M/N multisig
481  // Send the additional key set to all other signers
483  // Result of a "export_multisig_info" command in the wallet
484  // Send the sync data to all other signers
485  for (uint32_t i = 1; i < m_num_authorized_signers; ++i)
486  {
487  add_message(state, i, type, message_direction::out, content);
488  }
489  break;
490 
492  // Result of a "transfer" command in the wallet, or a "sign_multisig" command
493  // that did not yet result in the minimum number of signatures required
494  // Create a message "from me to me" as a container for the tx data
495  if (m_num_required_signers == 1)
496  {
497  // Probably rare, but possible: The 1 signature is already enough, correct the type
498  // Easier to correct here than asking all callers to detect this rare special case
500  }
501  add_message(state, 0, type, message_direction::in, content);
502  break;
503 
505  add_message(state, 0, type, message_direction::in, content);
506  break;
507 
508  default:
510  break;
511  }
512 }
unsigned int uint32_t
Definition: stdint.h:126
Definition: blake256.h:37
#define THROW_WALLET_EXCEPTION(err_type,...)
std::string to_string(t_connection_type type)
size_t add_message(const multisig_wallet_state &state, uint32_t signer_index, message_type type, message_direction direction, const std::string &content)
Here is the call graph for this function:

◆ read_from_file()

void mms::message_store::read_from_file ( const multisig_wallet_state state,
const std::string &  filename 
)

Definition at line 727 of file message_store.cpp.

728 {
729  boost::system::error_code ignored_ec;
730  bool file_exists = boost::filesystem::exists(filename, ignored_ec);
731  if (!file_exists)
732  {
733  // Simply do nothing if the file is not there; allows e.g. easy recovery
734  // from problems with the MMS by deleting the file
735  MERROR("No message store file found: " << filename);
736  return;
737  }
738 
742 
743  file_data read_file_data;
744  try
745  {
746  std::stringstream iss;
747  iss << buf;
749  ar >> read_file_data;
750  }
751  catch (const std::exception &e)
752  {
753  MERROR("MMS file " << filename << " has bad structure <iv,encrypted_data>: " << e.what());
755  }
756 
757  crypto::chacha_key key;
758  crypto::generate_chacha_key(&state.view_secret_key, sizeof(crypto::secret_key), key, 1);
759  std::string decrypted_data;
760  decrypted_data.resize(read_file_data.encrypted_data.size());
761  crypto::chacha20(read_file_data.encrypted_data.data(), read_file_data.encrypted_data.size(), key, read_file_data.iv, &decrypted_data[0]);
762 
763  try
764  {
765  std::stringstream iss;
766  iss << decrypted_data;
768  ar >> *this;
769  }
770  catch (const std::exception &e)
771  {
772  MERROR("MMS file " << filename << " has bad structure: " << e.what());
774  }
775 
776  m_filename = filename;
777 }
#define MERROR(x)
Definition: misc_log_ex.h:73
::std::string string
Definition: gtest-port.h:1097
void chacha20(const void *data, size_t length, const uint8_t *key, const uint8_t *iv, char *cipher)
const char * key
Definition: hmac_keccak.cpp:39
bool load_file_to_string(const std::string &path_to_file, std::string &target_str, size_t max_size=1000000000)
const char * buf
Definition: slow_memmem.cpp:74
expect< void > success() noexcept
Definition: expect.h:397
Definition: blake256.h:37
#define THROW_WALLET_EXCEPTION_IF(cond, err_type,...)
file_error_base< file_exists_message_index > file_exists
Here is the call graph for this function:

◆ send_message()

void mms::message_store::send_message ( const multisig_wallet_state state,
uint32_t  id 
)

Definition at line 1202 of file message_store.cpp.

1203 {
1204  message &m = get_message_ref_by_id(id);
1205  const authorized_signer &me = m_signers[0];
1206  const authorized_signer &receiver = m_signers[m.signer_index];
1207  transport_message dm;
1209 
1210  dm.timestamp = (uint64_t)time(NULL);
1211  dm.subject = "MMS V0 " + tools::get_human_readable_timestamp(dm.timestamp);
1212  dm.source_transport_address = me.transport_address;
1213  dm.source_etn_address = me.etn_address;
1214  if (m.type == message_type::auto_config_data)
1215  {
1216  // Encrypt with the public key derived from the auto-config token, and send to the
1217  // transport address likewise derived from that token
1218  public_key = me.auto_config_public_key;
1219  dm.destination_transport_address = me.auto_config_transport_address;
1220  // The destination Electroneum address is not yet known
1221  memset(&dm.destination_etn_address, 0, sizeof(cryptonote::account_public_address));
1222  }
1223  else
1224  {
1225  // Encrypt with the receiver's view public key
1226  public_key = receiver.etn_address.m_view_public_key;
1227  const authorized_signer &receiver = m_signers[m.signer_index];
1228  dm.destination_etn_address = receiver.etn_address;
1229  dm.destination_transport_address = receiver.transport_address;
1230  }
1231  encrypt(public_key, m.content, dm.content, dm.encryption_public_key, dm.iv);
1232  dm.type = (uint32_t)m.type;
1233  dm.hash = crypto::cn_fast_hash(dm.content.data(), dm.content.size());
1234  dm.round = m.round;
1235 
1236  crypto::generate_signature(dm.hash, me.etn_address.m_view_public_key, state.view_secret_key, dm.signature);
1237 
1238  m_transporter.send_message(dm);
1239 
1240  m.state=message_state::sent;
1241  m.sent= (uint64_t)time(NULL);
1242 }
void generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig)
Definition: crypto.h:292
time_t time
Definition: blockchain.cpp:93
unsigned int uint32_t
Definition: stdint.h:126
unsigned __int64 uint64_t
Definition: stdint.h:136
POD_CLASS public_key
Definition: crypto.h:76
void cn_fast_hash(const void *data, size_t length, char *hash)
std::string message("Message requiring signing")
Definition: blake256.h:37
bool send_message(const transport_message &message)
epee::misc_utils::struct_init< transport_message_t > transport_message
std::string get_human_readable_timestamp(uint64_t ts)
Definition: util.cpp:1077
Here is the call graph for this function:

◆ serialize()

template<class t_archive >
void mms::message_store::serialize ( t_archive &  a,
const unsigned int  ver 
)
inline

Definition at line 286 of file message_store.h.

287  {
288  a & m_active;
289  a & m_num_authorized_signers;
290  a & m_nettype;
291  a & m_num_required_signers;
292  a & m_signers;
293  a & m_messages;
294  a & m_next_message_id;
295  a & m_auto_send;
296  }
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1124

◆ set_active()

void mms::message_store::set_active ( bool  active)
inline

Definition at line 211 of file message_store.h.

211 { m_active = active; };
Here is the caller graph for this function:

◆ set_auto_send()

void mms::message_store::set_auto_send ( bool  auto_send)
inline

Definition at line 212 of file message_store.h.

212 { m_auto_send = auto_send; };

◆ set_message_processed_or_sent()

void mms::message_store::set_message_processed_or_sent ( uint32_t  id)

Definition at line 1155 of file message_store.cpp.

1156 {
1157  message &m = get_message_ref_by_id(id);
1158  if (m.state == message_state::waiting)
1159  {
1160  // So far a fairly cautious and conservative strategy: Only delete from Bitmessage
1161  // when fully processed (and e.g. not already after reception and writing into
1162  // the message store file)
1163  delete_transport_message(id);
1164  m.state = message_state::processed;
1165  }
1166  else if (m.state == message_state::ready_to_send)
1167  {
1168  m.state = message_state::sent;
1169  }
1170  m.modified = (uint64_t)time(NULL);
1171 }
time_t time
Definition: blockchain.cpp:93
unsigned __int64 uint64_t
Definition: stdint.h:136
std::string message("Message requiring signing")
Here is the caller graph for this function:

◆ set_messages_processed()

void mms::message_store::set_messages_processed ( const processing_data data)

Definition at line 1147 of file message_store.cpp.

1148 {
1149  for (size_t i = 0; i < data.message_ids.size(); ++i)
1150  {
1151  set_message_processed_or_sent(data.message_ids[i]);
1152  }
1153 }
void set_message_processed_or_sent(uint32_t id)
Here is the call graph for this function:

◆ set_options() [1/2]

void mms::message_store::set_options ( const boost::program_options::variables_map &  vm)

Definition at line 109 of file message_store.cpp.

110 {
111  const options opts{};
112  std::string bitmessage_address = command_line::get_arg(vm, opts.bitmessage_address);
113  epee::wipeable_string bitmessage_login = command_line::get_arg(vm, opts.bitmessage_login);
114  set_options(bitmessage_address, bitmessage_login);
115 }
::std::string string
Definition: gtest-port.h:1097
void set_options(const boost::program_options::variables_map &vm)
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
Definition: command_line.h:271
Here is the call graph for this function:

◆ set_options() [2/2]

void mms::message_store::set_options ( const std::string &  bitmessage_address,
const epee::wipeable_string bitmessage_login 
)

Definition at line 117 of file message_store.cpp.

118 {
119  m_transporter.set_options(bitmessage_address, bitmessage_login);
120 }
void set_options(const std::string &bitmessage_address, const epee::wipeable_string &bitmessage_login)
Here is the call graph for this function:

◆ set_signer()

void mms::message_store::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 
)

Definition at line 122 of file message_store.cpp.

127 {
128  THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + std::to_string(index));
129  authorized_signer &m = m_signers[index];
130  if (label)
131  {
132  m.label = label.get();
133  }
134  if (transport_address)
135  {
136  m.transport_address = transport_address.get();
137  }
138  if (etn_address)
139  {
140  m.etn_address_known = true;
141  m.etn_address = etn_address.get();
142  }
143  // Save to minimize the chance to loose that info (at least while in beta)
144  save(state);
145 }
Definition: blake256.h:37
#define THROW_WALLET_EXCEPTION_IF(cond, err_type,...)
std::string to_string(t_connection_type type)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ signer_config_complete()

bool mms::message_store::signer_config_complete ( ) const

Definition at line 153 of file message_store.cpp.

154 {
155  for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
156  {
157  const authorized_signer &m = m_signers[i];
158  if (m.label.empty() || m.transport_address.empty() || !m.etn_address_known)
159  {
160  return false;
161  }
162  }
163  return true;
164 }
unsigned int uint32_t
Definition: stdint.h:126
Here is the caller graph for this function:

◆ signer_labels_complete()

bool mms::message_store::signer_labels_complete ( ) const

Definition at line 168 of file message_store.cpp.

169 {
170  for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
171  {
172  const authorized_signer &m = m_signers[i];
173  if (m.label.empty())
174  {
175  return false;
176  }
177  }
178  return true;
179 }
unsigned int uint32_t
Definition: stdint.h:126

◆ signer_to_string()

std::string mms::message_store::signer_to_string ( const authorized_signer signer,
uint32_t  max_width 
)

Definition at line 1413 of file message_store.cpp.

1414 {
1415  std::string s = "";
1416  s.reserve(max_width);
1417  uint32_t avail = max_width;
1418  uint32_t label_len = signer.label.length();
1419  if (label_len > avail)
1420  {
1421  s.append(signer.label.substr(0, avail - 2));
1422  s.append("..");
1423  return s;
1424  }
1425  s.append(signer.label);
1426  avail -= label_len;
1427  uint32_t transport_addr_len = signer.transport_address.length();
1428  if ((transport_addr_len > 0) && (avail > 10))
1429  {
1430  s.append(": ");
1431  avail -= 2;
1432  if (transport_addr_len <= avail)
1433  {
1434  s.append(signer.transport_address);
1435  }
1436  else
1437  {
1438  s.append(signer.transport_address.substr(0, avail-2));
1439  s.append("..");
1440  }
1441  }
1442  return s;
1443 }
::std::string string
Definition: gtest-port.h:1097
unsigned int uint32_t
Definition: stdint.h:126

◆ start_auto_config()

void mms::message_store::start_auto_config ( const multisig_wallet_state state)

Definition at line 259 of file message_store.cpp.

260 {
261  for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
262  {
263  authorized_signer &m = m_signers[i];
264  if (!m.me)
265  {
266  setup_signer_for_auto_config(i, create_auto_config_token(), true);
267  }
268  m.auto_config_running = true;
269  }
270  save(state);
271 }
unsigned int uint32_t
Definition: stdint.h:126
Definition: blake256.h:37

◆ stop()

void mms::message_store::stop ( )
inline

Definition at line 280 of file message_store.h.

280 { m_run.store(false, std::memory_order_relaxed); m_transporter.stop(); }
Here is the call graph for this function:

◆ stop_auto_config()

void mms::message_store::stop_auto_config ( )

Definition at line 395 of file message_store.cpp.

396 {
397  for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
398  {
399  authorized_signer &m = m_signers[i];
400  if (!m.me && !m.auto_config_transport_address.empty())
401  {
402  // Try to delete those "unused API" addresses in PyBitmessage, especially since
403  // it seems it's not possible to delete them interactively, only to "disable" them
404  m_transporter.delete_transport_address(m.auto_config_transport_address);
405  }
406  m.auto_config_token.clear();
407  m.auto_config_public_key = crypto::null_pkey;
408  m.auto_config_secret_key = crypto::null_skey;
409  m.auto_config_transport_address.clear();
410  m.auto_config_running = false;
411  }
412 }
bool delete_transport_address(const std::string &transport_address)
const crypto::secret_key null_skey
Definition: crypto.cpp:73
unsigned int uint32_t
Definition: stdint.h:126
const crypto::public_key null_pkey
Definition: crypto.cpp:72
Here is the call graph for this function:

◆ tr()

static const char* mms::message_store::tr ( const char *  str)
inlinestatic

Definition at line 303 of file message_store.h.

303 { return i18n_translate(str, "tools::mms"); }
const char * i18n_translate(const char *s, const std::string &context)
Definition: i18n.cpp:323
Here is the call graph for this function:
Here is the caller graph for this function:

◆ unpack_signer_config()

void mms::message_store::unpack_signer_config ( const multisig_wallet_state state,
const std::string &  signer_config,
std::vector< authorized_signer > &  signers 
)

Definition at line 189 of file message_store.cpp.

191 {
192  try
193  {
194  std::stringstream iss;
195  iss << signer_config;
197  ar >> signers;
198  }
199  catch (...)
200  {
201  THROW_WALLET_EXCEPTION_IF(true, tools::error::wallet_internal_error, "Invalid structure of signer config");
202  }
203  uint32_t num_signers = (uint32_t)signers.size();
204  THROW_WALLET_EXCEPTION_IF(num_signers != m_num_authorized_signers, tools::error::wallet_internal_error, "Wrong number of signers in config: " + std::to_string(num_signers));
205 }
unsigned int uint32_t
Definition: stdint.h:126
#define THROW_WALLET_EXCEPTION_IF(cond, err_type,...)
std::string to_string(t_connection_type type)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ write_to_file()

void mms::message_store::write_to_file ( const multisig_wallet_state state,
const std::string &  filename 
)

Definition at line 700 of file message_store.cpp.

701 {
702  std::stringstream oss;
704  ar << *this;
705  std::string buf = oss.str();
706 
707  crypto::chacha_key key;
708  crypto::generate_chacha_key(&state.view_secret_key, sizeof(crypto::secret_key), key, 1);
709 
710  file_data write_file_data = boost::value_initialized<file_data>();
711  write_file_data.magic_string = "MMS";
712  write_file_data.file_version = 0;
713  write_file_data.iv = crypto::rand<crypto::chacha_iv>();
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]);
717  write_file_data.encrypted_data = encrypted_data;
718 
719  std::stringstream file_oss;
721  file_ar << write_file_data;
722 
723  bool success = epee::file_io_utils::save_string_to_file(filename, file_oss.str());
725 }
::std::string string
Definition: gtest-port.h:1097
void chacha20(const void *data, size_t length, const uint8_t *key, const uint8_t *iv, char *cipher)
const char * key
Definition: hmac_keccak.cpp:39
bool save_string_to_file(const std::string &path_to_file, const std::string &str)
Definition: file_io_utils.h:73
const char * buf
Definition: slow_memmem.cpp:74
expect< void > success() noexcept
Definition: expect.h:397
Definition: blake256.h:37
#define THROW_WALLET_EXCEPTION_IF(cond, err_type,...)

The documentation for this class was generated from the following files: