22 #include "qgssettings.h"
25 #include <QPushButton>
27 #include <QToolButton>
30 #include <QGlobalStatic>
32 QMutex QgsCredentialDialog::sIgnoredConnectionsCacheMutex;
39 static QString invalidStyle_(
const QString &selector = QStringLiteral(
"QLineEdit" ) )
41 return QStringLiteral(
"%1{color: rgb(200, 0, 0);}" ).arg( selector );
45 : QDialog( parent, fl )
49 connect( leMasterPass, &QgsPasswordLineEdit::textChanged,
this, &QgsCredentialDialog::leMasterPass_textChanged );
50 connect( leMasterPassVerify, &QgsPasswordLineEdit::textChanged,
this, &QgsCredentialDialog::leMasterPassVerify_textChanged );
51 connect( chkbxEraseAuthDb, &QCheckBox::toggled,
this, &QgsCredentialDialog::chkbxEraseAuthDb_toggled );
54 this, &QgsCredentialDialog::requestCredentials,
55 Qt::BlockingQueuedConnection );
57 this, &QgsCredentialDialog::requestCredentialsMasterPassword,
58 Qt::BlockingQueuedConnection );
61 mIgnoreButton->setToolTip( tr(
"All requests for this connection will be automatically rejected" ) );
62 QMenu *menu =
new QMenu( mIgnoreButton );
63 QAction *ignoreTemporarily =
new QAction( tr(
"Ignore for 10 Seconds" ), menu );
64 ignoreTemporarily->setToolTip( tr(
"All requests for this connection will be automatically rejected for 10 seconds" ) );
65 QAction *ignoreForSession =
new QAction( tr(
"Ignore for Session" ), menu );
66 ignoreForSession->setToolTip( tr(
"All requests for this connection will be automatically rejected for the duration of the current session" ) );
67 menu->addAction( ignoreTemporarily );
68 menu->addAction( ignoreForSession );
69 connect( ignoreTemporarily, &QAction::triggered,
this, [ = ]
71 mIgnoreMode = IgnoreTemporarily;
72 mIgnoreButton->setText( ignoreTemporarily->text() );
73 mIgnoreButton->setToolTip( ignoreTemporarily->toolTip() );
75 connect( ignoreForSession, &QAction::triggered,
this, [ = ]
77 mIgnoreMode = IgnoreForSession;
78 mIgnoreButton->setText( ignoreForSession->text() );
79 mIgnoreButton->setToolTip( ignoreForSession->toolTip() );
81 mIgnoreButton->setText( mIgnoreMode == IgnoreTemporarily ? ignoreTemporarily->text() : ignoreForSession->text() );
82 mIgnoreButton->setToolTip( mIgnoreMode == IgnoreTemporarily ? ignoreTemporarily->toolTip() : ignoreForSession->toolTip() );
83 mIgnoreButton->setMenu( menu );
84 mIgnoreButton->setMaximumHeight( mOkButton->sizeHint().height() );
87 connect( mOkButton, &QPushButton::clicked,
this, &QgsCredentialDialog::accept );
88 connect( mCancelButton, &QPushButton::clicked,
this, &QgsCredentialDialog::reject );
91 connect( mIgnoreButton, &QPushButton::clicked,
this, [ = ](
bool )
93 const QString realm { labelRealm->text() };
95 QMutexLocker locker( &sIgnoredConnectionsCacheMutex );
97 sIgnoredConnectionsCache->insert( realm );
99 if ( mIgnoreMode == IgnoreTemporarily )
101 QTimer::singleShot( 10000,
nullptr, [ = ]()
103 QgsDebugMsgLevel( QStringLiteral(
"Removing ignored connection from cache: %1" ).arg( realm ), 4 );
104 QMutexLocker locker( &sIgnoredConnectionsCacheMutex );
105 sIgnoredConnectionsCache->remove( realm );
111 leMasterPass->setPlaceholderText( tr(
"Required" ) );
112 chkbxPasswordHelperEnable->setText( tr(
"Store/update the master password in your %1" )
114 leUsername->setFocus();
120 if ( qApp->thread() != QThread::currentThread() )
122 QgsDebugMsg( QStringLiteral(
"emitting signal" ) );
124 QgsDebugMsg( QStringLiteral(
"signal returned %1 (username=%2)" ).arg( ok ?
"true" :
"false", username ) );
128 requestCredentials( realm, &username, &password, message, &ok );
133 void QgsCredentialDialog::requestCredentials(
const QString &realm, QString *username, QString *password,
const QString &message,
bool *ok )
135 Q_ASSERT( qApp->thread() == thread() && thread() == QThread::currentThread() );
138 QMutexLocker locker( &sIgnoredConnectionsCacheMutex );
139 if ( sIgnoredConnectionsCache->contains( realm ) )
141 QgsDebugMsg( QStringLiteral(
"Skipping ignored connection: " ) + realm );
146 stackedWidget->setCurrentIndex( 0 );
147 mIgnoreButton->show();
149 labelRealm->setText( realm );
150 leUsername->setText( *username );
151 lePassword->setText( *password );
152 labelMessage->setText( message );
153 labelMessage->setHidden( message.isEmpty() );
155 if ( leUsername->text().isEmpty() )
156 leUsername->setFocus();
158 lePassword->setFocus();
160 QWidget *activeWindow = qApp->activeWindow();
162 QApplication::setOverrideCursor( Qt::ArrowCursor );
165 *ok = exec() == QDialog::Accepted;
166 QgsDebugMsgLevel( QStringLiteral(
"exec(): %1" ).arg( *ok ?
"true" :
"false" ), 4 );
168 QApplication::restoreOverrideCursor();
171 activeWindow->raise();
175 *username = leUsername->text();
176 *password = lePassword->text();
183 if ( qApp->thread() != QThread::currentThread() )
190 requestCredentialsMasterPassword( &password, stored, &ok );
195 void QgsCredentialDialog::requestCredentialsMasterPassword( QString *password,
bool stored,
bool *ok )
198 stackedWidget->setCurrentIndex( 1 );
200 mIgnoreButton->hide();
201 leMasterPass->setFocus();
203 QString titletxt( stored ? tr(
"Enter CURRENT master authentication password" ) : tr(
"Set NEW master authentication password" ) );
204 lblPasswordTitle->setText( titletxt );
208 leMasterPassVerify->setVisible( !stored );
209 lblDontForget->setVisible( !stored );
211 QApplication::setOverrideCursor( Qt::ArrowCursor );
213 grpbxPassAttempts->setVisible(
false );
217 mOkButton->setEnabled(
false );
219 if ( passfailed >= 3 )
221 lblSavedForSession->setVisible(
false );
222 grpbxPassAttempts->setTitle( tr(
"Password attempts: %1" ).arg( passfailed ) );
223 grpbxPassAttempts->setVisible(
true );
227 QSize s = sizeHint();
228 s.setWidth( width() );
232 *ok = exec() == QDialog::Accepted;
233 QgsDebugMsgLevel( QStringLiteral(
"exec(): %1" ).arg( *ok ?
"true" :
"false" ), 4 );
237 bool passok = !leMasterPass->text().isEmpty();
238 if ( passok && stored && !chkbxEraseAuthDb->isChecked() )
243 if ( passok && !stored )
245 passok = ( leMasterPass->text() == leMasterPassVerify->text() );
248 if ( passok || chkbxEraseAuthDb->isChecked() )
250 if ( stored && chkbxEraseAuthDb->isChecked() )
256 *password = leMasterPass->text();
270 leMasterPass->setStyleSheet( invalidStyle_() );
271 if ( leMasterPassVerify->isVisible() )
273 leMasterPassVerify->setStyleSheet( invalidStyle_() );
282 if ( passfailed >= 5 )
289 leMasterPass->clear();
290 leMasterPassVerify->clear();
292 chkbxEraseAuthDb->setChecked(
false );
293 lblSavedForSession->setVisible(
true );
297 mOkButton->setEnabled(
true );
299 QApplication::restoreOverrideCursor();
301 if ( passfailed >= 5 )
307 void QgsCredentialDialog::leMasterPass_textChanged(
const QString &pass )
309 leMasterPass->setStyleSheet( QString() );
310 bool passok = !pass.isEmpty();
311 if ( leMasterPassVerify->isVisible() )
313 leMasterPassVerify->setStyleSheet( QString() );
314 passok = passok && ( leMasterPass->text() == leMasterPassVerify->text() );
316 mOkButton->setEnabled( passok );
318 if ( leMasterPassVerify->isVisible() && !passok )
320 leMasterPass->setStyleSheet( invalidStyle_() );
321 leMasterPassVerify->setStyleSheet( invalidStyle_() );
325 void QgsCredentialDialog::leMasterPassVerify_textChanged(
const QString &pass )
327 if ( leMasterPassVerify->isVisible() )
329 leMasterPass->setStyleSheet( QString() );
330 leMasterPassVerify->setStyleSheet( QString() );
333 bool passok = !pass.isEmpty() && ( leMasterPass->text() == leMasterPassVerify->text() );
334 mOkButton->setEnabled( passok );
337 leMasterPass->setStyleSheet( invalidStyle_() );
338 leMasterPassVerify->setStyleSheet( invalidStyle_() );
343 void QgsCredentialDialog::chkbxEraseAuthDb_toggled(
bool checked )
346 mOkButton->setEnabled(
true );
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
bool verifyMasterPassword(const QString &compare=QString())
Verify the supplied master password against any existing hash in authentication database.
void setPasswordHelperEnabled(bool enabled)
Password helper enabled setter.
void setScheduledAuthDatabaseErase(bool scheduleErase)
Schedule an optional erase of authentication database, starting when mutex is lockable.
bool passwordHelperEnabled() const
Password helper enabled getter.
static const QString AUTH_PASSWORD_HELPER_DISPLAY_NAME
The display name of the password helper (platform dependent)
QgsCredentialDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
QgsCredentialDialog constructor.
bool requestMasterPassword(QString &password, bool stored=false) override
request a master password
bool request(const QString &realm, QString &username, QString &password, const QString &message=QString()) override
request a password
void credentialsRequested(const QString &, QString *, QString *, const QString &, bool *)
void credentialsRequestedMasterPassword(QString *, bool, bool *)
void setInstance(QgsCredentials *instance)
register instance
Q_GLOBAL_STATIC(IgnoredConnectionsSet, sIgnoredConnectionsCache)
Temporary cache for ignored connections, to avoid GUI freezing by multiple credentials requests to th...
QSet< QString > IgnoredConnectionsSet
#define QgsDebugMsgLevel(str, level)