mirror of
https://github.com/QRouland/UTPass.git
synced 2025-01-24 07:36:39 +00:00
Add initial support for http git clone with authentification
This commit is contained in:
parent
46145241fc
commit
6ac11e2da7
@ -1,4 +1,4 @@
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
|
||||
set(PLUGIN "Git")
|
||||
|
||||
set(
|
||||
|
@ -3,31 +3,81 @@
|
||||
#include <QDebug>
|
||||
#include <QStandardPaths>
|
||||
|
||||
|
||||
#include "git.h"
|
||||
#include "libgit.h"
|
||||
|
||||
|
||||
bool Git::clone(QString url, QString destination_dir_path)
|
||||
template<class... Ts>
|
||||
struct overload : Ts... {
|
||||
using Ts::operator()...;
|
||||
};
|
||||
template<class... Ts>
|
||||
overload(Ts...) -> overload<Ts...>;
|
||||
|
||||
|
||||
QDir Git::clone_setup()
|
||||
{
|
||||
qInfo() << "Cloning " << url << " to destination " << destination_dir_path;
|
||||
QDir tmp_dir(QStandardPaths::writableLocation(
|
||||
QStandardPaths::CacheLocation).append("/clone"));
|
||||
QDir tmp_dir(QStandardPaths::writableLocation( QStandardPaths::CacheLocation).append("/clone"));
|
||||
|
||||
tmp_dir.removeRecursively();
|
||||
qDebug() << "Temp dir path is " << tmp_dir.absolutePath();
|
||||
|
||||
qDebug() << "Cloning " << url << " to tmp dir " << tmp_dir.absolutePath();
|
||||
auto ret = LibGit::instance()->clone(url, tmp_dir.absolutePath()); // TODO Better error handling
|
||||
return tmp_dir;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
qDebug() << "Removing password_store " << destination_dir_path;
|
||||
QDir destination_dir(destination_dir_path);
|
||||
|
||||
bool Git::clone_tear_down(QDir tmp_dir)
|
||||
{
|
||||
tmp_dir.removeRecursively();
|
||||
}
|
||||
|
||||
bool Git::move_to_destination(QString path, QDir tmp_dir)
|
||||
{
|
||||
qDebug() << "Removing password_store " << path;
|
||||
QDir destination_dir(path);
|
||||
destination_dir.removeRecursively();
|
||||
|
||||
qDebug() << "Moving cloned content to destination dir";
|
||||
QDir dir;
|
||||
qDebug() << tmp_dir.absolutePath() << " to " << destination_dir.absolutePath();
|
||||
ret = dir.rename(tmp_dir.absolutePath(), destination_dir.absolutePath()); // TODO Better error handling
|
||||
}
|
||||
//tmp_dir.removeRecursively();
|
||||
return dir.rename(tmp_dir.absolutePath(), destination_dir.absolutePath()); // TODO Better error handling
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Git::clone(QString url, QString path, mode_type mode) //, GitPlugin::RepoType type, QString pass)
|
||||
{
|
||||
auto v = overload {
|
||||
[](const Unset& x) { return "Unset"; },
|
||||
[](const HTTP& x) { return "Unset"; },
|
||||
[](const HTTPAuth& x) { return "HTTPAuth"; },
|
||||
[](const SSHAuth& x) { return "SSHAuth"; },
|
||||
[](const SSHKey& x) { return "SSHKey"; },
|
||||
};
|
||||
qInfo() << "Cloning " << url << " to destination " << path << " using " << std::visit(v, mode);
|
||||
|
||||
LibGit::instance()->set_mode(mode);
|
||||
auto tmp_dir = this->clone_setup();
|
||||
|
||||
qDebug() << "Cloning " << url << " to tmp dir " << tmp_dir.absolutePath();
|
||||
auto ret = LibGit::instance()->clone(url, tmp_dir.absolutePath()); // TODO Better error handling
|
||||
|
||||
if (ret) { this->move_to_destination(path, tmp_dir);}
|
||||
|
||||
tmp_dir.removeRecursively();
|
||||
LibGit::instance()->set_mode(Unset());
|
||||
|
||||
return ret ;
|
||||
}
|
||||
|
||||
bool Git::clone_http(QString url, QString path) //, GitPlugin::RepoType type, QString pass)
|
||||
{
|
||||
HTTP mode = {};
|
||||
return this->clone(url, path, mode);
|
||||
}
|
||||
|
||||
bool Git::clone_http_pass(QString url, QString path, QString pass) {
|
||||
HTTPAuth mode = { pass };
|
||||
return this->clone(url, path, mode);
|
||||
}
|
||||
|
@ -3,17 +3,29 @@
|
||||
|
||||
#include <QUrl>
|
||||
#include <QObject>
|
||||
#include <QtCore/QDir>
|
||||
|
||||
#include "libgit.h"
|
||||
|
||||
class Git : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
QDir clone_setup();
|
||||
bool move_to_destination(QString path, QDir tmp_dir);
|
||||
bool clone_tear_down(QDir tmp_dir);
|
||||
bool clone(QString url, QString path, mode_type mode);
|
||||
|
||||
|
||||
public:
|
||||
Git() = default;
|
||||
~Git() override = default;
|
||||
|
||||
Q_INVOKABLE bool clone(QString url, QString path);
|
||||
Q_INVOKABLE bool clone_http(QString url, QString path);
|
||||
Q_INVOKABLE bool clone_http_pass(QString url, QString path, QString pass);
|
||||
// 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);
|
||||
// Q_INVOKABLE bool update(QUrl url, QString path);
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include <QUrl>
|
||||
#include <QDebug>
|
||||
|
||||
#include <type_traits>
|
||||
extern "C" {
|
||||
#include <git2.h>
|
||||
}
|
||||
@ -7,6 +9,12 @@ extern "C" {
|
||||
#include "libgit.h"
|
||||
|
||||
|
||||
template<class... Ts>
|
||||
struct overload : Ts... {
|
||||
using Ts::operator()...;
|
||||
};
|
||||
template<class... Ts>
|
||||
overload(Ts...) -> overload<Ts...>;
|
||||
|
||||
LibGit::LibGit()
|
||||
{
|
||||
@ -18,32 +26,54 @@ LibGit::~LibGit()
|
||||
git_libgit2_shutdown();
|
||||
}
|
||||
|
||||
void LibGit::set_mode(mode_type type) {
|
||||
this->mode = type;
|
||||
}
|
||||
|
||||
int LibGit::credentials_cb(git_cred **out, const char *url, const char *username_from_url,
|
||||
unsigned int allowed_types, void *payload)
|
||||
{
|
||||
int error;
|
||||
const char *user, *pass;
|
||||
|
||||
/*
|
||||
* Ask the user via the UI. On error, store the information and return GIT_EUSER which will be
|
||||
* bubbled up to the code performing the fetch or push. Using GIT_EUSER allows the application
|
||||
* to know it was an error from the application instead of libgit2.
|
||||
*/
|
||||
// if ((error = ask_user(&user, &pass, url, username_from_url, allowed_types)) < 0) {
|
||||
// store_error(error);
|
||||
// return GIT_EUSER;
|
||||
// }
|
||||
user = "pass";
|
||||
pass = "pass";
|
||||
return git_cred_userpass_plaintext_new(out, user, pass);
|
||||
// return GIT_EUSER;
|
||||
// TODO : More precise Error Handling for UI
|
||||
auto instance = LibGit::instance();
|
||||
auto v = overload {
|
||||
[](const Unset& x) {
|
||||
qDebug() << "credentials_cb : Unset ";
|
||||
qWarning() << "credentials_cb : callback should never be call for Unset ";
|
||||
return (int) GIT_EUSER;
|
||||
},
|
||||
[](const HTTP& x) {
|
||||
qDebug() << "credentials_cb : HTTP ";
|
||||
qWarning() << "credentials_cb : callback should never be call for HTTP ";
|
||||
return (int) GIT_EUSER;
|
||||
},
|
||||
[&out, &username_from_url](const HTTPAuth& x) {
|
||||
qDebug() << "credentials_cb : HTTPAuth ";
|
||||
if(!username_from_url) {
|
||||
qWarning() << "credentials_cb : no username provided ";
|
||||
return (int) GIT_EUSER;
|
||||
}
|
||||
return git_cred_userpass_plaintext_new(out, username_from_url, x.pass.toLocal8Bit().constData());
|
||||
},
|
||||
[&](const SSHAuth& x) {
|
||||
qWarning() << "credentials_cb : SSHAuth to be implemented ";
|
||||
return (int) GIT_EUSER;
|
||||
}, // TODO
|
||||
[&](const SSHKey& x) {
|
||||
qWarning() << "credentials_cb : SSHKey to be implemented ";
|
||||
return (int) GIT_EUSER;
|
||||
} // TODO
|
||||
};
|
||||
return std::visit(v, instance->mode);
|
||||
}
|
||||
|
||||
|
||||
bool LibGit::clone(QString url, QString path)
|
||||
{
|
||||
git_repository *repo = NULL;
|
||||
git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
|
||||
|
||||
opts.fetch_opts.callbacks.credentials = *credentials_cb;
|
||||
|
||||
int ret = git_clone(&repo, url.toLocal8Bit().data(), path.toLocal8Bit().data(), &opts);
|
||||
if (ret != 0) {
|
||||
qDebug() << git_error_last()->message;
|
||||
@ -51,6 +81,8 @@ bool LibGit::clone(QString url, QString path)
|
||||
if (repo) {
|
||||
git_repository_free(repo);
|
||||
}
|
||||
|
||||
return ret == 0; // TODO Clean error handling to return specifics errors for the ui
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -3,19 +3,30 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
#include <git2/clone.h>
|
||||
extern "C" {
|
||||
#include <git2/transport.h>
|
||||
}
|
||||
#include <memory>
|
||||
#include <variant>
|
||||
|
||||
struct Unset { };
|
||||
struct HTTP { };
|
||||
struct HTTPAuth { QString pass; };
|
||||
struct SSHAuth { };
|
||||
struct SSHKey { };
|
||||
typedef std::variant<Unset, HTTP, HTTPAuth, SSHAuth, SSHKey> mode_type;
|
||||
|
||||
class LibGit
|
||||
{
|
||||
private:
|
||||
LibGit();
|
||||
|
||||
mode_type mode;
|
||||
|
||||
static int credentials_cb(git_cred **out, const char *url, const char *username_from_url,
|
||||
unsigned int allowed_types, void *payload);
|
||||
|
||||
|
||||
public:
|
||||
~LibGit();
|
||||
static std::shared_ptr<LibGit> instance()
|
||||
@ -27,6 +38,7 @@ public:
|
||||
void operator=(LibGit const &) = delete;
|
||||
|
||||
bool clone(QString url, QString path);
|
||||
void set_mode(mode_type type);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,10 +1,13 @@
|
||||
#include <QtQml>
|
||||
#include <cstring>
|
||||
|
||||
#include "plugin.h"
|
||||
#include "git.h"
|
||||
|
||||
|
||||
void GitPlugin::registerTypes(const char *uri)
|
||||
{
|
||||
//@uri Git
|
||||
qmlRegisterSingletonType<Git>(uri, 1, 0, "Git", [](QQmlEngine *, QJSEngine *) -> QObject * { return new Git; });
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
|
||||
set(PLUGIN "Pass")
|
||||
|
||||
set(
|
||||
|
@ -1,4 +1,4 @@
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
|
||||
set(PLUGIN "Utils")
|
||||
|
||||
set(
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: utpass.qrouland\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-10 21:31+0100\n"
|
||||
"POT-Creation-Date: 2025-01-13 17:55+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"
|
||||
@ -87,7 +87,8 @@ msgstr ""
|
||||
|
||||
#: ../qml/pages/PasswordList.qml:26
|
||||
msgid ""
|
||||
"No password found<br>You can import a password store zip in the settings"
|
||||
"No password found<br>You can import a password store by cloning or importing "
|
||||
"a zip in the settings"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/PasswordList.qml:65
|
||||
@ -111,30 +112,30 @@ msgstr ""
|
||||
msgid "Repo Url"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:45
|
||||
msgid "Git repo url"
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:53
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:52
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:69
|
||||
msgid "Clone"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:68
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:91
|
||||
msgid ""
|
||||
"Importing a git repo will delete<br>any existing password store!"
|
||||
"<br>Continue ?"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:80
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:103
|
||||
msgid "An error occured during git clone !"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:89
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:112
|
||||
#: ../qml/pages/settings/ImportZip.qml:82
|
||||
msgid "Password store sucessfully imported !"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:101
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:124
|
||||
msgid "Git Clone Import"
|
||||
msgstr ""
|
||||
|
||||
|
@ -19,10 +19,10 @@ MainView {
|
||||
//TODO use parameters to impove passphrase dialog
|
||||
var passphraseDialog = PopupUtils.open(Qt.resolvedUrl("dialogs/PassphraseDialog.qml"));
|
||||
passphraseDialog.activateFocus();
|
||||
var validated = function validated(passphrase) {
|
||||
var validated = function (passphrase) {
|
||||
responsePassphraseDialog(false, passphrase);
|
||||
};
|
||||
var canceled = function canceled() {
|
||||
var canceled = function () {
|
||||
responsePassphraseDialog(true, "");
|
||||
};
|
||||
passphraseDialog.validated.connect(validated);
|
||||
|
@ -23,7 +23,7 @@ Page {
|
||||
visible: folderModel.count == 0
|
||||
|
||||
Text {
|
||||
text: i18n.tr("No password found<br>You can import a password store zip in the settings")
|
||||
text: i18n.tr("No password found<br>You can import a password store by cloning or importing a zip in the settings")
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
@ -28,7 +28,7 @@ Page {
|
||||
}
|
||||
|
||||
Text {
|
||||
id: repoUrlLabe
|
||||
id: repoUrlLabel
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
@ -37,12 +37,29 @@ Page {
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: textFieldInput
|
||||
id: repoUrlInput
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
width: parent.width
|
||||
placeholderText: i18n.tr('Git repo url')
|
||||
}
|
||||
|
||||
Text {
|
||||
id: repoPasswordLabel
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
width: parent.width
|
||||
text: i18n.tr('Password')
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: repoPasswordInput
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
width: parent.width
|
||||
echoMode: TextInput.Password
|
||||
}
|
||||
|
||||
Button {
|
||||
@ -51,7 +68,13 @@ Page {
|
||||
width: parent.width
|
||||
text: i18n.tr('Clone')
|
||||
onClicked: {
|
||||
var ret = Git.clone(textFieldInput.text, Pass.password_store);
|
||||
var ret = false;
|
||||
if(repoPasswordInput.text === "") {
|
||||
ret = Git.clone_http(repoUrlInput.text, Pass.password_store);
|
||||
} else {
|
||||
ret = Git.clone_http_pass(repoUrlInput.text, Pass.password_store, repoPasswordInput.text);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
PopupUtils.open(dialogImportGitCloneSuccess);
|
||||
else
|
||||
|
Loading…
x
Reference in New Issue
Block a user