Page MenuHome GnuPG

No OneTemporary

diff --git a/NEWS b/NEWS
index 2511eff..6e01cc4 100644
--- a/NEWS
+++ b/NEWS
@@ -1,500 +1,502 @@
Noteworthy changes in version 1.3.2 (unreleased)
------------------------------------------------
* qt: Use light icons in dark mode. [T7230]
+ * qt: Make showing/hiding the password accessible. [T7736]
+
Noteworthy changes in version 1.3.1 (2024-07-03)
------------------------------------------------
* qt: Install and use pinentry icon. [rPf9c252a8d9]
* qt: Small fix for Qt5. [rP844360c9c9]
* qt: Fix Windows build of Qt6. [rP34019f954a]
* New envvar PINENTRY_KDE_USE_WALLET to enable the secret storage
integration on KDE. [rP23753cfb03]
Release-info: https://dev.gnupg.org/T7046
Noteworthy changes in version 1.3.0 (2024-03-18)
------------------------------------------------
* qt: Add new Qt6 frontend. [rP1e79123c38]
* qt: Set parent window on Wayland. [T6930]
* qt: Fix capslock detection on Wayland. [rP7dfc60a70d]
* qt: Fix window icon on Wayland. [T6887]
* qt: Add support for external password manager with libsecret.
[T6801]
* qt: Remove focus indication by text selection. [T5863]
* qt: Use same focus indication for labels as Kleopatra. [T5863]
* qt: Improve accessibility. [T5863]
* gnome3: Prefer gcr-4. [rP069c219223]
* curses: Fix timeout handling. [rP08408498b3]
* curses: Add SETREPEATOK and quality bar colors. [rP2f109972e4]
* curses: Add password quality meter. [rP2923707e75]
* curses,tty: Upon SIGINT, let pinentry exit gracefully. [T6641]
* w32: Fix non-focused window and simplify code. [rPabbecc67d9]
* Disable secret storage integration when running on KDE Plasma.
[rPefb6de7f]
* The Windows CE support has been removed.
Release-info: https://dev.gnupg.org/T7046
Noteworthy changes in version 1.2.1 (2022-08-24)
------------------------------------------------
* qt: Support building with Qt 5.9. [T5592]
* curses: Handle an error at curses initialization. [T5623]
* curses: Specify fg/bg when an extention of Ncurses is not available.
[T5631]
* qt: Fix translation of context menu entries. [T5786]
* qt: Further improve the accessibility. [T5863]
* qt: Fix moving focus to second input field when pressing Enter in
first input field. [T5866]
* qt: Update the cursor position when reformatting the text. [T5972]
* qt: Use foreground raising code also with the confirm prompt.
[T6134]
* Make the legacy qt4 version build again. [T5569]
* Make sure an entered PIN is always cleared from memory. [T5977]
* Build fixes for Windows. [T5893]
Noteworthy changes in version 1.2.0 (2021-08-25)
------------------------------------------------
* qt: Show a warning if Caps Lock is on on Windows, X11 (requires
libX11 and Qt5X11Extras), and Wayland (requires KF5WaylandClient).
[T4950]
* qt: Support password formatting. This makes generated passwords
easier to transcript. [T5517]
* qt: Fix showing of pinentry window on Wayland. [T5528]
* qt: Check passphrase constraints before accepting passphrase if
passphrase constraints are requested to be enforced. [T5532]
* qt: Improve detection of running in a GUI session. [T3659]
* qt: Improve accessibility when entering new password. [T5543]
Release-info: https://dev.gnupg.org/T5566
Noteworthy changes in version 1.1.1 (2021-01-21)
------------------------------------------------
* A EFL-based pinentry has been contributed.
* Disable echoing in backspace key is pressed first
(GTK, Qt, TQt, and ncurses pinentries).
* Support line editing in TTY pinentry.
* Remove support for old GTK+2 (< 2.12.0).
* Various minor fixes.
Noteworthy changes in version 1.1.0 (2017-12-03)
------------------------------------------------
* A FLTK1.3-based pinentry has been contributed.
* A TQt3-based pinentry has been contributed.
* New option --ttyalert for pinentry-curses to alert the user.
* Don't show "save passphrase" checkbox if secret service is
unavailable.
* The GTK Pinentry shows on Linux some information anout the process
which invoked the Pinentry.
* The GTK Pinentry does not anymore show tooltips when keyboard
grabbing is enabled.
* Fixed various minor problems.
Noteworthy changes in version 1.0.0 (2016-11-22)
------------------------------------------------
* Qt pinentry now supports repeat mode in one dialog.
* Qt and GTK pinentries now make it possible to show the entered
value.
* Qt pinentry now only grabs the keyboard if an entry field is
focused.
* Fixed foreground handling in pinentry-qt if compiled with Qt5 for
Windows.
* Fixed potential crash in Qt qualitybar calculation.
* GTK keyboard grabbing is now a bit more robust. The cursor is
changed to a big dot as a visual indication that a pinentry has
popped up and is waiting for input.
* The GNOME pinentry now falls back to curses if it can't use the
GCR system prompter or a screenlock is active.
* Fixed error output for cached passwords.
* A show/hide passphrase button or checkbox is now available with
some pinentry flavors.
* Improved diagnostics and error codes.
Noteworthy changes in version 0.9.7 (2015-12-07)
------------------------------------------------
* Fix regressions in the Qt pinentry.
* Fix minor problems pinnetyr-tty.
* New option --invisible-char.
Noteworthy changes in version 0.9.6 (2015-09-10)
------------------------------------------------
* Many improvements for the dump tty pinentry.
* Use the standard GTK+-2 text entry widget instead of our outdated
and back-then-it-was-more-secure text widget.
* Use the standard Qt text widget.
* Allow for building a static Qt variant.
* Fix regression in w32 pinentry.
Noteworthy changes in version 0.9.5 (2015-07-01)
------------------------------------------------
* Replaced the internal Assuan and gpg-error code by the standard
libassuan and libgpg-error libraries.
* Add a new Emacs pinentry and use as fallback for GUI programs.
* gnome3: The use-password-manager checkbox does now work.
* Gtk: Improved fallback to curses feature.
* curses: Recognize DEL as backspace.
Noteworthy changes in version 0.9.4 (2015-06-05)
------------------------------------------------
* Fix regression in GTK+ and curses pinentries.
Noteworthy changes in version 0.9.3 (2015-06-01)
------------------------------------------------
* Improved documentation
* New pinentry-gnome3
* More improvements for pinentry-tty.
* Fixes for pinentry-curses including support for Ctrl-W, Ctrl-U,
Ctrl-H, Ctrl-L, and Alt-Backspace
* New Assuan command to request clearing an external cache.
* Fixed problems linking to ncursesw.
* All kind of other minor fixes.
Noteworthy changes in version 0.9.2 (2015-05-11)
------------------------------------------------
* Support for saving the passphrase with libsecret.
* Escape key works in the Gtk+ pinentry.
* Improvements for pinentry-tty.
* Minor cleanups for the native Windows pinentry.
Noteworthy changes in version 0.9.1 (2015-03-18)
------------------------------------------------
* Fixed build problems for systems without ncurses.
* Reworked the option parser to allow building on systems without
getopt_long.
* Fixed Qt4 build problems.
Noteworthy changes in version 0.9.0 (2014-10-26)
------------------------------------------------
* New command SETREPEAT. Currently only supported for Gtk+-2.
* Gtk+-2: Pasting using the mouse is now supported.
* curses: Check that it is actually connected to a tty.
* Removed the old qt-3 and gtk+-1 pinentries.
Noteworthy changes in version 0.8.4 (2014-09-18)
------------------------------------------------
* New pinentry-tty version for dumb terminals.
* Qt4: New option to enable pasting the passphrase from clipboard
* Qt4: Improved accessiblity
* Qt4: Raise confirm message windows into foreground
* Qt4 (Windows): Improve the way pinentry-qt raises itself in the
foreground.
* Improved the build system.
Noteworthy changes in version 0.8.3 (2013-04-26)
------------------------------------------------
* Build fixes for newer mingw32 toolchains.
* Add SETTIMEOUT command for the gtk+-2 pinentry.
Noteworthy changes in version 0.8.2 (2012-08-08)
------------------------------------------------
* New SETTIMEOUT command for the qt4 pinentry.
* Wide character support for the curses pinentry.
* Various bug fixes.
Noteworthy changes in version 0.8.1 (2010-12-16)
------------------------------------------------
* The W32 pinentry now supports WindowsCE.
* The GTK pinentry now always sticks to the top and properly grabs
the keyboard.
* The protocol options default-cancel and default-ok now work for the
pinentry-gtk2 and pinentry-qt (that is QT3).
Noteworthy changes in version 0.8.0 (2010-03-03)
------------------------------------------------
* Beautified the qt4 pinentry
* Minor enhancements.
Noteworthy changes in version 0.7.6 (2009-06-19)
------------------------------------------------
* Make Gtk+-2 pinentry transient to the root window.
* Add Qt4 pinentry.
* Add native W32 pinentry.
* Fix utf-8 problem in Qt pinentries.
* Return GPG_ERR_CANCELED if during a "CONFIRM" command the user
closed the window.
* Add quality bar.
Noteworthy changes in version 0.7.5 (2008-02-15)
------------------------------------------------
* Fix cross compilation for Gtk+-2 pinentry.
* New Assuan command GETINFO with subcommands "version" and "pid".
Noteworthy changes in version 0.7.4 (2007-11-29)
------------------------------------------------
* Pinentry-gtk-2 and pinentry-qt now support a simple passphrase
quality indicator.
Noteworthy changes in version 0.7.3 (2007-07-06)
------------------------------------------------
* New command MESSAGE and --one-button compatibility option to
CONFIRM.
* New Assuan option touch-file to set a file which will be touched
after ncurses does not need the display anymore.
* New option --colors=FG,BG,SO to set the colors for the curses
pinentry.
* Pinentry-w32 does now basically work. It needs some finishing
though. For example the buttons should resize themself according
to the size of the text.
Noteworthy changes in version 0.7.2 (2005-01-27)
------------------------------------------------
* Remove bug in configure script that would use installed version of
Qt even if another path was explicitely specified with QTDIR.
* Honor the rpath setting for Qt.
* Add GTK+-2 pinentry.
* Install a symbolic link under the name "pinentry" that defaults to
pinentry-gtk, pinentry-qt, pinentry-gtk-2, or pinentry-curses, in
that order.
Noteworthy changes in version 0.7.1 (2004-04-21)
------------------------------------------------
* Removed unneeded Assuan cruft.
* Fixes for *BSD.
Noteworthy changes in version 0.7.0 (2003-12-23)
------------------------------------------------
* Make UTF8 description (prompt, error message, button texts) work.
* Make sure that secmem_term is called before program termination.
* Make assuan in Gtk and Curses pinentry use secure memory for
storage.
* Fixed a bug that would occur if a canceled GETPIN was immediately
followed by a CONFIRM.
* Disabled undo/redo in Qt pinentry.
* Print diagnostics for locale problems and return a new error code
in that case.
Noteworthy changes in version 0.6.8 (2003-02-07)
------------------------------------------------
* Bug fix in pinentry-qt.
Noteworthy changes in version 0.6.7 (2002-11-20)
------------------------------------------------
* Workaround for a bug in the curses version which led to an infinite
loop.
Noteworthy changes in version 0.6.6 (2002-11-09)
------------------------------------------------
* Fixed handling of DISPLAY and --display for the sake of the curses
fallback.
* UTF-8 conversion does now work for the GTK+ and CURSES version.
Noteworthy changes in version 0.6.5 (2002-09-30)
------------------------------------------------
* Handle Assuan options in the qt version.
Noteworthy changes in version 0.6.4 (2002-08-19)
------------------------------------------------
* Handle CONFIRM command in the qt version.
Noteworthy changes in version 0.6.3 (2002-06-26)
------------------------------------------------
* Minor bug fixes to the qt version.
Noteworthy changes in version 0.6.2 (2002-05-13)
------------------------------------------------
* Error texts can now be percent-escaped.
* The Curses pinentry supports multi-line error texts.
* The GTK+ and Qt pinentry can fall back to curses if no display is
available.
Noteworthy changes in version 0.6.1 (2002-04-25)
------------------------------------------------
* The Curses pinentry supports user-provided button texts via the
new SETOK and SETCANCEL commands.
* The Curses pinentry supports setting the desired character set
locale with --lc-ctype and correctly translates the UTF-8 strings
into that.
Noteworthy changes in version 0.6.0 (2002-04-05)
------------------------------------------------
* Merged all pinentry frontends into a single module.
* There is now a Curses frontend.
* The curses pinentry supports --ttyname and --ttytype options to
set the desired input/output terminal and its type.
Noteworthy changes in version 0.5.1 (2002-02-18)
------------------------------------------------
* CONFIRM command works
Noteworthy changes in version 0.5.0 (2002-01-04)
------------------------------------------------
* Window layout is somewhat nicer
* percent escape sequences do now work for SETDESC and SETERROR
diff --git a/qt/pinentrydialog.cpp b/qt/pinentrydialog.cpp
index 078fa3e..49c7dd6 100644
--- a/qt/pinentrydialog.cpp
+++ b/qt/pinentrydialog.cpp
@@ -1,780 +1,768 @@
/* pinentrydialog.cpp - A (not yet) secure Qt 4 dialog for PIN entry.
* Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB)
* Copyright 2007 Ingo Klöcker
* Copyright 2016 Intevation GmbH
* Copyright (C) 2021, 2022 g10 Code GmbH
*
* Written by Steffen Hansen <steffen@klaralvdalens-datakonsult.se>.
* Modified by Andre Heinecke <aheinecke@intevation.de>
* Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* 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. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-2.0+
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "pinentrydialog.h"
#include "accessibility.h"
#include "capslock.h"
#include "pinlineedit.h"
#include "util.h"
#include <QGridLayout>
#include <QProgressBar>
#include <QApplication>
#include <QFontMetrics>
#include <QStyle>
#include <QStyleHints>
#include <QPainter>
#include <QPushButton>
#include <QDialogButtonBox>
#include <QKeyEvent>
#include <QLabel>
#include <QPalette>
#include <QLineEdit>
#include <QAction>
#include <QCheckBox>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QMessageBox>
#include <QRegularExpression>
#include <QAccessible>
#include <QDebug>
#ifdef Q_OS_WIN
#include <windows.h>
#endif
void raiseWindow(QWidget *w)
{
w->setWindowState((w->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
w->activateWindow();
w->raise();
}
QPixmap applicationIconPixmap(const QIcon &overlayIcon)
{
QPixmap pm = qApp->windowIcon().pixmap(48, 48);
if (!overlayIcon.isNull()) {
QPainter painter(&pm);
const int emblemSize = 22;
painter.drawPixmap(pm.width() - emblemSize, 0,
overlayIcon.pixmap(emblemSize, emblemSize));
}
return pm;
}
void PinEntryDialog::slotTimeout()
{
_timed_out = true;
reject();
}
PinEntryDialog::PinEntryDialog(pinentry_t pe, QWidget *parent, const char *name,
bool modal,
const QString &repeatString,
const QString &visibilityTT,
const QString &hideTT)
: QDialog{parent}
, _have_quality_bar{!!pe->quality_bar}
, _pinentry_info{pe}
, mVisibilityTT{visibilityTT}
, mHideTT{hideTT}
{
Q_UNUSED(name)
if (modal) {
setWindowModality(Qt::ApplicationModal);
}
/* Check for dark scheme to determine the icons */
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
QStyleHints *styleHints = qApp->styleHints();
if (styleHints && styleHints->colorScheme() == Qt::ColorScheme::Dark) {
mIconSuffix = QStringLiteral("_dark");
}
#endif
QPalette redTextPalette;
redTextPalette.setColor(QPalette::WindowText, Qt::red);
+ const QIcon visibilityIcon = QIcon(QLatin1String(":/icons/visibility") + mIconSuffix);
+ const QIcon hideIcon = QIcon(QLatin1String(":/icons/hint") + mIconSuffix);
auto *const mainLayout = new QVBoxLayout{this};
auto *const hbox = new QHBoxLayout;
_icon = new QLabel(this);
_icon->setPixmap(applicationIconPixmap());
hbox->addWidget(_icon, 0, Qt::AlignVCenter | Qt::AlignLeft);
auto *const grid = new QGridLayout;
int row = 1;
_error = new QLabel{this};
_error->setTextFormat(Qt::PlainText);
_error->setTextInteractionFlags(Qt::TextSelectableByMouse);
_error->setPalette(redTextPalette);
_error->hide();
grid->addWidget(_error, row, 1, 1, 2);
row++;
_desc = new QLabel{this};
_desc->setTextFormat(Qt::PlainText);
_desc->setTextInteractionFlags(Qt::TextSelectableByMouse);
_desc->hide();
grid->addWidget(_desc, row, 1, 1, 2);
row++;
mCapsLockHint = new QLabel{this};
mCapsLockHint->setTextFormat(Qt::PlainText);
mCapsLockHint->setTextInteractionFlags(Qt::TextSelectableByMouse);
mCapsLockHint->setPalette(redTextPalette);
mCapsLockHint->setAlignment(Qt::AlignCenter);
mCapsLockHint->setVisible(false);
grid->addWidget(mCapsLockHint, row, 1, 1, 2);
row++;
{
_prompt = new QLabel(this);
_prompt->setTextFormat(Qt::PlainText);
_prompt->setTextInteractionFlags(Qt::TextSelectableByMouse);
_prompt->hide();
grid->addWidget(_prompt, row, 1);
const auto l = new QHBoxLayout;
_edit = new PinLineEdit(this);
_edit->setMaxLength(256);
_edit->setMinimumWidth(_edit->fontMetrics().averageCharWidth()*20 + 48);
_edit->setEchoMode(QLineEdit::Password);
_prompt->setBuddy(_edit);
l->addWidget(_edit, 1);
- if (!repeatString.isNull()) {
- mGenerateButton = new QPushButton{this};
- mGenerateButton->setIcon(QIcon(QLatin1String(":/icons/password-generate") + mIconSuffix));
- mGenerateButton->setVisible(false);
- l->addWidget(mGenerateButton);
+ if (!visibilityIcon.isNull() && !hideIcon.isNull()) {
+ mShowHideButton = new QPushButton{this};
+ mShowHideButton->setIcon(visibilityIcon);
+ mShowHideButton->setToolTip(mVisibilityTT);
+ l->addWidget(mShowHideButton);
}
grid->addLayout(l, row, 2);
}
- /* Set up the show password action */
- const QIcon visibilityIcon = QIcon(QLatin1String(":/icons/visibility") + mIconSuffix);
- const QIcon hideIcon = QIcon(QLatin1String(":/icons/hint") + mIconSuffix);
-#if QT_VERSION >= 0x050200
- if (!visibilityIcon.isNull() && !hideIcon.isNull()) {
- mVisiActionEdit = _edit->addAction(visibilityIcon, QLineEdit::TrailingPosition);
- mVisiActionEdit->setVisible(false);
- mVisiActionEdit->setToolTip(mVisibilityTT);
- } else
-#endif
- {
- if (!mVisibilityTT.isNull()) {
- row++;
- mVisiCB = new QCheckBox{mVisibilityTT, this};
- grid->addWidget(mVisiCB, row, 1, 1, 2, Qt::AlignLeft);
- }
+ if (!mShowHideButton && !mVisibilityTT.isNull()) {
+ row++;
+ mVisiCB = new QCheckBox{mVisibilityTT, this};
+ grid->addWidget(mVisiCB, row, 1, 1, 2, Qt::AlignLeft);
}
row++;
mConstraintsHint = new QLabel{this};
mConstraintsHint->setTextFormat(Qt::PlainText);
mConstraintsHint->setTextInteractionFlags(Qt::TextSelectableByMouse);
mConstraintsHint->setVisible(false);
grid->addWidget(mConstraintsHint, row, 2);
row++;
mFormattedPassphraseHintSpacer = new QLabel{this};
mFormattedPassphraseHintSpacer->setVisible(false);
mFormattedPassphraseHint = new QLabel{this};
mFormattedPassphraseHint->setTextFormat(Qt::PlainText);
mFormattedPassphraseHint->setTextInteractionFlags(Qt::TextSelectableByMouse);
mFormattedPassphraseHint->setVisible(false);
grid->addWidget(mFormattedPassphraseHintSpacer, row, 1);
grid->addWidget(mFormattedPassphraseHint, row, 2);
if (!repeatString.isNull()) {
row++;
auto repeatLabel = new QLabel{this};
repeatLabel->setTextFormat(Qt::PlainText);
repeatLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
repeatLabel->setText(repeatString);
grid->addWidget(repeatLabel, row, 1);
+ const auto l = new QHBoxLayout;
mRepeat = new PinLineEdit(this);
mRepeat->setMaxLength(256);
mRepeat->setEchoMode(QLineEdit::Password);
repeatLabel->setBuddy(mRepeat);
- grid->addWidget(mRepeat, row, 2);
+ l->addWidget(mRepeat, 1);
+
+ if (!repeatString.isNull()) {
+ mGenerateButton = new QPushButton{this};
+ mGenerateButton->setIcon(QIcon(QLatin1String(":/icons/password-generate") + mIconSuffix));
+ mGenerateButton->setVisible(false);
+ l->addWidget(mGenerateButton);
+ }
+ grid->addLayout(l, row, 2);
row++;
mRepeatError = new QLabel{this};
mRepeatError->setTextFormat(Qt::PlainText);
mRepeatError->setTextInteractionFlags(Qt::TextSelectableByMouse);
mRepeatError->setPalette(redTextPalette);
mRepeatError->hide();
grid->addWidget(mRepeatError, row, 2);
}
if (_have_quality_bar) {
row++;
_quality_bar_label = new QLabel(this);
_quality_bar_label->setTextFormat(Qt::PlainText);
_quality_bar_label->setTextInteractionFlags(Qt::TextSelectableByMouse);
_quality_bar_label->setAlignment(Qt::AlignVCenter);
grid->addWidget(_quality_bar_label, row, 1);
_quality_bar = new QProgressBar(this);
_quality_bar->setAlignment(Qt::AlignCenter);
_quality_bar_label->setBuddy(_quality_bar);
grid->addWidget(_quality_bar, row, 2);
}
++row;
mSavePassphraseCB = new QCheckBox{this};
mSavePassphraseCB->setVisible(false);
mSavePassphraseCB->setCheckState(!!_pinentry_info->may_cache_password
? Qt::Checked
: Qt::Unchecked);
#ifdef HAVE_LIBSECRET
if (_pinentry_info->allow_external_password_cache && _pinentry_info->keyinfo) {
mSavePassphraseCB->setVisible(true);
}
#endif
grid->addWidget(mSavePassphraseCB, row, 1, 1, 2);
hbox->addLayout(grid, 1);
mainLayout->addLayout(hbox);
QDialogButtonBox *const buttons = new QDialogButtonBox(this);
buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
_ok = buttons->button(QDialogButtonBox::Ok);
_cancel = buttons->button(QDialogButtonBox::Cancel);
if (style()->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons)) {
_ok->setIcon(style()->standardIcon(QStyle::SP_DialogOkButton));
_cancel->setIcon(style()->standardIcon(QStyle::SP_DialogCancelButton));
}
mainLayout->addStretch(1);
mainLayout->addWidget(buttons);
mainLayout->setSizeConstraint(QLayout::SetFixedSize);
if (_pinentry_info->timeout > 0) {
_timer = new QTimer(this);
connect(_timer, &QTimer::timeout, this, &PinEntryDialog::slotTimeout);
_timer->start(_pinentry_info->timeout * 1000);
}
connect(buttons, &QDialogButtonBox::accepted,
this, &PinEntryDialog::onAccept);
connect(buttons, &QDialogButtonBox::rejected,
this, &QDialog::reject);
connect(_edit, &QLineEdit::textChanged,
this, &PinEntryDialog::updateQuality);
connect(_edit, &QLineEdit::textChanged,
this, &PinEntryDialog::textChanged);
connect(_edit, &PinLineEdit::backspacePressed,
this, &PinEntryDialog::onBackspace);
if (mGenerateButton) {
connect(mGenerateButton, &QPushButton::clicked,
this, &PinEntryDialog::generatePin);
}
- if (mVisiActionEdit) {
- connect(mVisiActionEdit, &QAction::triggered,
+ if (mShowHideButton) {
+ connect(mShowHideButton, &QPushButton::clicked,
this, &PinEntryDialog::toggleVisibility);
}
if (mVisiCB) {
connect(mVisiCB, &QCheckBox::toggled,
this, &PinEntryDialog::toggleVisibility);
}
if (mRepeat) {
connect(mRepeat, &QLineEdit::textChanged,
this, &PinEntryDialog::textChanged);
}
connect(mSavePassphraseCB, &QCheckBox::toggled,
this, &PinEntryDialog::togglePasswordCaching);
auto capsLockWatcher = new CapsLockWatcher{this};
connect(capsLockWatcher, &CapsLockWatcher::stateChanged,
this, [this] (bool locked) {
mCapsLockHint->setVisible(locked);
});
connect(qApp, &QApplication::focusChanged,
this, &PinEntryDialog::focusChanged);
connect(qApp, &QApplication::applicationStateChanged,
this, &PinEntryDialog::checkCapsLock);
checkCapsLock();
#ifndef QT_NO_ACCESSIBILITY
QAccessible::installActivationObserver(this);
accessibilityActiveChanged(QAccessible::isActive());
#endif
#if QT_VERSION >= 0x050000
/* This is mostly an issue on Windows where this results
in the pinentry popping up nicely with an animation and
comes to front. It is not ifdefed for Windows only since
window managers on Linux like KWin can also have this
result in an animation when the pinentry is shown and
not just popping it up.
*/
if (qApp->platformName() != QLatin1String("wayland")) {
setWindowState(Qt::WindowMinimized);
QTimer::singleShot(0, this, [this] () {
raiseWindow(this);
});
}
#else
activateWindow();
raise();
#endif
}
PinEntryDialog::~PinEntryDialog()
{
#ifndef QT_NO_ACCESSIBILITY
QAccessible::removeActivationObserver(this);
#endif
}
void PinEntryDialog::keyPressEvent(QKeyEvent *e)
{
const auto returnPressed =
(!e->modifiers() && (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return))
|| (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter);
if (returnPressed && _edit->hasFocus() && mRepeat) {
// if the user pressed Return in the first input field, then move the
// focus to the repeat input field and prevent further event processing
// by QDialog (which would trigger the default button)
mRepeat->setFocus();
e->ignore();
return;
}
QDialog::keyPressEvent(e);
}
void PinEntryDialog::keyReleaseEvent(QKeyEvent *event)
{
QDialog::keyReleaseEvent(event);
checkCapsLock();
}
void PinEntryDialog::showEvent(QShowEvent *event)
{
QDialog::showEvent(event);
_edit->setFocus();
}
void PinEntryDialog::setDescription(const QString &txt)
{
_desc->setVisible(!txt.isEmpty());
_desc->setText(txt);
_icon->setPixmap(applicationIconPixmap());
setError(QString());
}
QString PinEntryDialog::description() const
{
return _desc->text();
}
void PinEntryDialog::setError(const QString &txt)
{
if (!txt.isNull()) {
_icon->setPixmap(applicationIconPixmap(QIcon{QStringLiteral(":/icons/data-error.svg")}));
}
_error->setText(txt);
_error->setVisible(!txt.isEmpty());
}
QString PinEntryDialog::error() const
{
return _error->text();
}
void PinEntryDialog::setPin(const QString &txt)
{
_edit->setPin(txt);
}
QString PinEntryDialog::pin() const
{
return _edit->pin();
}
void PinEntryDialog::setPrompt(const QString &txt)
{
_prompt->setText(txt);
_prompt->setVisible(!txt.isEmpty());
if (txt.contains("PIN"))
_disable_echo_allowed = false;
}
QString PinEntryDialog::prompt() const
{
return _prompt->text();
}
void PinEntryDialog::setOkText(const QString &txt)
{
_ok->setText(txt);
_ok->setVisible(!txt.isEmpty());
}
void PinEntryDialog::setCancelText(const QString &txt)
{
_cancel->setText(txt);
_cancel->setVisible(!txt.isEmpty());
}
void PinEntryDialog::setQualityBar(const QString &txt)
{
if (_have_quality_bar) {
_quality_bar_label->setText(txt);
}
}
void PinEntryDialog::setQualityBarTT(const QString &txt)
{
if (_have_quality_bar) {
_quality_bar->setToolTip(txt);
}
}
void PinEntryDialog::setGenpinLabel(const QString &txt)
{
if (!mGenerateButton) {
return;
}
mGenerateButton->setVisible(!txt.isEmpty());
if (!txt.isEmpty()) {
Accessibility::setName(mGenerateButton, txt);
}
}
void PinEntryDialog::setGenpinTT(const QString &txt)
{
if (mGenerateButton) {
mGenerateButton->setToolTip(txt);
}
}
void PinEntryDialog::setCapsLockHint(const QString &txt)
{
mCapsLockHint->setText(txt);
}
void PinEntryDialog::setFormattedPassphrase(const PinEntryDialog::FormattedPassphraseOptions &options)
{
mFormatPassphrase = options.formatPassphrase;
mFormattedPassphraseHint->setTextFormat(Qt::RichText);
mFormattedPassphraseHint->setText(QLatin1String("<html>") + options.hint.toHtmlEscaped() + QLatin1String("</html>"));
Accessibility::setName(mFormattedPassphraseHint, options.hint);
toggleFormattedPassphrase();
}
void PinEntryDialog::setConstraintsOptions(const ConstraintsOptions &options)
{
mEnforceConstraints = options.enforce;
mConstraintsHint->setText(options.shortHint);
if (!options.longHint.isEmpty()) {
mConstraintsHint->setToolTip(QLatin1String("<html>") +
options.longHint.toHtmlEscaped().replace(QLatin1String("\n\n"), QLatin1String("<br>")) +
QLatin1String("</html>"));
Accessibility::setDescription(mConstraintsHint, options.longHint);
}
mConstraintsErrorTitle = options.errorTitle;
mConstraintsHint->setVisible(mEnforceConstraints && !options.shortHint.isEmpty());
}
void PinEntryDialog::toggleFormattedPassphrase()
{
const bool enableFormatting = mFormatPassphrase && _edit->echoMode() == QLineEdit::Normal;
_edit->setFormattedPassphrase(enableFormatting);
if (mRepeat) {
mRepeat->setFormattedPassphrase(enableFormatting);
const bool hintAboutToBeHidden = mFormattedPassphraseHint->isVisible() && !enableFormatting;
if (hintAboutToBeHidden) {
// set hint spacer to current height of hint label before hiding the hint
mFormattedPassphraseHintSpacer->setMinimumHeight(mFormattedPassphraseHint->height());
mFormattedPassphraseHintSpacer->setVisible(true);
} else if (enableFormatting) {
mFormattedPassphraseHintSpacer->setVisible(false);
}
mFormattedPassphraseHint->setVisible(enableFormatting);
}
}
void PinEntryDialog::togglePasswordCaching(bool enabled)
{
_pinentry_info->may_cache_password = enabled;
}
void PinEntryDialog::onBackspace()
{
cancelTimeout();
if (_disable_echo_allowed) {
_edit->setEchoMode(QLineEdit::NoEcho);
if (mRepeat) {
mRepeat->setEchoMode(QLineEdit::NoEcho);
}
}
}
void PinEntryDialog::updateQuality(const QString &txt)
{
int length;
int percent;
QPalette pal;
_disable_echo_allowed = false;
if (!_have_quality_bar || !_pinentry_info) {
return;
}
const QByteArray utf8_pin = txt.toUtf8();
const char *pin = utf8_pin.constData();
length = strlen(pin);
percent = length ? pinentry_inq_quality(_pinentry_info, pin, length) : 0;
if (!length) {
_quality_bar->reset();
} else {
pal = _quality_bar->palette();
if (percent < 0) {
pal.setColor(QPalette::Highlight, QColor("red"));
percent = -percent;
} else {
pal.setColor(QPalette::Highlight, QColor("green"));
}
_quality_bar->setPalette(pal);
_quality_bar->setValue(percent);
}
}
void PinEntryDialog::setSavePassphraseCBText(const QString &text)
{
mSavePassphraseCB->setText(text);
}
void PinEntryDialog::focusChanged(QWidget *old, QWidget *now)
{
// Grab keyboard. It might be a little weird to do it here, but it works!
// Previously this code was in showEvent, but that did not work in Qt4.
if (!_pinentry_info || _pinentry_info->grab) {
if (_grabbed && old && (old == _edit || old == mRepeat)) {
old->releaseKeyboard();
_grabbed = false;
}
if (!_grabbed && now && (now == _edit || now == mRepeat)) {
now->grabKeyboard();
_grabbed = true;
}
}
}
void PinEntryDialog::textChanged(const QString &text)
{
Q_UNUSED(text);
cancelTimeout();
-
- if (mVisiActionEdit && sender() == _edit) {
- mVisiActionEdit->setVisible(!_edit->pin().isEmpty());
- }
- if (mGenerateButton) {
- mGenerateButton->setVisible(
- _edit->pin().isEmpty()
-#ifndef QT_NO_ACCESSIBILITY
- && !mGenerateButton->accessibleName().isEmpty()
-#endif
- );
- }
}
void PinEntryDialog::generatePin()
{
unique_malloced_ptr<char> pin{pinentry_inq_genpin(_pinentry_info)};
if (pin) {
if (_edit->echoMode() == QLineEdit::Password) {
- if (mVisiActionEdit) {
- mVisiActionEdit->trigger();
+ if (mShowHideButton) {
+ mShowHideButton->click();
}
if (mVisiCB) {
mVisiCB->setChecked(true);
}
}
const auto pinStr = QString::fromUtf8(pin.get());
_edit->setPin(pinStr);
mRepeat->setPin(pinStr);
// explicitly focus the first input field and select the generated password
_edit->setFocus();
_edit->selectAll();
}
}
void PinEntryDialog::toggleVisibility()
{
+ qDebug() << __func__;
if (sender() != mVisiCB) {
if (_edit->echoMode() == QLineEdit::Password) {
- if (mVisiActionEdit) {
- mVisiActionEdit->setIcon(QIcon(QLatin1String(":/icons/hint") + mIconSuffix));
- mVisiActionEdit->setToolTip(mHideTT);
+ if (mShowHideButton) {
+ mShowHideButton->setIcon(QIcon(QLatin1String(":/icons/hint") + mIconSuffix));
+ mShowHideButton->setToolTip(mHideTT);
}
_edit->setEchoMode(QLineEdit::Normal);
if (mRepeat) {
mRepeat->setEchoMode(QLineEdit::Normal);
}
} else {
- if (mVisiActionEdit) {
- mVisiActionEdit->setIcon(QIcon(QLatin1String(":/icons/visibility") + mIconSuffix));
- mVisiActionEdit->setToolTip(mVisibilityTT);
+ if (mShowHideButton) {
+ mShowHideButton->setIcon(QIcon(QLatin1String(":/icons/visibility") + mIconSuffix));
+ mShowHideButton->setToolTip(mVisibilityTT);
}
_edit->setEchoMode(QLineEdit::Password);
if (mRepeat) {
mRepeat->setEchoMode(QLineEdit::Password);
}
}
} else {
if (mVisiCB->isChecked()) {
if (mRepeat) {
mRepeat->setEchoMode(QLineEdit::Normal);
}
_edit->setEchoMode(QLineEdit::Normal);
} else {
if (mRepeat) {
mRepeat->setEchoMode(QLineEdit::Password);
}
_edit->setEchoMode(QLineEdit::Password);
}
}
toggleFormattedPassphrase();
}
QString PinEntryDialog::repeatedPin() const
{
if (mRepeat) {
return mRepeat->pin();
}
return QString();
}
bool PinEntryDialog::timedOut() const
{
return _timed_out;
}
void PinEntryDialog::setRepeatErrorText(const QString &err)
{
if (mRepeatError) {
mRepeatError->setText(err);
}
}
void PinEntryDialog::cancelTimeout()
{
if (_timer) {
_timer->stop();
}
}
void PinEntryDialog::checkCapsLock()
{
const auto state = capsLockState();
if (state != LockState::Unknown) {
mCapsLockHint->setVisible(state == LockState::On);
}
}
void PinEntryDialog::onAccept()
{
cancelTimeout();
if (mRepeat && mRepeat->pin() != _edit->pin()) {
#ifndef QT_NO_ACCESSIBILITY
if (QAccessible::isActive()) {
QMessageBox::information(this, mRepeatError->text(), mRepeatError->text());
} else
#endif
{
mRepeatError->setVisible(true);
}
return;
}
const auto result = checkConstraints();
if (result != PassphraseNotOk) {
accept();
}
}
#ifndef QT_NO_ACCESSIBILITY
void PinEntryDialog::accessibilityActiveChanged(bool active)
{
// Allow text labels to get focus if accessibility is active
const auto focusPolicy = active ? Qt::StrongFocus : Qt::ClickFocus;
_error->setFocusPolicy(focusPolicy);
_desc->setFocusPolicy(focusPolicy);
mCapsLockHint->setFocusPolicy(focusPolicy);
mConstraintsHint->setFocusPolicy(focusPolicy);
mFormattedPassphraseHint->setFocusPolicy(focusPolicy);
if (mRepeatError) {
mRepeatError->setFocusPolicy(focusPolicy);
}
}
#endif
PinEntryDialog::PassphraseCheckResult PinEntryDialog::checkConstraints()
{
if (!mEnforceConstraints) {
return PassphraseNotChecked;
}
const auto passphrase = _edit->pin().toUtf8();
unique_malloced_ptr<char> error{pinentry_inq_checkpin(
_pinentry_info, passphrase.constData(), passphrase.size())};
if (!error) {
return PassphraseOk;
}
const auto messageLines = QString::fromUtf8(QByteArray::fromPercentEncoding(error.get())).split(QChar{'\n'});
if (messageLines.isEmpty()) {
// shouldn't happen because pinentry_inq_checkpin() either returns NULL or a non-empty string
return PassphraseOk;
}
const auto firstLine = messageLines.first();
const auto indexOfFirstNonEmptyAdditionalLine = messageLines.indexOf(QRegularExpression{QStringLiteral(".*\\S.*")}, 1);
const auto additionalLines = indexOfFirstNonEmptyAdditionalLine > 0 ? messageLines.mid(indexOfFirstNonEmptyAdditionalLine).join(QChar{'\n'}) : QString{};
QMessageBox messageBox{this};
messageBox.setIcon(QMessageBox::Information);
messageBox.setWindowTitle(mConstraintsErrorTitle);
messageBox.setText(firstLine);
messageBox.setInformativeText(additionalLines);
messageBox.setStandardButtons(QMessageBox::Ok);
messageBox.exec();
return PassphraseNotOk;
}
#include "pinentrydialog.moc"
diff --git a/qt/pinentrydialog.h b/qt/pinentrydialog.h
index 16df737..6d80c4e 100644
--- a/qt/pinentrydialog.h
+++ b/qt/pinentrydialog.h
@@ -1,183 +1,183 @@
/* pinentrydialog.h - A (not yet) secure Qt 4 dialog for PIN entry.
* Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB)
* Copyright 2007 Ingo Klöcker
* Copyright 2016 Intevation GmbH
* Copyright (C) 2021, 2022 g10 Code GmbH
*
* Written by Steffen Hansen <steffen@klaralvdalens-datakonsult.se>.
* Modified by Andre Heinecke <aheinecke@intevation.de>
* Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* 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. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __PINENTRYDIALOG_H__
#define __PINENTRYDIALOG_H__
#include <QAccessible>
#include <QDialog>
#include <QStyle>
#include <QTimer>
#include "pinentry.h"
class QIcon;
class QLabel;
class QPushButton;
class QLineEdit;
class PinLineEdit;
class QString;
class QProgressBar;
class QCheckBox;
class QAction;
QPixmap applicationIconPixmap(const QIcon &overlayIcon = {});
void raiseWindow(QWidget *w);
class PinEntryDialog : public QDialog
#ifndef QT_NO_ACCESSIBILITY
, public QAccessible::ActivationObserver
#endif
{
Q_OBJECT
Q_PROPERTY(QString description READ description WRITE setDescription)
Q_PROPERTY(QString error READ error WRITE setError)
Q_PROPERTY(QString pin READ pin WRITE setPin)
Q_PROPERTY(QString prompt READ prompt WRITE setPrompt)
public:
struct FormattedPassphraseOptions
{
bool formatPassphrase;
QString hint;
};
struct ConstraintsOptions
{
bool enforce;
QString shortHint;
QString longHint;
QString errorTitle;
};
explicit PinEntryDialog(pinentry_t pe, QWidget *parent = 0, const char *name = 0,
bool modal = false,
const QString &repeatString = QString(),
const QString &visibiltyTT = QString(),
const QString &hideTT = QString());
~PinEntryDialog() override;
void setDescription(const QString &);
QString description() const;
void setError(const QString &);
QString error() const;
void setPin(const QString &);
QString pin() const;
QString repeatedPin() const;
void setRepeatErrorText(const QString &);
void setPrompt(const QString &);
QString prompt() const;
void setOkText(const QString &);
void setCancelText(const QString &);
void setQualityBar(const QString &);
void setQualityBarTT(const QString &);
void setGenpinLabel(const QString &);
void setGenpinTT(const QString &);
void setCapsLockHint(const QString &);
void setFormattedPassphrase(const FormattedPassphraseOptions &options);
void setConstraintsOptions(const ConstraintsOptions &options);
void setSavePassphraseCBText(const QString &text);
bool timedOut() const;
protected Q_SLOTS:
void updateQuality(const QString &);
void slotTimeout();
void textChanged(const QString &);
void focusChanged(QWidget *old, QWidget *now);
void toggleVisibility();
void onBackspace();
void generatePin();
void toggleFormattedPassphrase();
void togglePasswordCaching(bool enabled);
protected:
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *event) override;
void showEvent(QShowEvent *event) override;
private Q_SLOTS:
void cancelTimeout();
void checkCapsLock();
void onAccept();
private:
#ifndef QT_NO_ACCESSIBILITY
void accessibilityActiveChanged(bool active) override;
#endif
enum PassphraseCheckResult {
PassphraseNotChecked = -1,
PassphraseNotOk = 0,
PassphraseOk
};
PassphraseCheckResult checkConstraints();
private:
QLabel *_icon = nullptr;
QLabel *_desc = nullptr;
QLabel *_error = nullptr;
QLabel *_prompt = nullptr;
QLabel *_quality_bar_label = nullptr;
QProgressBar *_quality_bar = nullptr;
PinLineEdit *_edit = nullptr;
PinLineEdit *mRepeat = nullptr;
QLabel *mRepeatError = nullptr;
QPushButton *_ok = nullptr;
QPushButton *_cancel = nullptr;
bool _grabbed = false;
bool _have_quality_bar = false;
bool _timed_out = false;
bool _disable_echo_allowed = true;
bool mEnforceConstraints = false;
bool mFormatPassphrase = false;
pinentry_t _pinentry_info = nullptr;
QTimer *_timer = nullptr;
QString mVisibilityTT;
QString mHideTT;
- QAction *mVisiActionEdit = nullptr;
+ QPushButton *mShowHideButton = nullptr;
QPushButton *mGenerateButton = nullptr;
QCheckBox *mVisiCB = nullptr;
QLabel *mFormattedPassphraseHint = nullptr;
QLabel *mFormattedPassphraseHintSpacer = nullptr;
QLabel *mCapsLockHint = nullptr;
QLabel *mConstraintsHint = nullptr;
QString mConstraintsErrorTitle;
QCheckBox *mSavePassphraseCB = nullptr;
QString mIconSuffix;
};
#endif // __PINENTRYDIALOG_H__

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jan 20, 11:12 PM (8 h, 59 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
85/b9/a39dfc97428f11d88ddbac95ff20

Event Timeline