diff options
author | Anne Jan Brouwer <annejan@noprotocol.com> | 2015-05-27 02:33:42 +0200 |
---|---|---|
committer | Anne Jan Brouwer <annejan@noprotocol.com> | 2015-05-27 02:33:42 +0200 |
commit | 28eb98d219d29174b615a1325878629fdf5398b6 (patch) | |
tree | 90ad6a24cfd25ede0658e96c0dc2613963c54b14 | |
parent | 3b07fb6b804058ffabe03d3749598a711bf4bfc5 (diff) | |
parent | 4b9df93ff57dfd82f4ea96b2ee876b75d613e64e (diff) |
Merge branch 'feature/first-start-wizard' into develop
32 files changed, 2657 insertions, 448 deletions
diff --git a/.travis.yml b/.travis.yml index a4ca80c3..85a9df89 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,9 @@ language: cpp + +os: + - linux + - osx + compiler: - gcc - clang @@ -34,3 +39,7 @@ notifications: - "chat.freenode.net#IJhack" on_success: change on_failure: always + +matrix: + allow_failures: + - os: osx @@ -15,6 +15,8 @@ While QtPass will work with Qt4, currently multi-line editing is restricted to Q QtPass requires GCC 4.7 or later or any other 2011 ISO C++ standard compliant compiler. +Logo based on https://commons.wikimedia.org/wiki/File:Heart-padlock.svg by AnonMoos. + Security considerations ----------------------- Using this program will not magically keep your passwords secure against @@ -50,9 +52,10 @@ Known issues Planned features ---------------- +* Re-encryption after users-change (optional ofcourse) * Showing path in Add and Edit screen (currently sometimes confusing where I'm adding this password) * Right click handlers for file/folder and content -* First use wizards to set up password-store (and decryption key, currently always the gpg default key) +* ~~first use wizards to set up password-store (and decryption key, currently always the gpg default key)~~ * Profiles (to allow use of multiple password stores and decryption keys) with dropdown in main screen * Password generation with options for what kind you'd like * Templates (username, url etc) in Add / Edit screen (configurable templates) @@ -80,4 +83,3 @@ Further reading [Documentation](http://qtpass.org/) [Source code](https://github.com/IJHack/qtpass) - diff --git a/changelog b/changelog new file mode 120000 index 00000000..d526672c --- /dev/null +++ b/changelog @@ -0,0 +1 @@ +debian/changelog
\ No newline at end of file @@ -1,14 +1,20 @@ #include "dialog.h" #include "ui_dialog.h" +#include "mainwindow.h" +#include "keygendialog.h" +#include <QDebug> +#include <QMessageBox> +#include <QDir> /** * @brief Dialog::Dialog * @param parent */ -Dialog::Dialog(QWidget *parent) : +Dialog::Dialog(MainWindow *parent) : QDialog(parent), ui(new Ui::Dialog) { + mainWindow = parent; ui->setupUi(this); } @@ -17,6 +23,9 @@ Dialog::Dialog(QWidget *parent) : */ Dialog::~Dialog() { + mainWindow->setGitExecutable(ui->gitPath->text()); + mainWindow->setGpgExecutable(ui->gpgPath->text()); + mainWindow->setPassExecutable(ui->passPath->text()); } /** @@ -156,6 +165,7 @@ QString Dialog::selectExecutable() { QString Dialog::selectFolder() { QFileDialog dialog(this); dialog.setFileMode(QFileDialog::Directory); + dialog.setFilter(QDir::NoFilter); dialog.setOption(QFileDialog::ShowDirsOnly); if (dialog.exec()) { return dialog.selectedFiles().first(); @@ -202,7 +212,7 @@ void Dialog::on_toolButtonPass_clicked() void Dialog::on_toolButtonStore_clicked() { QString store = selectFolder(); - if (store != "") { + if (store != "") { // TODO call check ui->storePath->setText(store); } } @@ -348,3 +358,55 @@ void Dialog::addGPGId(bool addGPGId) { ui->checkBoxAddGPGId->setChecked(addGPGId); } +/** + * @brief Dialog::wizard + */ +void Dialog::wizard() +{ + //mainWindow->checkConfig(); + + QString gpg = ui->gpgPath->text(); + //QString gpg = mainWindow->getGpgExecutable(); + if(!QFile(gpg).exists()){ + QMessageBox::critical(this, tr("GnuPG not found"), + tr("Please install GnuPG on your system.<br>Install <strong>gpg</strong> using your favorite package manager<br>or <a href=\"https://www.gnupg.org/download/#sec-1-2\">download</a> it from GnuPG.org")); + + // TODO REST ? + } + + QStringList names = mainWindow->getSecretKeys(); + //qDebug() << names; + if (QFile(gpg).exists() && names.empty()) { + KeygenDialog d(this); + d.exec(); + } + + QString passStore = ui->storePath->text(); + if(!QFile(passStore + ".gpg-id").exists()){ + QMessageBox::critical(this, tr("Password store not initialised"), + tr("The folder %1 doesn't seem to be a password store or is not yet initialised.").arg(passStore)); + while(!QFile(passStore).exists()) { + on_toolButtonStore_clicked(); + passStore = ui->storePath->text(); + } + if (!QFile(passStore + ".gpg-id").exists()) { + // apears not to be store + // init yes / no ? + mainWindow->userDialog(passStore); + } + } + + // Can you use the store? + + + //ui->gpgPath->setText(gpg); +} + +/** + * @brief Dialog::genKey + * @param QString batch + */ +void Dialog::genKey(QString batch, QDialog *dialog) +{ + mainWindow->genKey(batch, dialog); +} @@ -3,8 +3,12 @@ #include <QDialog> #include <QFileDialog> +#include "mainwindow.h" namespace Ui { + +struct UserInfo; + class Dialog; } @@ -13,7 +17,7 @@ class Dialog : public QDialog Q_OBJECT public: - explicit Dialog(QWidget *parent = 0); + explicit Dialog(MainWindow *parent); ~Dialog(); void setPassPath(QString); void setGitPath(QString); @@ -37,6 +41,8 @@ public: bool hidePassword(); bool hideContent(); bool addGPGId(); + void wizard(); + void genKey(QString, QDialog *); private slots: void on_radioButtonNative_clicked(); @@ -53,6 +59,7 @@ private: void setGroupBoxState(); QString selectExecutable(); QString selectFolder(); + MainWindow *mainWindow; }; #endif // DIALOG_H diff --git a/keygendialog.cpp b/keygendialog.cpp new file mode 100644 index 00000000..9932ea26 --- /dev/null +++ b/keygendialog.cpp @@ -0,0 +1,141 @@ +#include "keygendialog.h" +#include "ui_keygendialog.h" +#include "progressindicator.h" +#include <QDebug> +#include <QMessageBox> + +KeygenDialog::KeygenDialog(Dialog *parent) : + QDialog(parent), + ui(new Ui::KeygenDialog) +{ + ui->setupUi(this); + dialog = parent; +} + +KeygenDialog::~KeygenDialog() +{ + delete ui; +} + +void KeygenDialog::on_passphrase1_textChanged(const QString &arg1) +{ + if (ui->passphrase1->text() == ui->passphrase2->text()) { + ui->buttonBox->setEnabled(true); + replace("Passphrase", arg1); + if (arg1 == "") { + no_protection(true); + } else { + no_protection(false); + } + } else { + ui->buttonBox->setEnabled(false); + } +} + +void KeygenDialog::on_passphrase2_textChanged(const QString &arg1) +{ + on_passphrase1_textChanged(arg1); +} + +void KeygenDialog::on_checkBox_stateChanged(int arg1) +{ + if (arg1) { + ui->plainTextEdit->setReadOnly(false); + ui->plainTextEdit->setEnabled(true); + } else { + ui->plainTextEdit->setReadOnly(true); + ui->plainTextEdit->setEnabled(false); + } +} + +void KeygenDialog::on_email_textChanged(const QString &arg1) +{ + replace("Name-Email", arg1); +} + +void KeygenDialog::on_name_textChanged(const QString &arg1) +{ + replace("Name-Real", arg1); +} + +/** + * @brief KeygenDialog::replace + * @param key + * @param value + */ +void KeygenDialog::replace(QString key, QString value) +{ + QStringList clear; + QString expert = ui->plainTextEdit->toPlainText(); + QStringList lines = expert.split(QRegExp("[\r\n]"),QString::SkipEmptyParts); + foreach (QString line, lines) { + line.replace(QRegExp(key+":.*"), key + ": " + value); + if (key == "Passphrase") { + line.replace("%no-protection", "Passphrase: " + value); + } + clear.append(line); + } + ui->plainTextEdit->setPlainText(clear.join("\n")); +} + +/** + * @brief KeygenDialog::no_protection + * @param enable + */\ +void KeygenDialog::no_protection(bool enable) +{ + QStringList clear; + QString expert = ui->plainTextEdit->toPlainText(); + QStringList lines = expert.split(QRegExp("[\r\n]"),QString::SkipEmptyParts); + foreach (QString line, lines) { + bool remove = false; + if (!enable) { + if (line.indexOf("%no-protection") == 0) { + remove = true; + } + } else { + if (line.indexOf("Passphrase") == 0) { + line = "%no-protection"; + } + } + if (!remove) { + clear.append(line); + } + } + ui->plainTextEdit->setPlainText(clear.join("\n")); +} + +/** + * @brief KeygenDialog::done + * @param r + */ +void KeygenDialog::done(int r) +{ + if(QDialog::Accepted == r) // ok was pressed + { + ui->widget->setEnabled(false); + ui->buttonBox->setEnabled(false); + ui->checkBox->setEnabled(false); + ui->plainTextEdit->setEnabled(false); + + QProgressIndicator* pi = new QProgressIndicator(); + pi->startAnimation(); + pi->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + ui->frame->hide(); + ui->label->setText(QString("We need to generate a lot of random bytes. It is a good idea to perform<br/>") + + "some other action (type on the keyboard, move the mouse, utilize the<br/>" + + "disks) during the prime generation; this gives the random number<br/>" + + "generator a better chance to gain enough entropy."); + + this->layout()->addWidget(pi); + + this->show(); + dialog->genKey(ui->plainTextEdit->toPlainText(), this); + } + else // cancel, close or exc was pressed + { + QDialog::done(r); + return; + } +} diff --git a/keygendialog.h b/keygendialog.h new file mode 100644 index 00000000..d808816a --- /dev/null +++ b/keygendialog.h @@ -0,0 +1,35 @@ +#ifndef KEYGENDIALOG_H +#define KEYGENDIALOG_H + +#include <QDialog> +#include "dialog.h" + +namespace Ui { +class KeygenDialog; +} + +class KeygenDialog : public QDialog +{ + Q_OBJECT + +public: + explicit KeygenDialog(Dialog *parent = 0); + ~KeygenDialog(); + +private slots: + void on_passphrase1_textChanged(const QString &arg1); + void on_passphrase2_textChanged(const QString &arg1); + void on_checkBox_stateChanged(int arg1); + void on_email_textChanged(const QString &arg1); + void on_name_textChanged(const QString &arg1); + +private: + Ui::KeygenDialog *ui; + void replace(QString, QString); + void done(int r); + void no_protection(bool enable); + Dialog *dialog; + +}; + +#endif // KEYGENDIALOG_H diff --git a/keygendialog.ui b/keygendialog.ui new file mode 100644 index 00000000..740e80e2 --- /dev/null +++ b/keygendialog.ui @@ -0,0 +1,219 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>KeygenDialog</class> + <widget class="QDialog" name="KeygenDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>606</width> + <height>480</height> + </rect> + </property> + <property name="windowTitle"> + <string>Generate GnuPG keypair</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Generate a new key pair</string> + </property> + </widget> + </item> + <item> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QWidget" name="widget" native="true"> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="0" colspan="2"> + <widget class="QLabel" name="labelPassphrase"> + <property name="text"> + <string>Passphrase</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="labelEmail"> + <property name="text"> + <string>Email</string> + </property> + </widget> + </item> + <item row="2" column="2" colspan="3"> + <widget class="QLineEdit" name="passphrase2"> + <property name="echoMode"> + <enum>QLineEdit::Password</enum> + </property> + </widget> + </item> + <item row="0" column="1" colspan="2"> + <widget class="QLineEdit" name="email"/> + </item> + <item row="0" column="3"> + <widget class="QLabel" name="labelName"> + <property name="text"> + <string>Name</string> + </property> + </widget> + </item> + <item row="1" column="2" colspan="3"> + <widget class="QLineEdit" name="passphrase1"> + <property name="echoMode"> + <enum>QLineEdit::Password</enum> + </property> + </widget> + </item> + <item row="0" column="4"> + <widget class="QLineEdit" name="name"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QLabel" name="labelPassphraseInfo"> + <property name="text"> + <string><html><head/><body><p>There is no limit on the length of a passphrase, and it should be carefully chosen. From the perspective of security, the passphrase to unlock the private key is one of the weakest points in GnuPG (and other public-key encryption systems as well) since it is the only protection you have if another individual gets your private key. <br/>Ideally, the passphrase should not use words from a dictionary and should mix the case of alphabetic characters as well as use non-alphabetic characters.<br/>A good passphrase is crucial to the secure use of GnuPG.</p></body></html></string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="checkBox"> + <property name="text"> + <string>Expert</string> + </property> + </widget> + </item> + <item> + <widget class="QPlainTextEdit" name="plainTextEdit"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="plainText"> + <string># QtPass GPG key generator +# +# first test version please comment +# +%echo Generating a default key +Key-Type: default +Subkey-Type: default +Name-Real: +Name-Comment: QtPass +Name-Email: +Expire-Date: 0 +%no-protection +# Do a commit here, so that we can later print "done" :-) +%commit +%echo done</string> + </property> + <property name="textInteractionFlags"> + <set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + <property name="backgroundVisible"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="labelExpertInfo"> + <property name="text"> + <string>For expert options check out the <a href="https://www.gnupg.org/documentation/manuals/gnupg/Unattended-GPG-key-generation.html">GnuPG manual</a></string> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>email</tabstop> + <tabstop>name</tabstop> + <tabstop>passphrase1</tabstop> + <tabstop>passphrase2</tabstop> + <tabstop>checkBox</tabstop> + <tabstop>plainTextEdit</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>KeygenDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>KeygenDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/localization/localization_de_DE.qm b/localization/localization_de_DE.qm Binary files differindex dfee88af..841b292a 100644 --- a/localization/localization_de_DE.qm +++ b/localization/localization_de_DE.qm diff --git a/localization/localization_de_DE.ts b/localization/localization_de_DE.ts index ce62a87a..9f78b6ad 100644 --- a/localization/localization_de_DE.ts +++ b/localization/localization_de_DE.ts @@ -9,80 +9,93 @@ <translation>Einstellungen</translation> </message> <message> - <location filename="../dialog.ui" line="20"/> + <location filename="../dialog.ui" line="81"/> <source>Pass</source> <translation>Pass</translation> </message> <message> - <location filename="../dialog.ui" line="26"/> - <location filename="../dialog.ui" line="72"/> - <location filename="../dialog.ui" line="79"/> - <location filename="../dialog.ui" line="135"/> + <location filename="../dialog.ui" line="64"/> + <location filename="../dialog.ui" line="71"/> + <location filename="../dialog.ui" line="87"/> + <location filename="../dialog.ui" line="125"/> <source>...</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dialog.ui" line="33"/> + <location filename="../dialog.ui" line="94"/> <source>Executable pass</source> <translation>Ausführbares pass</translation> </message> <message> - <location filename="../dialog.ui" line="46"/> + <location filename="../dialog.ui" line="38"/> <source>Native</source> <translation>Nativ</translation> </message> <message> - <location filename="../dialog.ui" line="58"/> + <location filename="../dialog.ui" line="22"/> + <source>&Native git/gpg</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dialog.ui" line="29"/> + <source>&Use pass</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dialog.ui" line="50"/> <source>Executable git</source> <translation>Ausführbares git</translation> </message> <message> - <location filename="../dialog.ui" line="65"/> + <location filename="../dialog.ui" line="57"/> <source>Executable gpg</source> <translation>Ausführbares gpg</translation> </message> <message> - <location filename="../dialog.ui" line="91"/> <source>Native git/gpg</source> - <translation>Systemeigenes git/gpg</translation> + <translation type="vanished">Systemeigenes git/gpg</translation> </message> <message> - <location filename="../dialog.ui" line="98"/> <source>Use pass</source> - <translation>Pass benutzen</translation> + <translation type="vanished">Pass benutzen</translation> </message> <message> - <location filename="../dialog.ui" line="117"/> + <location filename="../dialog.ui" line="107"/> <source>Other</source> <translation>Weiteres</translation> </message> <message> - <location filename="../dialog.ui" line="125"/> + <location filename="../dialog.ui" line="115"/> <source>Folder password-store</source> <translation>Ordner für Passwortspeicher</translation> </message> <message> - <location filename="../dialog.ui" line="146"/> + <location filename="../dialog.ui" line="136"/> <source>Clipboard</source> <translation>Zwischenablage</translation> </message> <message> - <location filename="../dialog.ui" line="153"/> + <location filename="../dialog.ui" line="143"/> <source>Autoclear</source> <translation>Automatisch löschen</translation> </message> <message> - <location filename="../dialog.ui" line="160"/> + <location filename="../dialog.ui" line="164"/> + <source>Automatically add .gpg-id files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../dialog.ui" line="176"/> <source>Seconds</source> <translation>Sekunden</translation> </message> <message> - <location filename="../dialog.ui" line="170"/> + <location filename="../dialog.ui" line="150"/> <source>Hide password</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../dialog.ui" line="177"/> + <location filename="../dialog.ui" line="157"/> <source>Hide content</source> <translation type="unfinished"></translation> </message> @@ -95,103 +108,266 @@ <translation>QtPass</translation> </message> <message> - <location filename="../mainwindow.ui" line="23"/> + <location filename="../mainwindow.ui" line="42"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.ui" line="49"/> + <source>Edit</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.ui" line="56"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.ui" line="63"/> + <source>Push</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.ui" line="70"/> <source>Update</source> <translation>Aktualisieren</translation> </message> <message> - <location filename="../mainwindow.ui" line="30"/> + <location filename="../mainwindow.ui" line="77"/> + <source>Users</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../mainwindow.ui" line="84"/> <source>Config</source> <translation>Einstellungen</translation> </message> <message> - <location filename="../mainwindow.ui" line="46"/> + <location filename="../mainwindow.ui" line="119"/> <source>X</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../mainwindow.ui" line="58"/> + <location filename="../mainwindow.ui" line="132"/> <source><!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:'.Helvetica Neue DeskInterface'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:16px; margin-left:0px; |