Merge branch 'secret-service-check'

Check if secret service can be used under Unix.

See https://github.com/wxWidgets/wxWidgets/pull/1733
This commit is contained in:
Vadim Zeitlin 2020-02-11 22:36:03 +01:00
commit 789858a4d9
6 changed files with 124 additions and 13 deletions

View File

@ -78,6 +78,8 @@ private:
class wxSecretStoreImpl : public wxRefCounter
{
public:
virtual bool IsOk(wxString* WXUNUSED(errmsg)) const { return true; }
virtual bool Save(const wxString& service,
const wxString& username,
const wxSecretValueImpl& password,

View File

@ -126,8 +126,9 @@ public:
~wxSecretStore();
// Check if this object is valid.
bool IsOk() const { return m_impl != NULL; }
// Check if this object is valid, i.e. can be used, and optionally fill in
// the provided error message string if it isn't.
bool IsOk(wxString* errmsg = NULL) const;
// Store a username/password combination.

View File

@ -166,14 +166,16 @@ public:
Example of storing credentials using this class:
@code
wxSecretStore store = wxSecretStore::GetDefault();
if ( store.IsOk() )
wxString errmsg;
if ( store.IsOk(&errmsg) )
{
if ( !store.Save("MyApp/MyService", username, password) )
wxLogWarning("Failed to save credentials to the system secret store.");
}
else
{
wxLogWarning("This system doesn't support storing passwords securely.");
wxLogWarning("This system doesn't support storing passwords securely "
"(%s).", errmsg);
}
@endcode
@ -201,13 +203,20 @@ public:
Returns the default secrets collection to use.
Call IsOk() on the returned object to check if this method succeeded.
Note that this method may show a dialog to the user under some
platforms, so it can take an arbitrarily long time to return.
*/
static wxSecretStore GetDefault();
/**
Check if this object is valid.
Check if this object can actually be used.
@param errmsg If not @NULL, this parameter is filled with a
user-readable error message explaining why the secret store can't
be used (this argument is new since wxWidgets 3.1.4)
*/
bool IsOk() const;
bool IsOk(wxString* errmsg = NULL) const;
/**
Store a username/password combination.

View File

@ -196,9 +196,11 @@ int main(int argc, char **argv)
}
wxSecretStore store = wxSecretStore::GetDefault();
if ( !store.IsOk() )
wxString errmsg;
if ( !store.IsOk(&errmsg) )
{
wxFprintf(stderr, "Failed to create default secret store.\n");
wxFprintf(stderr, "Failed to create default secret store (%s)\n",
errmsg);
return EXIT_FAILURE;
}

View File

@ -162,6 +162,19 @@ wxSecretStore::~wxSecretStore()
// Methods forwarded to wxSecretStoreImpl
// ----------------------------------------------------------------------------
bool
wxSecretStore::IsOk(wxString* errmsg) const
{
if ( !m_impl )
{
if ( errmsg )
*errmsg = _("Not available for this platform");
return false;
}
return m_impl->IsOk(errmsg);
}
bool
wxSecretStore::Save(const wxString& service,
const wxString& user,

View File

@ -119,6 +119,52 @@ private:
SecretValue* const m_value;
};
// Dummy implementation used when secret service is not available.
class wxSecretStoreNotAvailableImpl : public wxSecretStoreImpl
{
public:
explicit wxSecretStoreNotAvailableImpl(const wxString& error)
: m_error(error)
{
}
virtual bool IsOk(wxString* errmsg) const wxOVERRIDE
{
if ( errmsg )
*errmsg = m_error;
return false;
}
virtual bool Save(const wxString& WXUNUSED(service),
const wxString& WXUNUSED(user),
const wxSecretValueImpl& WXUNUSED(secret),
wxString& errmsg) wxOVERRIDE
{
errmsg = m_error;
return false;
}
virtual bool Load(const wxString& WXUNUSED(service),
wxString* WXUNUSED(user),
wxSecretValueImpl** WXUNUSED(secret),
wxString& errmsg) const wxOVERRIDE
{
errmsg = m_error;
return false;
}
virtual bool Delete(const wxString& WXUNUSED(service),
wxString& errmsg) wxOVERRIDE
{
errmsg = m_error;
return false;
}
private:
const wxString m_error;
};
// This implementation uses synchronous libsecret functions which is supposed
// to be a bad idea, but doesn't seem to be a big deal in practice and as there
// is no simple way to implement asynchronous API under the other platforms, it
@ -127,6 +173,25 @@ private:
class wxSecretStoreLibSecretImpl : public wxSecretStoreImpl
{
public:
static wxSecretStoreLibSecretImpl* Create(wxString& errmsg)
{
wxGtkError error;
SecretService* const service = secret_service_get_sync
(
SECRET_SERVICE_OPEN_SESSION,
NULL, // No cancellation
error.Out()
);
if ( !service )
{
errmsg = error.GetMessage();
return NULL;
}
// This passes ownership of service to the new object.
return new wxSecretStoreLibSecretImpl(service);
}
virtual bool Save(const wxString& service,
const wxString& user,
const wxSecretValueImpl& secret,
@ -142,7 +207,7 @@ public:
wxGtkError error;
if ( !secret_service_store_sync
(
NULL, // Default service
m_service,
GetSchema(),
BuildAttributes(service, user),
SECRET_COLLECTION_DEFAULT,
@ -167,7 +232,7 @@ public:
wxGtkError error;
GList* const found = secret_service_search_sync
(
NULL, // Default service
m_service,
GetSchema(),
BuildAttributes(service),
static_cast<SecretSearchFlags>
@ -209,8 +274,9 @@ public:
wxString& errmsg) wxOVERRIDE
{
wxGtkError error;
if ( !secret_password_clearv_sync
if ( !secret_service_clear_sync
(
m_service,
GetSchema(),
BuildAttributes(service),
NULL, // Can't be cancelled
@ -278,6 +344,15 @@ private:
NULL
));
}
// Ctor is private, Create() should be used for creating objects of this
// class.
explicit wxSecretStoreLibSecretImpl(SecretService* service)
: m_service(service)
{
}
wxGtkObject<SecretService> m_service;
};
const char* wxSecretStoreLibSecretImpl::FIELD_SERVICE = "service";
@ -298,8 +373,17 @@ wxSecretValueImpl* wxSecretValue::NewImpl(size_t size, const void *data)
/* static */
wxSecretStore wxSecretStore::GetDefault()
{
// There is only a single store under Windows anyhow.
return wxSecretStore(new wxSecretStoreLibSecretImpl());
// Try to create the real implementation.
wxString errmsg;
wxSecretStoreImpl* impl = wxSecretStoreLibSecretImpl::Create(errmsg);
if ( !impl )
{
// But if we failed, fall back to a dummy one, so that we could at
// least return the error to the code using this class.
impl = new wxSecretStoreNotAvailableImpl(errmsg);
}
return wxSecretStore(impl);
}
#endif // wxUSE_SECRETSTORE