Merge pull request #87 from hasselmm/plaintextstore
Extract PlainTextStore
This commit is contained in:
commit
effb484bdc
|
@ -127,7 +127,10 @@ add_definitions( -Wall )
|
|||
|
||||
if(WIN32)
|
||||
list(APPEND qtkeychain_SOURCES keychain_win.cpp)
|
||||
list(APPEND qtkeychain_LIBRARIES crypt32)
|
||||
if (!USE_CREDENTIAL_STORE)
|
||||
list(APPEND qtkeychain_LIBRARIES crypt32)
|
||||
list(APPEND qtkeychain_SOURCES plaintextstore.cpp)
|
||||
endif()
|
||||
#FIXME: mingw bug; otherwise getting undefined refs to RtlSecureZeroMemory there
|
||||
if(MINGW)
|
||||
add_definitions( -O2 )
|
||||
|
@ -145,7 +148,7 @@ if(APPLE)
|
|||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
list(APPEND qtkeychain_SOURCES keychain_unix.cpp gnomekeyring.cpp)
|
||||
list(APPEND qtkeychain_SOURCES keychain_unix.cpp gnomekeyring.cpp plaintextstore.cpp)
|
||||
qt_add_dbus_interface(qtkeychain_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/org.kde.KWallet.xml kwallet_interface KWalletInterface)
|
||||
list(APPEND qtkeychain_LIBRARIES ${QTDBUS_LIBRARIES} )
|
||||
endif()
|
||||
|
|
|
@ -84,6 +84,7 @@ friend class Job;
|
|||
friend class JobExecutor;
|
||||
friend class ReadPasswordJob;
|
||||
friend class WritePasswordJob;
|
||||
friend class PlainTextStore;
|
||||
};
|
||||
|
||||
class ReadPasswordJobPrivate : public JobPrivate {
|
||||
|
|
|
@ -8,23 +8,10 @@
|
|||
*****************************************************************************/
|
||||
#include "keychain_p.h"
|
||||
#include "gnomekeyring_p.h"
|
||||
|
||||
#include <QSettings>
|
||||
|
||||
#include <QScopedPointer>
|
||||
#include "plaintextstore_p.h"
|
||||
|
||||
using namespace QKeychain;
|
||||
|
||||
static QString typeKey( const QString& key )
|
||||
{
|
||||
return QString::fromLatin1( "%1/type" ).arg( key );
|
||||
}
|
||||
|
||||
static QString dataKey( const QString& key )
|
||||
{
|
||||
return QString::fromLatin1( "%1/data" ).arg( key );
|
||||
}
|
||||
|
||||
enum KeyringBackend {
|
||||
Backend_GnomeKeyring,
|
||||
Backend_Kwallet4,
|
||||
|
@ -217,15 +204,16 @@ void JobPrivate::gnomeKeyring_readCb( int result, const char* string, JobPrivate
|
|||
|
||||
void ReadPasswordJobPrivate::fallbackOnError(const QDBusError& err )
|
||||
{
|
||||
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
|
||||
QSettings* actual = q->settings() ? q->settings() : local.data();
|
||||
PlainTextStore plainTextStore( q->service(), q->settings() );
|
||||
|
||||
if ( q->insecureFallback() && actual->contains( dataKey( key ) ) ) {
|
||||
if ( q->insecureFallback() && plainTextStore.contains( key ) ) {
|
||||
mode = plainTextStore.readMode( key );
|
||||
data = plainTextStore.readData( key );
|
||||
|
||||
mode = JobPrivate::stringToMode( actual->value( typeKey( key ) ).toString() );
|
||||
data = actual->value( dataKey( key ) ).toByteArray();
|
||||
|
||||
q->emitFinished();
|
||||
if ( plainTextStore.error() != NoError )
|
||||
q->emitFinishedWithError( plainTextStore.error(), plainTextStore.errorString() );
|
||||
else
|
||||
q->emitFinished();
|
||||
} else {
|
||||
if ( err.type() == QDBusError::ServiceUnknown ) //KWalletd not running
|
||||
q->emitFinishedWithError( NoBackendAvailable, tr("No keychain service available") );
|
||||
|
@ -238,21 +226,20 @@ void ReadPasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watch
|
|||
watcher->deleteLater();
|
||||
const QDBusPendingReply<int> reply = *watcher;
|
||||
|
||||
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
|
||||
QSettings* actual = q->settings() ? q->settings() : local.data();
|
||||
|
||||
if ( reply.isError() ) {
|
||||
fallbackOnError( reply.error() );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( actual->contains( dataKey( key ) ) ) {
|
||||
PlainTextStore plainTextStore( q->service(), q->settings() );
|
||||
|
||||
if ( plainTextStore.contains( key ) ) {
|
||||
// We previously stored data in the insecure QSettings, but now have KWallet available.
|
||||
// Do the migration
|
||||
|
||||
data = actual->value( dataKey( key ) ).toByteArray();
|
||||
const WritePasswordJobPrivate::Mode mode = WritePasswordJobPrivate::stringToMode( actual->value( typeKey( key ) ).toString() );
|
||||
actual->remove( key );
|
||||
data = plainTextStore.readData( key );
|
||||
const WritePasswordJobPrivate::Mode mode = plainTextStore.readMode( key );
|
||||
plainTextStore.remove( key );
|
||||
|
||||
q->emitFinished();
|
||||
|
||||
|
@ -404,19 +391,18 @@ void WritePasswordJobPrivate::scheduledStart() {
|
|||
|
||||
void WritePasswordJobPrivate::fallbackOnError(const QDBusError &err)
|
||||
{
|
||||
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
|
||||
QSettings* actual = q->settings() ? q->settings() : local.data();
|
||||
|
||||
if ( !q->insecureFallback() ) {
|
||||
q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
|
||||
return;
|
||||
}
|
||||
|
||||
actual->setValue( QString::fromLatin1( "%1/type" ).arg( key ), mode );
|
||||
actual->setValue( QString::fromLatin1( "%1/data" ).arg( key ), data );
|
||||
actual->sync();
|
||||
PlainTextStore plainTextStore( q->service(), q->settings() );
|
||||
plainTextStore.write( key, data, mode );
|
||||
|
||||
q->emitFinished();
|
||||
if ( plainTextStore.error() != NoError )
|
||||
q->emitFinishedWithError( plainTextStore.error(), plainTextStore.errorString() );
|
||||
else
|
||||
q->emitFinished();
|
||||
}
|
||||
|
||||
void JobPrivate::gnomeKeyring_writeCb(int result, JobPrivate* self )
|
||||
|
@ -433,19 +419,15 @@ void JobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
|
|||
watcher->deleteLater();
|
||||
QDBusPendingReply<int> reply = *watcher;
|
||||
|
||||
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
|
||||
QSettings* actual = q->settings() ? q->settings() : local.data();
|
||||
|
||||
if ( reply.isError() ) {
|
||||
fallbackOnError( reply.error() );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( actual->contains( key ) )
|
||||
{
|
||||
PlainTextStore plainTextStore( q->service(), q->settings() );
|
||||
if ( plainTextStore.contains( key ) ) {
|
||||
// If we had previously written to QSettings, but we now have a kwallet available, migrate and delete old insecure data
|
||||
actual->remove( key );
|
||||
actual->sync();
|
||||
plainTextStore.remove( key );
|
||||
}
|
||||
|
||||
const int handle = reply.value();
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
* details, check the accompanying file 'COPYING'. *
|
||||
*****************************************************************************/
|
||||
#include "keychain_p.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include "plaintextstore_p.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
|
@ -22,8 +21,6 @@ using namespace QKeychain;
|
|||
|
||||
void ReadPasswordJobPrivate::scheduledStart() {
|
||||
LPCWSTR name = (LPCWSTR)key.utf16();
|
||||
//Use settings member if there, create local settings object if not
|
||||
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
|
||||
PCREDENTIALW cred;
|
||||
|
||||
if (!CredReadW(name, CRED_TYPE_GENERIC, 0, &cred)) {
|
||||
|
@ -94,13 +91,10 @@ void DeletePasswordJobPrivate::scheduledStart() {
|
|||
}
|
||||
#else
|
||||
void ReadPasswordJobPrivate::scheduledStart() {
|
||||
//Use settings member if there, create local settings object if not
|
||||
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
|
||||
QSettings* actual = q->settings() ? q->settings() : local.get();
|
||||
|
||||
QByteArray encrypted = actual->value( key ).toByteArray();
|
||||
if ( encrypted.isNull() ) {
|
||||
q->emitFinishedWithError( EntryNotFound, tr("Entry not found") );
|
||||
PlainTextStore plainTextStore( q->service(), q->settings() );
|
||||
QByteArray encrypted = plainTextStore.readData( key );
|
||||
if ( plainTextStore.error() != NoError ) {
|
||||
q->emitFinishedWithError( plainTextStore.error(), plainTextStore.errorString() );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -147,17 +141,10 @@ void WritePasswordJobPrivate::scheduledStart() {
|
|||
const QByteArray encrypted( reinterpret_cast<char*>( blob_out.pbData ), blob_out.cbData );
|
||||
LocalFree( blob_out.pbData );
|
||||
|
||||
//Use settings member if there, create local settings object if not
|
||||
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
|
||||
QSettings* actual = q->settings() ? q->settings() : local.get();
|
||||
actual->setValue( key, encrypted );
|
||||
actual->sync();
|
||||
if ( actual->status() != QSettings::NoError ) {
|
||||
|
||||
const QString errorString = actual->status() == QSettings::AccessError
|
||||
? tr("Could not store encrypted data in settings: access error")
|
||||
: tr("Could not store encrypted data in settings: format error");
|
||||
q->emitFinishedWithError( OtherError, errorString );
|
||||
PlainTextStore plainTextStore( q->service(), q->settings() );
|
||||
plainTextStore.write( key, encrypted, Binary );
|
||||
if ( plainTextStore.error() != NoError ) {
|
||||
q->emitFinishedWithError( plainTextStore.error(), plainTextStore.errorString() );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -165,16 +152,10 @@ void WritePasswordJobPrivate::scheduledStart() {
|
|||
}
|
||||
|
||||
void DeletePasswordJobPrivate::scheduledStart() {
|
||||
//Use settings member if there, create local settings object if not
|
||||
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
|
||||
QSettings* actual = q->settings() ? q->settings() : local.get();
|
||||
actual->remove( key );
|
||||
actual->sync();
|
||||
if ( actual->status() != QSettings::NoError ) {
|
||||
const QString err = actual->status() == QSettings::AccessError
|
||||
? tr("Could not delete encrypted data from settings: access error")
|
||||
: tr("Could not delete encrypted data from settings: format error");
|
||||
q->emitFinishedWithError( OtherError, err );
|
||||
PlainTextStore plainTextStore( q->service(), q->settings() );
|
||||
plainTextStore.remove( key );
|
||||
if ( plainTextStore.error() != NoError ) {
|
||||
q->emitFinishedWithError( plainTextStore.error(), plainTextStore.errorString() );
|
||||
} else {
|
||||
q->emitFinished();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/******************************************************************************
|
||||
* Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
|
||||
* Copyright (C) 2016 Mathias Hasselmann <mathias.hasselmann@kdab.com> *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution *
|
||||
* details, check the accompanying file 'COPYING'. *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "plaintextstore_p.h"
|
||||
|
||||
using namespace QKeychain;
|
||||
|
||||
namespace {
|
||||
#ifdef Q_OS_WIN
|
||||
inline QString dataKey(const QString &key) { return key; }
|
||||
#else // Q_OS_WIN
|
||||
inline QString dataKey(const QString &key) { return key + QLatin1String("/data"); }
|
||||
inline QString typeKey(const QString &key) { return key + QLatin1String("/type"); }
|
||||
#endif // Q_OS_WIN
|
||||
}
|
||||
|
||||
|
||||
PlainTextStore::PlainTextStore(const QString &service, QSettings *settings)
|
||||
: m_localSettings(settings ? 0 : new QSettings(service))
|
||||
, m_actualSettings(settings ? settings : m_localSettings.data())
|
||||
, m_error(NoError)
|
||||
{
|
||||
}
|
||||
|
||||
bool PlainTextStore::contains(const QString &key) const
|
||||
{
|
||||
return m_actualSettings->contains(dataKey(key));
|
||||
}
|
||||
|
||||
QByteArray PlainTextStore::readData(const QString &key)
|
||||
{
|
||||
return read(dataKey(key)).toByteArray();
|
||||
}
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
|
||||
JobPrivate::Mode PlainTextStore::readMode(const QString &key)
|
||||
{
|
||||
return JobPrivate::stringToMode(read(typeKey(key)).toString());
|
||||
}
|
||||
|
||||
#endif // Q_OS_WIN
|
||||
|
||||
void PlainTextStore::write(const QString &key, const QByteArray &data, JobPrivate::Mode mode)
|
||||
{
|
||||
if (m_actualSettings->status() != QSettings::NoError)
|
||||
return;
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
m_actualSettings->setValue(typeKey(key), JobPrivate::modeToString(mode));
|
||||
#else // Q_OS_WIN
|
||||
Q_UNUSED(mode);
|
||||
#endif // Q_OS_WIN
|
||||
m_actualSettings->setValue(dataKey(key), data);
|
||||
m_actualSettings->sync();
|
||||
|
||||
if (m_actualSettings->status() == QSettings::AccessError) {
|
||||
setError(AccessDenied, tr("Could not store data in settings: access error"));
|
||||
} else if (m_actualSettings->status() != QSettings::NoError) {
|
||||
setError(OtherError, tr("Could not store data in settings: format error"));
|
||||
} else {
|
||||
setError(NoError, QString());
|
||||
}
|
||||
}
|
||||
|
||||
void PlainTextStore::remove(const QString &key)
|
||||
{
|
||||
if (m_actualSettings->status() != QSettings::NoError)
|
||||
return;
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
m_actualSettings->remove(typeKey(key));
|
||||
#endif // Q_OS_WIN
|
||||
m_actualSettings->remove(dataKey(key));
|
||||
m_actualSettings->sync();
|
||||
|
||||
if (m_actualSettings->status() == QSettings::AccessError) {
|
||||
setError(AccessDenied, tr("Could not delete data from settings: access error"));
|
||||
} else if (m_actualSettings->status() != QSettings::NoError) {
|
||||
setError(OtherError, tr("Could not delete data from settings: format error"));
|
||||
} else {
|
||||
setError(NoError, QString());
|
||||
}
|
||||
}
|
||||
|
||||
void PlainTextStore::setError(Error error, const QString &errorString)
|
||||
{
|
||||
m_error = error;
|
||||
m_errorString = errorString;
|
||||
}
|
||||
|
||||
QVariant PlainTextStore::read(const QString &key)
|
||||
{
|
||||
const QVariant value = m_actualSettings->value(key);
|
||||
|
||||
if (value.isNull()) {
|
||||
setError(EntryNotFound, tr("Entry not found"));
|
||||
} else {
|
||||
setError(NoError, QString());
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/******************************************************************************
|
||||
* Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
|
||||
* Copyright (C) 2016 Mathias Hasselmann <mathias.hasselmann@kdab.com> *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution *
|
||||
* details, check the accompanying file 'COPYING'. *
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QTKEYCHAIN_PLAINTEXTSTORE_P_H
|
||||
#define QTKEYCHAIN_PLAINTEXTSTORE_P_H
|
||||
|
||||
#include "keychain_p.h"
|
||||
|
||||
namespace QKeychain {
|
||||
|
||||
class PlainTextStore {
|
||||
Q_DECLARE_TR_FUNCTIONS(QKeychain::PlainTextStore)
|
||||
|
||||
public:
|
||||
explicit PlainTextStore(const QString &service, QSettings *settings);
|
||||
|
||||
Error error() const { return m_error; }
|
||||
QString errorString() const { return m_errorString; }
|
||||
|
||||
bool contains(const QString &key) const;
|
||||
|
||||
QByteArray readData(const QString &key);
|
||||
JobPrivate::Mode readMode(const QString &key);
|
||||
|
||||
void write(const QString &key, const QByteArray &data, JobPrivate::Mode mode);
|
||||
void remove(const QString &key);
|
||||
|
||||
private:
|
||||
void setError(Error error, const QString &errorString);
|
||||
QVariant read(const QString &key);
|
||||
|
||||
const QScopedPointer<QSettings> m_localSettings;
|
||||
QSettings *const m_actualSettings;
|
||||
QString m_errorString;
|
||||
Error m_error;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QTKEYCHAIN_PLAINTEXTSTORE_P_H
|
Loading…
Reference in New Issue