password handling: fixed KWallet support, global configuration option

KWallet support was broken: syncevo-dbus-server checked
KDE_FULL_SESSION to determine whether it should use KWallet instead of
GNOME Keyring. That did not work, because the env variable was not set
for D-Bus daemons.

Automatically detecting KDE users is not possible at the
moment. Instead KDE users have to manually set the new "keyring"
global config property to "KDE" (case insensitive) if the
SyncEvolution installation supports both, because GNOME Keyring is the
default to avoid surprises for traditional users. If only KWallet
support is enabled, then this is not necessary.

"GNOME" and "true/false/1/0/yes/no" can also be set. This has the
advantage that keyring usage can be enabled permanently for the
command line in --daemon=no mode; normally keyrings are not used in
that mode because accessing them can bring up UI dialogs.

It also becomes possible to disable keyring usage in syncevo-dbus-server,
something which couldn't be done before.

The --keyring command line option is still supported, as an alias for
"[--sync-property] keyring=<value>". The default value for --keyring
is true, to match the traditional behavior. In contrast to other sync
properties, setting "keyring" does not require an explicit --run
parameter. Again this is done to mirror traditional usage.

Reading a password also (unintentionally) checked all supported
storages while searching for the password. Now it uses exactly
one storage and falls back to asking for the password directly.

The commit itself also cleans up the code a bit (reformatted, fixed
comments). Choosing the right slot in the password signals is done via
a new InitStateTri parameter which contains the "keyring" setting.
Error checking (unsupported keyring string, --keyring=yes and no
keyring enabled) is done in additional slots which run after all the
regular ones.

Parameter parsing for --sync and --keyring were unified. However,
there is the difference that --keyring has an implicit default value
("yes") and never has an additional parameter, in contrast to --sync,
which always is followed by one.

The new CmdlineTest::testKeyring covers different ways of using
--keyring. It relies on actually invoking keyring backends, something
not done by the default SyncContext UI. Therefore
CmdlineSyncClient+KeyringSyncCmdline were moved into libsyncevolution,
to be used by CmdlineTest.
This commit is contained in:
Patrick Ohly 2012-05-29 18:14:13 +02:00
parent d2fd4806c8
commit 8da86205df
26 changed files with 608 additions and 189 deletions

View File

@ -629,25 +629,10 @@ a list of valid values.
Suppresses most of the normal output during a synchronization. The
log file still contains all the information.
--keyring|-k
Save or retrieve passwords from the GNOME keyring when modifying the
configuration or running a synchronization. Note that using this option
applies to *all* passwords in a configuration, so setting a single
password as follows moves the other passwords into the keyring, if
they were not stored there already::
--keyring --configure --sync-property proxyPassword=foo
When passwords were stored in the keyring, their value is set to a single
hyphen ("-") in the configuration. This means that when running a
synchronization without the --keyring argument, the password has to be
entered interactively. The --print-config output always shows "-" instead
of retrieving the password from the keyring.
The SyncEvolution daemon always uses the GNOME keyring, regardless of
the --keyring command line parameter. Therefore --keyring only has an
effect in combination with --daemon=no, or when SyncEvolution was compiled
without daemon support (not the default).
--keyring[=<value>]|-k
A legacy option, now the same as setting the global keyring sync property.
When not specifying a value explicitly, "true" for "use some kind of
keyring" is implied. See "--sync-property keyring" for details.
--daemon[=yes/no]
By default, the SyncEvolution command line is executed inside the

View File

@ -44,11 +44,33 @@ inline const char *passwdStr(const std::string &str)
return str.empty() ? NULL : str.c_str();
}
bool GNOMELoadPasswordSlot(const std::string &passwordName,
static bool UseGNOMEKeyring(const InitStateTri &keyring)
{
// Disabled by user?
if (keyring.getValue() == InitStateTri::VALUE_FALSE) {
return false;
}
// If explicitly selected, it must be us.
if (keyring.getValue() == InitStateTri::VALUE_STRING &&
!boost::iequals(keyring.get(), "GNOME")) {
return false;
}
// Use GNOME Keyring.
return true;
}
bool GNOMELoadPasswordSlot(const InitStateTri &keyring,
const std::string &passwordName,
const std::string &descr,
const ConfigPasswordKey &key,
std::string &password)
InitStateString &password)
{
if (!UseGNOMEKeyring(keyring)) {
return false;
}
GnomeKeyringResult result;
GList* list;
@ -65,19 +87,22 @@ bool GNOMELoadPasswordSlot(const std::string &passwordName,
if(result == GNOME_KEYRING_RESULT_OK && list && list->data ) {
GnomeKeyringNetworkPasswordData *key_data;
key_data = (GnomeKeyringNetworkPasswordData*)list->data;
password = key_data->password;
password = std::string(key_data->password);
gnome_keyring_network_password_list_free(list);
return true;
}
// not found, ask user
return false;
return true;
}
bool GNOMESavePasswordSlot(const std::string &passwordName,
bool GNOMESavePasswordSlot(const InitStateTri &keyring,
const std::string &passwordName,
const std::string &password,
const ConfigPasswordKey &key)
{
if (!UseGNOMEKeyring(keyring)) {
return false;
}
guint32 itemId;
GnomeKeyringResult result;
// write password to keyring

View File

@ -22,17 +22,21 @@
#include <string>
#include <syncevo/util.h>
#include <syncevo/declarations.h>
SE_BEGIN_CXX
struct ConfigPasswordKey;
bool GNOMELoadPasswordSlot(const std::string &passwordName,
bool GNOMELoadPasswordSlot(const InitStateTri &keyring,
const std::string &passwordName,
const std::string &descr,
const ConfigPasswordKey &key,
std::string &password);
InitStateString &password);
bool GNOMESavePasswordSlot(const std::string &passwordName,
bool GNOMESavePasswordSlot(const InitStateTri &keyring,
const std::string &passwordName,
const std::string &password,
const ConfigPasswordKey &key);
SE_END_CXX

View File

@ -90,6 +90,33 @@ void KDEInitMainSlot(const char *appname)
}
}
static bool UseKWallet(const InitStateTri &keyring,
int slotCount)
{
// Disabled by user?
if (keyring.getValue() == InitStateTri::VALUE_FALSE) {
return false;
}
// When both (presumably) GNOME keyring and KWallet are available,
// check if the user really wanted KWallet before using KWallet
// instead of GNOME keyring. This default favors GNOME keyring
// over KWallet because SyncEvolution traditionally used that.
if (keyring.getValue() == InitStateTri::VALUE_TRUE &&
slotCount > 1) {
return false;
}
// If explicitly selected, it must be us.
if (keyring.getValue() == InitStateTri::VALUE_STRING &&
!boost::iequals(keyring.get(), "KDE")) {
return false;
}
// Use KWallet.
return true;
}
/**
* Here we use server sync url without protocol prefix and
* user account name as the key in the keyring.
@ -97,16 +124,14 @@ void KDEInitMainSlot(const char *appname)
* Also since the KWallet's API supports only storing (key,password)
* or Map<QString,QString> , the former is used.
*/
bool KWalletLoadPasswordSlot(const std::string &passwordName,
bool KWalletLoadPasswordSlot(const InitStateTri &keyring,
const std::string &passwordName,
const std::string &descr,
const ConfigPasswordKey &key,
std::string &password)
InitStateString &password)
{
// When both (presumably) GNOME keyring and KWallet are
// available, check if this is a KDE Session before using
// KWallet instead of GNOME keyring.
if (GetLoadPasswordSignal().num_slots() > 1 &&
!getenv("KDE_FULL_SESSION")) {
if (!UseKWallet(keyring,
GetLoadPasswordSignal().num_slots() - INTERNAL_LOAD_PASSWORD_SLOTS)) {
return false;
}
@ -123,29 +148,26 @@ bool KWalletLoadPasswordSlot(const std::string &passwordName,
//QString folder = QString::fromUtf8("Syncevolution");
const QLatin1String folder("Syncevolution");
password = "";
if (!KWallet::Wallet::keyDoesNotExist(wallet_name, folder, walletKey)) {
KWallet::Wallet *wallet = KWallet::Wallet::openWallet(wallet_name, -1, KWallet::Wallet::Synchronous);
if (wallet &&
wallet->setFolder(folder) &&
wallet->readPassword(walletKey, walletPassword) == 0) {
password = walletPassword.toStdString();
return true;
}
}
// not found, ask user
return false;
return true;
}
bool KWalletSavePasswordSlot(const std::string &passwordName,
bool KWalletSavePasswordSlot(const InitStateTri &keyring,
const std::string &passwordName,
const std::string &password,
const ConfigPasswordKey &key)
{
// see above
if (GetLoadPasswordSignal().num_slots() > 1 &&
!getenv("KDE_FULL_SESSION")) {
if (!UseKWallet(keyring,
GetSavePasswordSignal().num_slots() - INTERNAL_SAVE_PASSWORD_SLOTS)) {
return false;
}

View File

@ -22,6 +22,8 @@
#include <string>
#include <syncevo/util.h>
#include <syncevo/declarations.h>
SE_BEGIN_CXX
@ -29,12 +31,14 @@ struct ConfigPasswordKey;
void KDEInitMainSlot(const char *appname);
bool KWalletLoadPasswordSlot(const std::string &passwordName,
bool KWalletLoadPasswordSlot(const InitStateTri &keyring,
const std::string &passwordName,
const std::string &descr,
const ConfigPasswordKey &key,
std::string &password);
InitStateString &password);
bool KWalletSavePasswordSlot(const std::string &passwordName,
bool KWalletSavePasswordSlot(const InitStateTri &keyring,
const std::string &passwordName,
const std::string &password,
const ConfigPasswordKey &key);
SE_END_CXX

View File

@ -334,7 +334,7 @@ public:
ClientTest(const string &server,
const string &logbase,
const SyncOptions &options) :
CmdlineSyncClient(server, false, true),
CmdlineSyncClient(server, false),
m_logbase(logbase),
m_options(options),
m_started(false)

View File

@ -196,7 +196,9 @@ string DBusSync::askPassword(const string &passwordName,
return password;
}
void DBusSync::askPasswordAsync(const std::string &passwordName, const std::string &descr, const ConfigPasswordKey &key,
void DBusSync::askPasswordAsync(const std::string &passwordName,
const std::string &descr,
const ConfigPasswordKey &key,
const boost::function<void (const std::string &)> &success,
const boost::function<void ()> &failureException)
{
@ -205,8 +207,9 @@ void DBusSync::askPasswordAsync(const std::string &passwordName, const std::stri
m_passwordFailure.clear();
m_passwordDescr = descr;
string password;
if (GetLoadPasswordSignal()(passwordName, descr, key, password)) {
InitStateString password;
if (GetLoadPasswordSignal()(getKeyring(), passwordName, descr, key, password) &&
password.wasSet()) {
// handled
success(password);
return;
@ -279,9 +282,11 @@ void DBusSync::suspendFlagsChanged(SuspendFlags &flags)
}
}
bool DBusSync::savePassword(const std::string &passwordName, const std::string &password, const ConfigPasswordKey &key)
bool DBusSync::savePassword(const std::string &passwordName,
const std::string &password,
const ConfigPasswordKey &key)
{
if (GetSavePasswordSignal()(passwordName, password, key)) {
if (GetSavePasswordSignal()(getKeyring(), passwordName, password, key)) {
return true;
}

View File

@ -76,11 +76,15 @@ protected:
string askPassword(const string &passwordName,
const string &descr,
const ConfigPasswordKey &key);
virtual void askPasswordAsync(const std::string &passwordName, const std::string &descr, const ConfigPasswordKey &key,
virtual void askPasswordAsync(const std::string &passwordName,
const std::string &descr,
const ConfigPasswordKey &key,
const boost::function<void (const std::string &)> &success,
const boost::function<void ()> &failureException);
virtual bool savePassword(const std::string &passwordName, const std::string &password, const ConfigPasswordKey &key);
virtual bool savePassword(const std::string &passwordName,
const std::string &password,
const ConfigPasswordKey &key);
virtual void readStdin(std::string &content);
};

View File

@ -23,12 +23,18 @@
SE_BEGIN_CXX
DBusUserInterface::DBusUserInterface(const InitStateTri &keyring) :
m_keyring(keyring)
{
}
std::string DBusUserInterface::askPassword(const std::string &passwordName,
const std::string &descr,
const ConfigPasswordKey &key)
{
std::string password;
if (GetLoadPasswordSignal()(passwordName, descr, key, password)) {
InitStateString password;
if (GetLoadPasswordSignal()(m_keyring, passwordName, descr, key, password) &&
password.wasSet()) {
// handled
return password;
}
@ -41,7 +47,7 @@ bool DBusUserInterface::savePassword(const std::string &passwordName,
const std::string &password,
const ConfigPasswordKey &key)
{
if (GetSavePasswordSignal()(passwordName, password, key)) {
if (GetSavePasswordSignal()(m_keyring, passwordName, password, key)) {
return true;
}

View File

@ -21,6 +21,7 @@
#define DBUS_USER_INTERFACE_H
#include <syncevo/UserInterface.h>
#include <syncevo/util.h>
#include <syncevo/declarations.h>
SE_BEGIN_CXX
@ -33,15 +34,17 @@ SE_BEGIN_CXX
class DBusUserInterface : public UserInterface
{
public:
DBusUserInterface(const InitStateTri &keyring);
/*
* Ask password from gnome keyring, if not found, empty string
* Ask password from keyring, if not found, empty string
* is returned
*/
std::string askPassword(const std::string &passwordName,
const std::string &descr,
const ConfigPasswordKey &key);
//save password to gnome keyring, if not successful, false is returned.
//save password to keyring, if not successful, false is returned.
bool savePassword(const std::string &passwordName,
const std::string &password,
const ConfigPasswordKey &key);
@ -50,6 +53,9 @@ public:
* Read stdin via InfoRequest/Response.
*/
void readStdin(std::string &content);
private:
InitStateTri m_keyring;
};
SE_END_CXX

View File

@ -173,8 +173,8 @@ void ReadOperations::getNamedConfig(const std::string &configName,
}
syncConfig = dbusConfig.get();
} else {
DBusUserInterface ui;
dbusConfig = getLocalConfig(configName);
DBusUserInterface ui(dbusConfig->getKeyring());
//try to check password and read password from gnome keyring if possible
ConfigPropertyRegistry& registry = SyncConfig::getRegistry();
BOOST_FOREACH(const ConfigProperty *prop, registry) {

View File

@ -101,8 +101,6 @@ src/libstdc++.a :
src_syncevolution_SOURCES = \
src/syncevolution.cpp \
src/CmdlineSyncClient.h \
src/CmdlineSyncClient.cpp \
$(CORE_SOURCES)
if ENABLE_UNIT_TESTS
@ -219,7 +217,6 @@ endif # COND_DBUS
# link line.
src_client_test_SOURCES = \
src/client-test-app.cpp \
src/CmdlineSyncClient.cpp \
test/ClientTest.cpp \
test/ClientTest.h \
test/ClientTestAssert.h \

View File

@ -19,6 +19,7 @@
*/
#include <syncevo/Cmdline.h>
#include <syncevo/CmdlineSyncClient.h>
#include <syncevo/FilterConfigNode.h>
#include <syncevo/VolatileConfigNode.h>
#include <syncevo/IniConfigNode.h>
@ -104,6 +105,18 @@ bool Cmdline::parse()
return parse(parsed);
}
/**
* Detects "--sync foo", "--sync=foo", "-s foo".
*/
static bool IsKeyword(const std::string arg,
const char *longWord,
const char *shortWord)
{
return boost::istarts_with(arg, std::string(longWord) + "=") ||
boost::iequals(arg, longWord) ||
boost::iequals(arg, shortWord);
}
bool Cmdline::parse(vector<string> &parsed)
{
parsed.clear();
@ -143,21 +156,18 @@ bool Cmdline::parse(vector<string> &parsed)
break;
}
}
if (boost::iequals(m_argv[opt], "--sync") ||
boost::iequals(m_argv[opt], "-s")) {
opt++;
string param;
string cmdopt(m_argv[opt - 1]);
if (!parseProp(SOURCE_PROPERTY_TYPE,
m_argv[opt - 1], opt == m_argc ? NULL : m_argv[opt],
"sync")) {
if (IsKeyword(m_argv[opt], "--sync", "-s")) {
if (!parseAssignment(opt, parsed, SOURCE_PROPERTY_TYPE, "sync", NULL)) {
return false;
}
parsed.push_back(m_argv[opt]);
// disable requirement to add --run explicitly in order to
// be compatible with traditional command lines
m_run = true;
} else if (IsKeyword(m_argv[opt], "--keyring", "-k")) {
if (!parseAssignment(opt, parsed, SYNC_PROPERTY_TYPE, "keyring", "true")) {
return false;
}
} else if(boost::iequals(m_argv[opt], "--sync-property") ||
boost::iequals(m_argv[opt], "-y")) {
opt++;
@ -293,10 +303,6 @@ bool Cmdline::parse(vector<string> &parsed)
} else if(boost::iequals(m_argv[opt], "--version")) {
operations.push_back(m_argv[opt]);
m_version = true;
} else if (parseBool(opt, "--keyring", "-k", true, m_keyring, ok)) {
if (!ok) {
return false;
}
} else if (parseBool(opt, "--daemon", NULL, true, m_useDaemon, ok)) {
if (!ok) {
return false;
@ -403,7 +409,7 @@ bool Cmdline::isSync()
!m_restore.empty() ||
m_accessItems ||
m_dryrun ||
(!m_run && m_props.hasProperties())) {
(!m_run && m_props.hasProperties(FullProps::IGNORE_GLOBAL_PROPS))) {
return false;
} else {
return true;
@ -502,6 +508,13 @@ void Cmdline::copyConfig(const boost::shared_ptr<SyncConfig> &from,
from->setConfigFilter(false, entry.first, entry.second);
}
// Modify behavior of target UI before using it: set keyring
// property separately.
InitStateTri keyring = from->getKeyring();
if (keyring.wasSet()) {
to->setKeyring(keyring);
}
// Write into the requested configuration, creating it if necessary.
to->prepareConfigForWrite();
to->copy(*from, sources);
@ -820,15 +833,6 @@ bool Cmdline::run() {
if (m_dryrun) {
SyncContext::throwError("--dry-run not supported for configuration changes");
}
if (m_keyring &&
GetLoadPasswordSignal().empty()) {
SE_LOG_ERROR(NULL, NULL,
"This syncevolution binary was compiled without support for storing "
"passwords in a keyring or wallet, or the backends for that functionality are not usable. "
"Either store passwords in your configuration "
"files or enter them interactively on each program run.");
return false;
}
// name of renamed config ("foo.old") after migration
string newname;
@ -1194,7 +1198,7 @@ bool Cmdline::run() {
// extra sanity check
if (!m_sources.empty() ||
m_props.hasProperties()) {
m_props.hasProperties(FullProps::IGNORE_GLOBAL_PROPS)) {
usage(false, "too many parameters for --remove");
return false;
} else {
@ -1607,7 +1611,7 @@ bool Cmdline::run() {
// safety catch: if props are given, then --run
// is required
if (!m_run &&
(m_props.hasProperties())) {
(m_props.hasProperties(FullProps::IGNORE_GLOBAL_PROPS))) {
usage(false, "Properties specified, but neither '--configure' nor '--run' - what did you want?");
return false;
}
@ -1649,10 +1653,14 @@ string Cmdline::cmdOpt(const char *opt, const char *param)
if (opt) {
res += opt;
}
if (opt && param) {
// parameter was provided as part of option
bool included = opt && param &&
boost::ends_with(std::string(opt),
std::string("=") + param);
if (!included && opt && param) {
res += " ";
}
if (param) {
if (!included && param) {
res += param;
}
res += "'";
@ -1795,6 +1803,36 @@ bool Cmdline::parseProp(PropertyType propertyType,
}
}
bool Cmdline::parseAssignment(int &opt, vector<string> &parsed,
PropertyType propertyType,
const char *propname,
const char *def)
{
string param;
bool haveParam = false;
string cmdopt(m_argv[opt]);
size_t off = cmdopt.find('=');
if (off != cmdopt.npos) {
// value embedded in option
param = cmdopt.substr(off + 1);
haveParam = true;
} else if (!def && ++opt < m_argc) {
// assume next entry is parameter
param = m_argv[opt];
parsed.push_back(m_argv[opt]);
haveParam = true;
} else if (def) {
// use default
param = def;
haveParam = true;
}
return parseProp(propertyType,
cmdopt.c_str(),
haveParam ? param.c_str() : NULL,
propname);
}
bool Cmdline::listPropValues(const ConfigPropertyRegistry &validProps,
const string &propName,
const string &opt)
@ -2155,7 +2193,7 @@ static bool isPropAssignment(const string &buffer) {
// remove pure comment lines from buffer,
// also empty lines,
// also defaultPeer (because reference properties do not include global props)
// also defaultPeer and keyring (because reference properties do not include global props)
static string filterConfig(const string &buffer)
{
ostringstream res;
@ -2168,6 +2206,7 @@ static string filterConfig(const string &buffer)
string line = boost::copy_range<string>(*it);
if (!line.empty() &&
line.find("defaultPeer =") == line.npos &&
line.find("keyring =") == line.npos &&
(!boost::starts_with(line, "# ") ||
isPropAssignment(line.substr(2)))) {
res << line << endl;
@ -2413,6 +2452,7 @@ class CmdlineTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testMatchTemplate);
CPPUNIT_TEST(testAddSource);
CPPUNIT_TEST(testSync);
CPPUNIT_TEST(testKeyring);
CPPUNIT_TEST(testWebDAV);
CPPUNIT_TEST(testConfigure);
CPPUNIT_TEST(testConfigureTemplates);
@ -3238,6 +3278,11 @@ protected:
CPPUNIT_ASSERT_EQUAL_DIFF("", failure2.m_out.str());
CPPUNIT_ASSERT_EQUAL_DIFF("[ERROR] '--sync foo': not one of the valid values (two-way, slow, refresh-from-local, refresh-from-remote = refresh, one-way-from-local, one-way-from-remote = one-way, refresh-from-client = refresh-client, refresh-from-server = refresh-server, one-way-from-client = one-way-client, one-way-from-server = one-way-server, disabled = none)\n", failure2.m_err.str());
TestCmdline failure3("--sync=foo", NULL);
CPPUNIT_ASSERT(!failure3.m_cmdline->parse());
CPPUNIT_ASSERT_EQUAL_DIFF("", failure3.m_out.str());
CPPUNIT_ASSERT_EQUAL_DIFF("[ERROR] '--sync=foo': not one of the valid values (two-way, slow, refresh-from-local, refresh-from-remote = refresh, one-way-from-local, one-way-from-remote = one-way, refresh-from-client = refresh-client, refresh-from-server = refresh-server, one-way-from-client = one-way-client, one-way-from-server = one-way-server, disabled = none)\n", failure3.m_err.str());
TestCmdline help("--sync", " ?", NULL);
help.doit();
CPPUNIT_ASSERT_EQUAL_DIFF("--sync\n"
@ -3305,6 +3350,165 @@ protected:
CPPUNIT_ASSERT_NO_THROW(filter5.expectUsageError("[ERROR] a property name must be given in '=1'\n"));
}
void testKeyring() {
ScopedEnvChange xdg("XDG_CONFIG_HOME", m_testDir);
ScopedEnvChange home("HOME", m_testDir);
rm_r(m_testDir);
{
TestCmdline cmdline(NULL, NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(false, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_TRUE, keyring.getValue());
}
{
TestCmdline cmdline("--keyring", NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_TRUE, keyring.getValue());
}
{
TestCmdline cmdline("--sync-property", "keyring=True", NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_TRUE, keyring.getValue());
}
{
TestCmdline cmdline("keyring=True", NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_TRUE, keyring.getValue());
}
{
TestCmdline cmdline("--keyring=true", NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_TRUE, keyring.getValue());
}
{
TestCmdline cmdline("--keyring=1", NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_TRUE, keyring.getValue());
}
{
TestCmdline cmdline("--keyring=Yes", NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_TRUE, keyring.getValue());
}
{
TestCmdline cmdline("--keyring=false", NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_FALSE, keyring.getValue());
}
{
TestCmdline cmdline("--keyring=0", NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_FALSE, keyring.getValue());
}
{
TestCmdline cmdline("--keyring=NO", NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_FALSE, keyring.getValue());
}
{
TestCmdline cmdline("--keyring=GNOME", NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_STRING, keyring.getValue());
CPPUNIT_ASSERT_EQUAL(std::string("GNOME"), keyring.get());
}
// empty config prop
{
TestCmdline cmdline("--configure", "@default", NULL);
cmdline.doit();
}
{
TestCmdline cmdline("@foobar", NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(false, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_TRUE, keyring.getValue());
}
// now set the value permanently
{
TestCmdline cmdline("--keyring", "--configure", "@default", NULL);
cmdline.doit();
}
{
TestCmdline cmdline("@foobar", NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_TRUE, keyring.getValue());
}
{
TestCmdline cmdline("--keyring=KDE", "--configure", "@default", NULL);
cmdline.doit();
}
{
TestCmdline cmdline("@foobar", NULL);
boost::shared_ptr<SyncContext> context = cmdline.parse();
CPPUNIT_ASSERT(context);
InitStateTri keyring = context->getKeyring();
CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet());
CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_STRING, keyring.getValue());
CPPUNIT_ASSERT_EQUAL(std::string("KDE"), keyring.get());
}
// allow sync operation although --keyring was set
{
TestCmdline cmdline("keyring=GNOME", "foobar@default", NULL);
cmdline.doit(false);
CPPUNIT_ASSERT_EQUAL(std::string(""), cmdline.m_out.str());
CPPUNIT_ASSERT_EQUAL(std::string("[ERROR] No configuration for server \"foobar@default\" found.\n[ERROR] cannot proceed without configuration"), cmdline.m_err.str());
}
// catch invalid "keyring" value
{
TestCmdline cmdline("--configure",
"username=foo",
"password=bar",
"syncURL=http://no.such.server",
"keyring=no-such-keyring",
"foobar@default", NULL);
cmdline.doit(false);
CPPUNIT_ASSERT_EQUAL(std::string(""), cmdline.m_out.str());
CPPUNIT_ASSERT_EQUAL(std::string("[ERROR] Unsupported value for the \"keyring\" property, no such keyring found: no-such-keyring"),
cmdline.m_err.str());
}
}
void testWebDAV() {
#ifdef ENABLE_DAV
ScopedEnvChange templates("SYNCEVOLUTION_TEMPLATE_DIR", "templates");
@ -3505,7 +3709,9 @@ protected:
"\n"
"peerType (no default, unshared)\n"
"\n"
"defaultPeer (no default, global)\n");
"defaultPeer (no default, global)\n"
"\n"
"keyring (yes, global)\n");
string sourceProperties("sync (disabled, unshared, required)\n"
"\n"
@ -4714,7 +4920,7 @@ private:
m_argv[index + 1] = m_argvstr[index].c_str();
}
m_cmdline.set(new Cmdline(m_argvstr.size() + 1, m_argv.get()), "cmdline");
m_cmdline.set(new KeyringSyncCmdline(m_argvstr.size() + 1, m_argv.get()), "cmdline");
}
public:
@ -4741,6 +4947,16 @@ private:
popLogger();
}
boost::shared_ptr<SyncContext> parse()
{
if (!m_cmdline->parse()) {
return boost::shared_ptr<SyncContext>();
}
boost::shared_ptr<SyncContext> context(new SyncContext(m_cmdline->m_server));
context->setConfigFilter(true, "", m_cmdline->m_props.createSyncFilter(m_cmdline->m_server));
return context;
}
void doit(bool expectSuccess = true) {
bool success = false;
m_out.str("");

View File

@ -147,7 +147,6 @@ protected:
Bool m_printConfig;
Bool m_printSessions;
Bool m_dontrun;
Bool m_keyring;
Bool m_monitor;
Bool m_useDaemon;
FullProps m_props;
@ -214,6 +213,20 @@ protected:
const char *param,
const char *propname = NULL);
/**
* parse keyword which sets a certain property,
* like --sync=two-way, --sync two-way, ... for the "sync" property
*
* If a default value is give, then the format is like:
* --keyring[=<def>], --keyring=<value>, ...
* but not
* --keyring <value>
*/
bool parseAssignment(int &opt, std::vector<std::string> &parsed,
PropertyType propertyType,
const char *propname,
const char *def);
bool listPropValues(const ConfigPropertyRegistry &validProps,
const std::string &propName,
const std::string &opt);

View File

@ -27,10 +27,8 @@ SE_BEGIN_CXX
using namespace std;
CmdlineSyncClient::CmdlineSyncClient(const string &server,
bool doLogging,
bool useKeyring):
SyncContext(server, doLogging),
m_keyring(useKeyring)
bool doLogging):
SyncContext(server, doLogging)
{
setUserInterface(this);
}
@ -39,11 +37,12 @@ string CmdlineSyncClient::askPassword(const string &passwordName,
const string &descr,
const ConfigPasswordKey &key)
{
string password;
InitStateString password;
// try to use keyring, if allowed
if (m_keyring &&
GetLoadPasswordSignal()(passwordName, descr, key, password)) {
if (useKeyring() &&
GetLoadPasswordSignal()(getKeyring(), passwordName, descr, key, password) &&
password.wasSet()) {
// succcess
return password;
}
@ -62,7 +61,7 @@ string CmdlineSyncClient::askPassword(const string &passwordName,
if (len && buffer[len - 1] == '\n') {
buffer[len - 1] = 0;
}
password = buffer;
password = std::string(buffer);
} else {
throwError(string("could not read password for ") + descr);
}
@ -74,19 +73,10 @@ bool CmdlineSyncClient::savePassword(const string &passwordName,
const string &password,
const ConfigPasswordKey &key)
{
// use keyring?
if (m_keyring) {
if (GetSavePasswordSignal()(passwordName, password, key)) {
// saved!
return true;
}
/* if no keyring support and it was requested, then raise an error */
SyncContext::throwError("Cannot save " + passwordName + " as requested. "
"This SyncEvolution binary was compiled without support for storing "
"passwords in a keyring or wallet, or none of the backends providing that "
"functionality were usable. Either store passwords in your configuration "
"files or enter them interactively on each program run.\n");
if (useKeyring() &&
GetSavePasswordSignal()(getKeyring(), passwordName, password, key)) {
// saved!
return true;
}
// let config code store the password
@ -100,4 +90,12 @@ void CmdlineSyncClient::readStdin(string &content)
}
}
bool CmdlineSyncClient::useKeyring()
{
InitStateTri keyring = getKeyring();
return keyring.wasSet() &&
keyring.getValue() != InitStateTri::VALUE_FALSE &&
keyring.get() != "";
}
SE_END_CXX

View File

@ -21,6 +21,7 @@
#define INCL_CMDLINESYNCCLIENT
#include <syncevo/SyncContext.h>
#include <syncevo/Cmdline.h>
#include <syncevo/declarations.h>
SE_BEGIN_CXX
@ -33,8 +34,7 @@ SE_BEGIN_CXX
class CmdlineSyncClient : public SyncContext, private UserInterface {
public:
CmdlineSyncClient(const string &server,
bool doLogging = false,
bool useKeyring = false);
bool doLogging = false);
/**
* These 2 functions are from UserInterface and implement it
@ -47,13 +47,32 @@ class CmdlineSyncClient : public SyncContext, private UserInterface {
/** read from real stdin */
virtual void readStdin(string &content);
void setKeyring(bool keyring) { m_keyring = keyring; }
bool getKeyring() const { return m_keyring; }
private:
/** a bool flag used to indicate whether to use keyring to store password */
bool m_keyring;
/**
* special semantic of --daemon=no command line:
* don't use keyring if option is unset or
* explicitly false
*/
bool useKeyring();
};
/**
* This is a class derived from Cmdline. The purpose
* is to implement the factory method 'createSyncClient' to create
* new implemented 'CmdlineSyncClient' objects.
*/
class KeyringSyncCmdline : public Cmdline {
public:
KeyringSyncCmdline(int argc, const char * const * argv) :
Cmdline(argc, argv)
{}
/**
* create a user implemented sync client.
*/
SyncContext* createSyncClient() {
return new CmdlineSyncClient(m_server, true);
}
};
SE_END_CXX
#endif // INCL_CMDLINESYNCCLIENT

View File

@ -122,12 +122,23 @@ ConfigProps FullProps::createSourceFilter(const std::string &config,
return filter;
}
bool FullProps::hasProperties() const
bool FullProps::hasProperties(PropCheckMode mode) const
{
BOOST_FOREACH(const value_type &context, *this) {
if (!context.second.m_syncProps.empty()) {
if (mode == CHECK_ALL &&
!context.second.m_syncProps.empty()) {
return true;
}
if (mode == IGNORE_GLOBAL_PROPS) {
const ConfigPropertyRegistry &registry = SyncConfig::getRegistry();
BOOST_FOREACH(const StringPair &entry, context.second.m_syncProps) {
const ConfigProperty *prop = registry.find(entry.first);
if (!prop ||
prop->getSharing() != ConfigProperty::GLOBAL_SHARING) {
return true;
}
}
}
BOOST_FOREACH(const SourceProps::value_type &source, context.second.m_sourceProps) {
if (!source.second.empty()) {
return true;

View File

@ -85,8 +85,13 @@ struct ContextProps
class FullProps : public std::map<std::string, ContextProps, Nocase<std::string> >
{
public:
enum PropCheckMode {
CHECK_ALL,
IGNORE_GLOBAL_PROPS
};
/** any of the contained ConfigProps has entries */
bool hasProperties() const;
bool hasProperties(PropCheckMode mode) const;
/**
* Combines sync properties into one filter, giving "config"

View File

@ -423,7 +423,9 @@ public:
{}
/** implements password request by asking the parent via D-Bus */
virtual string askPassword(const string &passwordName, const string &descr, const ConfigPasswordKey &key)
virtual string askPassword(const string &passwordName,
const string &descr,
const ConfigPasswordKey &key)
{
SE_LOG_DEBUG(NULL, NULL, "local transport child: requesting password %s, %s via D-Bus",
passwordName.c_str(),

View File

@ -1418,8 +1418,43 @@ static SafeConfigProperty syncPropDeviceData("deviceData",
"information about the peer in the format described in the\n"
"Synthesis SDK manual under 'Session_SaveDeviceInfo'");
static SafeConfigProperty syncPropDefaultPeer("defaultPeer",
"the peer which is used by default in some frontends, like the sync-UI");
static SafeConfigProperty globalPropDefaultPeer("defaultPeer",
"the peer which is used by default in some frontends, like the sync-UI");
static ConfigProperty globalPropKeyring("keyring",
"Explicitly selects a certain safe password storage.\n"
"Depending on how SyncEvolution was compiled and installed\n"
"the following values are possible:\n"
"\n"
"GNOME\n GNOME Keyring\n"
"KDE\n KWallet\n"
"yes/true/1\n pick one automatically\n"
"no/false/0\n store passwords in SyncEvolution config files\n"
"\n"
"If unset, the default is to pick one automatically in\n"
"the D-Bus server and not use any keyring in the command\n"
"tool when running without that D-Bus server (because the\n"
"keyring might not be usable without a desktop session).\n"
"If support for only storage was compiled and installed,\n"
"then that is the one which gets picked. Otherwise the\n"
"default is to use GNOME Keyring (because distinguishing\n"
"between KDE and GNOME sessions automatically is tricky).\n"
"\n"
"Note that using this option applies to *all* passwords in\n"
"a configuration and that the --keyring command line option\n"
"is merely an alias for setting the global property, so setting\n"
"a single password as follows sets both `keyring` and\n"
"`proxyPasswords`, and also moves the other passwords into the\n"
"keyring, even if they were not stored there already:\n"
"\n"
" --keyring --configure proxyPassword=foo\n"
"\n"
"When passwords were stored in the keyring, their value is set to a single\n"
"hyphen (\"-\") in the configuration. This means that when running a\n"
"synchronization without the --keyring argument, the password has to be\n"
"entered interactively. The --print-config output always shows \"-\" instead\n"
"of retrieving the password from the keyring.\n",
"yes");
static StringConfigProperty syncPropAutoSync("autoSync",
"Controls automatic synchronization. Currently,\n"
@ -1469,17 +1504,17 @@ static SecondsConfigProperty syncPropAutoSyncDelay("autoSyncDelay",
"5M");
/* config and on-disk file versionsing */
static IntConfigProperty syncPropRootMinVersion("rootMinVersion", "");
static IntConfigProperty syncPropRootCurVersion("rootCurVersion", "");
static IntConfigProperty syncPropContextMinVersion("contextMinVersion", "");
static IntConfigProperty syncPropContextCurVersion("contextCurVersion", "");
static IntConfigProperty syncPropPeerMinVersion("peerMinVersion", "");
static IntConfigProperty syncPropPeerCurVersion("peerCurVersion", "");
static IntConfigProperty propRootMinVersion("rootMinVersion", "");
static IntConfigProperty propRootCurVersion("rootCurVersion", "");
static IntConfigProperty propContextMinVersion("contextMinVersion", "");
static IntConfigProperty propContextCurVersion("contextCurVersion", "");
static IntConfigProperty propPeerMinVersion("peerMinVersion", "");
static IntConfigProperty propPeerCurVersion("peerCurVersion", "");
static const IntConfigProperty *configVersioning[CONFIG_LEVEL_MAX][CONFIG_VERSION_MAX] = {
{ &syncPropRootMinVersion, &syncPropRootCurVersion },
{ &syncPropContextMinVersion, &syncPropContextCurVersion },
{ &syncPropPeerMinVersion, &syncPropPeerCurVersion }
{ &propRootMinVersion, &propRootCurVersion },
{ &propContextMinVersion, &propContextCurVersion },
{ &propPeerMinVersion, &propPeerCurVersion }
};
static const IntConfigProperty &getConfigVersionProp(ConfigLevel level, ConfigLimit limit)
@ -1573,7 +1608,8 @@ public:
registry.push_back(&syncPropConfigDate);
registry.push_back(&syncPropNonce);
registry.push_back(&syncPropDeviceData);
registry.push_back(&syncPropDefaultPeer);
registry.push_back(&globalPropDefaultPeer);
registry.push_back(&globalPropKeyring);
#if 0
// Must not be registered! Not valid for --sync-property and
@ -1607,24 +1643,25 @@ public:
syncPropConfigDate.setHidden(true);
syncPropNonce.setHidden(true);
syncPropDeviceData.setHidden(true);
syncPropRootMinVersion.setHidden(true);
syncPropRootCurVersion.setHidden(true);
syncPropContextMinVersion.setHidden(true);
syncPropContextCurVersion.setHidden(true);
syncPropPeerMinVersion.setHidden(true);
syncPropPeerCurVersion.setHidden(true);
propRootMinVersion.setHidden(true);
propRootCurVersion.setHidden(true);
propContextMinVersion.setHidden(true);
propContextCurVersion.setHidden(true);
propPeerMinVersion.setHidden(true);
propPeerCurVersion.setHidden(true);
// global sync properties
syncPropDefaultPeer.setSharing(ConfigProperty::GLOBAL_SHARING);
syncPropRootMinVersion.setSharing(ConfigProperty::GLOBAL_SHARING);
syncPropRootCurVersion.setSharing(ConfigProperty::GLOBAL_SHARING);
globalPropDefaultPeer.setSharing(ConfigProperty::GLOBAL_SHARING);
globalPropKeyring.setSharing(ConfigProperty::GLOBAL_SHARING);
propRootMinVersion.setSharing(ConfigProperty::GLOBAL_SHARING);
propRootCurVersion.setSharing(ConfigProperty::GLOBAL_SHARING);
// peer independent sync properties
syncPropLogDir.setSharing(ConfigProperty::SOURCE_SET_SHARING);
syncPropMaxLogDirs.setSharing(ConfigProperty::SOURCE_SET_SHARING);
syncPropDevID.setSharing(ConfigProperty::SOURCE_SET_SHARING);
syncPropContextMinVersion.setSharing(ConfigProperty::SOURCE_SET_SHARING);
syncPropContextCurVersion.setSharing(ConfigProperty::SOURCE_SET_SHARING);
propContextMinVersion.setSharing(ConfigProperty::SOURCE_SET_SHARING);
propContextCurVersion.setSharing(ConfigProperty::SOURCE_SET_SHARING);
}
} RegisterSyncConfigProperties;
@ -1913,8 +1950,10 @@ InitStateString SyncConfig::getNonce() const { return syncPropNonce.getProperty(
void SyncConfig::setNonce(const string &value) { syncPropNonce.setProperty(*getNode(syncPropNonce), value); }
InitStateString SyncConfig::getDeviceData() const { return syncPropDeviceData.getProperty(*getNode(syncPropDeviceData)); }
void SyncConfig::setDeviceData(const string &value) { syncPropDeviceData.setProperty(*getNode(syncPropDeviceData), value); }
InitStateString SyncConfig::getDefaultPeer() const { return syncPropDefaultPeer.getProperty(*getNode(syncPropDefaultPeer)); }
void SyncConfig::setDefaultPeer(const string &value) { syncPropDefaultPeer.setProperty(*getNode(syncPropDefaultPeer), value); }
InitStateString SyncConfig::getDefaultPeer() const { return globalPropDefaultPeer.getProperty(*getNode(globalPropDefaultPeer)); }
void SyncConfig::setDefaultPeer(const string &value) { globalPropDefaultPeer.setProperty(*getNode(globalPropDefaultPeer), value); }
InitStateTri SyncConfig::getKeyring() const { return globalPropKeyring.getProperty(*getNode(globalPropKeyring)); }
void SyncConfig::setKeyring(const string &value) { globalPropKeyring.setProperty(*getNode(globalPropKeyring), value); }
InitStateString SyncConfig::getAutoSync() const { return syncPropAutoSync.getProperty(*getNode(syncPropAutoSync)); }
void SyncConfig::setAutoSync(const string &value, bool temporarily) { syncPropAutoSync.setProperty(*getNode(syncPropAutoSync), value, temporarily); }

View File

@ -1376,6 +1376,9 @@ class SyncConfig {
virtual InitStateString getDefaultPeer() const;
virtual void setDefaultPeer(const std::string &value);
virtual InitStateTri getKeyring() const;
virtual void setKeyring(const std::string &value);
virtual InitStateString getLogDir() const;
virtual void setLogDir(const std::string &value, bool temporarily = false);

View File

@ -22,19 +22,70 @@
#include <syncevo/declarations.h>
SE_BEGIN_CXX
static bool CheckKeyring(const InitStateTri &keyring)
{
// Default slot, registered with higher priority
// than any other keyring backend. If we get here
// no other backend was chosen by the keyring
// property. If it is a string, then the string
// must have been invalid or unsupported.
if (keyring.wasSet() &&
keyring.getValue() == InitStateTri::VALUE_STRING &&
!keyring.get().empty()) {
SE_THROW("Unsupported value for the \"keyring\" property, no such keyring found: " + keyring.get());
}
return false;
}
static bool PreventPlainText(const InitStateTri &keyring,
const std::string &passwordName)
{
// Another slot, called after CheckKeyring when saving.
// Ensures that if keyring was meant to be used and
// couldn't be used, an error is throw instead of
// silently storing as plain text password.
if (keyring.getValue() != InitStateTri::VALUE_FALSE &&
!keyring.get().empty()) {
SE_THROW(StringPrintf("Cannot save %s as requested in %s."
"This SyncEvolution binary was compiled without support for storing "
"passwords in a keyring or wallet, or none of the backends providing that "
"functionality were usable. Either store passwords in your configuration "
"files or enter them interactively on each program run.\n",
passwordName.c_str(),
(keyring.getValue() == InitStateTri::VALUE_TRUE ||
keyring.get().empty()) ? "a secure keyring" :
keyring.get().c_str()));
}
return false;
}
LoadPasswordSignal &GetLoadPasswordSignal()
{
static LoadPasswordSignal loadPasswordSignal;
static class Signal : public LoadPasswordSignal {
public:
Signal() {
connect(100, boost::bind(CheckKeyring, _1));
}
} loadPasswordSignal;
return loadPasswordSignal;
}
SavePasswordSignal &GetSavePasswordSignal()
{
static SavePasswordSignal savePasswordSignal;
static class Signal : public SavePasswordSignal {
public:
Signal() {
connect(100, boost::bind(CheckKeyring, _1));
connect(101, boost::bind(PreventPlainText, _1, _2));
}
} savePasswordSignal;
return savePasswordSignal;
}
void UserInterface::askPasswordAsync(const std::string &passwordName, const std::string &descr, const ConfigPasswordKey &key,
void UserInterface::askPasswordAsync(const std::string &passwordName,
const std::string &descr,
const ConfigPasswordKey &key,
const boost::function<void (const std::string &)> &success,
const boost::function<void ()> &failureException)
{

View File

@ -24,6 +24,8 @@
#include <boost/signals2.hpp>
#include <syncevo/util.h>
#include <syncevo/declarations.h>
SE_BEGIN_CXX
@ -77,7 +79,9 @@ class UserInterface {
* to make user interface independent on Configuration Tree
* @return entered password
*/
virtual std::string askPassword(const std::string &passwordName, const std::string &descr, const ConfigPasswordKey &key) = 0;
virtual std::string askPassword(const std::string &passwordName,
const std::string &descr,
const ConfigPasswordKey &key) = 0;
/**
* A helper function which interactively asks the user for
@ -94,7 +98,9 @@ class UserInterface {
* @param key the key used to retrieve password. Using this instead of ConfigNode is
* to make user interface independent on Configuration Tree
*/
virtual void askPasswordAsync(const std::string &passwordName, const std::string &descr, const ConfigPasswordKey &key,
virtual void askPasswordAsync(const std::string &passwordName,
const std::string &descr,
const ConfigPasswordKey &key,
const boost::function<void (const std::string &)> &success,
const boost::function<void ()> &failureException);
@ -107,7 +113,9 @@ class UserInterface {
* @param key the key used to store password
* @return true if ui saves the password and false if not
*/
virtual bool savePassword(const std::string &passwordName, const std::string &password, const ConfigPasswordKey &key) = 0;
virtual bool savePassword(const std::string &passwordName,
const std::string &password,
const ConfigPasswordKey &key) = 0;
/**
* Read from stdin until end of stream. Must be connected to
@ -152,11 +160,14 @@ struct TrySlots
/**
* Same as ConfigUserInterface::askPassword(), except that the
* password is returned in retval and the return value indicates
* whether any slot was able to retrieve the value.
* password is returned as retval. If it was set, then the
* password was found in the keyring. The return value indicates
* whether any slot matched the configured keyring.
*
* Backends need to be sure that the user wants them to handle
* the request before doing the work and returning true.
* the request before doing the work and returning true. They
* should check the first parameter, the value of the "keyring"
* configuration option, to determine that.
*
* GNOME keyring and KWallet add themselves here and in
* SavePasswordSignal. KWallet adds itself with priority 0
@ -165,22 +176,28 @@ struct TrySlots
* storage, otherwise defers to GNOME keyring (or any other
* slot) by returning false.
*/
typedef boost::signals2::signal<bool (const std::string &passwordName,
typedef boost::signals2::signal<bool (const InitStateTri &keyring,
const std::string &passwordName,
const std::string &descr,
const ConfigPasswordKey &key,
std::string &password),
InitStateString &password),
TrySlots> LoadPasswordSignal;
LoadPasswordSignal &GetLoadPasswordSignal();
static const int INTERNAL_LOAD_PASSWORD_SLOTS = 1;
/**
* Same as AskPasswordSignal for saving.
*/
typedef boost::signals2::signal<bool (const std::string &passwordName,
typedef boost::signals2::signal<bool (const InitStateTri &keyring,
const std::string &passwordName,
const std::string &password,
const ConfigPasswordKey &key),
TrySlots> SavePasswordSignal;
SavePasswordSignal &GetSavePasswordSignal();
static const int INTERNAL_SAVE_PASSWORD_SLOTS = 2;
SE_END_CXX
#endif // INCL_USERINTERFACE

View File

@ -71,6 +71,8 @@ src_syncevo_sources = \
\
src/syncevo/Cmdline.cpp \
src/syncevo/Cmdline.h \
src/syncevo/CmdlineSyncClient.h \
src/syncevo/CmdlineSyncClient.cpp \
\
src/syncevo/SyncSource.h \
src/syncevo/SyncSource.cpp \

View File

@ -59,7 +59,7 @@ using namespace GDBusCXX;
#include <syncevo/SuspendFlags.h>
#include <syncevo/LogRedirect.h>
#include <syncevo/LocalTransportAgent.h>
#include "CmdlineSyncClient.h"
#include <syncevo/CmdlineSyncClient.h>
#include <dlfcn.h>
#include <signal.h>
@ -93,24 +93,6 @@ extern "C" EContact *e_contact_new_from_vcard(const char *vcard)
}
#endif
/**
* This is a class derived from Cmdline. The purpose
* is to implement the factory method 'createSyncClient' to create
* new implemented 'CmdlineSyncClient' objects.
*/
class KeyringSyncCmdline : public Cmdline {
public:
KeyringSyncCmdline(int argc, const char * const * argv) :
Cmdline(argc, argv)
{}
/**
* create a user implemented sync client.
*/
SyncContext* createSyncClient() {
return new CmdlineSyncClient(m_server, true, m_keyring);
}
};
#ifdef DBUS_SERVICE
class RemoteSession;
typedef map<string, StringMap> Config_t;
@ -450,7 +432,7 @@ int main( int argc, char **argv )
LoggerBase::instance().setLevel(Logger::DEBUG);
}
KeyringSyncCmdline cmdline(argc, argv);
SyncEvo::KeyringSyncCmdline cmdline(argc, argv);
vector<string> parsedArgs;
if(!cmdline.parse(parsedArgs)) {
return 1;

View File

@ -4126,17 +4126,18 @@ def injectValues(config):
def filterConfig(config):
'''remove pure comment lines from buffer, also empty lines, also
defaultPeer (because reference properties do not include global
defaultPeer/keyring (because reference properties do not include global
props)'''
config_lines = config.splitlines()
out = ''
for line in config_lines:
if line:
index = line.find("defaultPeer =")
if index == -1:
if line.startswith("# ") == False or isPropAssignment(line[2:]):
out += line + "\n"
if line and \
"defaultPeer =" not in line and \
"keyring =" not in line and \
(line.startswith("# ") == False or \
isPropAssignment(line[2:])):
out += line + "\n"
return out
@ -5613,6 +5614,8 @@ ConsumerReady (FALSE, unshared)
peerType (no default, unshared)
defaultPeer (no default, global)
keyring (yes, global)
""".format(self.getSSLServerCertificates())
sourceproperties = """sync (disabled, unshared, required)