1
0
mirror of https://github.com/QRouland/UTPass.git synced 2025-04-21 21:46:31 +00:00

Compare commits

..

10 Commits

21 changed files with 132 additions and 93 deletions

24
CHANGELOG.md Normal file
View File

@ -0,0 +1,24 @@
# 0.0.3: Git Initial Support and Move to RNP
- Port app to Focal
- Improve UI :
- Follow human interface guidelines
- Fix various components color to work with black theme
- Rewrite of Pass Plugin:
- Move from GPGMe to RNP for GPG operations due to issues running GPG agent in a confined app
- Improve multithreading code for GPG operations
- Add Git HTTP and HTTP AUTH clone for password store import feature
- Add delete password store feature
# 0.0.2 : Added translations
- Added French by Anne17 and Reda
- Added Catalan by Joan CiberSheep
- Added Spanish by Advocatux and Reda
Thanks to all the translators !
# 0.0.1 : Initial Release
- Import of gpg keys via file
- Suppression of gpg keys
- Import of password via a password store zip
- Password decryption
- Password copy to clipboard

View File

@ -20,10 +20,13 @@ Assuming that there are already passwords in another device using [ZX2C4s pas
Export gpg private keys in order to decrypt passwords: Export gpg private keys in order to decrypt passwords:
``` ```
gpg --output keys.gpg --export-secret-keys gpg --output keys.gpg --export-secret-keys <key>
``` ```
Export passwords, assuming they reside in *.password-store* folder: If your password store is already hosted in a Git repository that provides HTTP or HTTP with authentication for cloning (we're working to have support for SSH soon), you can clone your password store directly from the app.
Otherwise, follow these steps to export it to a ZIP file for importing.
Export passwords to a ZIP archive, assuming they reside in the *.password-store* folder:
``` ```
zip passwords.zip -r .password-store/ zip passwords.zip -r .password-store/
``` ```
@ -44,11 +47,9 @@ See [Contributing wiki page](https://github.com/QRouland/UTPass/wiki/Contributin
Some useful links related to UTPass development : Some useful links related to UTPass development :
* [Ubports](https://ubports.com/) : Ubuntu Touch Community * [Ubports](https://ubports.com/) : Ubuntu Touch Community
* [ZX2C4s pass command line application](https://www.passwordstore.org/) : the standard unix password manager. * [ZX2C4s pass command line application](https://www.passwordstore.org/) : The standard unix password manager.
* [Clickable](https://github.com/bhdouglass/clickable) : Compile, build, and deploy Ubuntu Touch click packages * [Clickable](https://github.com/bhdouglass/clickable) : Compile, build, and deploy Ubuntu Touch click packages
* [GnuPG](https://gnupg.org/): The GNU Privacy Guard * [Rnp](https://github.com/rnpgp/rnp) : High performance C++ OpenPGP library used by Mozilla Thunderbird
* [Gpgme](https://www.gnupg.org/software/gpgme/index.html) : GnuPG Made Easy (GPGME) is a library designed to make access to GnuPG easier for applications
## License ## License

View File

@ -10,7 +10,7 @@
"content-hub": "UTPass.contenthub" "content-hub": "UTPass.contenthub"
} }
}, },
"version": "0.0.3-dev", "version": "0.0.3",
"maintainer": "Quentin Rouland <quentin@qrouland.com>", "maintainer": "Quentin Rouland <quentin@qrouland.com>",
"framework" : "ubuntu-sdk-20.04" "framework" : "ubuntu-sdk-20.04"
} }

View File

@ -22,13 +22,13 @@ CloneJob::CloneJob(QString url, QString path, cred_type cred):
void CloneJob::run() void CloneJob::run()
{ {
auto tmp_dir = this->cloneSetup(); auto tmp_dir = this->cloneSetup();
auto err = this->clone(this->m_url, tmp_dir.absolutePath(), this->m_cred, this->credentialsCB); auto ret = this->clone(this->m_url, tmp_dir.absolutePath(), this->m_cred, this->credentialsCB);
if (!err) { if (ret) {
this->moveToDestination(tmp_dir, this->m_path); this->moveToDestination(tmp_dir, this->m_path);
} }
this->cloneTearDown(tmp_dir); this->cloneCleanUp(tmp_dir);
emit resultReady(err); // TODO Clean error handling to return specifics errors for the ui emit resultReady(!ret); // TODO Clean error handling to return specifics errors for the ui
} }
@ -37,26 +37,26 @@ QDir CloneJob::cloneSetup()
QDir tmp_dir(QStandardPaths::writableLocation( QStandardPaths::CacheLocation).append("/clone")); QDir tmp_dir(QStandardPaths::writableLocation( QStandardPaths::CacheLocation).append("/clone"));
tmp_dir.removeRecursively(); tmp_dir.removeRecursively();
qDebug() << "Temp dir path is " << tmp_dir.absolutePath(); qDebug() << "[CloneJob]Temp dir path is " << tmp_dir.absolutePath();
return tmp_dir; return tmp_dir;
} }
bool CloneJob::cloneTearDown(QDir tmp_dir) bool CloneJob::cloneCleanUp(QDir tmp_dir)
{ {
return tmp_dir.removeRecursively(); return tmp_dir.removeRecursively();
} }
bool CloneJob::moveToDestination(QDir tmp_dir, QString path) bool CloneJob::moveToDestination(QDir tmp_dir, QString path)
{ {
qDebug() << "Removing password_store " << path; qDebug() << "[CloneJob] Removing password_store " << path;
QDir destination_dir(path); QDir destination_dir(path);
destination_dir.removeRecursively(); destination_dir.removeRecursively();
qDebug() << "Moving cloned content to destination dir"; qDebug() << "[CloneJob] Moving cloned content to destination dir";
QDir dir; QDir dir;
qDebug() << tmp_dir.absolutePath() << " to " << destination_dir.absolutePath(); qDebug() << "[CloneJob]" << tmp_dir.absolutePath() << " to " << destination_dir.absolutePath();
return dir.rename(tmp_dir.absolutePath(), destination_dir.absolutePath()); // TODO Better error handling return dir.rename(tmp_dir.absolutePath(), destination_dir.absolutePath()); // TODO Better error handling
} }
@ -69,12 +69,17 @@ bool CloneJob::clone(QString url, QString path, cred_type cred, git_cred_acquire
opts.fetch_opts.callbacks.payload = &cred; opts.fetch_opts.callbacks.payload = &cred;
int ret = git_clone(&repo, url.toLocal8Bit().data(), path.toLocal8Bit().data(), &opts); int ret = git_clone(&repo, url.toLocal8Bit().data(), path.toLocal8Bit().data(), &opts);
if (ret != 0) { if (ret == GIT_EUSER ) {
qDebug() << git_error_last()->message; qDebug() << "[CloneJob] CallBack Error";
} else if (ret != 0) {
auto err = git_error_last(); // TODO Better error handling for return ui messages
if (err) {
qDebug() << "[CloneJob]" << git_error_last()->message;
}
} }
if (repo) { if (repo) {
git_repository_free(repo); git_repository_free(repo);
}// TODO Better error handling }
return ret != 0; return ret == 0;
} }

View File

@ -70,7 +70,7 @@ private:
* @param tmp_dir The temporary directory to tear down. * @param tmp_dir The temporary directory to tear down.
* @return `true` if the teardown was successful, `false` otherwise. * @return `true` if the teardown was successful, `false` otherwise.
*/ */
static bool cloneTearDown(QDir tmp_dir); static bool cloneCleanUp(QDir tmp_dir);
/** /**
* @brief Clones a repository from a specified URL. * @brief Clones a repository from a specified URL.

View File

@ -25,27 +25,27 @@ int GitJob::credentialsCB(git_cred **out, const char *url, const char *username_
auto v = overload { auto v = overload {
[](const HTTP & x) [](const HTTP & x)
{ {
qDebug() << "credentialsCB : HTTP "; qDebug() << "[GitJob] credentialsCB : HTTP ";
qWarning() << "credentialsCB : callback should never be call for HTTP "; qWarning() << "[GitJob] credentialsCB : callback should never be call for HTTP ";
return (int) GIT_EUSER; return (int) GIT_EUSER;
}, },
[&out, &username_from_url](const HTTPUserPass & x) [&out, &username_from_url](const HTTPUserPass & x)
{ {
qDebug() << "credentialsCB : HTTPUserPass "; qDebug() << "[GitJob] credentialsCB : HTTPUserPass ";
if (!username_from_url) { if (!username_from_url) {
qWarning() << "credentials_cb : no username provided "; qWarning() << "[GitJob] credentials_cb : no username provided ";
return (int) GIT_EUSER; return (int) GIT_EUSER;
} }
return git_cred_userpass_plaintext_new(out, username_from_url, x.pass.toLocal8Bit().constData()); return git_cred_userpass_plaintext_new(out, username_from_url, x.pass.toLocal8Bit().constData());
}, },
[](const SSHPass & x) [](const SSHPass & x)
{ {
qWarning() << "credentials_cb : SSHAuth to be implemented "; qWarning() << "[GitJob] credentials_cb : SSHAuth to be implemented ";
return (int) GIT_EUSER; return (int) GIT_EUSER;
}, // TODO }, // TODO
[](const SSHKey & x) [](const SSHKey & x)
{ {
qWarning() << "credentials_cb : SSHKey to be implemented "; qWarning() << "[GitJob] credentials_cb : SSHKey to be implemented ";
return (int) GIT_EUSER; return (int) GIT_EUSER;
} // TODO } // TODO
}; };

View File

@ -35,7 +35,7 @@ void DecryptJob::run()
ret = rnp_output_memory_get_buf(output, &buf, &buf_len, false); ret = rnp_output_memory_get_buf(output, &buf, &buf_len, false);
} }
if (ret == RNP_SUCCESS) { if (ret == RNP_SUCCESS) {
data = QString::fromUtf8((char*)buf); data = QString::fromUtf8((char*)buf, buf_len);
} }
rnp_input_destroy(input); rnp_input_destroy(input);

View File

@ -95,12 +95,12 @@ void Pass::slotShowSucceed(QString encrypted_file_path, QString plain_text)
bool Pass::deletePasswordStore() bool Pass::deletePasswordStore()
{ {
qInfo() << "[Pass] Delete Password Store at" << this->password_store(); qInfo() << "[Pass] Delete Password Store at" << this->m_password_store;
if (!this->m_sem->tryAcquire(1, 500)) { if (!this->m_sem->tryAcquire(1, 500)) {
qInfo() << "[Pass] A command is already running"; qInfo() << "[Pass] A command is already running";
return false; return false;
} }
auto job = new RmJob(this->password_store()); auto job = new RmJob(this->m_password_store);
connect(job, &RmJob::resultReady, this, &Pass::slotDeletePasswordStoreResult); connect(job, &RmJob::resultReady, this, &Pass::slotDeletePasswordStoreResult);
connect(job, &RmJob::finished, job, &QObject::deleteLater); connect(job, &RmJob::finished, job, &QObject::deleteLater);
job->start(); job->start();
@ -109,6 +109,7 @@ bool Pass::deletePasswordStore()
void Pass::slotDeletePasswordStoreResult(bool err) void Pass::slotDeletePasswordStoreResult(bool err)
{ {
this->initPasswordStore(); // reinit an empty password-store
if (err) { if (err) {
qInfo() << "[Pass] delete Password Store Failed"; qInfo() << "[Pass] delete Password Store Failed";
emit deletePasswordStoreFailed("failed to delete password store"); emit deletePasswordStoreFailed("failed to delete password store");

View File

@ -22,8 +22,8 @@ extern "C" {
class Pass : public QObject class Pass : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString password_store MEMBER m_password_store READ password_store WRITE set_password_store ) Q_PROPERTY(QString password_store MEMBER m_password_store WRITE set_password_store )
Q_PROPERTY(QString gpg_home MEMBER m_gpg_home READ gpg_home WRITE set_gpg_home ) Q_PROPERTY(QString gpg_home MEMBER m_gpg_home WRITE set_gpg_home )
private slots: private slots:
/** /**
@ -166,15 +166,6 @@ public:
*/ */
Pass(); Pass();
/**
* @brief Gets the path to the password store.
* @return The path to the password store.
*/
QString password_store() const
{
return this->m_password_store;
};
/** /**
* @brief Set the path to the password store. * @brief Set the path to the password store.
* @param The path to the password store. * @param The path to the password store.
@ -185,15 +176,6 @@ public:
this->m_password_store = password_store; this->m_password_store = password_store;
}; };
/**
* @brief Gets the path to the gpg home.
* @return The path to the gpg home.
*/
QString gpg_home() const
{
return this->m_gpg_home;
};
/** /**
* @brief Set the path to the gpg hom. * @brief Set the path to the gpg hom.
* @param The path to the gpg hom * @param The path to the gpg hom

View File

@ -52,6 +52,5 @@ void UnzipJob::run()
qDebug() << dir_import_path << " to " << this->m_dir_out; qDebug() << dir_import_path << " to " << this->m_dir_out;
auto ret = dir.rename(dir_import_path, this->m_dir_out.absolutePath()); auto ret = dir.rename(dir_import_path, this->m_dir_out.absolutePath());
tmp_dir.removeRecursively();; tmp_dir.removeRecursively();;
emit resultReady(ret); emit resultReady(!ret);
} }

View File

@ -29,7 +29,7 @@ void Utils::unzipResult(bool err)
qDebug() << "Unzip Result"; qDebug() << "Unzip Result";
if (err) { if (err) {
qInfo() << "Unzip Failed"; qInfo() << "Unzip Failed";
emit unzipFailed("failed to unzip archive"); emit unzipFailed();
} else { } else {
qInfo() << "Unzip Succeed"; qInfo() << "Unzip Succeed";
@ -45,3 +45,14 @@ QString Utils::manifestPath()
qInfo() << "Manifest path : " << path; qInfo() << "Manifest path : " << path;
return path; return path;
} }
bool Utils::rmFile(QUrl file_url)
{
return QFile::remove(file_url.toLocalFile());
}
bool Utils::rmDir(QUrl dir_url)
{
QDir dir(dir_url.toLocalFile());
return dir.removeRecursively();
}

View File

@ -34,9 +34,8 @@ signals:
/** /**
* @brief Emitted when the unzipping operation fails. * @brief Emitted when the unzipping operation fails.
* @param message The error message describing the failure.
*/ */
void unzipFailed(QString message); void unzipFailed();
private: private:
std::unique_ptr<QSemaphore> m_sem; /**< Semaphore for managing concurrent operations. */ std::unique_ptr<QSemaphore> m_sem; /**< Semaphore for managing concurrent operations. */
@ -48,19 +47,14 @@ public:
Utils(); Utils();
/** /**
* @brief Unzips a ZIP file to the specified output directory. * @brief Start a job to unzips a ZIP file to the specified output directory.
*
* This method extracts the contents of a ZIP file from the specified URL and saves them to the provided
* output directory path.
* *
* @param zip_url The URL of the ZIP file to unzip. * @param zip_url The URL of the ZIP file to unzip.
* @param dir_out The output directory where the contents of the ZIP file should be extracted. * @param dir_out The output directory where the contents of the ZIP file should be extracted.
* @return `true` if the unzipping operation was successful, `false` otherwise. * @return `true` if the unzipping job is started successfullly, `false` otherwise.
*/ */
Q_INVOKABLE bool unzip(QUrl zip_url, QString dir_out); Q_INVOKABLE bool unzip(QUrl zip_url, QString dir_out);
/** /**
* @brief Retrieves the path to the manifest data. * @brief Retrieves the path to the manifest data.
* *
@ -70,6 +64,22 @@ public:
*/ */
Q_INVOKABLE QString manifestPath(); Q_INVOKABLE QString manifestPath();
/**
* @brief Removes a file located at the specified URL.
*
* @param file_url The URL of the file to remove.
* @return `true` if the file was successfully removed; `false` otherwise.
*/
Q_INVOKABLE bool rmFile(QUrl file_url);
/**
* @brief Removes a directory located at the specified URL.
*
* @param dir_url The URL of the directory to remove.
* @return `true` if the directory was successfully removed; `false` otherwise.
*/
Q_INVOKABLE bool rmDir(QUrl dir_url);
}; };
#endif #endif

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: utpass.qrouland\n" "Project-Id-Version: utpass.qrouland\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-03 21:35+0100\n" "POT-Creation-Date: 2025-02-04 17:49+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -122,8 +122,8 @@ msgid "You're are about to delete<br>the current Password Store.<br>Continue ?"
msgstr "" msgstr ""
#: ../qml/pages/settings/DeleteRepo.qml:56 #: ../qml/pages/settings/DeleteRepo.qml:56
#: ../qml/pages/settings/ImportZip.qml:64 #: ../qml/pages/settings/ImportZip.qml:66
#: ../qml/pages/settings/InfoKeys.qml:170 #: ../qml/pages/settings/InfoKeys.qml:174
#: ../qml/pages/settings/git/ImportGitClone.qml:56 #: ../qml/pages/settings/git/ImportGitClone.qml:56
msgid "Yes" msgid "Yes"
msgstr "" msgstr ""
@ -137,37 +137,37 @@ msgid "Password Store deleted !"
msgstr "" msgstr ""
#: ../qml/pages/settings/DeleteRepo.qml:90 #: ../qml/pages/settings/DeleteRepo.qml:90
#: ../qml/pages/settings/InfoKeys.qml:212 #: ../qml/pages/settings/InfoKeys.qml:216
msgid "Info Keys" msgid "Info Keys"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportKeyFile.qml:59 #: ../qml/pages/settings/ImportKeyFile.qml:61
msgid "Key import failed !" msgid "Key import failed !"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportKeyFile.qml:68 #: ../qml/pages/settings/ImportKeyFile.qml:70
msgid "Key successfully imported !" msgid "Key successfully imported !"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportKeyFile.qml:79 #: ../qml/pages/settings/ImportKeyFile.qml:81
msgid "GPG Key Import" msgid "GPG Key Import"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportZip.qml:63 #: ../qml/pages/settings/ImportZip.qml:65
msgid "" msgid ""
"Importing a new zip will delete<br>any existing password store!<br>Continue ?" "Importing a new zip will delete<br>any existing password store!<br>Continue ?"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportZip.qml:77 #: ../qml/pages/settings/ImportZip.qml:79
msgid "Password store import failed !" msgid "Password store import failed !"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportZip.qml:86 #: ../qml/pages/settings/ImportZip.qml:88
#: ../qml/pages/settings/git/ImportGitClone.qml:78 #: ../qml/pages/settings/git/ImportGitClone.qml:78
msgid "Password store sucessfully imported !" msgid "Password store sucessfully imported !"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportZip.qml:98 #: ../qml/pages/settings/ImportZip.qml:100
msgid "Zip Password Store Import" msgid "Zip Password Store Import"
msgstr "" msgstr ""
@ -179,27 +179,27 @@ msgstr ""
msgid "Key ID :" msgid "Key ID :"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:120 #: ../qml/pages/settings/InfoKeys.qml:124
msgid "Users IDs : " msgid "User IDs : "
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:147 #: ../qml/pages/settings/InfoKeys.qml:151
msgid "Delete this key" msgid "Delete this key"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:169 #: ../qml/pages/settings/InfoKeys.qml:173
msgid "You're are about to delete<br>%1.<br>Continue ?" msgid "You're are about to delete<br>%1.<br>Continue ?"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:183 #: ../qml/pages/settings/InfoKeys.qml:187
msgid "Key removal failed !" msgid "Key removal failed !"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:192 #: ../qml/pages/settings/InfoKeys.qml:196
msgid "Key successfully deleted !" msgid "Key successfully deleted !"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:204 #: ../qml/pages/settings/InfoKeys.qml:208
msgid "An Error occured getting GPG keys !" msgid "An Error occured getting GPG keys !"
msgstr "" msgstr ""

View File

@ -19,12 +19,14 @@ Item {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: theme.palette.normal.background
Text { Text {
text: copyText.text text: copyText.text
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: units.gu(2) anchors.leftMargin: units.gu(2)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: theme.palette.normal.backgroundText
} }
Icon { Icon {

View File

@ -14,7 +14,7 @@ Component {
color: theme.palette.normal.background color: theme.palette.normal.background
Text { Text {
text: fileBaseName text: fileIsDir ? fileName : fileName.slice(0, -4) // remove .gpg if it's a file
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: units.gu(2) anchors.leftMargin: units.gu(2)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter

View File

@ -26,6 +26,7 @@ Page {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
color: theme.palette.normal.background
Flow { Flow {
id: container id: container

View File

@ -77,8 +77,8 @@ Page {
SuccessDialog { SuccessDialog {
textSuccess: i18n.tr("Password Store deleted !") textSuccess: i18n.tr("Password Store deleted !")
onDialogClosed: { onDialogClosed: {
pageStack.pop(); pageStack.clear();
pageStack.pop(); pageStack.push(Qt.resolvedUrl("../PasswordList.qml"));
} }
} }

View File

@ -30,10 +30,12 @@ Page {
console.log(importKeyFilePage.activeTransfer.items[0].url); console.log(importKeyFilePage.activeTransfer.items[0].url);
var status = Pass.importGPGKey(importKeyFilePage.activeTransfer.items[0].url); var status = Pass.importGPGKey(importKeyFilePage.activeTransfer.items[0].url);
Pass.importGPGKeySucceed.connect(function() { Pass.importGPGKeySucceed.connect(function() {
Utils.rmFile(importKeyFilePage.activeTransfer.items[0].url);
importKeyFilePage.activeTransfer = null; importKeyFilePage.activeTransfer = null;
PopupUtils.open(dialogImportKeyPageSucess); PopupUtils.open(dialogImportKeyPageSucess);
}); });
Pass.importGPGKeyFailed.connect(function(message) { Pass.importGPGKeyFailed.connect(function(message) {
Utils.rmFile(importKeyFilePage.activeTransfer.items[0].url);
importKeyFilePage.activeTransfer = null; importKeyFilePage.activeTransfer = null;
PopupUtils.open(dialogImportKeyPageError); PopupUtils.open(dialogImportKeyPageError);
}); });

View File

@ -32,12 +32,14 @@ Page {
if (importZipPage.activeTransfer.state === ContentTransfer.Charged) { if (importZipPage.activeTransfer.state === ContentTransfer.Charged) {
console.log("Charged"); console.log("Charged");
console.log(importZipPage.activeTransfer.items[0].url); console.log(importZipPage.activeTransfer.items[0].url);
var status = Utils.unzip(importZipPage.activeTransfer.items[0].url, Pass.getPasswordStore()); var status = Utils.unzip(importZipPage.activeTransfer.items[0].url, Pass.password_store);
Utils.unzipSucceed.connect(function() { Utils.unzipSucceed.connect(function() {
Utils.rmFile(importZipPage.activeTransfer.items[0].url);
importZipPage.activeTransfer = null; importZipPage.activeTransfer = null;
PopupUtils.open(dialogImportZipPageSuccess); PopupUtils.open(dialogImportZipPageSuccess);
}); });
Utils.unzipFailed.connect(function(message) { Utils.unzipFailed.connect(function() {
Utils.rmFile(importZipPage.activeTransfer.items[0].url);
importZipPage.activeTransfer = null; importZipPage.activeTransfer = null;
PopupUtils.open(dialogImportZipPageError); PopupUtils.open(dialogImportZipPageError);
}); });
@ -85,8 +87,8 @@ Page {
SuccessDialog { SuccessDialog {
textSuccess: i18n.tr("Password store sucessfully imported !") textSuccess: i18n.tr("Password store sucessfully imported !")
onDialogClosed: { onDialogClosed: {
pageStack.pop(); pageStack.clear();
pageStack.pop(); pageStack.push(Qt.resolvedUrl("../PasswordList.qml"));
} }
} }

View File

@ -89,12 +89,11 @@ Page {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: { text: {
if (!model.modelData) { if (!model.modelData)
""; "";
} else { else
model.modelData.keyid; model.modelData.keyid;
} }
}
color: theme.palette.normal.backgroundText color: theme.palette.normal.backgroundText
} }
@ -122,7 +121,7 @@ Page {
width: parent.width width: parent.width
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: i18n.tr('Users IDs : ') text: i18n.tr('User IDs : ')
color: theme.palette.normal.backgroundText color: theme.palette.normal.backgroundText
} }

View File

@ -77,8 +77,8 @@ Page {
SuccessDialog { SuccessDialog {
textSuccess: i18n.tr("Password store sucessfully imported !") textSuccess: i18n.tr("Password store sucessfully imported !")
onDialogClosed: { onDialogClosed: {
pageStack.pop(); pageStack.clear();
pageStack.pop(); pageStack.push(Qt.resolvedUrl("../../PasswordList.qml"));
} }
} }