Show an icon depending on the storage location of the signature

This commit is contained in:
Sune Vuorela 2023-12-07 12:15:03 +00:00
parent c94d47b07f
commit 3e1842a923
5 changed files with 89 additions and 1 deletions

View file

@ -49,6 +49,7 @@ public:
bool isSelfSigned = false;
QByteArray certificateData;
CertificateInfo::Backend backend = CertificateInfo::Backend::Unknown;
CertificateInfo::KeyLocation keyLocation = CertificateInfo::KeyLocation::Unknown;
std::function<bool(QString)> checkPasswordFunction;
};
@ -250,6 +251,16 @@ void CertificateInfo::setCertificateData(const QByteArray &certificateData)
d->certificateData = certificateData;
}
CertificateInfo::KeyLocation CertificateInfo::keyLocation() const
{
return d->keyLocation;
}
void CertificateInfo::setKeyLocation(KeyLocation location)
{
d->keyLocation = location;
}
CertificateInfo::Backend CertificateInfo::backend() const
{
return d->backend;

View file

@ -66,6 +66,21 @@ public:
*/
enum class EmptyString { /** Empty strings should just be empty*/ Empty, TranslatedNotAvailable /** Empty strings should be a localized version of "Not available" */ };
/** A signing key can be located in different places
* sometimes, for the user, it might be easier to pick
* the key located on a card if it have some visual
* indicator that it is somehow removable.
*
* \note a keylocation for a certificate without a private
*key (cannot be used for signing) will likely be "Unknown"
*/
enum class KeyLocation {
Unknown, /** We don't know the location */
Other, /** We know the location, but it is somehow not covered by this enum */
Computer, /** The key is on this computer */
HardwareToken /** The key is on a dedicated hardware token, either a smartcard or a dedicated usb token (e.g. gnuk, nitrokey or yubikey) */
};
/**
* Destructor
*/
@ -237,6 +252,20 @@ public:
* @since 23.08
*/
void setCertificateData(const QByteArray &certificateData);
/*
* Sets the location of the certificate
*
* see \ref KeyLocation enum for details
* @since 23.08
*/
void setKeyLocation(KeyLocation location);
/**
* the location of the certificate
*
* see \ref KeyLocation enum for details
*/
KeyLocation keyLocation() const;
/**
* The backend where the certificate originates.

View file

@ -56,6 +56,23 @@ static Okular::CertificateInfo::PublicKeyType fromPoppler(Poppler::CertificateIn
return Okular::CertificateInfo::OtherKey;
}
#if POPPLER_VERSION_MACRO > QT_VERSION_CHECK(23, 8, 0)
static Okular::CertificateInfo::KeyLocation fromPoppler(Poppler::CertificateInfo::KeyLocation location)
{
switch (location) {
case Poppler::CertificateInfo::KeyLocation::Computer:
return Okular::CertificateInfo::KeyLocation::Computer;
case Poppler::CertificateInfo::KeyLocation::Unknown:
return Okular::CertificateInfo::KeyLocation::Unknown;
case Poppler::CertificateInfo::KeyLocation::HardwareToken:
return Okular::CertificateInfo::KeyLocation::HardwareToken;
case Poppler::CertificateInfo::KeyLocation::Other:
return Okular::CertificateInfo::KeyLocation::Other;
}
return Okular::CertificateInfo::KeyLocation::Unknown;
}
#endif
Okular::CertificateInfo fromPoppler(const Poppler::CertificateInfo &pInfo)
{
Okular::CertificateInfo oInfo;
@ -79,6 +96,9 @@ Okular::CertificateInfo fromPoppler(const Poppler::CertificateInfo &pInfo)
oInfo.setPublicKeyStrength(pInfo.publicKeyStrength());
oInfo.setSelfSigned(pInfo.isSelfSigned());
oInfo.setCertificateData(pInfo.certificateData());
#if POPPLER_VERSION_MACRO > QT_VERSION_CHECK(23, 8, 0)
oInfo.setKeyLocation(fromPoppler(pInfo.keyLocation()));
#endif
oInfo.setCheckPasswordFunction([pInfo](const QString &password) {
#if POPPLER_VERSION_MACRO >= QT_VERSION_CHECK(23, 06, 0)
auto backend = Poppler::activeCryptoSignBackend();

View file

@ -233,6 +233,7 @@ std::optional<SigningInformation> getCertificateAndPasswordForSigning(PageView *
QStandardItemModel items;
QHash<QString, Okular::CertificateInfo> nickToCert;
int minWidth = -1;
bool showIcons = false;
int selectIndex = 0;
auto config = KSharedConfig::openConfig();
const QString lastNick = config->group(ConfigGroup).readEntry<QString>(ConfigLastKeyNick, QString());
@ -245,6 +246,22 @@ std::optional<SigningInformation> getCertificateAndPasswordForSigning(PageView *
minWidth = std::max(minWidth, std::max(cert.nickName().size(), emailAddress.size() + commonName.size()));
switch (cert.keyLocation()) {
case Okular::CertificateInfo::KeyLocation::Computer:
item->setData(QIcon::fromTheme(QStringLiteral("view-certificate")), Qt::DecorationRole);
showIcons = true;
break;
case Okular::CertificateInfo::KeyLocation::HardwareToken:
/* Better icon requested in https://bugs.kde.org/show_bug.cgi?id=428278*/
item->setData(QIcon::fromTheme(QStringLiteral("auth-sim")), Qt::DecorationRole);
showIcons = true;
break;
case Okular::CertificateInfo::KeyLocation::Unknown:; //
break;
case Okular::CertificateInfo::KeyLocation::Other:
break;
}
item->setData(cert.nickName(), Qt::DisplayRole);
item->setData(cert.subjectInfo(Okular::CertificateInfo::DistinguishedName, Okular::CertificateInfo::EmptyString::Empty), Qt::ToolTipRole);
item->setEditable(false);
@ -256,6 +273,9 @@ std::optional<SigningInformation> getCertificateAndPasswordForSigning(PageView *
}
SelectCertificateDialog dialog(pageView);
auto keyDelegate = new KeyDelegate(dialog.ui->list);
keyDelegate->showIcon = showIcons;
dialog.ui->list->setItemDelegate(keyDelegate);
QFontMetrics fm = dialog.fontMetrics();
dialog.ui->list->setMinimumWidth(fm.averageCharWidth() * (minWidth + 5));
dialog.ui->list->setModel(&items);
@ -446,7 +466,6 @@ SelectCertificateDialog::SelectCertificateDialog(QWidget *parent)
, ui {std::make_unique<Ui_SelectCertificateDialog>()}
{
ui->setupUi(this);
ui->list->setItemDelegate(new KeyDelegate(ui->list));
}
SelectCertificateDialog::~SelectCertificateDialog() = default;
@ -482,6 +501,9 @@ void KeyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, c
auto textRect = option.rect;
int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, option.widget) + 1;
if (showIcon) {
textRect.adjust(textRect.height() + textMargin, 0, 0, 0); // make space for icon
}
textRect.adjust(textMargin, 0, -textMargin, 0);
QRect topHalf {textRect.x(), textRect.y(), textRect.width(), textRect.height() / 2};
@ -490,6 +512,11 @@ void KeyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, c
style->drawItemText(painter, topHalf, (option.displayAlignment & Qt::AlignVertical_Mask) | Qt::AlignLeft, option.palette, true, index.data(Qt::DisplayRole).toString());
style->drawItemText(painter, bottomHalf, (option.displayAlignment & Qt::AlignVertical_Mask) | Qt::AlignRight, option.palette, true, index.data(Qt::UserRole + 1).toString());
style->drawItemText(painter, bottomHalf, (option.displayAlignment & Qt::AlignVertical_Mask) | Qt::AlignLeft, option.palette, true, index.data(Qt::UserRole).toString());
if (showIcon) {
if (auto icon = index.data(Qt::DecorationRole).value<QIcon>(); !icon.isNull()) {
icon.paint(painter, QRect(option.rect.topLeft(), QSize(textRect.height(), textRect.height())));
}
}
}
}

View file

@ -71,6 +71,7 @@ public:
using QStyledItemDelegate::QStyledItemDelegate;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const final;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const final;
bool showIcon = false;
};
class SelectCertificateDialog : public QDialog