# # # add_file "res/forms/dialogs/change_key_password.ui" # content [241cbef3ad9e2bad992bef55520c828ab8abd9dd] # # add_file "src/view/dialogs/ChangeKeyPassword.cpp" # content [9b1251e7a8547a9ad74274a4b8254bf91bf94943] # # add_file "src/view/dialogs/ChangeKeyPassword.h" # content [2a6c49b172801183406df48c4caee9fc0ee268af] # # patch "NEWS" # from [7b8445f0080d5a63d84d86cdaa5df474ac6bc126] # to [c9184fa1e0316e8b89728cf6824c69557d9e37c2] # # patch "guitone.pro" # from [427722d346990785a3b3598c7bc49d40f606c179] # to [8819a394eeff1b31d1077696920bf2397365d130] # # patch "src/view/dialogs/DatabaseDialogManager.cpp" # from [114836269d5a2ee7c9d086efdda82d69728f79b6] # to [2cc6cb87b8c1d5661f183fa98e2e9b251c63229c] # # patch "src/view/dialogs/DialogManager.cpp" # from [17c83a36fb60eb7e122c0b80b8e6ead7f8ba5796] # to [d333fbc6c81e14cb2f1dfc5bbe4ba6d0e78728d1] # # patch "src/view/dialogs/DialogManager.h" # from [eb6eec5ffed8e531e644cfa7da0c13f564339532] # to [0afd1af8cca28d7519209a560784949e19988e10] # # patch "src/view/dialogs/KeyManagement.cpp" # from [c282dc5376939e8814d89faeb099d5b677e2d07b] # to [d0e3556aea2c55f38f012973839dfc46973951e1] # # patch "src/view/dialogs/KeyManagement.h" # from [2661c45144f24e9241f4c73719c7e2ba9cc17f9b] # to [b53a2b1f764b2787cb72beaf6694f1904077e8fd] # ============================================================ --- res/forms/dialogs/change_key_password.ui 241cbef3ad9e2bad992bef55520c828ab8abd9dd +++ res/forms/dialogs/change_key_password.ui 241cbef3ad9e2bad992bef55520c828ab8abd9dd @@ -0,0 +1,170 @@ + + + ChangeKeyPassword + + + Qt::WindowModal + + + true + + + + 0 + 0 + 370 + 174 + + + + + 0 + 0 + + + + Change key password + + + + :/icons/guitone.png:/icons/guitone.png + + + false + + + false + + + + QFormLayout::ExpandingFieldsGrow + + + 16 + + + + + Old Password + + + + + + + + 0 + 0 + + + + QLineEdit::Password + + + + + + + Password + + + + + + + + 0 + 0 + + + + QLineEdit::Password + + + + + + + Repeat password + + + + + + + + 0 + 0 + + + + QLineEdit::Password + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set this option if you don't want to set up a lua hook which tells monotone the passphrase for key decryption.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">WARNING:</span> Passwords are stored unencrypted in guitone's settings!</p></body></html> + + + remember password + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + + buttonBox + accepted() + ChangeKeyPassword + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ChangeKeyPassword + reject() + + + 316 + 260 + + + 286 + 274 + + + + + ============================================================ --- src/view/dialogs/ChangeKeyPassword.cpp 9b1251e7a8547a9ad74274a4b8254bf91bf94943 +++ src/view/dialogs/ChangeKeyPassword.cpp 9b1251e7a8547a9ad74274a4b8254bf91bf94943 @@ -0,0 +1,135 @@ +/*************************************************************************** + * Copyright (C) 2010 by Thomas Keller * + * address@hidden * + * * + * 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 3 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 . * + ***************************************************************************/ + +#include "ChangeKeyPassword.h" +#include "MonotoneProcess.h" +#include "Settings.h" + +#include + +ChangeKeyPassword::ChangeKeyPassword(QWidget * parent) : Dialog(parent) +{ + setupUi(this); + Dialog::init(); +} + +ChangeKeyPassword::~ChangeKeyPassword() {} + +void ChangeKeyPassword::init(const QString & hash) +{ + keyHash = hash; + oldPasswd->clear(); + newPasswd->clear(); + newPasswd2->clear(); +} + +void ChangeKeyPassword::accept() +{ + if (oldPasswd->text().size() == 0 || + newPasswd->text().size() == 0 || + newPasswd2->text().size() == 0) + { + QMessageBox::information( + this, + tr("Missing information"), + tr("Please fill out all fields."), + QMessageBox::Ok + ); + return; + } + + if (newPasswd->text().compare(newPasswd2->text()) != 0) + { + QMessageBox::information( + this, + tr("Password mismatch"), + tr("The entered passwords did not match."), + QMessageBox::Ok + ); + return; + } + + QStringList args; + args << "passphrase" << keyHash; + + QByteArray input; + input.append(oldPasswd->text().toUtf8()); + input.append('\n'); + input.append(newPasswd->text().toUtf8()); + input.append('\n'); + input.append(newPasswd->text().toUtf8()); + input.append('\n'); + + // FIXME: this is a hack: since monotone (up to 0.46 at least) prompts + // four times for the current passphrase, we won't get notified if the + // key decryption failed until we virtually pressed enter a fourth time + // luckily this doesn't change the behaviour of the successful case + input.append('\n'); + + MonotoneProcess proc; + proc.start(args); + proc.write(input); + proc.waitForFinished(5000); + + QString output = proc.getBufferedOutput(); + if (!proc.successful()) + { + if (output.indexOf("failed to decrypt old private RSA key") != -1) + { + QMessageBox::critical( + this, + tr("Error changing password"), + tr("Wrong old password for key %1 given.").arg(keyHash), + QMessageBox::Ok, 0, 0 + ); + return; + } + + C(QString("error changing key passphrase: %1").arg(output)); + + QMessageBox::critical( + this, + tr("Error changing password"), + tr("An unknown error occurred - please check the log for details."), + QMessageBox::Ok, 0, 0 + ); + return; + } + + if (rememberPassword->isChecked()) + { + Settings::addItemToMap( + "KeyPasswords", + keyHash, + newPasswd->text() + ); + + QMessageBox::information( + this, + tr("Password saved"), + tr("Your key password has been saved. Please note that you " + "need to re-open the database or workspace you want to " + "use this key with."), + QMessageBox::Ok + ); + } + + emit passwordChanged(); + done(QDialog::Accepted); +} + ============================================================ --- src/view/dialogs/ChangeKeyPassword.h 2a6c49b172801183406df48c4caee9fc0ee268af +++ src/view/dialogs/ChangeKeyPassword.h 2a6c49b172801183406df48c4caee9fc0ee268af @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2010 by Thomas Keller * + * address@hidden * + * * + * 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 3 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 . * + ***************************************************************************/ + +#ifndef CHANGE_KEY_PASSWORD_H +#define CHANGE_KEY_PASSWORD_H + +#include "Dialog.h" +#include "vocab.h" +#include "ui_change_key_password.h" + +class ChangeKeyPassword : public Dialog, private Ui::ChangeKeyPassword +{ + Q_OBJECT +public: + ChangeKeyPassword(QWidget *); + ~ChangeKeyPassword(); + + void init(const QString &); + +signals: + void passwordChanged(); + +public slots: + void accept(); + +private: + QString keyHash; +}; + +#endif + ============================================================ --- NEWS 7b8445f0080d5a63d84d86cdaa5df474ac6bc126 +++ NEWS c9184fa1e0316e8b89728cf6824c69557d9e37c2 @@ -2,8 +2,14 @@ - NOTE: You need monotone 0.46 or later for this version - new: create new monotone databases - new: synchronize with other monotone databases via netsync + - new: update workspaces to the selected revision; warn if the new revision + is part of another source tree + - new: change the passphrase of a key + - new: sort and filter the key list + - new: remember the entered passphrase of a key for later usage, f.e. + in commits or for netsync actions - new: setup a new project with a given database - - new: directly select the key to sign a revision with in the commit dialog + - new: directly select the key to sign a revision within the commit dialog - new: link to monotone manual from the help menu (FS#23) - improved: lighter, more eye-friendly colors for diff views (FS#24) - bugfix: guitone no longer considers the workspace to be invalid if the last ============================================================ --- guitone.pro 427722d346990785a3b3598c7bc49d40f606c179 +++ guitone.pro 8819a394eeff1b31d1077696920bf2397365d130 @@ -53,6 +53,7 @@ HEADERS = src/view/widgets/TreeView.h \ src/view/dialogs/RevisionDiff.h \ src/view/dialogs/KeyManagement.h \ src/view/dialogs/GenerateKeypair.h \ + src/view/dialogs/ChangeKeyPassword.h \ src/view/dialogs/About.h \ src/view/dialogs/ChangesetBrowser.h \ src/view/dialogs/RevisionManifest.h \ @@ -143,6 +144,7 @@ SOURCES += src/view/widgets/TreeView.cpp src/view/dialogs/RevisionDiff.cpp \ src/view/dialogs/KeyManagement.cpp \ src/view/dialogs/GenerateKeypair.cpp \ + src/view/dialogs/ChangeKeyPassword.cpp \ src/view/dialogs/About.cpp \ src/view/dialogs/ChangesetBrowser.cpp \ src/view/dialogs/RevisionManifest.cpp \ @@ -212,6 +214,7 @@ FORMS += res/forms/dialogs/select_revi res/forms/dialogs/revision_diff.ui \ res/forms/dialogs/key_management.ui \ res/forms/dialogs/generate_keypair.ui \ + res/forms/dialogs/change_key_password.ui \ res/forms/dialogs/about.ui \ res/forms/dialogs/changeset_browser.ui \ res/forms/dialogs/manifest.ui \ ============================================================ --- src/view/dialogs/DatabaseDialogManager.cpp 114836269d5a2ee7c9d086efdda82d69728f79b6 +++ src/view/dialogs/DatabaseDialogManager.cpp 2cc6cb87b8c1d5661f183fa98e2e9b251c63229c @@ -176,6 +176,16 @@ void DatabaseDialogManager::showKeyManag keyManagement, SIGNAL(generateKeypair()), this, SLOT(showGenerateKeypair()) ); + + connect( + keyManagement, SIGNAL(changeKeyPassword(const QString &)), + this, SLOT(showChangeKeyPassword(const QString &)) + ); + + connect( + changeKeyPassword, SIGNAL(passwordChanged()), + keyManagement, SLOT(readKeys()) + ); } keyManagement->readKeys(); ============================================================ --- src/view/dialogs/DialogManager.cpp 17c83a36fb60eb7e122c0b80b8e6ead7f8ba5796 +++ src/view/dialogs/DialogManager.cpp d333fbc6c81e14cb2f1dfc5bbe4ba6d0e78728d1 @@ -20,14 +20,16 @@ DialogManager::DialogManager(QWidget * p #include "vocab.h" DialogManager::DialogManager(QWidget * parentWidget) - : QObject(parentWidget), about(0), preferences(0), createDatabase(0) + : QObject(parentWidget), about(0), preferences(0), + createDatabase(0), changeKeyPassword(0) {} DialogManager::~DialogManager() { - if (about) delete about; - if (preferences) delete preferences; - if (createDatabase) delete createDatabase; + if (about) delete about; + if (preferences) delete preferences; + if (createDatabase) delete createDatabase; + if (changeKeyPassword) delete changeKeyPassword; } QWidget * DialogManager::parentWidget() const @@ -75,6 +77,22 @@ void DialogManager::showCreateDatabase() showDialog(createDatabase); } +void DialogManager::showChangeKeyPassword(const QString & keyHash) +{ + if (!changeKeyPassword) + { + changeKeyPassword = new ChangeKeyPassword(parentWidget()); + + connect( + changeKeyPassword, SIGNAL(passwordChanged()), + this, SIGNAL(passwordChanged()) + ); + } + + changeKeyPassword->init(keyHash); + showDialog(changeKeyPassword); +} + void DialogManager::showDialog(Dialog * dlg) { if (!openDialogs.contains(dlg)) ============================================================ --- src/view/dialogs/DialogManager.h eb6eec5ffed8e531e644cfa7da0c13f564339532 +++ src/view/dialogs/DialogManager.h 0afd1af8cca28d7519209a560784949e19988e10 @@ -22,6 +22,7 @@ #include "About.h" #include "Preferences.h" #include "CreateDatabase.h" +#include "ChangeKeyPassword.h" #include "vocab.h" #include @@ -39,18 +40,21 @@ public slots: void showAbout(); void showPreferences(); void showCreateDatabase(); + void showChangeKeyPassword(const QString &); signals: void databaseCreated(const QString &); + void passwordChanged(); void allDialogsClosed(); protected: QWidget * parentWidget() const; void showDialog(Dialog *); - About * about; - Preferences * preferences; - CreateDatabase * createDatabase; + About * about; + Preferences * preferences; + CreateDatabase * createDatabase; + ChangeKeyPassword * changeKeyPassword; private: void cleanup(); ============================================================ --- src/view/dialogs/KeyManagement.cpp c282dc5376939e8814d89faeb099d5b677e2d07b +++ src/view/dialogs/KeyManagement.cpp d0e3556aea2c55f38f012973839dfc46973951e1 @@ -55,39 +55,61 @@ KeyManagement::KeyManagement(QWidget * p proxyModel, SLOT(setFilterWildcard(const QString &)) ); - popupMenu = new QMenu(this); + actCopyHash = new QAction(tr("Copy key hash to clipboard"), this); + connect( + actCopyHash, SIGNAL(triggered()), + this, SLOT(copyKeyHashToClipboard()) + ); - QAction * act = new QAction(tr("Copy key hash to clipboard"), this); - connect(act, SIGNAL(triggered()), this, SLOT(copyKeyHashToClipboard())); - popupMenu->addAction(act); + actCopyGivenName = new QAction(tr("Copy given name to clipboard"), this); + connect( + actCopyGivenName, SIGNAL(triggered()), + this, SLOT(copyGivenNameToClipboard()) + ); - act = new QAction(tr("Copy given name to clipboard"), this); - connect(act, SIGNAL(triggered()), this, SLOT(copyGivenNameToClipboard())); - popupMenu->addAction(act); + actCopyLocalName = new QAction(tr("Copy local name to clipboard"), this); + connect( + actCopyLocalName, SIGNAL(triggered()), + this, SLOT(copyLocalNameToClipboard()) + ); - act = new QAction(tr("Copy local name to clipboard"), this); - connect(act, SIGNAL(triggered()), this, SLOT(copyLocalNameToClipboard())); - popupMenu->addAction(act); + actCopyPublicKey = new QAction(tr("Copy public key data to clipboard"), this); + connect( + actCopyPublicKey, SIGNAL(triggered()), + this, SLOT(copyPubkeyDataToClipboard()) + ); - popupMenu->addSeparator(); + actForgetPassword = new QAction(tr("Forget remembered password"), this); + connect( + actForgetPassword, SIGNAL(triggered()), + this, SLOT(forgetPassword()) + ); - act = new QAction(tr("Copy public key data to clipboard"), this); - connect(act, SIGNAL(triggered()), this, SLOT(copyPubkeyDataToClipboard())); - popupMenu->addAction(act); + actChangePassword = new QAction(tr("Change password"), this); + connect( + actChangePassword, SIGNAL(triggered()), + this, SLOT(changePassword()) + ); - popupMenu->addSeparator(); - - act = new QAction(tr("Drop key"), this); - connect(act, SIGNAL(triggered()), this, SLOT(dropKey())); - popupMenu->addAction(act); + actDrop = new QAction(tr("Drop key"), this); + connect( + actDrop, SIGNAL(triggered()), + this, SLOT(dropKey()) + ); } KeyManagement::~KeyManagement() { delete proxyModel; delete model; - qDeleteAll(popupMenu->findChildren()); - delete popupMenu; + + delete actCopyHash; + delete actCopyGivenName; + delete actCopyLocalName; + delete actCopyPublicKey; + delete actForgetPassword; + delete actChangePassword; + delete actDrop; } void KeyManagement::readKeys() @@ -98,7 +120,33 @@ void KeyManagement::contextMenuEvent(con void KeyManagement::contextMenuEvent(const QModelIndexList & indexList, const QPoint & p) { Q_UNUSED(indexList); - popupMenu->exec(p); + + Key * key = getKeyFromSelection(); + if (key == 0) return; + + QMenu popupMenu; + + popupMenu.addAction(actCopyHash); + popupMenu.addAction(actCopyGivenName); + popupMenu.addAction(actCopyLocalName); + + popupMenu.addSeparator(); + popupMenu.addAction(actCopyPublicKey); + + if (key->isPrivate()) + { + popupMenu.addSeparator(); + popupMenu.addAction(actChangePassword); + if (!Settings::getItemFromMap("KeyPasswords", key->hash).isNull()) + { + popupMenu.addAction(actForgetPassword); + } + } + + popupMenu.addSeparator(); + popupMenu.addAction(actDrop); + + popupMenu.exec(p); } Key * KeyManagement::getKeyFromSelection() const @@ -116,8 +164,7 @@ void KeyManagement::copyKeyHashToClipboa void KeyManagement::copyKeyHashToClipboard() { Key * key = getKeyFromSelection(); - if (key == 0) - return; + if (key == 0) return; QClipboard * clipboard = QApplication::clipboard(); clipboard->setText(key->hash); @@ -126,8 +173,7 @@ void KeyManagement::copyGivenNameToClipb void KeyManagement::copyGivenNameToClipboard() { Key * key = getKeyFromSelection(); - if (key == 0) - return; + if (key == 0) return; QClipboard * clipboard = QApplication::clipboard(); clipboard->setText(key->given_name); @@ -136,8 +182,7 @@ void KeyManagement::copyLocalNameToClipb void KeyManagement::copyLocalNameToClipboard() { Key * key = getKeyFromSelection(); - if (key == 0) - return; + if (key == 0) return; QClipboard * clipboard = QApplication::clipboard(); clipboard->setText(key->local_name); @@ -147,8 +192,7 @@ void KeyManagement::copyPubkeyDataToClip void KeyManagement::copyPubkeyDataToClipboard() { Key * key = getKeyFromSelection(); - if (key == 0) - return; + if (key == 0) return; QClipboard * clipboard = QApplication::clipboard(); @@ -171,12 +215,27 @@ void KeyManagement::copyPubkeyDataToClip clipboard->setText(output); } -// TODO: should be converted to automate dropkey, if available +void KeyManagement::forgetPassword() +{ + Key * key = getKeyFromSelection(); + if (key == 0) return; + + Settings::removeItemFromMap("KeyPasswords", key->hash); + model->readKeys(); +} + +void KeyManagement::changePassword() +{ + Key * key = getKeyFromSelection(); + if (key == 0) return; + emit changeKeyPassword(key->hash); +} + + void KeyManagement::dropKey() { Key * key = getKeyFromSelection(); - if (key == 0) - return; + if (key == 0) return; QMessageBox::StandardButton btn = QMessageBox::question( this, ============================================================ --- src/view/dialogs/KeyManagement.h 2661c45144f24e9241f4c73719c7e2ba9cc17f9b +++ src/view/dialogs/KeyManagement.h b53a2b1f764b2787cb72beaf6694f1904077e8fd @@ -38,6 +38,7 @@ signals: void readKeys(); signals: + void changeKeyPassword(const QString &); void generateKeypair(); private: @@ -45,15 +46,24 @@ private: Keys * model; QSortFilterProxyModel * proxyModel; - QMenu * popupMenu; DatabaseFile databaseFile; + QAction * actCopyHash; + QAction * actCopyGivenName; + QAction * actCopyLocalName; + QAction * actCopyPublicKey; + QAction * actForgetPassword; + QAction * actChangePassword; + QAction * actDrop; + private slots: void contextMenuEvent(const QModelIndexList &, const QPoint &); void copyKeyHashToClipboard(); void copyGivenNameToClipboard(); void copyLocalNameToClipboard(); void copyPubkeyDataToClipboard(); + void forgetPassword(); + void changePassword(); void dropKey(); };