You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libpEpAdapter/src/passphrase_cache.cc

174 lines
4.7 KiB
C++

// This file is under GNU General Public License 3.0
// see LICENSE.txt
#include <cassert>
#include "Adapter.hh"
3 years ago
#include "passphrase_cache.hh"
3 years ago
#include "callback_dispatcher.hh"
3 years ago
pEp::PassphraseCache pEp::passphrase_cache;
3 years ago
namespace pEp {
PassphraseCache::cache_entry::cache_entry(const std::string& p, time_point t)
: passphrase{p, 0, PassphraseCache::cache_entry::max_len}, tp{t}
{
}
PassphraseCache::PassphraseCache(size_t max_size, duration timeout)
: _max_size{max_size}, _timeout{timeout}, _which(_cache.end()), first_time(true)
{
}
PassphraseCache::PassphraseCache(const PassphraseCache& second)
: _cache{second._cache}, _max_size{second._max_size}, _timeout{second._timeout},
_stored{second._stored}, _which(_cache.end()), first_time(true)
{
cleanup();
}
3 years ago
PassphraseCache& PassphraseCache::operator=(const PassphraseCache& second)
{
3 years ago
_cache = second._cache;
_max_size = second._max_size;
_timeout = second._timeout;
_which = _cache.end();
cleanup();
return *this;
}
const char* PassphraseCache::add(const std::string& passphrase)
3 years ago
{
if (!passphrase.empty()) {
const char* result = nullptr;
3 years ago
{
std::lock_guard<std::mutex> lock(_mtx);
3 years ago
while (_cache.size() >= _max_size)
_cache.pop_front();
3 years ago
_cache.push_back({passphrase, clock::now()});
auto back = _cache.end();
assert(!_cache.empty());
result = (--back)->passphrase.c_str();
}
callback_dispatcher.semaphore.go();
return result;
}
static const char* empty = "";
return empty;
3 years ago
}
const char* PassphraseCache::add_stored(const std::string& passphrase)
{
3 years ago
std::lock_guard<std::mutex> lock(_stored_mtx);
_stored = passphrase;
return _stored.c_str();
}
bool PassphraseCache::for_each_passphrase(const passphrase_callee& callee)
3 years ago
{
if (callee(std::string()))
return true;
3 years ago
{
3 years ago
std::lock_guard<std::mutex> lock(_stored_mtx);
3 years ago
if (!_stored.empty() && callee(_stored))
3 years ago
return true;
3 years ago
}
{
std::lock_guard<std::mutex> lock(_mtx);
cleanup();
for (auto entry = _cache.begin(); entry != _cache.end(); ++entry) {
3 years ago
if (callee(entry->passphrase)) {
refresh(entry);
return true;
}
}
3 years ago
}
return false;
}
void PassphraseCache::cleanup()
{
while (!_cache.empty() && _cache.front().tp < clock::now() - _timeout)
_cache.pop_front();
3 years ago
}
void PassphraseCache::refresh(cache::iterator entry)
{
entry->tp = clock::now();
_cache.splice(_cache.end(), _cache, entry);
}
const char* PassphraseCache::latest_passphrase(PassphraseCache& c)
{
3 years ago
if (c.first_time) {
c.cleanup();
c._which = c._cache.end();
c.first_time = false;
if (!c._stored.empty())
return c._stored.c_str();
}
3 years ago
if (c._cache.empty()) {
c.first_time = true;
3 years ago
throw Empty();
}
3 years ago
if (c._which == c._cache.begin()) {
c.first_time = true;
3 years ago
throw Exhausted();
}
3 years ago
3 years ago
--c._which;
return c._which->passphrase.c_str();
}
PEP_STATUS PassphraseCache::config_next_passphrase(bool reset, PEP_SESSION session)
{
static pEp::PassphraseCache _copy;
static bool new_copy = true;
if (reset) {
new_copy = true;
return PEP_STATUS_OK;
}
if (new_copy) {
_copy = passphrase_cache;
new_copy = false;
}
try {
::config_passphrase(session ? session : Adapter::session(), latest_passphrase(_copy));
return PEP_STATUS_OK;
} catch (pEp::PassphraseCache::Empty&) {
new_copy = true;
return PEP_PASSPHRASE_REQUIRED;
} catch (pEp::PassphraseCache::Exhausted&) {
new_copy = true;
return PEP_WRONG_PASSPHRASE;
}
}
PEP_STATUS PassphraseCache::ensure_passphrase(PEP_SESSION session, std::string fpr)
{
PEP_STATUS status;
for_each_passphrase([&](std::string passphrase) {
status = ::config_passphrase(session, passphrase.c_str());
if (status)
return true;
status = ::probe_encrypt(session, fpr.c_str());
return status == PEP_STATUS_OK;
});
return status;
}
}; // namespace pEp