1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-02-26 04:43:06 +01:00

Merge pull request #214 from tomahawk-player/osx-keychain-stop-nagging

Make OSX Keychain nag less
This commit is contained in:
Teo Mrnjavac 2013-09-12 13:15:58 -07:00
commit 0c41b46d0c
5 changed files with 189 additions and 9 deletions

View File

@ -619,6 +619,15 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion )
{
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 )
{
@ -630,6 +639,10 @@ 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 );
@ -651,12 +664,38 @@ 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
}
}

View File

@ -18,6 +18,10 @@
#include "CredentialsManager.h"
#ifdef Q_OS_MAC
#include "LocalConfigStorage.h"
#endif
#include "utils/Logger.h"
#include <qtkeychain/keychain.h>
@ -34,6 +38,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 +93,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 == LocalConfigStorage::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" << OSX_SINGLE_KEY;
}
else
{
#endif
foreach ( QString key, accountIds )
{
QKeychain::ReadPasswordJob* j = new QKeychain::ReadPasswordJob( service, this );
@ -98,13 +126,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 +187,21 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV
m_credentials.remove( csKey );
#ifdef Q_OS_MAC
if ( csKey.service() == LocalConfigStorage::credentialsServiceName() )
{
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 +210,15 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV
m_credentials.insert( csKey, value );
#ifdef Q_OS_MAC
if ( csKey.service() == LocalConfigStorage::credentialsServiceName() )
{
rewriteCredentialsOsx( csKey.service() );
return;
}
else
{
#endif
QKeychain::WritePasswordJob* wj = new QKeychain::WritePasswordJob( csKey.service(), this );
wj->setKey( csKey.key() );
@ -196,6 +247,9 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV
}
j = wj;
#ifdef Q_OS_MAC
}
#endif
}
j->setAutoDelete( false );
@ -208,6 +262,53 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV
}
#ifdef Q_OS_MAC
void
CredentialsManager::rewriteCredentialsOsx( const QString& service )
{
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() );
}
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->setTextData( data );
j->setAutoDelete( false );
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 +340,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 +377,9 @@ CredentialsManager::keychainJobFinished( QKeychain::Job* j )
}
m_credentials.insert( CredentialsStorageKey( readJob->service(), readJob->key() ), creds );
#ifdef Q_OS_MAC
}
#endif
}
else
{

View File

@ -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;

View File

@ -29,10 +29,18 @@ namespace Tomahawk
namespace Accounts
{
const QString LocalConfigStorage::s_credentialsServiceName = "Tomahawk";
#ifdef Q_OS_MAC
QString
LocalConfigStorage::credentialsServiceName()
{
return s_credentialsServiceName;
}
#endif
LocalConfigStorage::LocalConfigStorage( QObject* parent )
: ConfigStorage( parent )
, m_credentialsServiceName( "Tomahawk" )
{
m_accountIds = TomahawkSettings::instance()->accounts();
}
@ -46,10 +54,10 @@ LocalConfigStorage::init()
CredentialsManager* cm = AccountManager::instance()->credentialsManager();
connect( cm, SIGNAL( serviceReady( QString ) ),
this, SLOT( onCredentialsManagerReady( QString ) ) );
AccountManager::instance()->credentialsManager()->addService( m_credentialsServiceName,
AccountManager::instance()->credentialsManager()->addService( s_credentialsServiceName,
m_accountIds );
tDebug() << Q_FUNC_INFO << "LOADING ALL CREDENTIALS FOR SERVICE" << m_credentialsServiceName << m_accountIds;
tDebug() << Q_FUNC_INFO << "LOADING ALL CREDENTIALS FOR SERVICE" << s_credentialsServiceName << m_accountIds;
}
@ -63,7 +71,7 @@ LocalConfigStorage::id() const
void
LocalConfigStorage::onCredentialsManagerReady( const QString& service )
{
if ( service != m_credentialsServiceName )
if ( service != s_credentialsServiceName )
return;
//no need to listen for it any more
@ -109,7 +117,7 @@ LocalConfigStorage::save( const QString& accountId, const Account::Configuration
s->sync();
CredentialsManager* c = AccountManager::instance()->credentialsManager();
c->setCredentials( m_credentialsServiceName, accountId, cfg.credentials );
c->setCredentials( s_credentialsServiceName, accountId, cfg.credentials );
if ( !m_accountIds.contains( accountId ) )
m_accountIds.append( accountId );
@ -129,7 +137,7 @@ LocalConfigStorage::load( const QString& accountId, Account::Configuration& cfg
s->endGroup();
CredentialsManager* c = AccountManager::instance()->credentialsManager();
QVariant credentials = c->credentials( m_credentialsServiceName, accountId );
QVariant credentials = c->credentials( s_credentialsServiceName, accountId );
if ( credentials.type() == QVariant::Hash )
cfg.credentials = credentials.toHash();
}
@ -149,7 +157,7 @@ LocalConfigStorage::remove( const QString& accountId )
s->remove( "accounts/" + accountId );
CredentialsManager* c = AccountManager::instance()->credentialsManager();
c->setCredentials( m_credentialsServiceName, accountId, QVariantHash() );
c->setCredentials( s_credentialsServiceName, accountId, QVariantHash() );
}
}

View File

@ -47,12 +47,15 @@ public:
virtual void load( const QString& accountId, Account::Configuration& cfg ) const;
virtual void remove( const QString& accountId );
#ifdef Q_OS_MAC
static QString credentialsServiceName();
#endif
private slots:
void onCredentialsManagerReady( const QString& service );
private:
const QString m_credentialsServiceName;
static const QString s_credentialsServiceName;
QStringList m_accountIds;
static LocalConfigStorage* s_instance;