add way to store plain QByteArray instead of only QString and make naming more generic in the process
This commit is contained in:
parent
8d590e0729
commit
3751a18e71
25
keychain.cpp
25
keychain.cpp
|
@ -32,28 +32,37 @@ QString Keychain::errorString() const {
|
||||||
return d->errorString;
|
return d->errorString;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Keychain::writePassword( const QString& account, const QString& password, OverwriteMode om ) {
|
void Keychain::writePassword( const QString &key, const QString &password, OverwriteMode om ) {
|
||||||
|
writeEntry( key, password.toUtf8(), om );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Keychain::writeEntry( const QString& key, const QByteArray& ba, OverwriteMode om ) {
|
||||||
QString err;
|
QString err;
|
||||||
const Error ret = d->writePasswordImpl( account, password, om, &err );
|
const Error ret = d->writeEntryImpl( key, ba, om, &err );
|
||||||
d->error = ret;
|
d->error = ret;
|
||||||
d->errorString = err;
|
d->errorString = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Keychain::readPassword( const QString& account ) {
|
QString Keychain::readPassword( const QString& key ) {
|
||||||
|
const QByteArray ba = readEntry( key );
|
||||||
|
return QString::fromUtf8( ba.constData(), ba.size() );
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray Keychain::readEntry( const QString& key ) {
|
||||||
QString err;
|
QString err;
|
||||||
QString pw;
|
QByteArray pw;
|
||||||
const Error ret = d->readPasswordImpl( &pw, account, &err );
|
const Error ret = d->readEntryImpl( &pw, key, &err );
|
||||||
d->error = ret;
|
d->error = ret;
|
||||||
d->errorString = err;
|
d->errorString = err;
|
||||||
if ( ret != NoError )
|
if ( ret != NoError )
|
||||||
return QString();
|
return QByteArray();
|
||||||
else
|
else
|
||||||
return pw;
|
return pw;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Keychain::deletePassword( const QString& account ) {
|
void Keychain::deleteEntry( const QString& key ) {
|
||||||
QString err;
|
QString err;
|
||||||
const Error ret = d->deletePasswordImpl( account, &err );
|
const Error ret = d->deleteEntryImpl( key, &err );
|
||||||
d->error = ret;
|
d->error = ret;
|
||||||
d->errorString = err;
|
d->errorString = err;
|
||||||
}
|
}
|
||||||
|
|
57
keychain.h
57
keychain.h
|
@ -13,7 +13,14 @@
|
||||||
|
|
||||||
namespace QKeychain {
|
namespace QKeychain {
|
||||||
/**
|
/**
|
||||||
|
* Provides access to platform-specific key stores for secure persistence of
|
||||||
|
* passwords and other sensitive user data.
|
||||||
*
|
*
|
||||||
|
* On Windows, TODO
|
||||||
|
* On Mac OS X, the OS X keychain is used.
|
||||||
|
* On other Unixes, TODO
|
||||||
|
*
|
||||||
|
* TODO we don't guarantee anything
|
||||||
*/
|
*/
|
||||||
class Keychain {
|
class Keychain {
|
||||||
public:
|
public:
|
||||||
|
@ -35,11 +42,11 @@ public:
|
||||||
*/
|
*/
|
||||||
enum Error {
|
enum Error {
|
||||||
NoError=0, /*< No error occurred, operation was successful */
|
NoError=0, /*< No error occurred, operation was successful */
|
||||||
PasswordNotFound, /*< For the given account no password was found */
|
EntryNotFound, /*< For the given key no data was found */
|
||||||
CouldNotDeletePassword, /*< Could not delete existing password */
|
CouldNotDeleteEntry, /*< Could not delete existing secret data */
|
||||||
AccessDeniedByUser, /*< User denied access to keychain */
|
AccessDeniedByUser, /*< User denied access to keychain */
|
||||||
AccessDenied, /*< Access denied for other reasons */
|
AccessDenied, /*< Access denied for other reasons */
|
||||||
EntryAlreadyExists, /*< There is already a password for the given account and overwriting was not enforced */
|
EntryAlreadyExists, /*< There is already an entry for the given key and overwriting was not enforced */
|
||||||
OtherError /*< Something else went wrong (errorString() might provide details) */
|
OtherError /*< Something else went wrong (errorString() might provide details) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,7 +55,7 @@ public:
|
||||||
*/
|
*/
|
||||||
enum OverwriteMode {
|
enum OverwriteMode {
|
||||||
DoNotOverwrite, /*< Do not overwrite existing entries */
|
DoNotOverwrite, /*< Do not overwrite existing entries */
|
||||||
ForceOverwrite /*< Replace old passowrd by new one */
|
ForceOverwrite /*< Replace old data by new one */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,32 +74,52 @@ public:
|
||||||
QString errorString() const;
|
QString errorString() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a @p password in the keychain, for a given @p account.
|
* Stores a @p password in the keychain, for a given @p key.
|
||||||
* error() and errorString() hold the result of the write operation.
|
* error() and errorString() hold the result of the write operation.
|
||||||
*
|
*
|
||||||
* @param account the account to store a password for
|
* @param key the key to store a password for
|
||||||
* @param the password to store
|
* @param password the password to store
|
||||||
* @param om Whether to overwrite existing passwords
|
* @param om Whether to overwrite existing passwords
|
||||||
*/
|
*/
|
||||||
void writePassword( const QString& account,
|
void writePassword( const QString& key,
|
||||||
const QString& password,
|
const QString& password,
|
||||||
OverwriteMode om=DoNotOverwrite );
|
OverwriteMode om=DoNotOverwrite );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the @p password for an @p account from the keychain.
|
* Stores @p data in the keychain, for a given @p key.
|
||||||
* error() and errorString() hold the result of the read operation.
|
* error() and errorString() hold the result of the write operation.
|
||||||
*
|
*
|
||||||
* @param account the account ot read the password for
|
* @param key the key to store a password for
|
||||||
|
* @param data the data to store
|
||||||
|
* @param om Whether to overwrite existing passwords
|
||||||
*/
|
*/
|
||||||
QString readPassword( const QString& account );
|
void writeEntry( const QString& key,
|
||||||
|
const QByteArray& data,
|
||||||
|
OverwriteMode om=DoNotOverwrite );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the @p password for an @p account from the keychain.
|
* Reads the password for a given @p key from the keychain.
|
||||||
* error() and errorString() hold the result of the read operation.
|
* error() and errorString() hold the result of the read operation.
|
||||||
*
|
*
|
||||||
* @param account The account to delete the password for
|
* @param key the key ot read the password for
|
||||||
*/
|
*/
|
||||||
void deletePassword( const QString& account );
|
QString readPassword( const QString& key );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads data for a given @p key from the keychain.
|
||||||
|
* error() and errorString() hold the result of the read operation.
|
||||||
|
*
|
||||||
|
* @param key the key ot read the password for
|
||||||
|
*/
|
||||||
|
QByteArray readEntry( const QString& key );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the data for a @p key from the keychain.
|
||||||
|
* error() and errorString() hold the result of the delete operation.
|
||||||
|
*
|
||||||
|
* @param key The key to delete the data for
|
||||||
|
*/
|
||||||
|
void deleteEntry( const QString& key );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Private;
|
class Private;
|
||||||
|
|
|
@ -32,7 +32,7 @@ static QString strForStatus( OSStatus os ) {
|
||||||
return QString::fromUtf8( buf, strlen( buf ) );
|
return QString::fromUtf8( buf, strlen( buf ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
static OSStatus readPw( QString* pw,
|
static OSStatus readPw( QByteArray* pw,
|
||||||
const QString& service,
|
const QString& service,
|
||||||
const QString& account,
|
const QString& account,
|
||||||
SecKeychainItemRef* ref ) {
|
SecKeychainItemRef* ref ) {
|
||||||
|
@ -53,7 +53,7 @@ static OSStatus readPw( QString* pw,
|
||||||
&data,
|
&data,
|
||||||
ref );
|
ref );
|
||||||
if ( ret == noErr ) {
|
if ( ret == noErr ) {
|
||||||
*pw = QString::fromUtf8( reinterpret_cast<const char*>( data ), len );
|
*pw = QByteArray( reinterpret_cast<const char*>( data ), len );
|
||||||
const OSStatus ret2 = SecKeychainItemFreeContent ( 0, data );
|
const OSStatus ret2 = SecKeychainItemFreeContent ( 0, data );
|
||||||
if ( ret2 != noErr )
|
if ( ret2 != noErr )
|
||||||
qWarning() << "Could not free item content: " << strForStatus( ret2 );
|
qWarning() << "Could not free item content: " << strForStatus( ret2 );
|
||||||
|
@ -61,7 +61,7 @@ static OSStatus readPw( QString* pw,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Keychain::Error Keychain::Private::readPasswordImpl( QString* pw,
|
Keychain::Error Keychain::Private::readEntryImpl( QByteArray* pw,
|
||||||
const QString& account,
|
const QString& account,
|
||||||
QString* err ) {
|
QString* err ) {
|
||||||
Q_ASSERT( pw );
|
Q_ASSERT( pw );
|
||||||
|
@ -73,29 +73,28 @@ Keychain::Error Keychain::Private::readPasswordImpl( QString* pw,
|
||||||
return NoError;
|
return NoError;
|
||||||
case errSecItemNotFound:
|
case errSecItemNotFound:
|
||||||
*err = tr("Password not found");
|
*err = tr("Password not found");
|
||||||
return PasswordNotFound;
|
return EntryNotFound;
|
||||||
default:
|
default:
|
||||||
*err = strForStatus( ret );
|
*err = strForStatus( ret );
|
||||||
return OtherError;
|
return OtherError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Keychain::Error Keychain::Private::writePasswordImpl( const QString& account,
|
Keychain::Error Keychain::Private::writeEntryImpl( const QString& account,
|
||||||
const QString& password,
|
const QByteArray& data,
|
||||||
Keychain::OverwriteMode ov,
|
Keychain::OverwriteMode ov,
|
||||||
QString* err ) {
|
QString* err ) {
|
||||||
Q_ASSERT( err );
|
Q_ASSERT( err );
|
||||||
err->clear();
|
err->clear();
|
||||||
const QByteArray serviceData = service.toUtf8();
|
const QByteArray serviceData = service.toUtf8();
|
||||||
const QByteArray accountData = account.toUtf8();
|
const QByteArray accountData = account.toUtf8();
|
||||||
const QByteArray passwordData = password.toUtf8();
|
|
||||||
const OSStatus ret = SecKeychainAddGenericPassword( NULL, //default keychain
|
const OSStatus ret = SecKeychainAddGenericPassword( NULL, //default keychain
|
||||||
serviceData.size(),
|
serviceData.size(),
|
||||||
serviceData.constData(),
|
serviceData.constData(),
|
||||||
accountData.size(),
|
accountData.size(),
|
||||||
accountData.constData(),
|
accountData.constData(),
|
||||||
passwordData.size(),
|
data.size(),
|
||||||
passwordData.constData(),
|
data.constData(),
|
||||||
NULL //item reference
|
NULL //item reference
|
||||||
);
|
);
|
||||||
if ( ret != noErr ) {
|
if ( ret != noErr ) {
|
||||||
|
@ -106,11 +105,11 @@ Keychain::Error Keychain::Private::writePasswordImpl( const QString& account,
|
||||||
*err = tr("Entry already exists");
|
*err = tr("Entry already exists");
|
||||||
return EntryAlreadyExists;
|
return EntryAlreadyExists;
|
||||||
}
|
}
|
||||||
Error derr = deletePasswordImpl( account, err );
|
Error derr = deleteEntryImpl( account, err );
|
||||||
if ( derr != NoError )
|
if ( derr != NoError )
|
||||||
return CouldNotDeletePassword;
|
return CouldNotDeleteEntry;
|
||||||
else
|
else
|
||||||
return writePasswordImpl( account, password, ov, err );
|
return writeEntryImpl( account, data, ov, err );
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
*err = strForStatus( ret );
|
*err = strForStatus( ret );
|
||||||
|
@ -121,10 +120,10 @@ Keychain::Error Keychain::Private::writePasswordImpl( const QString& account,
|
||||||
return NoError;
|
return NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
Keychain::Error Keychain::Private::deletePasswordImpl( const QString& account,
|
Keychain::Error Keychain::Private::deleteEntryImpl( const QString& account,
|
||||||
QString* err ) {
|
QString* err ) {
|
||||||
SecKeychainItemRef ref;
|
SecKeychainItemRef ref;
|
||||||
QString pw;
|
QByteArray pw;
|
||||||
const OSStatus ret1 = readPw( &pw, service, account, &ref );
|
const OSStatus ret1 = readPw( &pw, service, account, &ref );
|
||||||
if ( ret1 == errSecItemNotFound )
|
if ( ret1 == errSecItemNotFound )
|
||||||
return NoError; // No item stored, we're done
|
return NoError; // No item stored, we're done
|
||||||
|
@ -141,6 +140,6 @@ Keychain::Error Keychain::Private::deletePasswordImpl( const QString& account,
|
||||||
return NoError;
|
return NoError;
|
||||||
//TODO map error code
|
//TODO map error code
|
||||||
*err = strForStatus( ret2 );
|
*err = strForStatus( ret2 );
|
||||||
return CouldNotDeletePassword;
|
return CouldNotDeleteEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,13 +19,13 @@ class Keychain::Private {
|
||||||
public:
|
public:
|
||||||
explicit Private( const QString& s ) : service( s ) {}
|
explicit Private( const QString& s ) : service( s ) {}
|
||||||
|
|
||||||
Keychain::Error writePasswordImpl( const QString& account,
|
Keychain::Error writeEntryImpl( const QString& account,
|
||||||
const QString& password,
|
const QByteArray& data,
|
||||||
Keychain::OverwriteMode,
|
Keychain::OverwriteMode,
|
||||||
QString* errorString );
|
QString* errorString );
|
||||||
Keychain::Error deletePasswordImpl( const QString& account,
|
Keychain::Error deleteEntryImpl( const QString& account,
|
||||||
QString* errorString );
|
QString* errorString );
|
||||||
Keychain::Error readPasswordImpl( QString* password,
|
Keychain::Error readEntryImpl( QByteArray* password,
|
||||||
const QString& account,
|
const QString& account,
|
||||||
QString* errorString );
|
QString* errorString );
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ int main( int argc, char** argv ) {
|
||||||
if ( ++it != args.constEnd() )
|
if ( ++it != args.constEnd() )
|
||||||
return printUsage();
|
return printUsage();
|
||||||
Keychain k( QLatin1String("qtkeychain-testclient") );
|
Keychain k( QLatin1String("qtkeychain-testclient") );
|
||||||
k.deletePassword( acc );
|
k.deleteEntry( acc );
|
||||||
if ( k.error() ) {
|
if ( k.error() ) {
|
||||||
std::cerr << "Deleting password failed: " << qPrintable(k.errorString()) << std::endl;
|
std::cerr << "Deleting password failed: " << qPrintable(k.errorString()) << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
Loading…
Reference in New Issue