1
0
mirror of https://github.com/QRouland/UTPass.git synced 2025-06-24 22:42:28 +00:00

Add initial support for http git clone with authentification

This commit is contained in:
2025-01-13 17:59:08 +01:00
parent 46145241fc
commit 6ac11e2da7
12 changed files with 187 additions and 54 deletions

View File

@ -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(

View File

@ -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();
return tmp_dir;
}
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();
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) {
qDebug() << "Removing password_store " << destination_dir_path;
QDir destination_dir(destination_dir_path);
destination_dir.removeRecursively();
if (ret) { this->move_to_destination(path, tmp_dir);}
tmp_dir.removeRecursively();
LibGit::instance()->set_mode(Unset());
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 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);
}

View File

@ -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);
};

View File

@ -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,39 +26,63 @@ 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;
qDebug() << git_error_last()->message;
}
if (repo) {
git_repository_free(repo);
git_repository_free(repo);
}
return ret == 0; // TODO Clean error handling to return specifics errors for the ui
return ret;
}

View File

@ -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

View File

@ -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; });
}