diff --git a/CMakeLists.txt b/CMakeLists.txt index 91365aa73..6d0b79c6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -266,12 +266,14 @@ macro_log_feature(QTWEETLIB_FOUND "QTweetLib" "Qt Twitter Library" "https://gith macro_optional_find_package(LibLastFm 1.0.0) macro_log_feature(LIBLASTFM_FOUND "liblastfm" "Qt library for the Last.fm webservices" "https://github.com/lastfm/liblastfm" TRUE "" "liblastfm is needed for scrobbling tracks to Last.fm and fetching cover artwork") +if( NOT APPLE ) if( TOMAHAWK_QT5 ) macro_optional_find_package(Qt5Keychain 0.1.0) else() macro_optional_find_package(QtKeychain 0.1.0) endif() macro_log_feature(QTKEYCHAIN_FOUND "QtKeychain" "Provides support for secure credentials storage" "https://github.com/frankosterfeld/qtkeychain" TRUE "" "") +endif() if( UNIX AND NOT APPLE ) macro_optional_find_package(TelepathyQt 0.9.3) diff --git a/src/libtomahawk/TomahawkSettings.cpp b/src/libtomahawk/TomahawkSettings.cpp index d7c09275c..5b9429822 100644 --- a/src/libtomahawk/TomahawkSettings.cpp +++ b/src/libtomahawk/TomahawkSettings.cpp @@ -617,17 +617,12 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion ) } else if ( oldVersion == 14 ) { + //No upgrade on OSX: we keep storing credentials in TomahawkSettings + //because QtKeychain and/or OSX Keychain is flaky. --Teo 12/2013 +#ifndef Q_OS_MAC const QStringList accounts = value( "accounts/allaccounts" ).toStringList(); tDebug() << "About to move these accounts to QtKeychain:" << accounts; - //On OSX we store everything under a single Keychain key, so we first need - //to gather all the entries in a QVariantMap and then write them all in a - //single shot. - //NOTE: The following OSX-specific #ifdefs do not affect the config file - // format, which stays the same on all platforms. --Teo 9/2013 -#ifdef Q_OS_MAC - QVariantMap everythingMap; -#endif //Move storage of Credentials from QSettings to QtKeychain foreach ( const QString& account, accounts ) { @@ -639,10 +634,6 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion ) if ( !creds.isEmpty() ) { -#ifdef Q_OS_MAC - everythingMap.insert( account, creds ); - tDebug() << "Preparing upgrade for account" << account; -#else QKeychain::WritePasswordJob* j = new QKeychain::WritePasswordJob( QLatin1String( "Tomahawk" ), this ); j->setKey( account ); j->setAutoDelete( true ); @@ -664,38 +655,13 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion ) j->setTextData( data ); j->start(); -#endif //Q_OS_MAC } remove( "credentials" ); endGroup(); } - -#ifdef Q_OS_MAC - QJson::Serializer serializer; - bool ok; - QByteArray data = serializer.serialize( everythingMap, &ok ); - - if ( ok ) - { - QKeychain::WritePasswordJob* j = new QKeychain::WritePasswordJob( QLatin1String( "Tomahawk" ), this ); - j->setKey( "tomahawksecrets" ); //Tomahawk::Accounts::OSX_SINGLE_KEY in CredentialsManager.cpp - j->setAutoDelete( true ); - - j->setTextData( data ); - - tDebug() << "Performing OSX-specific upgrade for all accounts."; - - j->start(); - } - else - { - tDebug() << "Cannot serialize credentials for OSX-specific upgrade" - << "in map:" << everythingMap.keys(); - } -#endif - +#endif //Q_OS_MAC } } diff --git a/src/libtomahawk/accounts/CredentialsManager.cpp b/src/libtomahawk/accounts/CredentialsManager.cpp index 410bc45cb..8c9d62224 100644 --- a/src/libtomahawk/accounts/CredentialsManager.cpp +++ b/src/libtomahawk/accounts/CredentialsManager.cpp @@ -18,16 +18,15 @@ #include "CredentialsManager.h" -#ifdef Q_OS_MAC -#include "LocalConfigStorage.h" -#endif - #include "utils/Logger.h" +#ifdef Q_OS_MAC +#include "TomahawkSettings.h" +#else #include - #include #include +#endif #include @@ -38,11 +37,6 @@ namespace Tomahawk namespace Accounts { -#ifdef Q_OS_MAC -const QString OSX_SINGLE_KEY = QString( "tomahawksecrets" ); -#endif - - CredentialsStorageKey::CredentialsStorageKey( const QString& service, const QString& key ) : m_service( service ) , m_key( key ) @@ -93,24 +87,24 @@ CredentialsManager::loadCredentials( const QString &service ) const QStringList& accountIds = m_services.value( service ); tDebug() << Q_FUNC_INFO << "keys for service" << service << ":" << accountIds; - //HACK: OSX Keychain inevitably pops up a dialog for every key. - // Therefore, we make sure that our LocalConfigStorage stores everything - // into a single key. #ifdef Q_OS_MAC - if ( service == LocalConfigStorage::credentialsServiceName() ) + foreach ( QString key, accountIds ) { - QKeychain::ReadPasswordJob* j = new QKeychain::ReadPasswordJob( service, this ); - j->setKey( OSX_SINGLE_KEY ); - j->setAutoDelete( false ); - connect( j, SIGNAL( finished( QKeychain::Job* ) ), - SLOT( keychainJobFinished( QKeychain::Job* ) ) ); - m_readJobs[ service ] << j; - j->start(); - tDebug() << "Launching OSX-specific QtKeychain readJob for" << OSX_SINGLE_KEY; + tDebug() << "beginGroup" << QString( "accounts/%1" ).arg( key ); + TomahawkSettings::instance()->beginGroup( QString( "accounts/%1" ).arg( key ) ); + const QVariantHash creds = TomahawkSettings::instance()->value( "credentials" ).toHash(); + tDebug() << creds[ "username" ] + << ( creds[ "password" ].isNull() ? ", no password" : ", has password" ); + + if ( !creds.isEmpty() ) + { + m_credentials.insert( CredentialsStorageKey( service, key ), creds ); + } + TomahawkSettings::instance()->endGroup(); } - else - { -#endif + + emit serviceReady( service ); +#else foreach ( QString key, accountIds ) { QKeychain::ReadPasswordJob* j = new QKeychain::ReadPasswordJob( service, this ); @@ -125,15 +119,13 @@ CredentialsManager::loadCredentials( const QString &service ) j->start(); tDebug() << "Launching QtKeychain readJob for" << key; } -#ifdef Q_OS_MAC - } -#endif if ( m_readJobs[ service ].isEmpty() ) { // We did not launch any readJob, so we're done already. emit serviceReady( service ); } +#endif //Q_OS_MAC } @@ -190,21 +182,13 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV m_credentials.remove( csKey ); #ifdef Q_OS_MAC - tDebug() << Q_FUNC_INFO << "about to rewrite all credentials because of" << csKey.key() << "removal"; - if ( csKey.service() == LocalConfigStorage::credentialsServiceName() ) - { - rewriteCredentialsOsx( csKey.service() ); - return; - } - else - { - tDebug() << "About to run DeletePasswordJob. This should pretty much never happen on OSX."; -#endif + TomahawkSettings::instance()->beginGroup( QString( "accounts/%1" ).arg( csKey.key() ) ); + TomahawkSettings::instance()->remove( "credentials" ); + TomahawkSettings::instance()->endGroup(); +#else QKeychain::DeletePasswordJob* dj = new QKeychain::DeletePasswordJob( csKey.service(), this ); dj->setKey( csKey.key() ); j = dj; -#ifdef Q_OS_MAC - } #endif } else @@ -215,16 +199,10 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV m_credentials.insert( csKey, value ); #ifdef Q_OS_MAC - tDebug() << Q_FUNC_INFO << "about to rewrite all credentials because of" << csKey.key() << "insert/update"; - if ( csKey.service() == LocalConfigStorage::credentialsServiceName() ) - { - rewriteCredentialsOsx( csKey.service() ); - return; - } - else - { - tDebug() << "About to run WritePasswordJob. This should pretty much never happen on OSX."; -#endif + TomahawkSettings::instance()->beginGroup( QString( "accounts/%1" ).arg( csKey.key() ) ); + TomahawkSettings::instance()->setValue( "credentials", value ); + TomahawkSettings::instance()->endGroup(); +#else QKeychain::WritePasswordJob* wj = new QKeychain::WritePasswordJob( csKey.service(), this ); wj->setKey( csKey.key() ); @@ -253,11 +231,10 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV } j = wj; -#ifdef Q_OS_MAC - } -#endif +#endif //Q_OS_MAC } +#ifndef Q_OS_MAC j->setAutoDelete( false ); #if defined( Q_OS_UNIX ) && !defined( Q_OS_MAC ) j->setInsecureFallback( true ); @@ -266,69 +243,8 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV SLOT( keychainJobFinished( QKeychain::Job* ) ) ); j->start(); tDebug() << Q_FUNC_INFO << "launched" << j->metaObject()->className() << "for service" << j->service(); -} - - -#ifdef Q_OS_MAC -void -CredentialsManager::rewriteCredentialsOsx( const QString& service ) -{ - tDebug() << "Q_FUNC_INFO" << "OSX-specific starting."; - if ( service != LocalConfigStorage::credentialsServiceName() ) - return; - - QVariantMap everythingMap; - - for ( QHash< CredentialsStorageKey, QVariant >::const_iterator it = m_credentials.constBegin(); - it != m_credentials.constEnd(); ++it ) - { - if ( it.key().service() != service ) - continue; - - everythingMap.insert( it.key().key(), it.value() ); - } - - tDebug() << "About to JSON-serialize QVariantMap with the following keys:" << everythingMap.keys(); - - QJson::Serializer serializer; - bool ok; - serializer.setIndentMode(QJson::IndentFull); - QByteArray data = serializer.serialize( everythingMap, &ok ); - - if ( ok ) - { - tDebug() << "Serialization ok. About to perform OSX-specific rewrite for service" << service; - } - else - { - tDebug() << "Cannot serialize credentials for OSX-specific rewrite, service:" << service - << "keys:" << m_services.value( service ) - << "in map:" << everythingMap.keys(); - return; - } - - QKeychain::WritePasswordJob* j = new QKeychain::WritePasswordJob( service, this ); - j->setKey( OSX_SINGLE_KEY ); - j->setTextData( data ); - - j->setAutoDelete( false ); - - connect( j, SIGNAL( finished( QKeychain::Job* ) ), - SLOT( keychainJobFinished( QKeychain::Job* ) ) ); - j->start(); - tDebug() << "Launched OSX-specific rewrite job. The following should appear in Keychain Access:"; - QString dataString = QString::fromLatin1(data); - QStringList dataSL = dataString.split("\n"); - for ( QStringList::iterator it = dataSL.begin(); - it != dataSL.end(); ++it ) - { - if ( it->contains( "\"password\" :" ) ) - *it = QString( "***** password line hidden *****" ); - } - dataString = dataSL.join( "\n" ); - tDebug() << dataString; -} #endif +} void @@ -348,6 +264,7 @@ CredentialsManager::setCredentials( const QString& serviceName, const QString& k void CredentialsManager::keychainJobFinished( QKeychain::Job* j ) { +#ifndef Q_OS_MAC tDebug() << Q_FUNC_INFO; if ( QKeychain::ReadPasswordJob* readJob = qobject_cast< QKeychain::ReadPasswordJob* >( j ) ) { @@ -362,33 +279,6 @@ CredentialsManager::keychainJobFinished( QKeychain::Job* j ) creds = parser.parse( readJob->textData().toLatin1(), &ok ); -#ifdef Q_OS_MAC - tDebug() << Q_FUNC_INFO << "about to check of OSX-specific key storage."; - if ( readJob->key() == OSX_SINGLE_KEY ) - { - QVariantMap everythingMap = creds.toMap(); - tDebug() << "Main map keys:" << everythingMap.keys(); - for ( QVariantMap::const_iterator jt = everythingMap.constBegin(); - jt != everythingMap.constEnd(); ++jt ) - { - QVariantMap map = jt.value().toMap(); - tDebug() << "Keys:" << map.keys(); - QVariantHash hash; - for ( QVariantMap::const_iterator it = map.constBegin(); - it != map.constEnd(); ++it ) - { - hash.insert( it.key(), it.value() ); - } - QVariant oneCred = QVariant( hash ); - - tDebug() << "Inserting creds from OSX keychain for service" << readJob->service() << "key:" << jt.key(); - m_credentials.insert( CredentialsStorageKey( readJob->service(), jt.key() ), oneCred ); - } - } - else - { - tDebug() << Q_FUNC_INFO << "This should pretty much never happen on OSX."; -#endif QVariantMap map = creds.toMap(); QVariantHash hash; for ( QVariantMap::const_iterator it = map.constBegin(); @@ -404,9 +294,6 @@ CredentialsManager::keychainJobFinished( QKeychain::Job* j ) } m_credentials.insert( CredentialsStorageKey( readJob->service(), readJob->key() ), creds ); -#ifdef Q_OS_MAC - } -#endif } else { @@ -432,6 +319,7 @@ CredentialsManager::keychainJobFinished( QKeychain::Job* j ) << ( ( j->error() == QKeychain::NoError ) ? "without error" : QString( "with ERROR: %1 %2" ).arg( j->error() ).arg( j->errorString() ) ); } j->deleteLater(); +#endif //Q_OS_MAC } } //namespace Accounts diff --git a/src/libtomahawk/accounts/CredentialsManager.h b/src/libtomahawk/accounts/CredentialsManager.h index bc00261ce..86fb2f2c9 100644 --- a/src/libtomahawk/accounts/CredentialsManager.h +++ b/src/libtomahawk/accounts/CredentialsManager.h @@ -26,7 +26,6 @@ #include #include - namespace QKeychain { class Job; @@ -85,10 +84,6 @@ protected: QVariant credentials( const CredentialsStorageKey& key ) const; void setCredentials( const CredentialsStorageKey& key, const QVariant& value, bool tryToWriteAsString = false ); -#ifdef Q_OS_MAC - void rewriteCredentialsOsx( const QString& service ); -#endif - private: QHash< QString, QStringList > m_services; QHash< CredentialsStorageKey, QVariant > m_credentials;