Verified Commit 904a3c08 authored by Ingo Klöcker's avatar Ingo Klöcker Committed by Ingo Klöcker
Browse files

Use UserIDs instead of indexes for identifying selected user IDs

This fixes a mix-up of user IDs caused by indexes calculated on all
user IDs vs. on valid user IDs only. Additionally, the improved
equality check for user IDs fixes a mix-up of user IDs with the same
text on the same key (e.g. if a user ID was revoked and then re-added).

GnuPG-bug-id: 6265
parent 172f645d
Pipeline #260262 passed with stage
in 2 minutes and 15 seconds
......@@ -17,8 +17,10 @@
#include "exportopenpgpcertstoservercommand.h"
#include "dialogs/certifycertificatedialog.h"
#include "utils/keys.h"
#include "utils/tags.h"
#include <Libkleo/Algorithm>
#include <Libkleo/KeyCache>
#include <Libkleo/Formatting>
......@@ -260,11 +262,24 @@ void CertifyCertificateCommand::Private::slotCertificationPrepared()
{
Q_ASSERT(dialog);
const auto selectedUserIds = dialog->selectedUserIDs();
std::vector<unsigned int> userIdIndexes;
userIdIndexes.reserve(selectedUserIds.size());
for (unsigned int i = 0, numUserIds = target.numUserIDs(); i < numUserIds; ++i) {
const auto userId = target.userID(i);
const bool userIdIsSelected = Kleo::any_of(selectedUserIds, [userId](const auto &uid) {
return Kleo::userIDsAreEqual(userId, uid);
});
if (userIdIsSelected) {
userIdIndexes.push_back(i);
}
}
createJob();
Q_ASSERT(job);
job->setExportable(dialog->exportableCertificationSelected());
job->setNonRevocable(dialog->nonRevocableCertificationSelected());
job->setUserIDsToSign(dialog->selectedUserIDs());
job->setUserIDsToSign(userIdIndexes);
job->setSigningKey(dialog->selectedSecretKey());
job->setCheckLevel(dialog->selectedCheckLevel());
if (!dialog->tags().isEmpty()) {
......
......@@ -128,7 +128,7 @@ void CertifyCertificateDialog::setSelectedUserIDs(const std::vector<UserID> &uid
mCertWidget->selectUserIDs(uids);
}
std::vector<unsigned int> CertifyCertificateDialog::selectedUserIDs() const
std::vector<GpgME::UserID> CertifyCertificateDialog::selectedUserIDs() const
{
return mCertWidget->selectedUserIDs();
}
......
......@@ -37,7 +37,7 @@ public:
bool nonRevocableCertificationSelected() const;
void setSelectedUserIDs(const std::vector<GpgME::UserID> &uids);
std::vector<unsigned int> selectedUserIDs() const;
std::vector<GpgME::UserID> selectedUserIDs() const;
GpgME::Key selectedSecretKey() const;
......
......@@ -25,6 +25,7 @@
#include <KSeparator>
#include <KSharedConfig>
#include <Libkleo/Algorithm>
#include <Libkleo/DefaultKeyFilter>
#include <Libkleo/KeySelectionCombo>
#include <Libkleo/Formatting>
......@@ -54,6 +55,11 @@
using namespace Kleo;
static QDebug operator<<(QDebug s, const GpgME::UserID &userID)
{
return s << Formatting::prettyUserID(userID);
}
namespace {
// Maybe move this in its own file
......@@ -187,12 +193,28 @@ private:
GpgME::Key mExcludedKey;
};
class UserIDItem : public QStandardItem
{
public:
explicit UserIDItem(const GpgME::UserID &uid)
: mUserId{uid}
{}
GpgME::UserID userId()
{
return mUserId;
}
private:
GpgME::UserID mUserId;
};
class UserIDModel : public QStandardItemModel
{
Q_OBJECT
public:
enum Role {
UserIDIndex = Qt::UserRole
UserID = Qt::UserRole
};
explicit UserIDModel(QObject *parent = nullptr) : QStandardItemModel(parent) {}
......@@ -213,9 +235,8 @@ public:
i++;
continue;
}
auto const item = new QStandardItem;
const auto item = new UserIDItem{uid};
item->setText(Formatting::prettyUserID(uid));
item->setData(i, UserIDIndex);
item->setCheckable(true);
item->setEditable(false);
item->setCheckState(Qt::Checked);
......@@ -224,38 +245,42 @@ public:
}
}
void setCheckedUserIDs(const std::vector<unsigned int> &uids)
void setCheckedUserIDs(const std::vector<GpgME::UserID> &uids)
{
std::vector<unsigned int> sorted = uids;
std::sort(sorted.begin(), sorted.end());
for (int i = 0, end = rowCount(); i != end; ++i) {
item(i)->setCheckState(std::binary_search(sorted.begin(), sorted.end(), i) ? Qt::Checked : Qt::Unchecked);
const auto uidItem = userIdItem(i);
const auto itemUserId = uidItem->userId();
const bool userIdIsInList = Kleo::any_of(uids, [itemUserId](const auto &uid) {
return Kleo::userIDsAreEqual(itemUserId, uid);
});
uidItem->setCheckState(userIdIsInList ? Qt::Checked : Qt::Unchecked);
}
}
std::vector<unsigned int> checkedUserIDs() const
std::vector<GpgME::UserID> checkedUserIDs() const
{
std::vector<unsigned int> ids;
std::vector<GpgME::UserID> userIds;
userIds.reserve(rowCount());
for (int i = 0; i < rowCount(); ++i) {
if (item(i)->checkState() == Qt::Checked) {
ids.push_back(item(i)->data(UserIDIndex).toUInt());
const auto uidItem = userIdItem(i);
if (uidItem->checkState() == Qt::Checked) {
userIds.push_back(uidItem->userId());
}
}
qCDebug(KLEOPATRA_LOG) << "Checked uids are: " << ids;
return ids;
qCDebug(KLEOPATRA_LOG) << "Checked user IDs:" << userIds;
return userIds;
}
private:
UserIDItem *userIdItem(int row) const
{
return static_cast<UserIDItem *>(item(row));
}
private:
GpgME::Key m_key;
};
static bool uidEqual(const GpgME::UserID &lhs, const GpgME::UserID &rhs)
{
return qstrcmp(lhs.parent().primaryFingerprint(),
rhs.parent().primaryFingerprint()) == 0
&& qstrcmp(lhs.id(), rhs.id()) == 0;
}
auto checkBoxSize(const QCheckBox *checkBox)
{
QStyleOptionButton opt;
......@@ -600,24 +625,10 @@ public:
void selectUserIDs(const std::vector<GpgME::UserID> &uids)
{
const auto all = mTarget.userIDs();
std::vector<unsigned int> indexes;
indexes.reserve(uids.size());
for (const auto &uid: uids) {
const unsigned int idx =
std::distance(all.cbegin(), std::find_if(all.cbegin(), all.cend(),
[uid](const GpgME::UserID &other) { return uidEqual(uid, other); }));
if (idx < all.size()) {
indexes.push_back(idx);
}
}
mUserIDModel.setCheckedUserIDs(indexes);
mUserIDModel.setCheckedUserIDs(uids);
}
std::vector<unsigned int> selectedUserIDs() const
std::vector<GpgME::UserID> selectedUserIDs() const
{
return mUserIDModel.checkedUserIDs();
}
......@@ -766,7 +777,7 @@ void CertifyWidget::selectUserIDs(const std::vector<GpgME::UserID> &uids)
d->selectUserIDs(uids);
}
std::vector<unsigned int> CertifyWidget::selectedUserIDs() const
std::vector<GpgME::UserID> CertifyWidget::selectedUserIDs() const
{
return d->selectedUserIDs();
}
......
......@@ -39,7 +39,7 @@ public:
void selectUserIDs(const std::vector<GpgME::UserID> &uids);
/* The user IDs that should be signed */
std::vector<unsigned int> selectedUserIDs() const;
std::vector<GpgME::UserID> selectedUserIDs() const;
/* The secret key selected */
GpgME::Key secKey() const;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment