6#include <boost/algorithm/string.hpp>
21 if (std::find_if(
name.begin(),
name.end(), !boost::algorithm::is_alnum() && !boost::algorithm::is_any_of(
"._-")) !=
name.end())
return false;
22 return boost::filesystem::path(
name).filename().string() ==
name;
28 wallets.emplace(
"SecureEnclave", std::make_unique<se_wallet>());
29 }
catch(
const std::exception& ) {}
36 boost::filesystem::remove(lock_path);
41 auto now = std::chrono::system_clock::now();
42 timeout_time = now + timeout;
43 SYS_ASSERT(timeout_time >= now && timeout_time.time_since_epoch().count() > 0, invalid_lock_timeout_exception,
"Overflow on timeout_time, specified ${t}, now ${now}, timeout_time ${timeout_time}",
44 (
"t", t.count())(
"now", now.time_since_epoch().count())(
"timeout_time", timeout_time.time_since_epoch().count()));
47void wallet_manager::check_timeout() {
48 if (timeout_time != timepoint_t::max()) {
49 const auto& now = std::chrono::system_clock::now();
50 if (now >= timeout_time) {
53 timeout_time = now + timeout;
65 SYS_THROW(chain::wallet_exist_exception,
"Wallet with name: '${n}' already exists at ${path}", (
"n",
name)(
"path",
fc::path(wallet_filename)));
70 auto wallet = make_unique<soft_wallet>(
d);
71 wallet->set_password(password);
72 wallet->set_wallet_filename(wallet_filename.string());
73 wallet->unlock(password);
75 wallet->unlock(password);
78 wallet->save_wallet_file();
82 auto it = wallets.find(
name);
83 if (it != wallets.end()) {
86 wallets.emplace(
name, std::move(wallet));
97 auto wallet = std::make_unique<soft_wallet>(
d);
99 wallet->set_wallet_filename(wallet_filename.string());
100 if (!wallet->load_wallet_file()) {
101 SYS_THROW(chain::wallet_nonexistent_exception,
"Unable to open file: ${f}", (
"f", wallet_filename.string()));
106 auto it = wallets.find(
name);
107 if (it != wallets.end()) {
110 wallets.emplace(
name, std::move(wallet));
115 std::vector<std::string> result;
116 for (
const auto& i : wallets) {
117 if (i.second->is_locked()) {
118 result.emplace_back(i.first);
120 result.emplace_back(i.first +
" *");
129 if (wallets.count(
name) == 0)
130 SYS_THROW(chain::wallet_nonexistent_exception,
"Wallet not found: ${w}", (
"w",
name));
131 auto& w = wallets.at(
name);
133 SYS_THROW(chain::wallet_locked_exception,
"Wallet is locked: ${w}", (
"w",
name));
134 w->check_password(pw);
135 return w->list_keys();
140 SYS_ASSERT(!wallets.empty(), wallet_not_available_exception,
"You don't have any wallet!");
141 flat_set<public_key_type> result;
142 bool is_all_wallet_locked =
true;
143 for (
const auto& i : wallets) {
144 if (!i.second->is_locked()) {
145 result.merge(i.second->list_public_keys());
147 is_all_wallet_locked &= i.second->is_locked();
149 SYS_ASSERT(!is_all_wallet_locked, wallet_locked_exception,
"You don't have any unlocked wallet!");
156 for (
auto& i : wallets) {
157 if (!i.second->is_locked()) {
165 if (wallets.count(
name) == 0) {
166 SYS_THROW(chain::wallet_nonexistent_exception,
"Wallet not found: ${w}", (
"w",
name));
168 auto& w = wallets.at(
name);
169 if (w->is_locked()) {
177 if (wallets.count(
name) == 0) {
180 auto& w = wallets.at(
name);
181 if (!w->is_locked()) {
182 SYS_THROW(chain::wallet_unlocked_exception,
"Wallet is already unlocked: ${w}", (
"w",
name));
190 if (wallets.count(
name) == 0) {
191 SYS_THROW(chain::wallet_nonexistent_exception,
"Wallet not found: ${w}", (
"w",
name));
193 auto& w = wallets.at(
name);
194 if (w->is_locked()) {
195 SYS_THROW(chain::wallet_locked_exception,
"Wallet is locked: ${w}", (
"w",
name));
197 w->import_key(wif_key);
202 if (wallets.count(
name) == 0) {
203 SYS_THROW(chain::wallet_nonexistent_exception,
"Wallet not found: ${w}", (
"w",
name));
205 auto& w = wallets.at(
name);
206 if (w->is_locked()) {
207 SYS_THROW(chain::wallet_locked_exception,
"Wallet is locked: ${w}", (
"w",
name));
209 w->check_password(password);
215 if (wallets.count(
name) == 0) {
216 SYS_THROW(chain::wallet_nonexistent_exception,
"Wallet not found: ${w}", (
"w",
name));
218 auto& w = wallets.at(
name);
219 if (w->is_locked()) {
220 SYS_THROW(chain::wallet_locked_exception,
"Wallet is locked: ${w}", (
"w",
name));
223 string upper_key_type = boost::to_upper_copy<std::string>(
key_type);
224 return w->create_key(upper_key_type);
232 for (
const auto& pk : keys) {
234 for (
const auto& i : wallets) {
235 if (!i.second->is_locked()) {
245 SYS_THROW(chain::wallet_missing_pub_key_exception,
"Public key not found in unlocked wallets ${k}", (
"k", pk));
257 for (
const auto& i : wallets) {
258 if (!i.second->is_locked()) {
259 std::optional<signature_type> sig = i.second->try_sign_digest(
digest, key);
266 SYS_THROW(chain::wallet_missing_pub_key_exception,
"Public key not found in unlocked wallets ${k}", (
"k", key));
270 if(wallets.find(
name) != wallets.end())
271 SYS_THROW(wallet_exception,
"Tried to use wallet name that already exists.");
272 wallets.emplace(
name, std::move(wallet));
275void wallet_manager::start_lock_watch(std::shared_ptr<boost::asio::deadline_timer> t)
277 t->async_wait([t,
this](
const boost::system::error_code& )
280 boost::system::error_code ec;
281 auto rc = bfs::status(lock_path, ec);
282 if(ec != boost::system::error_code()) {
283 if(
rc.type() == bfs::file_not_found) {
285 SYS_THROW(wallet_exception,
"Lock file removed while kiod still running. Terminating.");
288 t->expires_from_now(boost::posix_time::seconds(1));
293void wallet_manager::initialize_lock() {
296 lock_path = dir /
"wallet.lock";
298 std::ofstream x(lock_path.string());
299 SYS_ASSERT(!x.fail(), wallet_exception,
"Failed to open wallet lock file at ${f}", (
"f", lock_path.string()));
301 wallet_dir_lock = std::make_unique<boost::interprocess::file_lock>(lock_path.string().c_str());
302 if(!wallet_dir_lock->try_lock()) {
303 wallet_dir_lock.reset();
304 SYS_THROW(wallet_exception,
"Failed to lock access to wallet directory; is another kiod running?");
306 auto timer = std::make_shared<boost::asio::deadline_timer>(
appbase::app().get_io_service(), boost::posix_time::seconds(1));
307 start_lock_watch(timer);
#define SYS_THROW(exc_type, FORMAT,...)
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
static private_key generate()
wraps boost::filesystem::path to provide platform independent path manipulation.
void unlock(const std::string &name, const std::string &password)
void own_and_use_wallet(const string &name, std::unique_ptr< wallet_api > &&wallet)
Takes ownership of a wallet to use.
map< public_key_type, private_key_type > list_keys(const string &name, const string &pw)
void set_timeout(const std::chrono::seconds &t)
void lock_all()
Locks all the unlocked wallets.
chain::signed_transaction sign_transaction(const chain::signed_transaction &txn, const flat_set< public_key_type > &keys, const chain::chain_id_type &id)
flat_set< public_key_type > get_public_keys()
void import_key(const std::string &name, const std::string &wif_key)
std::string create(const std::string &name)
void open(const std::string &name)
void remove_key(const std::string &name, const std::string &password, const std::string &key)
string create_key(const std::string &name, const std::string &key_type)
chain::signature_type sign_digest(const chain::digest_type &digest, const public_key_type &key)
std::vector< std::string > list_wallets()
void lock(const std::string &name)
#define FC_LOG_AND_RETHROW()
fc::sha256 digest(const T &value)
bool exists(const path &p)
std::string gen_password()
constexpr auto password_prefix
bool valid_filename(const string &name)
Immutable except for fc::from_variant.
constexpr bool empty() const
vector< bytes > context_free_data
for each context-free action, there is an entry here
vector< signature_type > signatures
digest_type sig_digest(const chain_id_type &chain_id, const vector< bytes > &cfd=vector< bytes >()) const