diff --git a/CMakeLists.txt b/CMakeLists.txt index 83c574412..712974d92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,11 +121,6 @@ macro_log_feature(Boost_FOUND "Boost" "Provides free peer-reviewed portable C++ macro_optional_find_package(QCA2) macro_log_feature(QCA2_FOUND "QCA2" "Provides encryption and signing functions required for Grooveshark resolver" "http://delta.affinix.com/qca/" FALSE "" "") -if( NOT QTKEYCHAIN_INCLUDE_DIRS OR NOT QTKEYCHAIN_LIBRARIES ) -macro_optional_find_package(QtKeychain) -macro_log_feature(QTKEYCHAIN_FOUND "QtKeychain" "Provides support for secure password storage" "https://github.com/frankosterfeld/qtkeychain" TRUE "" "") -endif() - macro_optional_find_package(LibAttica) macro_log_feature(LIBATTICA_FOUND "libattica" "Provides support for automatic fetching and managing of resolvers from the tomahawk website" "https://projects.kde.org/projects/kdesupport/attica" TRUE "" "") @@ -164,6 +159,17 @@ SET( LIBPORTFWD_LIBRARY tomahawk_portfwd ) SET( LIBPORTFWD_LIBRARIES ${LIBPORTFWD_LIBRARY} ) ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/libportfwd ) +### qtkeychain +SET( QTKEYCHAIN_INCLUDE_DIRS ${THIRDPARTY_DIR}/qtkeychain ) +SET( QTKEYCHAIN_LIBRARY qtkeychain ) +SET( QTKEYCHAIN_LIBRARIES ${QTKEYCHAIN_LIBRARY} ) +ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/qtkeychain/qtkeychain ) + +if( NOT QTKEYCHAIN_INCLUDE_DIRS OR NOT QTKEYCHAIN_LIBRARIES ) +macro_optional_find_package(QtKeychain) +macro_log_feature(QTKEYCHAIN_FOUND "QtKeychain" "Provides support for secure password storage" "https://github.com/frankosterfeld/qtkeychain" TRUE "" "") +endif() + # we need pthreads too #macro_optional_find_package(Threads) #macro_log_feature(THREADS_FOUND "Threads" "Threading Library" "" TRUE "" "Platform specific library for threading") diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index a9d309d64..18199c42a 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -327,8 +327,8 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/. ${LIBECHONEST_INCLUDE_DIR}/.. ${CLUCENE_INCLUDE_DIRS} ${PHONON_INCLUDES} - ${QTKEYCHAIN_INCLUD_DIRS} - ${QTKEYCHAIN_INCLUD_DIRS}/.. + ${QTKEYCHAIN_INCLUDE_DIRS} + ${QTKEYCHAIN_INCLUDE_DIRS}/.. ${CMAKE_BINARY_DIR}/thirdparty/liblastfm2/src playlist diff --git a/thirdparty/qtkeychain/CMakeLists.txt b/thirdparty/qtkeychain/CMakeLists.txt new file mode 100644 index 000000000..46a848a8c --- /dev/null +++ b/thirdparty/qtkeychain/CMakeLists.txt @@ -0,0 +1,105 @@ +cmake_minimum_required(VERSION 2.8) +project(qtkeychain) + +### + +set(QTKEYCHAIN_VERSION 0) +set(QTKEYCHAIN_SOVERSION 0) + +### + +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${PROJECT_SOURCE_DIR}/cmake/Modules") +include(GNUInstallDirs) + +if(UNIX AND NOT APPLE) + find_package(Qt4 COMPONENTS QtCore QtDBus REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore REQUIRED) +endif() + +include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}) + +list(APPEND qtkeychain_LIBRARIES ${QT_QTCORE_LIBRARY}) +set(qtkeychain_SOURCES + keychain.cpp +) + + +if(WIN32) + list(APPEND qtkeychain_SOURCES keychain_win.cpp) + list(APPEND qtkeychain_LIBRARIES crypt32) + #FIXME: mingw bug; otherwise getting undefined refs to RtlSecureZeroMemory there + if(MINGW) + add_definitions( -O2 ) + endif() +endif() + +if(APPLE) + list(APPEND qtkeychain_SOURCES keychain_mac.cpp) + + find_library(COREFOUNDATION_LIBRARY CoreFoundation) + list(APPEND qtkeychain_LIBRARIES ${COREFOUNDATION_LIBRARY}) + + find_library(SECURITY_LIBRARY Security) + list(APPEND qtkeychain_LIBRARIES ${SECURITY_LIBRARY}) +endif() + +if(UNIX AND NOT APPLE) + list(APPEND qtkeychain_SOURCES keychain_dbus.cpp) + qt4_add_dbus_interface(qtkeychain_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/org.kde.KWallet.xml kwallet_interface KWalletInterface) + list(APPEND qtkeychain_LIBRARIES ${QT_QTDBUS_LIBRARY}) +endif() + +QT4_WRAP_CPP(qtkeychain_MOC_OUTFILES keychain.h keychain_p.h) + +if(NOT QTKEYCHAIN_STATIC) + add_library(qtkeychain SHARED ${qtkeychain_SOURCES} ${qtkeychain_MOC_OUTFILES}) + set_target_properties(qtkeychain PROPERTIES COMPILE_DEFINITIONS QKEYCHAIN_BUILD_QKEYCHAIN_LIB) + target_link_libraries(qtkeychain ${qtkeychain_LIBRARIES}) +else() + add_library(qtkeychain STATIC ${qtkeychain_SOURCES} ${qtkeychain_MOC_OUTFILES}) + set_target_properties(qtkeychain PROPERTIES COMPILE_DEFINITIONS QKEYCHAIN_STATICLIB) +endif() + +set_target_properties(qtkeychain PROPERTIES + VERSION ${QTKEYCHAIN_VERSION} + SOVERSION ${QTKEYCHAIN_SOVERSION} +) + +install(FILES keychain.h qkeychain_export.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qtkeychain/ +) + +install(TARGETS qtkeychain + EXPORT QtKeychainLibraryDepends + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +add_executable( testclient testclient.cpp ) +target_link_libraries( testclient qtkeychain) + + +### +### CMake config file +### + +export(TARGETS qtkeychain FILE "${PROJECT_BINARY_DIR}/QtKeychainLibraryDepends.cmake") +export(PACKAGE QtKeychain) + +configure_file(QtKeychainBuildTreeSettings.cmake.in + "${PROJECT_BINARY_DIR}/QtKeychainBuildTreeSettings.cmake" @ONLY) +configure_file(QtKeychainConfig.cmake.in + "${PROJECT_BINARY_DIR}/QtKeychainConfig.cmake" @ONLY) +configure_file(QtKeychainConfigVersion.cmake.in + "${PROJECT_BINARY_DIR}/QtKeychainConfigVersion.cmake" @ONLY) + +install(EXPORT QtKeychainLibraryDepends + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/QtKeychain" +) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/QtKeychainConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/QtKeychainConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/QtKeychain +) diff --git a/thirdparty/qtkeychain/COPYING b/thirdparty/qtkeychain/COPYING new file mode 100644 index 000000000..cca2a5c9a --- /dev/null +++ b/thirdparty/qtkeychain/COPYING @@ -0,0 +1,20 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/thirdparty/qtkeychain/QtKeychainBuildTreeSettings.cmake.in b/thirdparty/qtkeychain/QtKeychainBuildTreeSettings.cmake.in new file mode 100644 index 000000000..3f9e9f66b --- /dev/null +++ b/thirdparty/qtkeychain/QtKeychainBuildTreeSettings.cmake.in @@ -0,0 +1,4 @@ +set(QTKEYCHAIN_INCLUDE_DIRS + "@PROJECT_SOURCE_DIR@" + "@PROJECT_BINARY_DIR@" +) diff --git a/thirdparty/qtkeychain/QtKeychainConfig.cmake.in b/thirdparty/qtkeychain/QtKeychainConfig.cmake.in new file mode 100644 index 000000000..dff5802ae --- /dev/null +++ b/thirdparty/qtkeychain/QtKeychainConfig.cmake.in @@ -0,0 +1,20 @@ +# - Config file for the FooBar package +# It defines the following variables +# FOOBAR_INCLUDE_DIRS - include directories for FooBar +# FOOBAR_LIBRARIES - libraries to link against +# FOOBAR_EXECUTABLE - the bar executable + +# Compute paths +get_filename_component(QTKEYCHAIN_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +if(EXISTS "${QTKEYCHAIN_CMAKE_DIR}/CMakeCache.txt") + # In build tree + include("${QTKEYCHAIN_CMAKE_DIR}/QtKeychainBuildTreeSettings.cmake") +else() + set(QTKEYCHAIN_INCLUDE_DIRS "${QTKEYCHAIN_CMAKE_DIR}/../../") +endif() + +# Our library dependencies (contains definitions for IMPORTED targets) +include("${QTKEYCHAIN_CMAKE_DIR}/QtKeychainLibraryDepends.cmake") + +# These are IMPORTED targets created by FooBarLibraryDepends.cmake +set(QTKEYCHAIN_LIBRARIES qtkeychain) diff --git a/thirdparty/qtkeychain/QtKeychainConfigVersion.cmake.in b/thirdparty/qtkeychain/QtKeychainConfigVersion.cmake.in new file mode 100644 index 000000000..fba821a64 --- /dev/null +++ b/thirdparty/qtkeychain/QtKeychainConfigVersion.cmake.in @@ -0,0 +1,11 @@ +set(PACKAGE_VERSION "@QTKEYCHAIN_VERSION@") + +# Check whether the requested PACKAGE_FIND_VERSION is compatible +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() diff --git a/thirdparty/qtkeychain/ReadMe.markdown b/thirdparty/qtkeychain/ReadMe.markdown new file mode 120000 index 000000000..3cefeef2e --- /dev/null +++ b/thirdparty/qtkeychain/ReadMe.markdown @@ -0,0 +1 @@ +ReadMe.txt \ No newline at end of file diff --git a/thirdparty/qtkeychain/ReadMe.txt b/thirdparty/qtkeychain/ReadMe.txt new file mode 100644 index 000000000..b6388f267 --- /dev/null +++ b/thirdparty/qtkeychain/ReadMe.txt @@ -0,0 +1,16 @@ +QtKeychain +========== + +QtKeychain is a Qt API to store passwords and other secret data securely. How the data is stored depends on the platform: + + * **Mac OS X:** Passwords are stored in the OS X Keychain. + + * **Linux/Unix:** If running, KWallet (via D-Bus) is used. +Support for the GNOME Keyring via freedesktop.org's +[Secret Storage D-Bus specification](http://freedesktop.org/wiki/Specifications/secret-storage-spec "Secret Storage specification") is planned but not yet implemented. + + * **Windows:** Windows does not provide a service for secure storage. QtKeychain uses the Windows API function [CryptProtectData](http://msdn.microsoft.com/en-us/library/windows/desktop/aa380261%28v=vs.85%29.aspx "CryptProtectData function") to encrypt the password with the user's logon credentials. The encrypted data is then persisted via QSettings. + +In unsupported environments QtKeychain will report an error. It will never store any data unencrypted. + +**License:** QtKeychain is available under the [Modified BSD License](http://www.gnu.org/licenses/license-list.html#ModifiedBSD). See the file COPYING for details. diff --git a/thirdparty/qtkeychain/cmake/Modules/GNUInstallDirs.cmake b/thirdparty/qtkeychain/cmake/Modules/GNUInstallDirs.cmake new file mode 100644 index 000000000..0302e4bef --- /dev/null +++ b/thirdparty/qtkeychain/cmake/Modules/GNUInstallDirs.cmake @@ -0,0 +1,188 @@ +# - Define GNU standard installation directories +# Provides install directory variables as defined for GNU software: +# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html +# Inclusion of this module defines the following variables: +# CMAKE_INSTALL_ - destination for files of a given type +# CMAKE_INSTALL_FULL_ - corresponding absolute path +# where is one of: +# BINDIR - user executables (bin) +# SBINDIR - system admin executables (sbin) +# LIBEXECDIR - program executables (libexec) +# SYSCONFDIR - read-only single-machine data (etc) +# SHAREDSTATEDIR - modifiable architecture-independent data (com) +# LOCALSTATEDIR - modifiable single-machine data (var) +# LIBDIR - object code libraries (lib or lib64 or lib/ on Debian) +# INCLUDEDIR - C header files (include) +# OLDINCLUDEDIR - C header files for non-gcc (/usr/include) +# DATAROOTDIR - read-only architecture-independent data root (share) +# DATADIR - read-only architecture-independent data (DATAROOTDIR) +# INFODIR - info documentation (DATAROOTDIR/info) +# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale) +# MANDIR - man documentation (DATAROOTDIR/man) +# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME) +# Each CMAKE_INSTALL_ value may be passed to the DESTINATION options of +# install() commands for the corresponding file type. If the includer does +# not define a value the above-shown default will be used and the value will +# appear in the cache for editing by the user. +# Each CMAKE_INSTALL_FULL_ value contains an absolute path constructed +# from the corresponding destination by prepending (if necessary) the value +# of CMAKE_INSTALL_PREFIX. + +#============================================================================= +# Copyright 2011 Nikita Krupen'ko +# Copyright 2011 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# Installation directories +# +if(NOT DEFINED CMAKE_INSTALL_BINDIR) + set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)") +endif() + +if(NOT DEFINED CMAKE_INSTALL_SBINDIR) + set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)") +endif() + +if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR) + set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)") +endif() + +if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR) + set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)") +endif() + +if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR) + set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)") +endif() + +if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR) + set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)") +endif() + +if(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(_LIBDIR_DEFAULT "lib") + # Override this default 'lib' with 'lib64' iff: + # - we are on Linux system but NOT cross-compiling + # - we are NOT on debian + # - we are on a 64 bits system + # reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf + # For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if + # CMAKE_LIBRARY_ARCHITECTURE is set (which contains e.g. "i386-linux-gnu" + # See http://wiki.debian.org/Multiarch + if(CMAKE_SYSTEM_NAME MATCHES "Linux" + AND NOT CMAKE_CROSSCOMPILING) + if (EXISTS "/etc/debian_version") # is this a debian system ? + if(CMAKE_LIBRARY_ARCHITECTURE) + set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}") + endif() + else() # not debian, rely on CMAKE_SIZEOF_VOID_P: + if(NOT DEFINED CMAKE_SIZEOF_VOID_P) + message(AUTHOR_WARNING + "Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. " + "Please enable at least one language before including GNUInstallDirs.") + else() + if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(_LIBDIR_DEFAULT "lib64") + endif() + endif() + endif() + endif() + set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})") +endif() + +if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR) + set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)") +endif() + +if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR) + set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)") +endif() + +if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR) + set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)") +endif() + +#----------------------------------------------------------------------------- +# Values whose defaults are relative to DATAROOTDIR. Store empty values in +# the cache and store the defaults in local variables if the cache values are +# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes. + +if(NOT CMAKE_INSTALL_DATADIR) + set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)") + set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}") +endif() + +if(NOT CMAKE_INSTALL_INFODIR) + set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)") + set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info") +endif() + +if(NOT CMAKE_INSTALL_LOCALEDIR) + set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)") + set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale") +endif() + +if(NOT CMAKE_INSTALL_MANDIR) + set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)") + set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man") +endif() + +if(NOT CMAKE_INSTALL_DOCDIR) + set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)") + set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}") +endif() + +#----------------------------------------------------------------------------- + +mark_as_advanced( + CMAKE_INSTALL_BINDIR + CMAKE_INSTALL_SBINDIR + CMAKE_INSTALL_LIBEXECDIR + CMAKE_INSTALL_SYSCONFDIR + CMAKE_INSTALL_SHAREDSTATEDIR + CMAKE_INSTALL_LOCALSTATEDIR + CMAKE_INSTALL_LIBDIR + CMAKE_INSTALL_INCLUDEDIR + CMAKE_INSTALL_OLDINCLUDEDIR + CMAKE_INSTALL_DATAROOTDIR + CMAKE_INSTALL_DATADIR + CMAKE_INSTALL_INFODIR + CMAKE_INSTALL_LOCALEDIR + CMAKE_INSTALL_MANDIR + CMAKE_INSTALL_DOCDIR + ) + +# Result directories +# +foreach(dir + BINDIR + SBINDIR + LIBEXECDIR + SYSCONFDIR + SHAREDSTATEDIR + LOCALSTATEDIR + LIBDIR + INCLUDEDIR + OLDINCLUDEDIR + DATAROOTDIR + DATADIR + INFODIR + LOCALEDIR + MANDIR + DOCDIR + ) + if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}}) + set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}") + else() + set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}") + endif() +endforeach() diff --git a/thirdparty/qtkeychain/keychain.cpp b/thirdparty/qtkeychain/keychain.cpp new file mode 100644 index 000000000..4080537c4 --- /dev/null +++ b/thirdparty/qtkeychain/keychain.cpp @@ -0,0 +1,173 @@ +/****************************************************************************** + * Copyright (C) 2011 Frank Osterfeld * + * * + * 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 "keychain.h" +#include "keychain_p.h" + +using namespace QKeychain; + +Job::Job( const QString& service, QObject *parent ) + : QObject( parent ) + , d ( new Private( service ) ) { +} + +Job::~Job() { + delete d; +} + +QString Job::service() const { + return d->service; +} + +QSettings* Job::settings() const { + return d->settings; +} + +void Job::setSettings( QSettings* settings ) { + d->settings = settings; +} + +void Job::start() { + QMetaObject::invokeMethod( this, "doStart", Qt::QueuedConnection ); +} + +bool Job::autoDelete() const { + return d->autoDelete; +} + +void Job::setAutoDelete( bool autoDelete ) { + d->autoDelete = autoDelete; +} + +bool Job::insecureFallback() const { + return d->insecureFallback; +} + +void Job::setInsecureFallback( bool insecureFallback ) { + d->insecureFallback = insecureFallback; +} + +void Job::emitFinished() { + emit finished( this ); + if ( d->autoDelete ) + deleteLater(); +} + +void Job::emitFinishedWithError( Error error, const QString& errorString ) { + d->error = error; + d->errorString = errorString; + emitFinished(); +} + +Error Job::error() const { + return d->error; +} + +QString Job::errorString() const { + return d->errorString; +} + +void Job::setError( Error error ) { + d->error = error; +} + +void Job::setErrorString( const QString& errorString ) { + d->errorString = errorString; +} + +ReadPasswordJob::ReadPasswordJob( const QString& service, QObject* parent ) + : Job( service, parent ) + , d( new Private( this ) ) +{} + +ReadPasswordJob::~ReadPasswordJob() { + delete d; +} + +QString ReadPasswordJob::textData() const { + return QString::fromUtf8( d->data ); +} + +QByteArray ReadPasswordJob::binaryData() const { + return d->data; +} + +QString ReadPasswordJob::key() const { + return d->key; +} + +void ReadPasswordJob::setKey( const QString& key ) { + d->key = key; +} + +void ReadPasswordJob::doStart() { + d->doStart(); +} + +WritePasswordJob::WritePasswordJob( const QString& service, QObject* parent ) + : Job( service, parent ) + , d( new Private( this ) ) { +} + +WritePasswordJob::~WritePasswordJob() { + delete d; +} + +QString WritePasswordJob::key() const { + return d->key; +} + +void WritePasswordJob::setKey( const QString& key ) { + d->key = key; +} + +void WritePasswordJob::setBinaryData( const QByteArray& data ) { + d->binaryData = data; + d->mode = Private::Binary; +} + +void WritePasswordJob::setTextData( const QString& data ) { + d->textData = data; + d->mode = Private::Text; +} + +void WritePasswordJob::doStart() { + d->doStart(); +} + +DeletePasswordJob::DeletePasswordJob( const QString& service, QObject* parent ) + : Job( service, parent ) + , d( new Private( this ) ) { +} + +DeletePasswordJob::~DeletePasswordJob() { + delete d; +} + +void DeletePasswordJob::doStart() { + //Internally, to delete a password we just execute a write job with no data set (null byte array). + //In all current implementations, this deletes the entry so this is sufficient + WritePasswordJob* job = new WritePasswordJob( service(), this ); + connect( job, SIGNAL(finished(QKeychain::Job*)), d, SLOT(jobFinished(QKeychain::Job*)) ); + job->setKey( d->key ); + job->start(); +} + +QString DeletePasswordJob::key() const { + return d->key; +} + +void DeletePasswordJob::setKey( const QString& key ) { + d->key = key; +} + +void DeletePasswordJob::Private::jobFinished( Job* job ) { + q->setError( job->error() ); + q->setErrorString( job->errorString() ); + q->emitFinished(); +} diff --git a/thirdparty/qtkeychain/keychain.h b/thirdparty/qtkeychain/keychain.h new file mode 100644 index 000000000..6b08a6537 --- /dev/null +++ b/thirdparty/qtkeychain/keychain.h @@ -0,0 +1,132 @@ +/****************************************************************************** + * Copyright (C) 2011 Frank Osterfeld * + * * + * 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 KEYCHAIN_H +#define KEYCHAIN_H + +#include "qkeychain_export.h" + +#include +#include + +class QSettings; + +namespace QKeychain { + +/** + * Error codes + */ +enum Error { + NoError=0, /**< No error occurred, operation was successful */ + EntryNotFound, /**< For the given key no data was found */ + CouldNotDeleteEntry, /**< Could not delete existing secret data */ + AccessDeniedByUser, /**< User denied access to keychain */ + AccessDenied, /**< Access denied for other reasons */ + NoBackendAvailable, /**< No platform-specific keychain service available */ + NotImplemented, /**< Not implemented on platform */ + OtherError /**< Something else went wrong (errorString() might provide details) */ +}; + +class QKEYCHAIN_EXPORT Job : public QObject { + Q_OBJECT +public: + explicit Job( const QString& service, QObject* parent=0 ); + ~Job(); + + QSettings* settings() const; + void setSettings( QSettings* settings ); + + void start(); + + QString service() const; + + Error error() const; + QString errorString() const; + + bool autoDelete() const; + void setAutoDelete( bool autoDelete ); + + bool insecureFallback() const; + void setInsecureFallback( bool insecureFallback ); + +Q_SIGNALS: + void finished( QKeychain::Job* ); + +protected: + Q_INVOKABLE virtual void doStart() = 0; + + void setError( Error error ); + void setErrorString( const QString& errorString ); + void emitFinished(); + void emitFinishedWithError(Error, const QString& errorString); + +private: + class Private; + Private* const d; +}; + +class QKEYCHAIN_EXPORT ReadPasswordJob : public Job { + Q_OBJECT +public: + explicit ReadPasswordJob( const QString& service, QObject* parent=0 ); + ~ReadPasswordJob(); + + QString key() const; + void setKey( const QString& key ); + + QByteArray binaryData() const; + QString textData() const; + +protected: + void doStart(); + +private: + class Private; + Private* const d; +}; + +class QKEYCHAIN_EXPORT WritePasswordJob : public Job { + Q_OBJECT +public: + explicit WritePasswordJob( const QString& service, QObject* parent=0 ); + ~WritePasswordJob(); + + QString key() const; + void setKey( const QString& key ); + + void setBinaryData( const QByteArray& data ); + void setTextData( const QString& data ); + +protected: + void doStart(); + +private: + class Private; + Private* const d; +}; + +class QKEYCHAIN_EXPORT DeletePasswordJob : public Job { + Q_OBJECT +public: + explicit DeletePasswordJob( const QString& service, QObject* parent=0 ); + ~DeletePasswordJob(); + + QString key() const; + void setKey( const QString& key ); + +protected: + void doStart(); + +private: + class Private; + Private* const d; +}; + +} // namespace QtKeychain + +#endif diff --git a/thirdparty/qtkeychain/keychain_dbus.cpp b/thirdparty/qtkeychain/keychain_dbus.cpp new file mode 100644 index 000000000..93c79f0f6 --- /dev/null +++ b/thirdparty/qtkeychain/keychain_dbus.cpp @@ -0,0 +1,160 @@ +/****************************************************************************** + * Copyright (C) 2011 Frank Osterfeld * + * * + * 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 "keychain_p.h" + +#include + +#include + +using namespace QKeychain; + +void ReadPasswordJob::Private::doStart() { + iface = new org::kde::KWallet( QLatin1String("org.kde.kwalletd"), QLatin1String("/modules/kwalletd"), QDBusConnection::sessionBus(), this ); + const QDBusPendingReply reply = iface->open( QLatin1String("kdewallet"), 0, q->service() ); + QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, this ); + connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) ); +} + +void ReadPasswordJob::Private::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) { + watcher->deleteLater(); + const QDBusPendingReply reply = *watcher; + if ( reply.isError() ) { + const QDBusError err = reply.error(); + + if ( q->insecureFallback() ) { + std::auto_ptr local( !q->settings() ? new QSettings( q->service() ) : 0 ); + QSettings* actual = q->settings() ? q->settings() : local.get(); + + data = actual->value( key ).toByteArray(); + + q->emitFinished(); + } else { + if ( err.type() == QDBusError::ServiceUnknown ) //KWalletd not running + q->emitFinishedWithError( NoBackendAvailable, tr("No keychain service available") ); + else + q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) ); + + return; + } + } + + walletHandle = reply.value(); + + if ( walletHandle < 0 ) { + q->emitFinishedWithError( AccessDenied, tr("Access to keychain denied") ); + return; + } + + const QDBusPendingReply nextReply = iface->entryType( walletHandle, q->service(), key, q->service() ); + QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this ); + connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletEntryTypeFinished(QDBusPendingCallWatcher*)) ); +} + +void ReadPasswordJob::Private::kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher ) { + watcher->deleteLater(); + if ( watcher->isError() ) { + const QDBusError err = watcher->error(); + q->emitFinishedWithError( OtherError, tr("Could not determine data type: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) ); + return; + } + + const QDBusPendingReply reply = *watcher; + + dataType = reply.value() == 1/*Password*/ ? Text : Binary; + + const QDBusPendingCall nextReply = dataType == Text + ? QDBusPendingCall( iface->readPassword( walletHandle, q->service(), key, q->service() ) ) + : QDBusPendingCall( iface->readEntry( walletHandle, q->service(), key, q->service() ) ); + QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this ); + connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletReadFinished(QDBusPendingCallWatcher*)) ); +} + +void ReadPasswordJob::Private::kwalletReadFinished( QDBusPendingCallWatcher* watcher ) { + watcher->deleteLater(); + if ( watcher->isError() ) { + const QDBusError err = watcher->error(); + q->emitFinishedWithError( OtherError, tr("Could not read password: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) ); + return; + } + + if ( dataType == Binary ) { + QDBusPendingReply reply = *watcher; + data = reply.value(); + } else { + QDBusPendingReply reply = *watcher; + data = reply.value().toUtf8(); + } + q->emitFinished(); +} + +void WritePasswordJob::Private::doStart() { + iface = new org::kde::KWallet( QLatin1String("org.kde.kwalletd"), QLatin1String("/modules/kwalletd"), QDBusConnection::sessionBus(), this ); + const QDBusPendingReply reply = iface->open( QLatin1String("kdewallet"), 0, q->service() ); + QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, this ); + connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) ); +} + +void WritePasswordJob::Private::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) { + watcher->deleteLater(); + QDBusPendingReply reply = *watcher; + if ( reply.isError() ) { + if ( q->insecureFallback() ) { + std::auto_ptr local( !q->settings() ? new QSettings( q->service() ) : 0 ); + QSettings* actual = q->settings() ? q->settings() : local.get(); + + if ( mode == Delete ) { + actual->remove( key ); + actual->sync(); + + q->emitFinished(); + return; + } + const QByteArray data = mode == Binary ? binaryData : textData.toUtf8(); + actual->setValue( key, data ); + actual->sync(); + + q->emitFinished(); + } else { + const QDBusError err = reply.error(); + q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) ); + } + return; + } + + const int handle = reply.value(); + + if ( handle < 0 ) { + q->emitFinishedWithError( AccessDenied, tr("Access to keychain denied") ); + return; + } + + QDBusPendingReply nextReply; + + if ( !textData.isEmpty() ) + nextReply = iface->writePassword( handle, q->service(), key, textData, q->service() ); + else if ( !binaryData.isEmpty() ) + nextReply = iface->writeEntry( handle, q->service(), key, binaryData, q->service() ); + else + nextReply = iface->removeEntry( handle, q->service(), key, q->service() ); + + QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this ); + connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletWriteFinished(QDBusPendingCallWatcher*)) ); +} + +void WritePasswordJob::Private::kwalletWriteFinished( QDBusPendingCallWatcher* watcher ) { + watcher->deleteLater(); + QDBusPendingReply reply = *watcher; + if ( reply.isError() ) { + const QDBusError err = reply.error(); + q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) ); + return; + } + + q->emitFinished(); +} diff --git a/thirdparty/qtkeychain/keychain_mac.cpp b/thirdparty/qtkeychain/keychain_mac.cpp new file mode 100644 index 000000000..d81ecf511 --- /dev/null +++ b/thirdparty/qtkeychain/keychain_mac.cpp @@ -0,0 +1,159 @@ +/****************************************************************************** + * Copyright (C) 2011 Frank Osterfeld * + * * + * 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 "keychain_p.h" + +#include +#include +#include + +using namespace QKeychain; + +template +struct Releaser { + explicit Releaser( const T& v ) : value( v ) {} + ~Releaser() { + CFRelease( value ); + } + + const T value; +}; + +static QString strForStatus( OSStatus os ) { + const Releaser str( SecCopyErrorMessageString( os, 0 ) ); + const char * const buf = CFStringGetCStringPtr( str.value, kCFStringEncodingUTF8 ); + if ( !buf ) + return QString(); + return QString::fromUtf8( buf, strlen( buf ) ); +} + +static OSStatus readPw( QByteArray* pw, + const QString& service, + const QString& account, + SecKeychainItemRef* ref ) { + Q_ASSERT( pw ); + pw->clear(); + const QByteArray serviceData = service.toUtf8(); + const QByteArray accountData = account.toUtf8(); + + void* data = 0; + UInt32 len = 0; + + const OSStatus ret = SecKeychainFindGenericPassword( NULL, // default keychain + serviceData.size(), + serviceData.constData(), + accountData.size(), + accountData.constData(), + &len, + &data, + ref ); + if ( ret == noErr ) { + *pw = QByteArray( reinterpret_cast( data ), len ); + const OSStatus ret2 = SecKeychainItemFreeContent ( 0, data ); + if ( ret2 != noErr ) + qWarning() << "Could not free item content: " << strForStatus( ret2 ); + } + return ret; +} + +void ReadPasswordJob::Private::doStart() +{ + QString errorString; + Error error = NoError; + const OSStatus ret = readPw( &data, q->service(), q->key(), 0 ); + + switch ( ret ) { + case noErr: + break; + case errSecItemNotFound: + errorString = tr("Password not found"); + error = EntryNotFound; + break; + default: + errorString = strForStatus( ret ); + error = OtherError; + break; + } + q->emitFinishedWithError( error, errorString ); +} + + +static QKeychain::Error deleteEntryImpl( const QString& service, const QString& account, QString* err ) { + SecKeychainItemRef ref; + QByteArray pw; + const OSStatus ret1 = readPw( &pw, service, account, &ref ); + if ( ret1 == errSecItemNotFound ) + return NoError; // No item stored, we're done + if ( ret1 != noErr ) { + *err = strForStatus( ret1 ); + //TODO map error code, set errstr + return OtherError; + } + const Releaser releaser( ref ); + + const OSStatus ret2 = SecKeychainItemDelete( ref ); + + if ( ret2 == noErr ) + return NoError; + //TODO map error code + *err = strForStatus( ret2 ); + return CouldNotDeleteEntry; +} + +static QKeychain::Error writeEntryImpl( const QString& service, + const QString& account, + const QByteArray& data, + QString* err ) { + Q_ASSERT( err ); + err->clear(); + const QByteArray serviceData = service.toUtf8(); + const QByteArray accountData = account.toUtf8(); + const OSStatus ret = SecKeychainAddGenericPassword( NULL, //default keychain + serviceData.size(), + serviceData.constData(), + accountData.size(), + accountData.constData(), + data.size(), + data.constData(), + NULL //item reference + ); + if ( ret != noErr ) { + switch ( ret ) { + case errSecDuplicateItem: + { + Error derr = deleteEntryImpl( service, account, err ); + if ( derr != NoError ) + return CouldNotDeleteEntry; + else + return writeEntryImpl( service, account, data, err ); + } + default: + *err = strForStatus( ret ); + return OtherError; + } + } + + return NoError; +} + +void WritePasswordJob::Private::doStart() +{ + QString errorString; + Error error = NoError; + + if ( mode == Delete ) { + const Error derr = deleteEntryImpl( q->service(), key, &errorString ); + if ( derr != NoError ) + error = CouldNotDeleteEntry; + q->emitFinishedWithError( error, errorString ); + return; + } + const QByteArray data = mode == Text ? textData.toUtf8() : binaryData; + error = writeEntryImpl( q->service(), key, data, &errorString ); + q->emitFinishedWithError( error, errorString ); +} diff --git a/thirdparty/qtkeychain/keychain_p.h b/thirdparty/qtkeychain/keychain_p.h new file mode 100644 index 000000000..726289703 --- /dev/null +++ b/thirdparty/qtkeychain/keychain_p.h @@ -0,0 +1,122 @@ +/****************************************************************************** + * Copyright (C) 2011 Frank Osterfeld * + * * + * 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 KEYCHAIN_P_H +#define KEYCHAIN_P_H + +#include +#include +#include +#include + +#if defined(Q_OS_UNIX) && !defined(Q_WS_MAC) + +#include + +#include "kwallet_interface.h" +#else + +class QDBusPendingCallWatcher; + +#endif + +#include "keychain.h" + +namespace QKeychain { + +class Job::Private : public QObject { + Q_OBJECT +public: + Private( const QString& service_ ) + : error( NoError ) + , service( service_ ) + , autoDelete( true ) + , insecureFallback( false ) {} + + QKeychain::Error error; + QString errorString; + QString service; + bool autoDelete; + bool insecureFallback; + QPointer settings; +}; + +class ReadPasswordJob::Private : public QObject { + Q_OBJECT +public: + explicit Private( ReadPasswordJob* qq ) : q( qq ), walletHandle( 0 ), dataType( Text ) {} + void doStart(); + ReadPasswordJob* const q; + QByteArray data; + QString key; + int walletHandle; + enum DataType { + Binary, + Text + }; + DataType dataType; + +#if defined(Q_OS_UNIX) && !defined(Q_WS_MAC) + org::kde::KWallet* iface; + +private Q_SLOTS: + void kwalletOpenFinished( QDBusPendingCallWatcher* watcher ); + void kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher ); + void kwalletReadFinished( QDBusPendingCallWatcher* watcher ); +#else //moc's too dumb to respect above macros, so just define empty slot implementations +private Q_SLOTS: + void kwalletOpenFinished( QDBusPendingCallWatcher* ) {} + void kwalletEntryTypeFinished( QDBusPendingCallWatcher* ) {} + void kwalletReadFinished( QDBusPendingCallWatcher* ) {} +#endif + +}; + +class WritePasswordJob::Private : public QObject { + Q_OBJECT +public: + explicit Private( WritePasswordJob* qq ) : q( qq ), mode( Delete ) {} + void doStart(); + enum Mode { + Delete, + Text, + Binary + }; + WritePasswordJob* const q; + Mode mode; + QString key; + QByteArray binaryData; + QString textData; + +#if defined(Q_OS_UNIX) && !defined(Q_WS_MAC) + org::kde::KWallet* iface; + +private Q_SLOTS: + void kwalletOpenFinished( QDBusPendingCallWatcher* watcher ); + void kwalletWriteFinished( QDBusPendingCallWatcher* watcher ); +#else +private Q_SLOTS: + void kwalletOpenFinished( QDBusPendingCallWatcher* ) {} + void kwalletWriteFinished( QDBusPendingCallWatcher* ) {} +#endif +}; + +class DeletePasswordJob::Private : public QObject { + Q_OBJECT +public: + explicit Private( DeletePasswordJob* qq ) : q( qq ) {} + void doStart(); + DeletePasswordJob* const q; + QString key; +private Q_SLOTS: + void jobFinished( QKeychain::Job* ); +}; + +} + +#endif // KEYCHAIN_P_H diff --git a/thirdparty/qtkeychain/keychain_win.cpp b/thirdparty/qtkeychain/keychain_win.cpp new file mode 100644 index 000000000..76b4116ab --- /dev/null +++ b/thirdparty/qtkeychain/keychain_win.cpp @@ -0,0 +1,107 @@ +/****************************************************************************** + * Copyright (C) 2011 Frank Osterfeld * + * * + * 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 "keychain_p.h" + +#include + +#include +#include + +#include + +using namespace QKeychain; + +void ReadPasswordJob::Private::doStart() { + //Use settings member if there, create local settings object if not + std::auto_ptr 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") ); + return; + } + + DATA_BLOB blob_in, blob_out; + + blob_in.pbData = reinterpret_cast( encrypted.data() ); + blob_in.cbData = encrypted.size(); + + const BOOL ret = CryptUnprotectData( &blob_in, + NULL, + NULL, + NULL, + NULL, + 0, + &blob_out ); + if ( !ret ) { + q->emitFinishedWithError( OtherError, tr("Could not decrypt data") ); + return; + } + + data = QByteArray( reinterpret_cast( blob_out.pbData ), blob_out.cbData ); + SecureZeroMemory( blob_out.pbData, blob_out.cbData ); + LocalFree( blob_out.pbData ); + + q->emitFinished(); +} + +void WritePasswordJob::Private::doStart() { + if ( mode == Delete ) { + //Use settings member if there, create local settings object if not + std::auto_ptr 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 ); + } else { + q->emitFinished(); + } + return; + } + + QByteArray data = mode == Binary ? binaryData : textData.toUtf8(); + DATA_BLOB blob_in, blob_out; + blob_in.pbData = reinterpret_cast( data.data() ); + blob_in.cbData = data.size(); + const BOOL res = CryptProtectData( &blob_in, + L"QKeychain-encrypted data", + NULL, + NULL, + NULL, + 0, + &blob_out ); + if ( !res ) { + q->emitFinishedWithError( OtherError, tr("Encryption failed") ); //TODO more details available? + return; + } + + const QByteArray encrypted( reinterpret_cast( blob_out.pbData ), blob_out.cbData ); + LocalFree( blob_out.pbData ); + + //Use settings member if there, create local settings object if not + std::auto_ptr 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 ); + return; + } + + q->emitFinished(); +} diff --git a/thirdparty/qtkeychain/org.kde.KWallet.xml b/thirdparty/qtkeychain/org.kde.KWallet.xml new file mode 100644 index 000000000..548c2f82b --- /dev/null +++ b/thirdparty/qtkeychain/org.kde.KWallet.xml @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/thirdparty/qtkeychain/qkeychain_export.h b/thirdparty/qtkeychain/qkeychain_export.h new file mode 100644 index 000000000..1bb1669cb --- /dev/null +++ b/thirdparty/qtkeychain/qkeychain_export.h @@ -0,0 +1,17 @@ +#ifndef QKEYCHAIN_EXPORT_H +#define QKEYCHAIN_EXPORT_H + +#include + +# ifdef QKEYCHAIN_STATICLIB +# undef QKEYCHAIN_SHAREDLIB +# define QKEYCHAIN_EXPORT +# else +# ifdef QKEYCHAIN_BUILD_QKEYCHAIN_LIB +# define QKEYCHAIN_EXPORT Q_DECL_EXPORT +# else +# define QKEYCHAIN_EXPORT Q_DECL_IMPORT +# endif +# endif + +#endif diff --git a/thirdparty/qtkeychain/testclient.cpp b/thirdparty/qtkeychain/testclient.cpp new file mode 100644 index 000000000..b38113073 --- /dev/null +++ b/thirdparty/qtkeychain/testclient.cpp @@ -0,0 +1,98 @@ +/****************************************************************************** + * Copyright (C) 2011 Frank Osterfeld * + * * + * 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 +#include + +#include "keychain.h" +#include + +using namespace QKeychain; + +static int printUsage() { + std::cerr << "testclient store " << std::endl; + std::cerr << "testclient restore " << std::endl; + std::cerr << "testclient delete " << std::endl; + return 1; +} + +int main( int argc, char** argv ) { + QCoreApplication app( argc, argv ); + const QStringList args = app.arguments(); + if ( args.count() < 2 ) + return printUsage(); + + QStringList::ConstIterator it = args.constBegin(); + ++it; + + if ( *it == QLatin1String("store") ) { + if ( ++it == args.constEnd() ) + return printUsage(); + const QString acc = *it; + if ( ++it == args.constEnd() ) + return printUsage(); + const QString pass = *it; + if ( ++it != args.constEnd() ) + return printUsage(); + WritePasswordJob job( QLatin1String("qtkeychain-testclient") ); + job.setAutoDelete( false ); + job.setKey( acc ); + job.setTextData( pass ); + QEventLoop loop; + job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) ); + job.start(); + loop.exec(); + if ( job.error() ) { + std::cerr << "Storing password failed: " << qPrintable(job.errorString()) << std::endl; + return 1; + } + std::cout << "Password stored successfully" << std::endl; + } else if ( *it == QLatin1String("restore") ) { + if ( ++it == args.constEnd() ) + return printUsage(); + const QString acc = *it; + if ( ++it != args.constEnd() ) + return printUsage(); + ReadPasswordJob job( QLatin1String("qtkeychain-testclient") ); + job.setAutoDelete( false ); + job.setKey( acc ); + QEventLoop loop; + job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) ); + job.start(); + loop.exec(); + + const QString pw = job.textData(); + if ( job.error() ) { + std::cerr << "Restoring password failed: " << qPrintable(job.errorString()) << std::endl; + return 1; + } + std::cout << qPrintable(pw) << std::endl; + } else if ( *it == QLatin1String("delete") ) { + if ( ++it == args.constEnd() ) + return printUsage(); + const QString acc = *it; + if ( ++it != args.constEnd() ) + return printUsage(); + DeletePasswordJob job( QLatin1String("qtkeychain-testclient") ); + job.setAutoDelete( false ); + job.setKey( acc ); + QEventLoop loop; + job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) ); + job.start(); + loop.exec(); + + if ( job.error() ) { + std::cerr << "Deleting password failed: " << qPrintable(job.errorString()) << std::endl; + return 1; + } + std::cout << "Password deleted successfully" << std::endl; + } else { + return printUsage(); + } +} +