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:
parent
d2fd4806c8
commit
8da86205df
23
README.rst
23
README.rst
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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("");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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 ®istry = 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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue