From c8b2f81bf8b45874c34b2ef464d1e0955aa5ef44 Mon Sep 17 00:00:00 2001 From: SET Date: Fri, 6 Nov 2020 21:42:50 +0100 Subject: [PATCH] Optimize certification trust level management. A private key should be editable to Unknown or Ultimate levels only. A public key should be editable to all levels except Ultimate. Undefined level is excluded for both public and private keys. The public WTreeTableNode may list private keys if the user does not manage these private keys. Inform of this state in the tool tip. The certification trust level is excluded for any change. --- K7Main.cpp | 2 +- KeyEdit.cpp | 63 +++++++++++++++++++--------- KeyEdit.h | 17 ++++++-- Tools.cpp | 32 ++++++++++---- Tools.h | 1 + WTAPPROOT/K7/K7.xml | 3 +- WTAPPROOT/K7/K7_fr.xml | 3 +- nbproject/private/configurations.xml | 2 + nbproject/private/private.xml | 9 +--- 9 files changed, 89 insertions(+), 43 deletions(-) diff --git a/K7Main.cpp b/K7Main.cpp index 58c3052..a7e8f55 100644 --- a/K7Main.cpp +++ b/K7Main.cpp @@ -265,7 +265,7 @@ void K7Main::DisplayKeys(const vector& kList, const WString& grpLabe * Here we allow the owner trust level of primary keys to be changed anytime. * Kleopatra doesn't do that for primary keys having ultimate trust level. */ - lblOwnerTrust->doubleClicked().connect(std::bind(&KeyEdit::OnOwnerTrustDoubleClicked, m_keyEdit, keyNode)); + lblOwnerTrust->doubleClicked().connect(std::bind(&KeyEdit::OnOwnerTrustDoubleClicked, m_keyEdit, keyNode, k.hasSecret())); lblOwnerTrust->setToolTip(TR("TTTDoubleCLick")); } keyNode->setColumnWidget(2, unique_ptr (lblOwnerTrust)); diff --git a/KeyEdit.cpp b/KeyEdit.cpp index 57c6d55..22f24fb 100644 --- a/KeyEdit.cpp +++ b/KeyEdit.cpp @@ -12,6 +12,7 @@ #include #include #include "GpgMEWorker.h" +#include "Tools.h" using namespace std; @@ -28,29 +29,48 @@ KeyEdit::~KeyEdit() delete m_popupUid; } -void KeyEdit::OnOwnerTrustDoubleClicked(WTreeTableNode * keyNode) +void KeyEdit::OnOwnerTrustDoubleClicked(WTreeTableNode * keyNode, bool keyHasSecret) { /* - * TODO : decide if we should exclude any primary key with ultimate trust - * level for any further change. + * A private key that a user does not manage will have its public part + * listed in the public WTreeTableNode. The certification trust level must + * not be editable by anyone. + */ + WText * lblFpr = static_cast (keyNode->columnWidget(3)); + if (!IsOurKey(lblFpr->text()) && Tools::KeyHasSecret(lblFpr->text())) { + m_owner->m_tmwMessage->SetText(TR("OwnerTrustReadOnly")); + return; + } + /* + * We leave a primary key with ultimate trust level for further change. + * kleopatra does not do that. */ WComboBox * cmbOwnerTrust = new WComboBox(); - FillOwnerTrustCombo(cmbOwnerTrust); - cmbOwnerTrust->blurred().connect(std::bind(&KeyEdit::OnOwnerTrustBlurred, this, keyNode)); + FillOwnerTrustCombo(cmbOwnerTrust, keyHasSecret); + cmbOwnerTrust->blurred().connect(std::bind(&KeyEdit::OnOwnerTrustBlurred, this, keyNode, keyHasSecret)); WText * lblOwnerTrust = static_cast (keyNode->columnWidget(2)); cmbOwnerTrust->setCurrentIndex(cmbOwnerTrust->findText(lblOwnerTrust->text())); - // If nothing gets changed, don't go to engine. + /* + * Prepare to check for change in combobox item. + * Change is detected by index, not value. + */ cmbOwnerTrust->setAttributeValue("previousTrustLevel", std::to_string(cmbOwnerTrust->currentIndex())); keyNode->setColumnWidget(2, unique_ptr (cmbOwnerTrust)); // +++ cmbOwnerTrust->setFocus(); } -void KeyEdit::OnOwnerTrustBlurred(WTreeTableNode* keyNode) +void KeyEdit::OnOwnerTrustBlurred(WTreeTableNode* keyNode, bool keyHasSecret) { + // Get new level (not index) WComboBox * cmbOwnerTrust = static_cast (keyNode->columnWidget(2)); + shared_ptr aiModel = cmbOwnerTrust->model(); + WStandardItemModel * iModel = static_cast (aiModel.get()); + WStandardItem * item = iModel->item(cmbOwnerTrust->currentIndex(), 0); + int newLevel = Tools::ToInt(item->text().toUTF8()); + WText * lblOwnerTrust = new WText(cmbOwnerTrust->currentText()); - lblOwnerTrust->doubleClicked().connect(std::bind(&KeyEdit::OnOwnerTrustDoubleClicked, this, keyNode)); + lblOwnerTrust->doubleClicked().connect(std::bind(&KeyEdit::OnOwnerTrustDoubleClicked, this, keyNode, keyHasSecret)); const WText * lblFpr = static_cast (keyNode->columnWidget(3)); const uint newTrustLevel = cmbOwnerTrust->currentIndex(); const WString previousTrustLevel = cmbOwnerTrust->attributeValue("previousTrustLevel"); @@ -58,9 +78,9 @@ void KeyEdit::OnOwnerTrustBlurred(WTreeTableNode* keyNode) // If nothing was changed, don't go to engine. if (WString(std::to_string(newTrustLevel)) == previousTrustLevel) return; - + GpgMEWorker gpgWorker; - GpgME::Error e = gpgWorker.EditOwnerTrust(lblFpr->text().toUTF8().c_str(), (GpgME::Key::OwnerTrust) newTrustLevel); + GpgME::Error e = gpgWorker.EditOwnerTrust(lblFpr->text().toUTF8().c_str(), (GpgME::Key::OwnerTrust) newLevel); if (e.code() != 0) { lblOwnerTrust->setText(previousTrustLevel); @@ -70,21 +90,24 @@ void KeyEdit::OnOwnerTrustBlurred(WTreeTableNode* keyNode) m_owner->m_tmwMessage->SetText(TR("OwnerTrustSuccess")); } -void KeyEdit::FillOwnerTrustCombo(WComboBox * cmb) +void KeyEdit::FillOwnerTrustCombo(WComboBox * cmb, bool keyHasSecret) { - /* - * We should perhaps exclude OwnerTrust::Ultimate. - * kleopatra doesn't do that. - */ shared_ptr siModel = make_shared (); OwnerTrustMap OwnerTrustLevel = m_owner->OwnerTrustLevel; vector> colIndex; vector> colText; - OwnerTrustMap::iterator it; - for (it = OwnerTrustLevel.begin(); it != OwnerTrustLevel.end(); it++) - { - colIndex.push_back(cpp14::make_unique (std::to_string((*it).first))); - colText.push_back(cpp14::make_unique ((*it).second)); + colIndex.push_back(cpp14::make_unique (std::to_string(UserID::Validity::Unknown))); + colText.push_back(cpp14::make_unique (TR("UidUnknown"))); + if (keyHasSecret) { + colIndex.push_back(cpp14::make_unique (std::to_string(UserID::Validity::Ultimate))); + colText.push_back(cpp14::make_unique (TR("UidUltimate"))); + } else { + colIndex.push_back(cpp14::make_unique (std::to_string(UserID::Validity::Never))); + colText.push_back(cpp14::make_unique (TR("UidNever"))); + colIndex.push_back(cpp14::make_unique (std::to_string(UserID::Validity::Marginal))); + colText.push_back(cpp14::make_unique (TR("UidMarginal"))); + colIndex.push_back(cpp14::make_unique (std::to_string(UserID::Validity::Full))); + colText.push_back(cpp14::make_unique (TR("UidFull"))); } siModel->appendColumn(std::move(colIndex)); siModel->appendColumn(std::move(colText)); diff --git a/KeyEdit.h b/KeyEdit.h index 044347d..e1a9677 100644 --- a/KeyEdit.h +++ b/KeyEdit.h @@ -31,13 +31,15 @@ public: /** * Shows a combobox with all trust levels * @param keyNode + * @param keyHasSecret */ - void OnOwnerTrustDoubleClicked(WTreeTableNode * keyNode); + void OnOwnerTrustDoubleClicked(WTreeTableNode * keyNode, bool keyHasSecret); /** * Saves any changes in trust level * @param keyNode + * @param keyHasSecret */ - void OnOwnerTrustBlurred(WTreeTableNode * keyNode); + void OnOwnerTrustBlurred(WTreeTableNode * keyNode, bool keyHasSecret); /** * If the fingerprint is that of a private key we manage, returns true. * @param fpr @@ -56,8 +58,15 @@ private: K7Main * m_owner; PopupCertifyUserId * m_popupUid; WString m_targetKeyFpr; - - void FillOwnerTrustCombo(WComboBox * cmb); + /** + * Unknown is common. + * \n If keyHasSecret is true, show only Ultimate level. + * \n Else, show everything except Ultimate. + * \n Undefined is not included. + * @param cmb + * @param keyHasSecret + */ + void FillOwnerTrustCombo(WComboBox * cmb, bool keyHasSecret); void CertifyKey(); }; diff --git a/Tools.cpp b/Tools.cpp index 6b59968..80cb4bc 100644 --- a/Tools.cpp +++ b/Tools.cpp @@ -13,10 +13,12 @@ using namespace std; -Tools::Tools() { +Tools::Tools() +{ } -Tools::~Tools() { +Tools::~Tools() +{ } bool Tools::ConfigKeyIdMatchesKey(const GpgME::Key& k, const WString& configKeyId) @@ -27,7 +29,8 @@ bool Tools::ConfigKeyIdMatchesKey(const GpgME::Key& k, const WString& configKeyI || configKeyId == WString(k.primaryFingerprint())); } -int Tools::ToInt(const string& s) { +int Tools::ToInt(const string& s) +{ istringstream buffer(s.c_str()); int num; buffer >> num; @@ -37,8 +40,8 @@ int Tools::ToInt(const string& s) { WString Tools::TexttualBool(bool value) { const WString res = value - ? WString::tr("Yes") - : WString::tr("No"); + ? WString::tr("Yes") + : WString::tr("No"); return res; } @@ -55,8 +58,8 @@ WString Tools::GetKeyStatus(const GpgME::Key& k) status += WString(WString::tr("KeyStatusIsDisabled")) + sep + TexttualBool(k.isDisabled()) + nl; status += WString(WString::tr("KeyStatusIsExpired")) + sep + TexttualBool(k.isExpired()) + nl; status += WString(WString::tr("KeyStatusIsRevoked")) + sep + TexttualBool(k.isRevoked()) + nl + nl; - status += WString(WString::tr("KeyTypeIsSecret")) + sep + TexttualBool(k.isSecret()); - + status += WString(WString::tr("KeyTypeIsSecret")) + sep + TexttualBool(KeyHasSecret(k.primaryFingerprint())); + return status; } @@ -70,7 +73,7 @@ WString Tools::GetUidStatus(const GpgME::UserID& uid) status += WString(WString::tr("UserStatusIsNull")) + sep + TexttualBool(uid.isNull()) + nl; status += WString(WString::tr("UserStatusIsInvalid")) + sep + TexttualBool(uid.isInvalid()) + nl; status += WString(WString::tr("UserStatusIsRevoked")) + sep + TexttualBool(uid.isRevoked()); - + return status; } @@ -86,7 +89,18 @@ WString Tools::GetSigStatus(const GpgME::UserID::Signature& sig) status += WString(WString::tr("SigStatusIsExportable")) + sep + TexttualBool(sig.isExportable()) + nl; status += WString(WString::tr("SigStatusIsExpired")) + sep + TexttualBool(sig.isExpired()) + nl; status += WString(WString::tr("SigStatusIsRevokation")) + sep + TexttualBool(sig.isRevokation()); - + return status; } +bool Tools::KeyHasSecret(const WString& fpr) +{ + Error e; + GpgMEWorker gpgw; + GpgME::Key k = gpgw.FindKey(fpr.toUTF8().c_str(), e, true); // Look for a private key + if (e.code() != 0 && e.code() != 16383) + { // 16383 : end of file, when key is not private + return false; + } + return (!k.isNull()); +} diff --git a/Tools.h b/Tools.h index 54258dd..f474c3d 100644 --- a/Tools.h +++ b/Tools.h @@ -43,6 +43,7 @@ public: static WString GetKeyStatus(const GpgME::Key& k); static WString GetUidStatus(const GpgME::UserID& uid); static WString GetSigStatus(const GpgME::UserID::Signature& sig); + static bool KeyHasSecret(const WString& fpr); private: diff --git a/WTAPPROOT/K7/K7.xml b/WTAPPROOT/K7/K7.xml index 415dc44..e2c8348 100644 --- a/WTAPPROOT/K7/K7.xml +++ b/WTAPPROOT/K7/K7.xml @@ -66,6 +66,7 @@ Double click to edit This is your key + Owner trust level read only; a primary key coexists and you don't manage it. Owner trust level succesfully changed Owner trust level failed to be changed @@ -89,7 +90,7 @@ Disabled Expired Revoked - Secret + Coexists with a secret key User status Bad diff --git a/WTAPPROOT/K7/K7_fr.xml b/WTAPPROOT/K7/K7_fr.xml index 6dcd5a2..ae48ee0 100644 --- a/WTAPPROOT/K7/K7_fr.xml +++ b/WTAPPROOT/K7/K7_fr.xml @@ -66,6 +66,7 @@ Double cliquez pour éditer C'est votre clé + Confiance dans la certification en lecture seule; une clé primaire coexiste et vous ne la gérez pas. Confiance dans la certification changée avec succès Échec de changement de la confiance dans la certification @@ -89,7 +90,7 @@ Désactivé Expiré Revoqué - Secret + Coexiste avec une clé secrète État de l'utilisateur Mauvais diff --git a/nbproject/private/configurations.xml b/nbproject/private/configurations.xml index 2c9b830..1f82c50 100644 --- a/nbproject/private/configurations.xml +++ b/nbproject/private/configurations.xml @@ -13,6 +13,8 @@ + + diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml index 850251b..14a195b 100644 --- a/nbproject/private/private.xml +++ b/nbproject/private/private.xml @@ -7,14 +7,9 @@ - file:/home/user/Documents/published/K7/PopupDeleter.h - file:/home/user/Documents/published/K7/K7Main.h - file:/home/user/Documents/published/K7/PopupUploader.h + file:/home/user/Documents/published/K7/AppConfig.cpp file:/home/user/Documents/published/K7/K7Main.cpp - file:/home/user/Documents/published/K7/PopupCertifyUserId.cpp - file:/home/user/Documents/published/K7/PopupUploader.cpp - file:/home/user/Documents/published/K7/PopupCertifyUserId.h - file:/home/user/Documents/published/K7/PopupDeleter.cpp + file:/home/user/Documents/published/K7/main.cpp