1
0
mirror of https://github.com/QRouland/UTPass.git synced 2025-02-24 04:14:55 +00:00

Add support for ssh clone

This commit is contained in:
Quentin Rouland 2025-02-21 15:50:27 +01:00
parent 5683db69c7
commit 884488b9ed
16 changed files with 558 additions and 184 deletions

View File

@ -12,8 +12,15 @@ extern "C" {
#include "jobs/gitjob.h"
Git::Git():
m_sem(std::unique_ptr<QSemaphore>(new QSemaphore(1)))
m_sem(std::unique_ptr<QSemaphore>(new QSemaphore(1))),
m_ssh_homedir (QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation).append("/.ssh"))
{
qDebug() << "[Git] SSH Home is " << m_ssh_homedir.absolutePath();
QDir m_ssh_homedir(this->m_ssh_homedir);
if (!m_ssh_homedir.exists()) {
m_ssh_homedir.mkpath(".");
}
git_libgit2_init();
}
@ -26,7 +33,7 @@ Git::~Git()
bool Git::clone(QString url, QString path, cred_type mode)
{
if (!this->m_sem->tryAcquire(1, 500)) {
qWarning() << "Can acquire git semaphore a command is already running ";
qWarning() << "[Git] Can acquire git semaphore a command is already running ";
return false;
}
auto v = overload {
@ -44,18 +51,26 @@ bool Git::clone(QString url, QString path, cred_type mode)
bool Git::cloneHttp(QString url, QString path)
{
qInfo() << "Call clone command Http " << url << " " << path;
qInfo() << "[Git] Call clone command Http " << url << " " << path;
HTTP mode = {};
return this->clone(url, path, mode);
}
bool Git::cloneHttpPass(QString url, QString path, QString pass)
{
qInfo() << "Call clone command HttpPass " << url << " " << path;
qInfo() << "[Git] Call clone command HttpPass " << url << " " << path;
HTTPUserPass mode = { pass };
return this->clone(url, path, mode);
}
bool Git::cloneSshKey(QString url, QString path, QString passphrase)
{
qInfo() << "[Git] Call clone command HttpPass " << url << " " << path;
SSHKey mode = { this->pubKeyPath(), this->privKeyPath(), passphrase };
return this->clone(url, path, mode);
}
void Git::cloneResult(const bool err)
{
@ -66,3 +81,23 @@ void Git::cloneResult(const bool err)
}
this->m_sem->release();
}
bool Git::importSshKey(QUrl source_path, bool is_private){
auto destination_path = is_private ? this->privKeyPath() : this->pubKeyPath();
QFile source_file(source_path.toLocalFile());
if (!source_file.exists()) {
qWarning() << "[Git] Source file does not exist.";
return false;
}
QDir target_dir = QFileInfo(destination_path).absoluteDir();
if (!target_dir.exists()) {
if (!target_dir.mkpath(".")) {
qWarning() << "[Git] Failed to create target directory.";
return false;
}
}
return source_file.copy(destination_path);
}

View File

@ -2,6 +2,7 @@
#define GIT_H
#include "jobs/gitjob.h"
#include "qdebug.h"
#include <QUrl>
#include <QObject>
#include <QSemaphore>
@ -16,6 +17,8 @@
class Git : public QObject
{
Q_OBJECT
Q_PROPERTY(QString privKey READ pubKeyPath)
Q_PROPERTY(QString pubKey READ privKeyPath)
private slots:
/**
@ -47,6 +50,7 @@ signals:
private:
std::unique_ptr<QSemaphore> m_sem; /**< Semaphore for managing concurrent operations. */
QDir m_ssh_homedir; /**< Directory that contains the SSH keys (public and private). */
/**
* @brief Clones a repository from a specified URL.
@ -61,6 +65,27 @@ private:
*/
bool clone(QString url, QString path, cred_type mode);
protected:
/**
* @brief Get the path to the public keyring.
*
* @return The file path to the public key.
*/
QString pubKeyPath()
{
return this->m_ssh_homedir.filePath("id_rsa.pub");
}
/**
* @brief Get the path to the secret keyring.
*
* @return The file path to the private key.
*/
QString privKeyPath()
{
return this->m_ssh_homedir.filePath("id_rsa");
}
public:
/**
* @brief Constructor for the Git class.
@ -76,6 +101,9 @@ public:
*/
~Git() override;
Q_INVOKABLE bool importSshKey(QUrl source_path, bool is_private);
/**
* @brief Clones a repository over HTTP.
*
@ -97,13 +125,22 @@ public:
* @param url The HTTP URL of the Git repository to clone.
* @param path The destination path for the cloned repository.
* @param pass The password used for HTTP authentication.
* @return `true` if the clone operation was successful, `false` otherwise.
* @return `true` if the clone job operation was successfully started, `false` otherwise.
*/
Q_INVOKABLE bool cloneHttpPass(QString url, QString path, QString pass);
// Future SSH support methods:
// Q_INVOKABLE bool clone_ssh_pass(QString url, QString path, QString pass);
// Q_INVOKABLE bool clone_ssh_key(QString url, QString path, QString pub_key, QString priv_key, QString passphrase);
/**
* @brief Clones a repository over SSH with a key for authentication.
*
* This method clones a Git repository from the specified ssh URL using the provided password for authentication,
* and saves it to the given destination path.
*
* @param url The HTTP URL of the Git repository to clone.
* @param path The destination path for the cloned repository.
* @param passphrase The passphrase used for SSH authentication.
* @return `true` if the clone job operation was successfully started, `false` otherwise.
*/
Q_INVOKABLE bool cloneSshKey(QString url, QString path, QString passphrase);
// Q_INVOKABLE bool update(QUrl url, QString path);
// ....

View File

@ -18,17 +18,7 @@ GitJob::~GitJob()
git_libgit2_shutdown();
}
bool GitJob::getUsername(char **username, QString maybe_username, const char *username_from_url)
{
if (username_from_url) {
*username = strdup(username_from_url);
return true;
} else if (!maybe_username.isNull()) {
*username = maybe_username.toLocal8Bit().data();
return true;
}
return false;
}
int GitJob::credentialsCB(git_cred **out, const char *url, const char *username_from_url,
unsigned int allowed_types, void *payload)

View File

@ -1,6 +1,7 @@
#ifndef GITJOB_H
#define GITJOB_H
#include <QDir>
#include <QThread>
extern "C" {
#include <git2.h>

View File

@ -9,5 +9,4 @@ void GitPlugin::registerTypes(const char *uri)
{
//@uri Git
qmlRegisterSingletonType<Git>(uri, 1, 0, "Git", [](QQmlEngine *, QJSEngine *) -> QObject * { return new Git; });
}

View File

@ -15,7 +15,7 @@ bool Utils::unzip(QUrl zip_url, QString dir_out_path)
if (!this->m_sem->tryAcquire(1, 500)) {
return false;
}
qInfo() << "Unzip path " << zip_url << " to " << dir_out_path;
qInfo() << "[Utils] Unzip path " << zip_url << " to " << dir_out_path;
auto job = new UnzipJob(zip_url, QDir(dir_out_path));
connect(job, &UnzipJob::resultReady, this, &Utils::unzipResult);
connect(job, &UnzipJob::finished, job, &QObject::deleteLater);
@ -26,13 +26,13 @@ bool Utils::unzip(QUrl zip_url, QString dir_out_path)
void Utils::unzipResult(bool err)
{
qDebug() << "Unzip Result";
qDebug() << "[Utils] Unzip Result";
if (err) {
qInfo() << "Unzip Failed";
qInfo() << "[Utils] Unzip Failed";
emit unzipFailed();
} else {
qInfo() << "Unzip Succeed";
qInfo() << "[Utils] Unzip Succeed";
emit unzipSucceed();
}
this->m_sem->release(1);
@ -42,7 +42,7 @@ void Utils::unzipResult(bool err)
QString Utils::manifestPath()
{
auto path = QDir(QDir::currentPath()).filePath("manifest_.json");
qInfo() << "Manifest path : " << path;
qInfo() << "[Utils] Manifest path : " << path;
return path;
}
@ -56,3 +56,12 @@ bool Utils::rmDir(QUrl dir_url)
QDir dir(dir_url.toLocalFile());
return dir.removeRecursively();
}
bool Utils::fileExists(QUrl path)
{
QString p = path.toLocalFile();
auto ret = QFileInfo::exists(p) && QFileInfo(p).isFile();
qDebug() << "[Utils]" << path << " existing file :" << ret;
return ret;
}

View File

@ -80,6 +80,14 @@ public:
*/
Q_INVOKABLE bool rmDir(QUrl dir_url);
/**
* @brief Verify that file exists at the specified URL.
*
* @param path The URL of the file to verfidy.
* @return `true` if the file exist; `false` otherwise.
*/
Q_INVOKABLE bool fileExists(QUrl path);
};
#endif

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: utpass.qrouland\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-04 17:49+0100\n"
"POT-Creation-Date: 2025-02-21 15:49+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,6 +17,64 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: ../qml/components/GitCloneHttp.qml:22
#: ../qml/components/GitCloneHttpAuth.qml:22
#: ../qml/components/GitCloneSshKey.qml:41
msgid "Repo Url"
msgstr ""
#: ../qml/components/GitCloneHttp.qml:47
#: ../qml/components/GitCloneHttpAuth.qml:67
#: ../qml/components/GitCloneSshKey.qml:143
msgid "Clone"
msgstr ""
#: ../qml/components/GitCloneHttpAuth.qml:42
#: ../qml/components/GitCloneHttpAuth.qml:53
msgid "Password"
msgstr ""
#: ../qml/components/GitCloneSshKey.qml:61
msgid "SSH private key"
msgstr ""
#: ../qml/components/GitCloneSshKey.qml:70
msgid "Import SSH private key"
msgstr ""
#: ../qml/components/GitCloneSshKey.qml:79
msgid "Delete SSH private key"
msgstr ""
#: ../qml/components/GitCloneSshKey.qml:89
msgid "SSH public key"
msgstr ""
#: ../qml/components/GitCloneSshKey.qml:98
msgid "Delete SSH public key"
msgstr ""
#: ../qml/components/GitCloneSshKey.qml:107
msgid "Import SSH public key"
msgstr ""
#: ../qml/components/GitCloneSshKey.qml:118
#: ../qml/components/GitCloneSshKey.qml:129
msgid "Passphrase"
msgstr ""
#: ../qml/components/ImportFile.qml:18
msgid "Import succeeded !"
msgstr ""
#: ../qml/components/ImportFile.qml:19
msgid "Import failed !"
msgstr ""
#: ../qml/components/ImportFile.qml:20
msgid "File Import"
msgstr ""
#: ../qml/dialogs/ErrorDialog.qml:12
msgid "Error !"
msgstr ""
@ -75,82 +133,110 @@ msgstr ""
msgid "Released under the terms of the GNU GPL v3"
msgstr ""
#: ../qml/pages/Info.qml:132 ../qml/pages/headers/MainHeader.qml:33
#: ../qml/pages/Info.qml:132 ../qml/pages/headers/MainHeader.qml:38
msgid "Info"
msgstr ""
#: ../qml/pages/PasswordList.qml:45
#: ../qml/pages/PasswordList.qml:79
msgid "No password found"
msgstr ""
#: ../qml/pages/PasswordList.qml:58
#: ../qml/pages/PasswordList.qml:92
msgid "You can import a password store by cloning or"
msgstr ""
#: ../qml/pages/PasswordList.qml:65
#: ../qml/pages/PasswordList.qml:99
msgid "importing a password store zip in the settings"
msgstr ""
#: ../qml/pages/PasswordList.qml:100
#: ../qml/pages/PasswordList.qml:176
msgid "Decryption failed !"
msgstr ""
#: ../qml/pages/PasswordList.qml:114
#: ../qml/pages/PasswordList.qml:198
msgid "Back"
msgstr ""
#: ../qml/pages/PasswordList.qml:121 ../qml/pages/headers/MainHeader.qml:9
#: ../qml/pages/PasswordList.qml:205 ../qml/pages/headers/MainHeader.qml:14
#: ../qml/pages/headers/StackHeader.qml:9 UTPass.desktop.in.h:1
msgid "UTPass"
msgstr ""
#: ../qml/pages/headers/MainHeader.qml:26 ../qml/pages/settings/Settings.qml:75
msgid "Settings"
msgstr ""
#: ../qml/pages/headers/MainHeader.qml:57
#: ../qml/pages/headers/MainHeader.qml:20
#: ../qml/pages/headers/MainHeader.qml:62
msgid "Search"
msgstr ""
#: ../qml/pages/settings/DeleteRepo.qml:42
#: ../qml/pages/settings/Settings.qml:58
#: ../qml/pages/headers/MainHeader.qml:31 ../qml/pages/settings/Settings.qml:73
msgid "Settings"
msgstr ""
#: ../qml/pages/settings/DeleteRepo.qml:43
#: ../qml/pages/settings/DeleteRepo.qml:93
#: ../qml/pages/settings/Settings.qml:56
msgid "Delete Password Store"
msgstr ""
#: ../qml/pages/settings/DeleteRepo.qml:55
#: ../qml/pages/settings/DeleteRepo.qml:56
msgid "You're are about to delete<br>the current Password Store.<br>Continue ?"
msgstr ""
#: ../qml/pages/settings/DeleteRepo.qml:56
#: ../qml/pages/settings/DeleteRepo.qml:57
#: ../qml/pages/settings/ImportGitClone.qml:142
#: ../qml/pages/settings/ImportZip.qml:66
#: ../qml/pages/settings/InfoKeys.qml:174
#: ../qml/pages/settings/git/ImportGitClone.qml:56
msgid "Yes"
msgstr ""
#: ../qml/pages/settings/DeleteRepo.qml:69
#: ../qml/pages/settings/DeleteRepo.qml:70
msgid "Password Store removal failed !"
msgstr ""
#: ../qml/pages/settings/DeleteRepo.qml:78
#: ../qml/pages/settings/DeleteRepo.qml:79
msgid "Password Store deleted !"
msgstr ""
#: ../qml/pages/settings/DeleteRepo.qml:90
#: ../qml/pages/settings/InfoKeys.qml:216
msgid "Info Keys"
#: ../qml/pages/settings/ImportGitClone.qml:141
msgid ""
"Importing a git repo will delete<br>any existing password store!"
"<br>Continue ?"
msgstr ""
#: ../qml/pages/settings/ImportKeyFile.qml:61
msgid "Key import failed !"
#: ../qml/pages/settings/ImportGitClone.qml:155
msgid "An error occured during git clone !"
msgstr ""
#: ../qml/pages/settings/ImportKeyFile.qml:70
#: ../qml/pages/settings/ImportGitClone.qml:164
#: ../qml/pages/settings/ImportZip.qml:88
msgid "Password store sucessfully imported !"
msgstr ""
#: ../qml/pages/settings/ImportGitClone.qml:176
msgid "Git Clone Import"
msgstr ""
#: ../qml/pages/settings/ImportKeyFile.qml:8
msgid "GPG Key Import"
msgstr ""
#: ../qml/pages/settings/ImportKeyFile.qml:9
msgid "Key successfully imported !"
msgstr ""
#: ../qml/pages/settings/ImportKeyFile.qml:81
msgid "GPG Key Import"
#: ../qml/pages/settings/ImportKeyFile.qml:10
msgid "Key import failed !"
msgstr ""
#: ../qml/pages/settings/ImportSSHkey.qml:10
msgid "SSH Key Import"
msgstr ""
#: ../qml/pages/settings/ImportSSHkey.qml:11
msgid "SSH Key successfully imported !"
msgstr ""
#: ../qml/pages/settings/ImportSSHkey.qml:12
msgid "SSH Key import failed !"
msgstr ""
#: ../qml/pages/settings/ImportZip.qml:65
@ -162,11 +248,6 @@ msgstr ""
msgid "Password store import failed !"
msgstr ""
#: ../qml/pages/settings/ImportZip.qml:88
#: ../qml/pages/settings/git/ImportGitClone.qml:78
msgid "Password store sucessfully imported !"
msgstr ""
#: ../qml/pages/settings/ImportZip.qml:100
msgid "Zip Password Store Import"
msgstr ""
@ -203,59 +284,34 @@ msgstr ""
msgid "An Error occured getting GPG keys !"
msgstr ""
#: ../qml/pages/settings/Settings.qml:23
#: ../qml/pages/settings/InfoKeys.qml:216
msgid "Info Keys"
msgstr ""
#: ../qml/pages/settings/Settings.qml:21
msgid "GPG"
msgstr ""
#: ../qml/pages/settings/Settings.qml:29
#: ../qml/pages/settings/Settings.qml:27
msgid "Import a GPG key file"
msgstr ""
#: ../qml/pages/settings/Settings.qml:34
#: ../qml/pages/settings/Settings.qml:32
msgid "Show GPG keys"
msgstr ""
#: ../qml/pages/settings/Settings.qml:42
#: ../qml/pages/settings/Settings.qml:40
msgid "Password Store"
msgstr ""
#: ../qml/pages/settings/Settings.qml:48
#: ../qml/pages/settings/Settings.qml:46
msgid "Import a Password Store using Git"
msgstr ""
#: ../qml/pages/settings/Settings.qml:53
#: ../qml/pages/settings/Settings.qml:51
msgid "Import a Password Store Zip"
msgstr ""
#: ../qml/pages/settings/Settings.qml:67
#: ../qml/pages/settings/Settings.qml:65
msgid "Warning: importing delete any exiting Password Store"
msgstr ""
#: ../qml/pages/settings/git/GitCloneHttp.qml:16
#: ../qml/pages/settings/git/GitCloneHttpAuth.qml:16
msgid "Repo Url"
msgstr ""
#: ../qml/pages/settings/git/GitCloneHttp.qml:40
#: ../qml/pages/settings/git/GitCloneHttpAuth.qml:60
msgid "Clone"
msgstr ""
#: ../qml/pages/settings/git/GitCloneHttpAuth.qml:35
#: ../qml/pages/settings/git/GitCloneHttpAuth.qml:46
msgid "Password"
msgstr ""
#: ../qml/pages/settings/git/ImportGitClone.qml:55
msgid ""
"Importing a git repo will delete<br>any existing password store!"
"<br>Continue ?"
msgstr ""
#: ../qml/pages/settings/git/ImportGitClone.qml:69
msgid "An error occured during git clone !"
msgstr ""
#: ../qml/pages/settings/git/ImportGitClone.qml:90
msgid "Git Clone Import"
msgstr ""

View File

@ -0,0 +1,149 @@
import Git 1.0
import Lomiri.Components 1.3
import Pass 1.0
import Utils 1.0
import QtQuick 2.4
Column {
property alias importSshPrivKeyButton : repoImportPrivKeyButton
property alias importSshPubKeyButton : repoImportPubKeyButton
property alias deleteSshPrivKeyButton : repoDeletePrivKeyButton
property alias deleteSshPubKeyButton : repoDeletePubKeyButton
property bool __sshPrivKeyAvailable : false
property bool __sshPubKeyAvailable : false
signal repoUrlChanged(string url)
function setRepoUrl(url) {
repoUrlInput.text = url;
}
function update() {
__sshPrivKeyAvailable = Utils.fileExists(Git.privKey);
__sshPubKeyAvailable = Utils.fileExists(Git.pubKey);
}
Component.onCompleted: {
update();
}
anchors.top: parent.fill
spacing: units.gu(1)
Text {
id: repoUrlLabel
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: parent.width
text: i18n.tr('Repo Url')
color: theme.palette.normal.backgroundText
}
TextField {
id: repoUrlInput
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: parent.width
placeholderText: "<username>@<hostname>"
onTextChanged: repoUrlChanged(repoUrlInput.text)
}
Text {
id: repoPrivKeyLabel
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: parent.width
text: i18n.tr('SSH private key')
color: theme.palette.normal.backgroundText
}
Button {
id: repoImportPrivKeyButton
width: parent.width
color: theme.palette.normal.positive
text: i18n.tr('Import SSH private key')
visible: !__sshPrivKeyAvailable
}
Button {
id: repoDeletePrivKeyButton
width: parent.width
color: theme.palette.normal.negative
text: i18n.tr('Delete SSH private key')
visible: __sshPrivKeyAvailable
}
Text {
id: repoPubKeyLabel
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: parent.width
text: i18n.tr('SSH public key')
color: theme.palette.normal.backgroundText
}
Button {
id: repoDeletePubKeyButton
width: parent.width
color: theme.palette.normal.negative
text: i18n.tr('Delete SSH public key')
visible: __sshPrivKeyAvailable
}
Button {
id: repoImportPubKeyButton
width: parent.width
color: theme.palette.normal.positive
text: i18n.tr('Import SSH public key')
visible: !__sshPrivKeyAvailable
}
Text {
id: repoPassphraseLabel
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: parent.width
text: i18n.tr('Passphrase')
color: theme.palette.normal.backgroundText
}
TextField {
id: repoPassphraseInput
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: parent.width
echoMode: TextInput.Password
placeholderText: i18n.tr('Passphrase')
}
Rectangle {
width: parent.width
height: units.gu(1)
color: theme.palette.normal.background
}
Button {
id: buttonClone
width: parent.width
color: theme.palette.normal.positive
text: i18n.tr('Clone')
onClicked: {
Git.cloneSSHKey(repoUrlInput.text, Pass.Passphrase_store, repoPassphraseInput.text);
}
}
}

View File

@ -0,0 +1,71 @@
import "../dialogs"
import "../pages/headers"
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import Lomiri.Content 1.3
import Pass 1.0
import QtQuick 2.4
import Utils 1.0
Page {
id: importKeyFilePage
property var activeTransfer
property alias contentPicker : contentPicker
property alias dialogImportKeyPageError : dialogImportKeyPageError
property alias dialogImportKeyPageSucess : dialogImportKeyPageSucess
property string headerTitle : i18n.tr("Import succeeded !")
property string dialogErrorTxt : i18n.tr("Import failed !")
property string dialogSuccessTxt : i18n.tr("File Import")
ContentPeerPicker {
id: contentPicker
anchors.top: importKeyHeader.bottom
anchors.bottom: parent.bottom
anchors.topMargin: importKeyFilePage.header.height
width: parent.width
visible: parent.visible
showTitle: false
contentType: ContentType.Text
handler: ContentHandler.Source
onCancelPressed: {
pageStack.pop();
}
}
ContentTransferHint {
id: transferHint
anchors.fill: parent
activeTransfer: importKeyFilePage.activeTransfer
}
Component {
id: dialogImportKeyPageError
ErrorDialog {
textError: importKeyFilePage.dialogErrorTxt
}
}
Component {
id: dialogImportKeyPageSucess
SuccessDialog {
textSuccess: importKeyFilePage.dialogSuccessTxt
onDialogClosed: {
pageStack.pop();
}
}
}
header: StackHeader {
id: importKeyHeader
title: importKeyFilePage.headerTitle
}
}

View File

@ -19,6 +19,7 @@ Page {
for (var i = 0; i < __passwords.length; i++) {
if (__passwords[i].toUpperCase().indexOf(filter.toUpperCase()) > -1)
ret.push(__passwords[i]);
}
}
return ret;
@ -179,6 +180,7 @@ Page {
Timer {
id: searchTimer
interval: 500
onTriggered: __searchUpdateModel()
}

View File

@ -2,11 +2,12 @@ import Lomiri.Components 1.3
import QtQuick 2.4
PageHeader {
//property alias searchBarText: searchBar.text
//signal searchBarTextChanged(string text)
id: mainHeader
property alias searchBar: searchBar
//property alias searchBarText: searchBar.text
//signal searchBarTextChanged(string text)
width: parent.width
height: units.gu(6)
@ -20,9 +21,9 @@ PageHeader {
onTriggered: {
searchBar.visible = !searchBar.visible;
labelTitle.visible = !searchBar.visible;
if (searchBar.visible === true) {
if (searchBar.visible === true)
searchBar.focus = true;
}
}
},
Action {

View File

@ -90,7 +90,7 @@ Page {
header: StackHeader {
id: deleteRepoPageHeader
title: i18n.tr('Info Keys')
title: i18n.tr('Delete Password Store')
}
}

View File

@ -8,20 +8,28 @@ import Lomiri.Components.Pickers 1.3
import Lomiri.Components.Popups 1.3
import Pass 1.0
import QtQuick 2.4
import Utils 1.0
Page {
id: importGitClonePage
property int __gitModeHTTP : 0
property int __gitModeHTTP_AUTH : 1
property int __gitModeSSH_KEY : 2
property string __repoUrl
function __loadForm() {
switch (combo.selectedIndex) {
case 0:
case __gitModeHTTP:
importGitCloneForm.source = Qt.resolvedUrl("../../components/GitCloneHttp.qml");
break;
case 1:
case __gitModeHTTP_AUTH:
importGitCloneForm.source = Qt.resolvedUrl("../../components/GitCloneHttpAuth.qml");
break;
case __gitModeSSH_KEY:
importGitCloneForm.source = Qt.resolvedUrl("../../components/GitCloneSshKey.qml");
break;
}
}
@ -29,6 +37,10 @@ Page {
Git.cloneSucceed.connect(function() {
GitSettings.type = combo.selectedIndex;
GitSettings.repoUrl = importGitClonePage.__repoUrl;
if(GitSettings.type != __gitModeSSH_KEY) { // ensure there no ssh key is kept if swicthing to another git mode
Utils.rmFile(Git.privKey);
Utils.rmFile(Git.pubKey);
}
PopupUtils.open(dialogGitCloneSuccess);
});
Git.cloneFailed.connect(function() {
@ -64,7 +76,7 @@ Page {
id: combo
width: parent.width
model: ["HTTP", "HTTP AUTH"]
model: ["HTTP", "HTTP AUTH", "SSH KEY"]
onDelegateClicked: function(i) {
timer.setTimeout(function() {
__loadForm();
@ -98,6 +110,25 @@ Page {
importGitClonePage.__repoUrl = url;
});
importGitCloneForm.item.setRepoUrl(importGitClonePage.__repoUrl);
switch (combo.selectedIndex) {
case __gitModeHTTP:
break;
case __gitModeHTTP_AUTH:
break;
case __gitModeSSH_KEY:
importGitCloneForm.item.importSshPrivKeyButton.clicked.connect(function() {
pageStack.push(Qt.resolvedUrl("ImportSSHkey.qml"), {
"isPrivateKey": true
});
});
importGitCloneForm.item.importSshPubKeyButton.clicked.connect(function() {
pageStack.push(Qt.resolvedUrl("ImportSSHkey.qml"), {
"isPrivateKey": false
});
});
break;
}
}
}

View File

@ -1,84 +1,35 @@
import "../../dialogs"
import "../headers"
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import Lomiri.Content 1.3
import "../../components"
import Pass 1.0
import QtQuick 2.4
import Utils 1.0
Page {
ImportFile {
id: importKeyFilePage
property var activeTransfer
headerTitle: i18n.tr("GPG Key Import")
dialogSuccessTxt : i18n.tr("Key successfully imported !")
dialogErrorTxt : i18n.tr("Key import failed !")
ContentPeerPicker {
anchors.top: importKeyHeader.bottom
anchors.bottom: parent.bottom
anchors.topMargin: importKeyFilePage.header.height
width: parent.width
visible: parent.visible
showTitle: false
contentType: ContentType.Text
handler: ContentHandler.Source
onPeerSelected: {
contentPicker.onPeerSelected: {
{
peer.selectionType = ContentTransfer.Single;
importKeyFilePage.activeTransfer = peer.request();
importKeyFilePage.activeTransfer.stateChanged.connect(function() {
if (importKeyFilePage.activeTransfer.state === ContentTransfer.Charged) {
console.log("Charged");
console.log(importKeyFilePage.activeTransfer.items[0].url);
var status = Pass.importGPGKey(importKeyFilePage.activeTransfer.items[0].url);
Pass.importGPGKey(importKeyFilePage.activeTransfer.items[0].url);
Pass.importGPGKeySucceed.connect(function() {
Utils.rmFile(importKeyFilePage.activeTransfer.items[0].url);
importKeyFilePage.activeTransfer = null;
PopupUtils.open(dialogImportKeyPageSucess);
PopupUtils.open(importKeyFilePage.dialogImportKeyPageSucess);
});
Pass.importGPGKeyFailed.connect(function(message) {
Utils.rmFile(importKeyFilePage.activeTransfer.items[0].url);
importKeyFilePage.activeTransfer = null;
PopupUtils.open(dialogImportKeyPageError);
PopupUtils.open(importKeyFilePage.dialogImportKeyPageError);
});
}
});
}
onCancelPressed: {
pageStack.pop();
}
}
ContentTransferHint {
id: transferHint
anchors.fill: parent
activeTransfer: importKeyFilePage.activeTransfer
}
Component {
id: dialogImportKeyPageError
ErrorDialog {
textError: i18n.tr("Key import failed !")
}
}
Component {
id: dialogImportKeyPageSucess
SuccessDialog {
textSuccess: i18n.tr("Key successfully imported !")
onDialogClosed: {
pageStack.pop();
}
}
}
header: StackHeader {
id: importKeyHeader
title: i18n.tr("GPG Key Import")
}
}

View File

@ -0,0 +1,34 @@
import "../../components"
import Utils 1.0
import Git 1.0
ImportFile {
id: importSSHKeyPage
property bool isPrivateKey
headerTitle: i18n.tr("SSH Key Import")
dialogSuccessTxt : i18n.tr("SSH Key successfully imported !")
dialogErrorTxt : i18n.tr("SSH Key import failed !")
contentPicker.onPeerSelected: {
{
peer.selectionType = ContentTransfer.Single;
importSSHKeyPage.activeTransfer = peer.request();
importSSHKeyPage.activeTransfer.stateChanged.connect(function() {
if (importSSHKeyPage.activeTransfer.state === ContentTransfer.Charged) {
console.log("Charged");
console.log(importSSHKeyPage.activeTransfer.items[0].url);
var ret = Git.importSshKey(importSSHKeyPage.activeTransfer.items[0].url, isPrivateKey);
Utils.rmFile(importSSHKeyPage.activeTransfer.items[0].url);
importSSHKeyPage.activeTransfer = null;
if(ret) {
PopupUtils.open(importSSHKeyPage.dialogImportKeyPageSucess);
} else {
PopupUtils.open(importSSHKeyPage.dialogImportKeyPageError);
}
}
});
}
}
}