diff --git a/src/libtomahawk/accounts/CredentialsManager.cpp b/src/libtomahawk/accounts/CredentialsManager.cpp index 865dcc817..570536ef4 100644 --- a/src/libtomahawk/accounts/CredentialsManager.cpp +++ b/src/libtomahawk/accounts/CredentialsManager.cpp @@ -34,6 +34,11 @@ 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 ) @@ -84,6 +89,25 @@ 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 == "Tomahawk" ) //LocalConfigStorage::m_credentialsServiceName + { + 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" << key; + } + else + { +#endif foreach ( QString key, accountIds ) { QKeychain::ReadPasswordJob* j = new QKeychain::ReadPasswordJob( service, this ); @@ -98,13 +122,15 @@ 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 ); } - } @@ -157,9 +183,21 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV m_credentials.remove( csKey ); +#ifdef Q_OS_MAC + if ( csKey.service() == "Tomahawk" ) + { + rewriteCredentialsOsx( csKey.service() ); + return; + } + else + { +#endif QKeychain::DeletePasswordJob* dj = new QKeychain::DeletePasswordJob( csKey.service(), this ); dj->setKey( csKey.key() ); j = dj; +#ifdef Q_OS_MAC + } +#endif } else { @@ -168,6 +206,15 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV m_credentials.insert( csKey, value ); +#ifdef Q_OS_MAC + if ( csKey.service() == "Tomahawk" ) + { + rewriteCredentialsOsx( csKey.service() ); + return; + } + else + { +#endif QKeychain::WritePasswordJob* wj = new QKeychain::WritePasswordJob( csKey.service(), this ); wj->setKey( csKey.key() ); @@ -196,6 +243,9 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV } j = wj; +#ifdef Q_OS_MAC + } +#endif } j->setAutoDelete( false ); @@ -208,6 +258,54 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV } +#ifdef Q_OS_MAC +void +CredentialsManager::rewriteCredentialsOsx( const QString& service ) +{ + if ( service != "Tomahawk" ) //always LocalConfigStorage::m_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() ); + } + + QJson::Serializer serializer; + bool ok; + QByteArray data = serializer.serialize( everythingMap, &ok ); + + if ( ok ) + { + tDebug() << "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->setAutoDelete( false ); +#if defined( Q_OS_UNIX ) && !defined( Q_OS_MAC ) + j->setInsecureFallback( true ); +#endif + connect( j, SIGNAL( finished( QKeychain::Job* ) ), + SLOT( keychainJobFinished( QKeychain::Job* ) ) ); + j->start(); +} +#endif + + void CredentialsManager::setCredentials( const QString& serviceName, const QString& key, const QVariantHash& value ) { @@ -239,6 +337,28 @@ CredentialsManager::keychainJobFinished( QKeychain::Job* j ) creds = parser.parse( readJob->textData().toLatin1(), &ok ); +#ifdef Q_OS_MAC + if ( readJob->key() == OSX_SINGLE_KEY ) + { + QVariantMap everythingMap = creds.toMap(); + for ( QVariantMap::const_iterator jt = everythingMap.constBegin(); + jt != everythingMap.constEnd(); ++jt ) + { + QVariantMap map = jt.value().toMap(); + QVariantHash hash; + for ( QVariantMap::const_iterator it = map.constBegin(); + it != map.constEnd(); ++it ) + { + hash.insert( it.key(), it.value() ); + } + QVariant oneCred = QVariant( hash ); + + m_credentials.insert( CredentialsStorageKey( readJob->service(), jt.key() ), oneCred ); + } + } + else + { +#endif QVariantMap map = creds.toMap(); QVariantHash hash; for ( QVariantMap::const_iterator it = map.constBegin(); @@ -254,6 +374,9 @@ CredentialsManager::keychainJobFinished( QKeychain::Job* j ) } m_credentials.insert( CredentialsStorageKey( readJob->service(), readJob->key() ), creds ); +#ifdef Q_OS_MAC + } +#endif } else { diff --git a/src/libtomahawk/accounts/CredentialsManager.h b/src/libtomahawk/accounts/CredentialsManager.h index 851e8d9b6..bc00261ce 100644 --- a/src/libtomahawk/accounts/CredentialsManager.h +++ b/src/libtomahawk/accounts/CredentialsManager.h @@ -85,6 +85,10 @@ 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;