7ceb1f6a4d
- boost::tuple → std::tuple (serialize.h, miner.cpp, script.cpp, walletdb.cpp) - boost::shared_ptr → std::shared_ptr (trianglesrpc.cpp) - boost::variant → std::variant for CTxDestination (script.h) - boost::get → std::get_if (main.cpp, rpcblockchain.cpp, coincontroldialog.cpp, wallet.cpp) - boost::apply_visitor → std::visit (base58.h, script.cpp, rpcwallet.cpp, test/base58_tests.cpp) - boost::static_visitor removed from all visitor classes - boost::lexical_cast → std::to_string/std::stoll (smessage.cpp, rpcsmessage.cpp) - Removed unused boost/lexical_cast.hpp includes (rest.cpp, trianglesrpc.cpp) - Removed boost/variant/get.hpp include (rpcdump.cpp) - Upgraded vendored LZ4 from 1.1.3 to 1.10.0 - Updated LZ4_compress() → LZ4_compress_default() (smessage.cpp) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
985 lines
31 KiB
C++
985 lines
31 KiB
C++
// Copyright (c) 2014 The ShadowCoin developers
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include "main.h"
|
|
#include "trianglesrpc.h"
|
|
|
|
#include <string>
|
|
|
|
#include "smessage.h"
|
|
#include "init.h" // pwalletMain
|
|
|
|
using namespace json_spirit;
|
|
using namespace std;
|
|
|
|
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, json_spirit::Object& entry);
|
|
|
|
|
|
|
|
Value smsgenable(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() != 0)
|
|
throw runtime_error(
|
|
"smsgenable \n"
|
|
"Enable secure messaging.");
|
|
|
|
if (fSecMsgEnabled)
|
|
throw runtime_error("Secure messaging is already enabled.");
|
|
|
|
Object result;
|
|
if (!SecureMsgEnable())
|
|
{
|
|
result.push_back(Pair("result", "Failed to enable secure messaging."));
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Enabled secure messaging."));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Value smsgdisable(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() != 0)
|
|
throw runtime_error(
|
|
"smsgdisable \n"
|
|
"Disable secure messaging.");
|
|
if (!fSecMsgEnabled)
|
|
throw runtime_error("Secure messaging is already disabled.");
|
|
|
|
Object result;
|
|
if (!SecureMsgDisable())
|
|
{
|
|
result.push_back(Pair("result", "Failed to disable secure messaging."));
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Disabled secure messaging."));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Value smsgoptions(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() > 3)
|
|
throw runtime_error(
|
|
"smsgoptions [list|set <optname> <value>]\n"
|
|
"List and manage options.");
|
|
|
|
std::string mode = "list";
|
|
if (params.size() > 0)
|
|
{
|
|
mode = params[0].get_str();
|
|
};
|
|
|
|
Object result;
|
|
|
|
if (mode == "list")
|
|
{
|
|
result.push_back(Pair("option", std::string("newAddressRecv = ") + (smsgOptions.fNewAddressRecv ? "true" : "false")));
|
|
result.push_back(Pair("option", std::string("newAddressAnon = ") + (smsgOptions.fNewAddressAnon ? "true" : "false")));
|
|
|
|
result.push_back(Pair("result", "Success."));
|
|
} else
|
|
if (mode == "set")
|
|
{
|
|
if (params.size() < 3)
|
|
{
|
|
result.push_back(Pair("result", "Too few parameters."));
|
|
result.push_back(Pair("expected", "set <optname> <value>"));
|
|
return result;
|
|
};
|
|
|
|
std::string optname = params[1].get_str();
|
|
std::string value = params[2].get_str();
|
|
|
|
if (optname == "newAddressRecv")
|
|
{
|
|
if (value == "+" || value == "on" || value == "true" || value == "1")
|
|
{
|
|
smsgOptions.fNewAddressRecv = true;
|
|
} else
|
|
if (value == "-" || value == "off" || value == "false" || value == "0")
|
|
{
|
|
smsgOptions.fNewAddressRecv = false;
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Unknown value."));
|
|
return result;
|
|
};
|
|
result.push_back(Pair("set option", std::string("newAddressRecv = ") + (smsgOptions.fNewAddressRecv ? "true" : "false")));
|
|
} else
|
|
if (optname == "newAddressAnon")
|
|
{
|
|
if (value == "+" || value == "on" || value == "true" || value == "1")
|
|
{
|
|
smsgOptions.fNewAddressAnon = true;
|
|
} else
|
|
if (value == "-" || value == "off" || value == "false" || value == "0")
|
|
{
|
|
smsgOptions.fNewAddressAnon = false;
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Unknown value."));
|
|
return result;
|
|
};
|
|
result.push_back(Pair("set option", std::string("newAddressAnon = ") + (smsgOptions.fNewAddressAnon ? "true" : "false")));
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Option not found."));
|
|
return result;
|
|
};
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Unknown Mode."));
|
|
result.push_back(Pair("expected", "smsgoption [list|set <optname> <value>]"));
|
|
};
|
|
return result;
|
|
}
|
|
|
|
Value smsglocalkeys(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() > 3)
|
|
throw runtime_error(
|
|
"smsglocalkeys [whitelist|all|wallet|recv <+/-> <address>|anon <+/-> <address>]\n"
|
|
"List and manage keys.");
|
|
|
|
if (!fSecMsgEnabled)
|
|
throw runtime_error("Secure messaging is disabled.");
|
|
|
|
Object result;
|
|
|
|
std::string mode = "whitelist";
|
|
if (params.size() > 0)
|
|
{
|
|
mode = params[0].get_str();
|
|
};
|
|
|
|
char cbuf[256];
|
|
|
|
if (mode == "whitelist"
|
|
|| mode == "all")
|
|
{
|
|
uint32_t nKeys = 0;
|
|
int all = mode == "all" ? 1 : 0;
|
|
for (std::vector<SecMsgAddress>::iterator it = smsgAddresses.begin(); it != smsgAddresses.end(); ++it)
|
|
{
|
|
if (!all
|
|
&& !it->fReceiveEnabled)
|
|
continue;
|
|
|
|
CTrianglesAddress coinAddress(it->sAddress);
|
|
if (!coinAddress.IsValid())
|
|
continue;
|
|
|
|
std::string sPublicKey;
|
|
|
|
CKeyID keyID;
|
|
if (!coinAddress.GetKeyID(keyID))
|
|
continue;
|
|
|
|
CPubKey pubKey;
|
|
if (!pwalletMain->GetPubKey(keyID, pubKey))
|
|
continue;
|
|
if (!pubKey.IsValid()
|
|
|| !pubKey.IsCompressed())
|
|
{
|
|
continue;
|
|
};
|
|
|
|
|
|
sPublicKey = EncodeBase58(pubKey.Raw());
|
|
|
|
std::string sLabel = pwalletMain->mapAddressBook[keyID];
|
|
std::string sInfo;
|
|
if (all)
|
|
sInfo = std::string("Receive ") + (it->fReceiveEnabled ? "on, " : "off, ");
|
|
sInfo += std::string("Anon ") + (it->fReceiveAnon ? "on" : "off");
|
|
result.push_back(Pair("key", it->sAddress + " - " + sPublicKey + " " + sInfo + " - " + sLabel));
|
|
|
|
nKeys++;
|
|
};
|
|
|
|
|
|
snprintf(cbuf, sizeof(cbuf), "%u keys listed.", nKeys);
|
|
result.push_back(Pair("result", std::string(cbuf)));
|
|
|
|
} else
|
|
if (mode == "recv")
|
|
{
|
|
if (params.size() < 3)
|
|
{
|
|
result.push_back(Pair("result", "Too few parameters."));
|
|
result.push_back(Pair("expected", "recv <+/-> <address>"));
|
|
return result;
|
|
};
|
|
|
|
std::string op = params[1].get_str();
|
|
std::string addr = params[2].get_str();
|
|
|
|
std::vector<SecMsgAddress>::iterator it;
|
|
for (it = smsgAddresses.begin(); it != smsgAddresses.end(); ++it)
|
|
{
|
|
if (addr != it->sAddress)
|
|
continue;
|
|
break;
|
|
};
|
|
|
|
if (it == smsgAddresses.end())
|
|
{
|
|
result.push_back(Pair("result", "Address not found."));
|
|
return result;
|
|
};
|
|
|
|
if (op == "+" || op == "on" || op == "add" || op == "a")
|
|
{
|
|
it->fReceiveEnabled = true;
|
|
} else
|
|
if (op == "-" || op == "off" || op == "rem" || op == "r")
|
|
{
|
|
it->fReceiveEnabled = false;
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Unknown operation."));
|
|
return result;
|
|
};
|
|
|
|
std::string sInfo;
|
|
sInfo = std::string("Receive ") + (it->fReceiveEnabled ? "on, " : "off,");
|
|
sInfo += std::string("Anon ") + (it->fReceiveAnon ? "on" : "off");
|
|
result.push_back(Pair("result", "Success."));
|
|
result.push_back(Pair("key", it->sAddress + " " + sInfo));
|
|
return result;
|
|
|
|
} else
|
|
if (mode == "anon")
|
|
{
|
|
if (params.size() < 3)
|
|
{
|
|
result.push_back(Pair("result", "Too few parameters."));
|
|
result.push_back(Pair("expected", "anon <+/-> <address>"));
|
|
return result;
|
|
};
|
|
|
|
std::string op = params[1].get_str();
|
|
std::string addr = params[2].get_str();
|
|
|
|
std::vector<SecMsgAddress>::iterator it;
|
|
for (it = smsgAddresses.begin(); it != smsgAddresses.end(); ++it)
|
|
{
|
|
if (addr != it->sAddress)
|
|
continue;
|
|
break;
|
|
};
|
|
|
|
if (it == smsgAddresses.end())
|
|
{
|
|
result.push_back(Pair("result", "Address not found."));
|
|
return result;
|
|
};
|
|
|
|
if (op == "+" || op == "on" || op == "add" || op == "a")
|
|
{
|
|
it->fReceiveAnon = true;
|
|
} else
|
|
if (op == "-" || op == "off" || op == "rem" || op == "r")
|
|
{
|
|
it->fReceiveAnon = false;
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Unknown operation."));
|
|
return result;
|
|
};
|
|
|
|
std::string sInfo;
|
|
sInfo = std::string("Receive ") + (it->fReceiveEnabled ? "on, " : "off,");
|
|
sInfo += std::string("Anon ") + (it->fReceiveAnon ? "on" : "off");
|
|
result.push_back(Pair("result", "Success."));
|
|
result.push_back(Pair("key", it->sAddress + " " + sInfo));
|
|
return result;
|
|
|
|
} else
|
|
if (mode == "wallet")
|
|
{
|
|
uint32_t nKeys = 0;
|
|
for (const auto& entry : pwalletMain->mapAddressBook)
|
|
{
|
|
if (!IsMine(*pwalletMain, entry.first))
|
|
continue;
|
|
|
|
CTrianglesAddress coinAddress(entry.first);
|
|
if (!coinAddress.IsValid())
|
|
continue;
|
|
|
|
std::string address;
|
|
std::string sPublicKey;
|
|
address = coinAddress.ToString();
|
|
|
|
CKeyID keyID;
|
|
if (!coinAddress.GetKeyID(keyID))
|
|
continue;
|
|
|
|
CPubKey pubKey;
|
|
if (!pwalletMain->GetPubKey(keyID, pubKey))
|
|
continue;
|
|
if (!pubKey.IsValid()
|
|
|| !pubKey.IsCompressed())
|
|
{
|
|
continue;
|
|
};
|
|
|
|
sPublicKey = EncodeBase58(pubKey.Raw());
|
|
|
|
result.push_back(Pair("key", address + " - " + sPublicKey + " - " + entry.second));
|
|
nKeys++;
|
|
};
|
|
|
|
snprintf(cbuf, sizeof(cbuf), "%u keys listed from wallet.", nKeys);
|
|
result.push_back(Pair("result", std::string(cbuf)));
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Unknown Mode."));
|
|
result.push_back(Pair("expected", "smsglocalkeys [whitelist|all|wallet|recv <+/-> <address>|anon <+/-> <address>]"));
|
|
};
|
|
|
|
return result;
|
|
};
|
|
|
|
Value smsgscanchain(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() != 0)
|
|
throw runtime_error(
|
|
"smsgscanchain \n"
|
|
"Look for public keys in the block chain.");
|
|
|
|
if (!fSecMsgEnabled)
|
|
throw runtime_error("Secure messaging is disabled.");
|
|
|
|
Object result;
|
|
if (!SecureMsgScanBlockChain())
|
|
{
|
|
result.push_back(Pair("result", "Scan Chain Failed."));
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Scan Chain Completed."));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Value smsgscanbuckets(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() != 0)
|
|
throw runtime_error(
|
|
"smsgscanbuckets \n"
|
|
"Force rescan of all messages in the bucket store.");
|
|
|
|
if (!fSecMsgEnabled)
|
|
throw runtime_error("Secure messaging is disabled.");
|
|
|
|
if (pwalletMain->IsLocked())
|
|
throw runtime_error("Wallet is locked.");
|
|
|
|
Object result;
|
|
if (!SecureMsgScanBuckets())
|
|
{
|
|
result.push_back(Pair("result", "Scan Buckets Failed."));
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Scan Buckets Completed."));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Value smsgaddkey(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() != 2)
|
|
throw runtime_error(
|
|
"smsgaddkey <address> <pubkey>\n"
|
|
"Add address, pubkey pair to database.");
|
|
|
|
if (!fSecMsgEnabled)
|
|
throw runtime_error("Secure messaging is disabled.");
|
|
|
|
std::string addr = params[0].get_str();
|
|
std::string pubk = params[1].get_str();
|
|
|
|
Object result;
|
|
int rv = SecureMsgAddAddress(addr, pubk);
|
|
if (rv != 0)
|
|
{
|
|
result.push_back(Pair("result", "Public key not added to db."));
|
|
switch (rv)
|
|
{
|
|
case 2: result.push_back(Pair("reason", "publicKey is invalid.")); break;
|
|
case 3: result.push_back(Pair("reason", "publicKey does not match address.")); break;
|
|
case 4: result.push_back(Pair("reason", "address is already in db.")); break;
|
|
case 5: result.push_back(Pair("reason", "address is invalid.")); break;
|
|
default: result.push_back(Pair("reason", "error.")); break;
|
|
};
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Added public key to db."));
|
|
};
|
|
|
|
return result;
|
|
}
|
|
|
|
Value smsggetpubkey(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() != 1)
|
|
throw runtime_error(
|
|
"smsggetpubkey <address>\n"
|
|
"Return the base58 encoded compressed public key for an address.\n"
|
|
"Tests localkeys first, then looks in public key db.\n");
|
|
|
|
if (!fSecMsgEnabled)
|
|
throw runtime_error("Secure messaging is disabled.");
|
|
|
|
|
|
std::string address = params[0].get_str();
|
|
std::string publicKey;
|
|
|
|
Object result;
|
|
int rv = SecureMsgGetLocalPublicKey(address, publicKey);
|
|
switch (rv)
|
|
{
|
|
case 0:
|
|
result.push_back(Pair("result", "Success."));
|
|
result.push_back(Pair("address in wallet", address));
|
|
result.push_back(Pair("compressed public key", publicKey));
|
|
return result; // success, don't check db
|
|
case 2:
|
|
case 3:
|
|
result.push_back(Pair("result", "Failed."));
|
|
result.push_back(Pair("message", "Invalid address."));
|
|
return result;
|
|
case 4:
|
|
break; // check db
|
|
//case 1:
|
|
default:
|
|
result.push_back(Pair("result", "Failed."));
|
|
result.push_back(Pair("message", "Error."));
|
|
return result;
|
|
};
|
|
|
|
CTrianglesAddress coinAddress(address);
|
|
|
|
|
|
CKeyID keyID;
|
|
if (!coinAddress.GetKeyID(keyID))
|
|
{
|
|
result.push_back(Pair("result", "Failed."));
|
|
result.push_back(Pair("message", "Invalid address."));
|
|
return result;
|
|
};
|
|
|
|
CPubKey cpkFromDB;
|
|
rv = SecureMsgGetStoredKey(keyID, cpkFromDB);
|
|
|
|
switch (rv)
|
|
{
|
|
case 0:
|
|
if (!cpkFromDB.IsValid()
|
|
|| !cpkFromDB.IsCompressed())
|
|
{
|
|
result.push_back(Pair("result", "Failed."));
|
|
result.push_back(Pair("message", "Invalid address."));
|
|
} else
|
|
{
|
|
//cpkFromDB.SetCompressedPubKey(); // make sure key is compressed
|
|
publicKey = EncodeBase58(cpkFromDB.Raw());
|
|
|
|
result.push_back(Pair("result", "Success."));
|
|
result.push_back(Pair("peer address in DB", address));
|
|
result.push_back(Pair("compressed public key", publicKey));
|
|
};
|
|
break;
|
|
case 2:
|
|
result.push_back(Pair("result", "Failed."));
|
|
result.push_back(Pair("message", "Address not found in wallet or db."));
|
|
return result;
|
|
//case 1:
|
|
default:
|
|
result.push_back(Pair("result", "Failed."));
|
|
result.push_back(Pair("message", "Error, GetStoredKey()."));
|
|
return result;
|
|
};
|
|
|
|
return result;
|
|
}
|
|
|
|
Value smsgsend(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() != 3)
|
|
throw runtime_error(
|
|
"smsgsend <addrFrom> <addrTo> <message>\n"
|
|
"Send an encrypted message from addrFrom to addrTo.");
|
|
|
|
if (!fSecMsgEnabled)
|
|
throw runtime_error("Secure messaging is disabled.");
|
|
|
|
std::string addrFrom = params[0].get_str();
|
|
std::string addrTo = params[1].get_str();
|
|
std::string msg = params[2].get_str();
|
|
|
|
|
|
Object result;
|
|
|
|
std::string sError;
|
|
if (SecureMsgSend(addrFrom, addrTo, msg, sError) != 0)
|
|
{
|
|
result.push_back(Pair("result", "Send failed."));
|
|
result.push_back(Pair("error", sError));
|
|
} else
|
|
result.push_back(Pair("result", "Sent."));
|
|
|
|
return result;
|
|
}
|
|
|
|
Value smsgsendanon(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() != 2)
|
|
throw runtime_error(
|
|
"smsgsendanon <addrTo> <message>\n"
|
|
"Send an anonymous encrypted message to addrTo.");
|
|
|
|
if (!fSecMsgEnabled)
|
|
throw runtime_error("Secure messaging is disabled.");
|
|
|
|
std::string addrFrom = "anon";
|
|
std::string addrTo = params[0].get_str();
|
|
std::string msg = params[1].get_str();
|
|
|
|
|
|
Object result;
|
|
std::string sError;
|
|
if (SecureMsgSend(addrFrom, addrTo, msg, sError) != 0)
|
|
{
|
|
result.push_back(Pair("result", "Send failed."));
|
|
result.push_back(Pair("error", sError));
|
|
} else
|
|
result.push_back(Pair("result", "Sent."));
|
|
|
|
return result;
|
|
}
|
|
|
|
Value smsginbox(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() > 1) // defaults to read
|
|
throw runtime_error(
|
|
"smsginbox [all|unread|clear]\n"
|
|
"Decrypt and display all received messages.\n"
|
|
"Warning: clear will delete all messages.");
|
|
|
|
if (!fSecMsgEnabled)
|
|
throw runtime_error("Secure messaging is disabled.");
|
|
|
|
if (pwalletMain->IsLocked())
|
|
throw runtime_error("Wallet is locked.");
|
|
|
|
std::string mode = "unread";
|
|
if (params.size() > 0)
|
|
{
|
|
mode = params[0].get_str();
|
|
}
|
|
|
|
|
|
Object result;
|
|
|
|
std::vector<unsigned char> vchKey;
|
|
vchKey.resize(16);
|
|
memset(&vchKey[0], 0, 16);
|
|
|
|
{
|
|
LOCK(cs_smsgDB);
|
|
|
|
SecMsgDB dbInbox;
|
|
|
|
if (!dbInbox.Open("cr+"))
|
|
throw runtime_error("Could not open DB.");
|
|
|
|
uint32_t nMessages = 0;
|
|
char cbuf[256];
|
|
|
|
std::string sPrefix("im");
|
|
unsigned char chKey[18];
|
|
|
|
if (mode == "clear")
|
|
{
|
|
dbInbox.TxnBegin();
|
|
|
|
leveldb::Iterator* it = dbInbox.pdb->NewIterator(leveldb::ReadOptions());
|
|
while (dbInbox.NextSmesgKey(it, sPrefix, chKey))
|
|
{
|
|
dbInbox.EraseSmesg(chKey);
|
|
nMessages++;
|
|
};
|
|
delete it;
|
|
dbInbox.TxnCommit();
|
|
|
|
snprintf(cbuf, sizeof(cbuf), "Deleted %u messages.", nMessages);
|
|
result.push_back(Pair("result", std::string(cbuf)));
|
|
} else
|
|
if (mode == "all"
|
|
|| mode == "unread")
|
|
{
|
|
int fCheckReadStatus = mode == "unread" ? 1 : 0;
|
|
|
|
SecMsgStored smsgStored;
|
|
MessageData msg;
|
|
|
|
dbInbox.TxnBegin();
|
|
|
|
leveldb::Iterator* it = dbInbox.pdb->NewIterator(leveldb::ReadOptions());
|
|
while (dbInbox.NextSmesg(it, sPrefix, chKey, smsgStored))
|
|
{
|
|
if (fCheckReadStatus
|
|
&& !(smsgStored.status & SMSG_MASK_UNREAD))
|
|
continue;
|
|
|
|
uint32_t nPayload = smsgStored.vchMessage.size() - SMSG_HDR_LEN;
|
|
if (SecureMsgDecrypt(false, smsgStored.sAddrTo, &smsgStored.vchMessage[0], &smsgStored.vchMessage[SMSG_HDR_LEN], nPayload, msg) == 0)
|
|
{
|
|
Object objM;
|
|
objM.push_back(Pair("received", getTimeString(smsgStored.timeReceived, cbuf, sizeof(cbuf))));
|
|
objM.push_back(Pair("sent", getTimeString(msg.timestamp, cbuf, sizeof(cbuf))));
|
|
objM.push_back(Pair("from", msg.sFromAddress));
|
|
objM.push_back(Pair("to", smsgStored.sAddrTo));
|
|
objM.push_back(Pair("text", std::string((char*)&msg.vchMessage[0]))); // ugh
|
|
|
|
result.push_back(Pair("message", objM));
|
|
} else
|
|
{
|
|
result.push_back(Pair("message", "Could not decrypt."));
|
|
};
|
|
|
|
if (fCheckReadStatus)
|
|
{
|
|
smsgStored.status &= ~SMSG_MASK_UNREAD;
|
|
dbInbox.WriteSmesg(chKey, smsgStored);
|
|
};
|
|
nMessages++;
|
|
};
|
|
delete it;
|
|
dbInbox.TxnCommit();
|
|
|
|
snprintf(cbuf, sizeof(cbuf), "%u messages shown.", nMessages);
|
|
result.push_back(Pair("result", std::string(cbuf)));
|
|
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Unknown Mode."));
|
|
result.push_back(Pair("expected", "[all|unread|clear]."));
|
|
};
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
Value smsgoutbox(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() > 1) // defaults to read
|
|
throw runtime_error(
|
|
"smsgoutbox [all|clear]\n"
|
|
"Decrypt and display all sent messages.\n"
|
|
"Warning: clear will delete all sent messages.");
|
|
|
|
if (!fSecMsgEnabled)
|
|
throw runtime_error("Secure messaging is disabled.");
|
|
|
|
if (pwalletMain->IsLocked())
|
|
throw runtime_error("Wallet is locked.");
|
|
|
|
std::string mode = "all";
|
|
if (params.size() > 0)
|
|
{
|
|
mode = params[0].get_str();
|
|
}
|
|
|
|
|
|
Object result;
|
|
|
|
std::string sPrefix("sm");
|
|
unsigned char chKey[18];
|
|
memset(&chKey[0], 0, 18);
|
|
|
|
{
|
|
LOCK(cs_smsgDB);
|
|
|
|
SecMsgDB dbOutbox;
|
|
|
|
if (!dbOutbox.Open("cr+"))
|
|
throw runtime_error("Could not open DB.");
|
|
|
|
uint32_t nMessages = 0;
|
|
char cbuf[256];
|
|
|
|
if (mode == "clear")
|
|
{
|
|
dbOutbox.TxnBegin();
|
|
|
|
leveldb::Iterator* it = dbOutbox.pdb->NewIterator(leveldb::ReadOptions());
|
|
while (dbOutbox.NextSmesgKey(it, sPrefix, chKey))
|
|
{
|
|
dbOutbox.EraseSmesg(chKey);
|
|
nMessages++;
|
|
};
|
|
delete it;
|
|
dbOutbox.TxnCommit();
|
|
|
|
|
|
snprintf(cbuf, sizeof(cbuf), "Deleted %u messages.", nMessages);
|
|
result.push_back(Pair("result", std::string(cbuf)));
|
|
} else
|
|
if (mode == "all")
|
|
{
|
|
SecMsgStored smsgStored;
|
|
MessageData msg;
|
|
leveldb::Iterator* it = dbOutbox.pdb->NewIterator(leveldb::ReadOptions());
|
|
while (dbOutbox.NextSmesg(it, sPrefix, chKey, smsgStored))
|
|
{
|
|
uint32_t nPayload = smsgStored.vchMessage.size() - SMSG_HDR_LEN;
|
|
|
|
if (SecureMsgDecrypt(false, smsgStored.sAddrOutbox, &smsgStored.vchMessage[0], &smsgStored.vchMessage[SMSG_HDR_LEN], nPayload, msg) == 0)
|
|
{
|
|
Object objM;
|
|
objM.push_back(Pair("sent", getTimeString(msg.timestamp, cbuf, sizeof(cbuf))));
|
|
objM.push_back(Pair("from", msg.sFromAddress));
|
|
objM.push_back(Pair("to", smsgStored.sAddrTo));
|
|
objM.push_back(Pair("text", std::string((char*)&msg.vchMessage[0]))); // ugh
|
|
|
|
result.push_back(Pair("message", objM));
|
|
} else
|
|
{
|
|
result.push_back(Pair("message", "Could not decrypt."));
|
|
};
|
|
nMessages++;
|
|
};
|
|
delete it;
|
|
|
|
snprintf(cbuf, sizeof(cbuf), "%u sent messages shown.", nMessages);
|
|
result.push_back(Pair("result", std::string(cbuf)));
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Unknown Mode."));
|
|
result.push_back(Pair("expected", "[all|clear]."));
|
|
};
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
|
|
Value smsgbuckets(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() > 1)
|
|
throw runtime_error(
|
|
"smsgbuckets [stats|dump]\n"
|
|
"Display some statistics.");
|
|
|
|
if (!fSecMsgEnabled)
|
|
throw runtime_error("Secure messaging is disabled.");
|
|
|
|
std::string mode = "stats";
|
|
if (params.size() > 0)
|
|
{
|
|
mode = params[0].get_str();
|
|
};
|
|
|
|
Object result;
|
|
|
|
char cbuf[256];
|
|
if (mode == "stats")
|
|
{
|
|
uint32_t nBuckets = 0;
|
|
uint32_t nMessages = 0;
|
|
uint64_t nBytes = 0;
|
|
{
|
|
LOCK(cs_smsg);
|
|
std::map<int64_t, SecMsgBucket>::iterator it;
|
|
it = smsgBuckets.begin();
|
|
|
|
for (it = smsgBuckets.begin(); it != smsgBuckets.end(); ++it)
|
|
{
|
|
std::set<SecMsgToken>& tokenSet = it->second.setTokens;
|
|
|
|
std::string sBucket = std::to_string(it->first);
|
|
std::string sFile = sBucket + "_01.dat";
|
|
|
|
snprintf(cbuf, sizeof(cbuf), "%"PRIszu, tokenSet.size());
|
|
std::string snContents(cbuf);
|
|
|
|
std::string sHash = std::to_string(it->second.hash);
|
|
|
|
nBuckets++;
|
|
nMessages += tokenSet.size();
|
|
|
|
Object objM;
|
|
objM.push_back(Pair("bucket", sBucket));
|
|
objM.push_back(Pair("time", getTimeString(it->first, cbuf, sizeof(cbuf))));
|
|
objM.push_back(Pair("no. messages", snContents));
|
|
objM.push_back(Pair("hash", sHash));
|
|
objM.push_back(Pair("last changed", getTimeString(it->second.timeChanged, cbuf, sizeof(cbuf))));
|
|
|
|
boost::filesystem::path fullPath = GetDataDir() / "smsgStore" / sFile;
|
|
|
|
|
|
if (!boost::filesystem::exists(fullPath))
|
|
{
|
|
// -- If there is a file for an empty bucket something is wrong.
|
|
if (tokenSet.size() == 0)
|
|
objM.push_back(Pair("file size", "Empty bucket."));
|
|
else
|
|
objM.push_back(Pair("file size, error", "File not found."));
|
|
} else
|
|
{
|
|
try {
|
|
|
|
uint64_t nFBytes = 0;
|
|
nFBytes = boost::filesystem::file_size(fullPath);
|
|
nBytes += nFBytes;
|
|
objM.push_back(Pair("file size", fsReadable(nFBytes)));
|
|
} catch (const boost::filesystem::filesystem_error& ex)
|
|
{
|
|
objM.push_back(Pair("file size, error", ex.what()));
|
|
};
|
|
};
|
|
|
|
result.push_back(Pair("bucket", objM));
|
|
};
|
|
}; // LOCK(cs_smsg);
|
|
|
|
|
|
std::string snBuckets = std::to_string(nBuckets);
|
|
std::string snMessages = std::to_string(nMessages);
|
|
|
|
Object objM;
|
|
objM.push_back(Pair("buckets", snBuckets));
|
|
objM.push_back(Pair("messages", snMessages));
|
|
objM.push_back(Pair("size", fsReadable(nBytes)));
|
|
result.push_back(Pair("total", objM));
|
|
|
|
} else
|
|
if (mode == "dump")
|
|
{
|
|
{
|
|
LOCK(cs_smsg);
|
|
std::map<int64_t, SecMsgBucket>::iterator it;
|
|
it = smsgBuckets.begin();
|
|
|
|
for (it = smsgBuckets.begin(); it != smsgBuckets.end(); ++it)
|
|
{
|
|
std::string sFile = std::to_string(it->first) + "_01.dat";
|
|
|
|
try {
|
|
boost::filesystem::path fullPath = GetDataDir() / "smsgStore" / sFile;
|
|
boost::filesystem::remove(fullPath);
|
|
} catch (const boost::filesystem::filesystem_error& ex)
|
|
{
|
|
//objM.push_back(Pair("file size, error", ex.what()));
|
|
printf("Error removing bucket file %s.\n", ex.what());
|
|
};
|
|
};
|
|
smsgBuckets.clear();
|
|
}; // LOCK(cs_smsg);
|
|
|
|
result.push_back(Pair("result", "Removed all buckets."));
|
|
|
|
} else
|
|
{
|
|
result.push_back(Pair("result", "Unknown Mode."));
|
|
result.push_back(Pair("expected", "[stats|dump]."));
|
|
};
|
|
|
|
|
|
return result;
|
|
};
|
|
|
|
Value smsgbroadcast(const Array& params, bool fHelp)
|
|
{
|
|
if (fHelp || params.size() != 2)
|
|
throw runtime_error(
|
|
"smsgbroadcast <addrFrom> <message>\n"
|
|
"Send an encrypted message to all known public keys in the smsgDB.\n"
|
|
"Returns the number of recipients and any failures.");
|
|
|
|
if (!fSecMsgEnabled)
|
|
throw runtime_error("Secure messaging is disabled.");
|
|
|
|
if (pwalletMain->IsLocked())
|
|
throw runtime_error("Wallet is locked.");
|
|
|
|
std::string addrFrom = params[0].get_str();
|
|
std::string msg = params[1].get_str();
|
|
|
|
// Validate sender address
|
|
CTrianglesAddress coinAddrFrom(addrFrom);
|
|
if (!coinAddrFrom.IsValid())
|
|
throw runtime_error("Invalid from address.");
|
|
|
|
Object result;
|
|
uint32_t nSent = 0;
|
|
uint32_t nFailed = 0;
|
|
Array failures;
|
|
|
|
{
|
|
LOCK(cs_smsgDB);
|
|
|
|
SecMsgDB dbPub;
|
|
if (!dbPub.Open("r"))
|
|
throw runtime_error("Could not open smsgDB.");
|
|
|
|
// Iterate all "pk" entries
|
|
std::string sPrefix("pk");
|
|
leveldb::Iterator* it = dbPub.pdb->NewIterator(leveldb::ReadOptions());
|
|
for (it->Seek(sPrefix); it->Valid(); it->Next())
|
|
{
|
|
std::string key = it->key().ToString();
|
|
if (key.size() < 2 || key[0] != 'p' || key[1] != 'k')
|
|
break;
|
|
|
|
// Deserialize the CKeyID from the key (after "pk" prefix)
|
|
CDataStream ssKey(key.data(), key.data() + key.size(), SER_DISK, CLIENT_VERSION);
|
|
char prefix[2];
|
|
ssKey >> prefix[0];
|
|
ssKey >> prefix[1];
|
|
CKeyID ckidTo;
|
|
ssKey >> ckidTo;
|
|
|
|
// Convert CKeyID to address string
|
|
CTrianglesAddress addrTo(ckidTo);
|
|
if (!addrTo.IsValid())
|
|
continue;
|
|
|
|
std::string sAddrTo = addrTo.ToString();
|
|
|
|
// Skip sending to self
|
|
if (sAddrTo == addrFrom)
|
|
continue;
|
|
|
|
std::string sError;
|
|
if (SecureMsgSend(addrFrom, sAddrTo, msg, sError) != 0)
|
|
{
|
|
nFailed++;
|
|
Object objFail;
|
|
objFail.push_back(Pair("address", sAddrTo));
|
|
objFail.push_back(Pair("error", sError));
|
|
failures.push_back(objFail);
|
|
} else
|
|
{
|
|
nSent++;
|
|
}
|
|
}
|
|
delete it;
|
|
}
|
|
|
|
char cbuf[256];
|
|
snprintf(cbuf, sizeof(cbuf), "Broadcast sent to %u recipients, %u failed.", nSent, nFailed);
|
|
result.push_back(Pair("result", std::string(cbuf)));
|
|
result.push_back(Pair("sent", (int)nSent));
|
|
result.push_back(Pair("failed", (int)nFailed));
|
|
if (nFailed > 0)
|
|
result.push_back(Pair("failures", failures));
|
|
|
|
return result;
|
|
};
|