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:
commit
789858a4d9
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user