mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-12 09:04:33 +02:00
Disable QtKeychain on OSX.
This commit is contained in:
@@ -266,12 +266,14 @@ macro_log_feature(QTWEETLIB_FOUND "QTweetLib" "Qt Twitter Library" "https://gith
|
|||||||
macro_optional_find_package(LibLastFm 1.0.0)
|
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")
|
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 )
|
if( TOMAHAWK_QT5 )
|
||||||
macro_optional_find_package(Qt5Keychain 0.1.0)
|
macro_optional_find_package(Qt5Keychain 0.1.0)
|
||||||
else()
|
else()
|
||||||
macro_optional_find_package(QtKeychain 0.1.0)
|
macro_optional_find_package(QtKeychain 0.1.0)
|
||||||
endif()
|
endif()
|
||||||
macro_log_feature(QTKEYCHAIN_FOUND "QtKeychain" "Provides support for secure credentials storage" "https://github.com/frankosterfeld/qtkeychain" TRUE "" "")
|
macro_log_feature(QTKEYCHAIN_FOUND "QtKeychain" "Provides support for secure credentials storage" "https://github.com/frankosterfeld/qtkeychain" TRUE "" "")
|
||||||
|
endif()
|
||||||
|
|
||||||
if( UNIX AND NOT APPLE )
|
if( UNIX AND NOT APPLE )
|
||||||
macro_optional_find_package(TelepathyQt 0.9.3)
|
macro_optional_find_package(TelepathyQt 0.9.3)
|
||||||
|
@@ -617,17 +617,12 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion )
|
|||||||
}
|
}
|
||||||
else if ( oldVersion == 14 )
|
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();
|
const QStringList accounts = value( "accounts/allaccounts" ).toStringList();
|
||||||
tDebug() << "About to move these accounts to QtKeychain:" << accounts;
|
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
|
//Move storage of Credentials from QSettings to QtKeychain
|
||||||
foreach ( const QString& account, accounts )
|
foreach ( const QString& account, accounts )
|
||||||
{
|
{
|
||||||
@@ -639,10 +634,6 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion )
|
|||||||
|
|
||||||
if ( !creds.isEmpty() )
|
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 );
|
QKeychain::WritePasswordJob* j = new QKeychain::WritePasswordJob( QLatin1String( "Tomahawk" ), this );
|
||||||
j->setKey( account );
|
j->setKey( account );
|
||||||
j->setAutoDelete( true );
|
j->setAutoDelete( true );
|
||||||
@@ -664,38 +655,13 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion )
|
|||||||
|
|
||||||
j->setTextData( data );
|
j->setTextData( data );
|
||||||
j->start();
|
j->start();
|
||||||
#endif //Q_OS_MAC
|
|
||||||
}
|
}
|
||||||
|
|
||||||
remove( "credentials" );
|
remove( "credentials" );
|
||||||
|
|
||||||
endGroup();
|
endGroup();
|
||||||
}
|
}
|
||||||
|
#endif //Q_OS_MAC
|
||||||
#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
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,16 +18,15 @@
|
|||||||
|
|
||||||
#include "CredentialsManager.h"
|
#include "CredentialsManager.h"
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
#include "LocalConfigStorage.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
#include "TomahawkSettings.h"
|
||||||
|
#else
|
||||||
#include <qtkeychain/keychain.h>
|
#include <qtkeychain/keychain.h>
|
||||||
|
|
||||||
#include <qjson/serializer.h>
|
#include <qjson/serializer.h>
|
||||||
#include <qjson/parser.h>
|
#include <qjson/parser.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
@@ -38,11 +37,6 @@ namespace Tomahawk
|
|||||||
namespace Accounts
|
namespace Accounts
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
const QString OSX_SINGLE_KEY = QString( "tomahawksecrets" );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
CredentialsStorageKey::CredentialsStorageKey( const QString& service, const QString& key )
|
CredentialsStorageKey::CredentialsStorageKey( const QString& service, const QString& key )
|
||||||
: m_service( service )
|
: m_service( service )
|
||||||
, m_key( key )
|
, m_key( key )
|
||||||
@@ -93,24 +87,24 @@ CredentialsManager::loadCredentials( const QString &service )
|
|||||||
const QStringList& accountIds = m_services.value( service );
|
const QStringList& accountIds = m_services.value( service );
|
||||||
tDebug() << Q_FUNC_INFO << "keys for service" << service << ":" << accountIds;
|
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
|
#ifdef Q_OS_MAC
|
||||||
if ( service == LocalConfigStorage::credentialsServiceName() )
|
foreach ( QString key, accountIds )
|
||||||
{
|
{
|
||||||
QKeychain::ReadPasswordJob* j = new QKeychain::ReadPasswordJob( service, this );
|
tDebug() << "beginGroup" << QString( "accounts/%1" ).arg( key );
|
||||||
j->setKey( OSX_SINGLE_KEY );
|
TomahawkSettings::instance()->beginGroup( QString( "accounts/%1" ).arg( key ) );
|
||||||
j->setAutoDelete( false );
|
const QVariantHash creds = TomahawkSettings::instance()->value( "credentials" ).toHash();
|
||||||
connect( j, SIGNAL( finished( QKeychain::Job* ) ),
|
tDebug() << creds[ "username" ]
|
||||||
SLOT( keychainJobFinished( QKeychain::Job* ) ) );
|
<< ( creds[ "password" ].isNull() ? ", no password" : ", has password" );
|
||||||
m_readJobs[ service ] << j;
|
|
||||||
j->start();
|
if ( !creds.isEmpty() )
|
||||||
tDebug() << "Launching OSX-specific QtKeychain readJob for" << OSX_SINGLE_KEY;
|
{
|
||||||
|
m_credentials.insert( CredentialsStorageKey( service, key ), creds );
|
||||||
}
|
}
|
||||||
else
|
TomahawkSettings::instance()->endGroup();
|
||||||
{
|
}
|
||||||
#endif
|
|
||||||
|
emit serviceReady( service );
|
||||||
|
#else
|
||||||
foreach ( QString key, accountIds )
|
foreach ( QString key, accountIds )
|
||||||
{
|
{
|
||||||
QKeychain::ReadPasswordJob* j = new QKeychain::ReadPasswordJob( service, this );
|
QKeychain::ReadPasswordJob* j = new QKeychain::ReadPasswordJob( service, this );
|
||||||
@@ -125,15 +119,13 @@ CredentialsManager::loadCredentials( const QString &service )
|
|||||||
j->start();
|
j->start();
|
||||||
tDebug() << "Launching QtKeychain readJob for" << key;
|
tDebug() << "Launching QtKeychain readJob for" << key;
|
||||||
}
|
}
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ( m_readJobs[ service ].isEmpty() )
|
if ( m_readJobs[ service ].isEmpty() )
|
||||||
{
|
{
|
||||||
// We did not launch any readJob, so we're done already.
|
// We did not launch any readJob, so we're done already.
|
||||||
emit serviceReady( service );
|
emit serviceReady( service );
|
||||||
}
|
}
|
||||||
|
#endif //Q_OS_MAC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -190,21 +182,13 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV
|
|||||||
m_credentials.remove( csKey );
|
m_credentials.remove( csKey );
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
tDebug() << Q_FUNC_INFO << "about to rewrite all credentials because of" << csKey.key() << "removal";
|
TomahawkSettings::instance()->beginGroup( QString( "accounts/%1" ).arg( csKey.key() ) );
|
||||||
if ( csKey.service() == LocalConfigStorage::credentialsServiceName() )
|
TomahawkSettings::instance()->remove( "credentials" );
|
||||||
{
|
TomahawkSettings::instance()->endGroup();
|
||||||
rewriteCredentialsOsx( csKey.service() );
|
#else
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tDebug() << "About to run DeletePasswordJob. This should pretty much never happen on OSX.";
|
|
||||||
#endif
|
|
||||||
QKeychain::DeletePasswordJob* dj = new QKeychain::DeletePasswordJob( csKey.service(), this );
|
QKeychain::DeletePasswordJob* dj = new QKeychain::DeletePasswordJob( csKey.service(), this );
|
||||||
dj->setKey( csKey.key() );
|
dj->setKey( csKey.key() );
|
||||||
j = dj;
|
j = dj;
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -215,16 +199,10 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV
|
|||||||
m_credentials.insert( csKey, value );
|
m_credentials.insert( csKey, value );
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
tDebug() << Q_FUNC_INFO << "about to rewrite all credentials because of" << csKey.key() << "insert/update";
|
TomahawkSettings::instance()->beginGroup( QString( "accounts/%1" ).arg( csKey.key() ) );
|
||||||
if ( csKey.service() == LocalConfigStorage::credentialsServiceName() )
|
TomahawkSettings::instance()->setValue( "credentials", value );
|
||||||
{
|
TomahawkSettings::instance()->endGroup();
|
||||||
rewriteCredentialsOsx( csKey.service() );
|
#else
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tDebug() << "About to run WritePasswordJob. This should pretty much never happen on OSX.";
|
|
||||||
#endif
|
|
||||||
QKeychain::WritePasswordJob* wj = new QKeychain::WritePasswordJob( csKey.service(), this );
|
QKeychain::WritePasswordJob* wj = new QKeychain::WritePasswordJob( csKey.service(), this );
|
||||||
wj->setKey( csKey.key() );
|
wj->setKey( csKey.key() );
|
||||||
|
|
||||||
@@ -253,11 +231,10 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV
|
|||||||
}
|
}
|
||||||
|
|
||||||
j = wj;
|
j = wj;
|
||||||
#ifdef Q_OS_MAC
|
#endif //Q_OS_MAC
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef Q_OS_MAC
|
||||||
j->setAutoDelete( false );
|
j->setAutoDelete( false );
|
||||||
#if defined( Q_OS_UNIX ) && !defined( Q_OS_MAC )
|
#if defined( Q_OS_UNIX ) && !defined( Q_OS_MAC )
|
||||||
j->setInsecureFallback( true );
|
j->setInsecureFallback( true );
|
||||||
@@ -266,69 +243,8 @@ CredentialsManager::setCredentials( const CredentialsStorageKey& csKey, const QV
|
|||||||
SLOT( keychainJobFinished( QKeychain::Job* ) ) );
|
SLOT( keychainJobFinished( QKeychain::Job* ) ) );
|
||||||
j->start();
|
j->start();
|
||||||
tDebug() << Q_FUNC_INFO << "launched" << j->metaObject()->className() << "for service" << j->service();
|
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
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -348,6 +264,7 @@ CredentialsManager::setCredentials( const QString& serviceName, const QString& k
|
|||||||
void
|
void
|
||||||
CredentialsManager::keychainJobFinished( QKeychain::Job* j )
|
CredentialsManager::keychainJobFinished( QKeychain::Job* j )
|
||||||
{
|
{
|
||||||
|
#ifndef Q_OS_MAC
|
||||||
tDebug() << Q_FUNC_INFO;
|
tDebug() << Q_FUNC_INFO;
|
||||||
if ( QKeychain::ReadPasswordJob* readJob = qobject_cast< QKeychain::ReadPasswordJob* >( j ) )
|
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 );
|
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();
|
QVariantMap map = creds.toMap();
|
||||||
QVariantHash hash;
|
QVariantHash hash;
|
||||||
for ( QVariantMap::const_iterator it = map.constBegin();
|
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 );
|
m_credentials.insert( CredentialsStorageKey( readJob->service(), readJob->key() ), creds );
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
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->error() == QKeychain::NoError ) ? "without error" : QString( "with ERROR: %1 %2" ).arg( j->error() ).arg( j->errorString() ) );
|
||||||
}
|
}
|
||||||
j->deleteLater();
|
j->deleteLater();
|
||||||
|
#endif //Q_OS_MAC
|
||||||
}
|
}
|
||||||
|
|
||||||
} //namespace Accounts
|
} //namespace Accounts
|
||||||
|
@@ -26,7 +26,6 @@
|
|||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
|
|
||||||
namespace QKeychain
|
namespace QKeychain
|
||||||
{
|
{
|
||||||
class Job;
|
class Job;
|
||||||
@@ -85,10 +84,6 @@ protected:
|
|||||||
QVariant credentials( const CredentialsStorageKey& key ) const;
|
QVariant credentials( const CredentialsStorageKey& key ) const;
|
||||||
void setCredentials( const CredentialsStorageKey& key, const QVariant& value, bool tryToWriteAsString = false );
|
void setCredentials( const CredentialsStorageKey& key, const QVariant& value, bool tryToWriteAsString = false );
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
void rewriteCredentialsOsx( const QString& service );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash< QString, QStringList > m_services;
|
QHash< QString, QStringList > m_services;
|
||||||
QHash< CredentialsStorageKey, QVariant > m_credentials;
|
QHash< CredentialsStorageKey, QVariant > m_credentials;
|
||||||
|
Reference in New Issue
Block a user