mirror of
https://github.com/QRouland/UTPass.git
synced 2025-01-24 07:36:39 +00:00
Initial git clone feature
This commit is contained in:
parent
d33932be6d
commit
5e5a092da1
@ -3,6 +3,10 @@ cmake_minimum_required(VERSION 3.5.1)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND dpkg-architecture -qDEB_HOST_ARCH
|
||||
OUTPUT_VARIABLE CLICK_ARCH
|
||||
@ -31,7 +35,8 @@ set(DATA_DIR /)
|
||||
|
||||
set(DESKTOP_FILE_NAME ${PROJECT_NAME}.desktop)
|
||||
|
||||
add_executable(${PROJECT_NAME} main.cpp)
|
||||
add_executable(${PROJECT_NAME} main.cpp
|
||||
qml/pages/settings/ImportGitClone.qml)
|
||||
qt5_use_modules(${PROJECT_NAME} Gui Qml Quick)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
|
@ -1,2 +1,3 @@
|
||||
add_subdirectory(Git)
|
||||
add_subdirectory(Pass)
|
||||
add_subdirectory(Utils)
|
||||
|
37
plugins/Git/CMakeLists.txt
Normal file
37
plugins/Git/CMakeLists.txt
Normal file
@ -0,0 +1,37 @@
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(PLUGIN "Git")
|
||||
|
||||
set(
|
||||
SRC
|
||||
plugin.cpp
|
||||
libgit.cpp
|
||||
git.cpp
|
||||
|
||||
)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
execute_process(
|
||||
COMMAND dpkg-architecture -qDEB_HOST_MULTIARCH
|
||||
OUTPUT_VARIABLE ARCH_TRIPLET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
if(ARCH_TRIPLET STREQUAL "")
|
||||
set(ARCH_TRIPLET x86_64-linux-gnu)
|
||||
endif()
|
||||
|
||||
add_library(${PLUGIN} MODULE ${SRC})
|
||||
set_target_properties(${PLUGIN} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGIN})
|
||||
qt5_use_modules(${PLUGIN} Qml Quick DBus)
|
||||
|
||||
|
||||
add_library(libgit2 SHARED IMPORTED)
|
||||
set_property(TARGET libgit2 PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libgit2.so")
|
||||
|
||||
target_link_libraries(${PLUGIN} libgit2)
|
||||
|
||||
|
||||
set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}")
|
||||
install(TARGETS ${PLUGIN} DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/)
|
||||
install(FILES qmldir DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/)
|
18
plugins/Git/git.cpp
Normal file
18
plugins/Git/git.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include <QUrl>
|
||||
#include <QtCore/QDir>
|
||||
#include <QDebug>
|
||||
|
||||
#include "git.h"
|
||||
#include "libgit.h"
|
||||
|
||||
|
||||
Git::Git()
|
||||
{}
|
||||
|
||||
bool Git::clone(QString url, QString path)
|
||||
{
|
||||
qInfo() << "Cloning " << url << "password_store to " << path;
|
||||
QDir dir(path);
|
||||
dir.removeRecursively(); // TODO see if we delete only after sucessfull clone / Will be change anyway when will add update etc..
|
||||
return LibGit::instance()->clone(url, path);
|
||||
}
|
20
plugins/Git/git.h
Normal file
20
plugins/Git/git.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef GIT_H
|
||||
#define GIT_H
|
||||
|
||||
#include <QUrl>
|
||||
#include <QObject>
|
||||
|
||||
|
||||
class Git : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Git();
|
||||
~Git() override = default;
|
||||
|
||||
Q_INVOKABLE bool clone(QString url, QString path);
|
||||
// Q_INVOKABLE bool update(QUrl url, QString path);
|
||||
};
|
||||
|
||||
#endif
|
51
plugins/Git/libgit.cpp
Normal file
51
plugins/Git/libgit.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include <QUrl>
|
||||
#include <QDebug>
|
||||
extern "C" {
|
||||
#include <git2.h>
|
||||
}
|
||||
|
||||
#include "libgit.h"
|
||||
|
||||
|
||||
|
||||
LibGit::LibGit()
|
||||
{
|
||||
git_libgit2_init();
|
||||
}
|
||||
|
||||
LibGit::~LibGit() {
|
||||
git_libgit2_shutdown();
|
||||
}
|
||||
|
||||
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 = "user";
|
||||
// pass = "pass";
|
||||
// return git_cred_userpass_plaintext_new(out, user, pass);
|
||||
return GIT_EUSER;
|
||||
}
|
||||
|
||||
bool LibGit::clone(QString url, QString path) {
|
||||
qDebug("yo");
|
||||
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 (repo) {
|
||||
git_repository_free(repo);
|
||||
}
|
||||
return ret == 0; // TODO Clean error handling to return specifics errors for the ui
|
||||
}
|
32
plugins/Git/libgit.h
Normal file
32
plugins/Git/libgit.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef LIBGIT_H
|
||||
#define LIBGIT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
extern "C" {
|
||||
#include <git2/transport.h>
|
||||
}
|
||||
#include <memory>
|
||||
|
||||
class LibGit
|
||||
{
|
||||
private:
|
||||
LibGit();
|
||||
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()
|
||||
{
|
||||
static std::shared_ptr<LibGit> s{new LibGit};
|
||||
return s;
|
||||
}
|
||||
LibGit(LibGit const &) = delete;
|
||||
void operator=(LibGit const &) = delete;
|
||||
|
||||
bool clone(QString url, QString path);
|
||||
};
|
||||
|
||||
#endif
|
10
plugins/Git/plugin.cpp
Normal file
10
plugins/Git/plugin.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include <QtQml>
|
||||
|
||||
#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; });
|
||||
}
|
16
plugins/Git/plugin.h
Normal file
16
plugins/Git/plugin.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef GITPLUGIN_H
|
||||
#define GITPLUGIN_H
|
||||
|
||||
#include <QQmlExtensionPlugin>
|
||||
|
||||
class GitPlugin : public QQmlExtensionPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID
|
||||
"org.qt-project.Qt.QQmlExtensionInterface")
|
||||
|
||||
public:
|
||||
void registerTypes(const char *uri) override;
|
||||
};
|
||||
|
||||
#endif
|
2
plugins/Git/qmldir
Normal file
2
plugins/Git/qmldir
Normal file
@ -0,0 +1,2 @@
|
||||
module Git
|
||||
plugin Git
|
@ -4,7 +4,6 @@ set(PLUGIN "Pass")
|
||||
set(
|
||||
SRC
|
||||
plugin.cpp
|
||||
git.cpp
|
||||
pass.cpp
|
||||
gpg.cpp
|
||||
passkeymodel.h
|
||||
@ -43,10 +42,8 @@ set_property(TARGET libgpgmepp PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPL
|
||||
add_library(libqgpgme SHARED IMPORTED)
|
||||
set_property(TARGET libqgpgme PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libqgpgme.so")
|
||||
|
||||
add_library(libgit2 SHARED IMPORTED)
|
||||
set_property(TARGET libgit2 PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libgit2.so")
|
||||
|
||||
target_link_libraries(${PLUGIN} gpgerror libassuan libgpgme libgpgmepp libqgpgme libgit2)
|
||||
target_link_libraries(${PLUGIN} gpgerror libassuan libgpgme libgpgmepp libqgpgme)
|
||||
|
||||
|
||||
set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}")
|
||||
|
@ -1,32 +0,0 @@
|
||||
|
||||
|
||||
|
||||
#include <QDebug>
|
||||
#include <QUrl>
|
||||
extern "C" {
|
||||
#include <git2.h>
|
||||
}
|
||||
|
||||
#include "git.h"
|
||||
|
||||
|
||||
|
||||
Git::Git()
|
||||
{
|
||||
git_libgit2_init();
|
||||
}
|
||||
|
||||
Git::~Git() {
|
||||
git_libgit2_shutdown();
|
||||
}
|
||||
|
||||
bool Git::clone(QString url, QString path) {
|
||||
git_repository *repo = NULL;
|
||||
git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
|
||||
|
||||
int ret = git_clone(&repo, url.toLocal8Bit().data(), path.toLocal8Bit().data(), &opts);
|
||||
if (repo) {
|
||||
git_repository_free(repo);
|
||||
}
|
||||
return ret == 0; // TODO better error handling to return specifics errors for the ui
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
#ifndef GIT_H
|
||||
#define GIT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
#include <memory>
|
||||
|
||||
class Git
|
||||
{
|
||||
private:
|
||||
Git();
|
||||
public:
|
||||
|
||||
~Git();
|
||||
|
||||
static std::shared_ptr<Git> instance()
|
||||
{
|
||||
static std::shared_ptr<Git> s{new Git};
|
||||
return s;
|
||||
}
|
||||
Git(Git const &) = delete;
|
||||
void operator=(Git const &) = delete;
|
||||
|
||||
bool clone(QString url, QString path);
|
||||
};
|
||||
|
||||
#endif
|
@ -13,6 +13,7 @@ class Gpg
|
||||
{
|
||||
private:
|
||||
Gpg();
|
||||
|
||||
QObject *m_window;
|
||||
|
||||
QString findCommandPath(const QString &command);
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include <QtCore/QDir>
|
||||
|
||||
#include "pass.h"
|
||||
#include "git.h"
|
||||
#include "gpg.h"
|
||||
#include "passkeymodel.h"
|
||||
|
||||
@ -22,8 +21,9 @@ void Pass::init(QObject *window)
|
||||
Gpg::instance()->setWindow(window);
|
||||
|
||||
QDir dir(m_password_store);
|
||||
if (!dir.exists())
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
qInfo() << "Password Store is :" << m_password_store;
|
||||
}
|
||||
|
||||
@ -62,13 +62,3 @@ QVariant Pass::gpgGetAllKeysModel()
|
||||
Gpg::instance()->getAllKeys().second));
|
||||
}
|
||||
|
||||
QString Pass::getPasswordStore()
|
||||
{
|
||||
return m_password_store;
|
||||
}
|
||||
|
||||
bool Pass::gitClone(QString url)
|
||||
{
|
||||
qInfo() << "Cloning . password_store from " << url;
|
||||
return Git::instance()->clone(url, m_password_store);
|
||||
}
|
||||
|
@ -9,6 +9,9 @@
|
||||
class Pass : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString password_store READ password_store)
|
||||
|
||||
private:
|
||||
QString m_password_store;
|
||||
|
||||
signals:
|
||||
@ -16,18 +19,17 @@ signals:
|
||||
void decryptCanceled();
|
||||
void decryptFailed();
|
||||
|
||||
|
||||
public:
|
||||
Pass();
|
||||
~Pass() override = default;
|
||||
|
||||
QString password_store() const { return m_password_store; }
|
||||
|
||||
Q_INVOKABLE void init(QObject *window);
|
||||
Q_INVOKABLE QString getPasswordStore();
|
||||
Q_INVOKABLE void decrypt(QUrl url);
|
||||
Q_INVOKABLE bool gpgDeleteKeyId(QString id);
|
||||
Q_INVOKABLE bool gpgImportKeyFromFile(QUrl url);
|
||||
Q_INVOKABLE QVariant gpgGetAllKeysModel();
|
||||
Q_INVOKABLE bool gitClone(QString url);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: utpass.qrouland\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-07 13:36+0000\n"
|
||||
"POT-Creation-Date: 2025-01-10 13:46+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"
|
||||
@ -37,8 +37,8 @@ msgstr ""
|
||||
msgid "Error !"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/dialogs/ErrorDialog.qml:15 ../qml/dialogs/SuccessDialog.qml:15
|
||||
msgid "OK"
|
||||
#: ../qml/dialogs/ErrorDialog.qml:15
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/dialogs/PassphraseDialog.qml:7
|
||||
@ -57,6 +57,10 @@ msgstr ""
|
||||
msgid "Success !"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/dialogs/SuccessDialog.qml:15
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/Info.qml:11 ../qml/pages/headers/MainHeader.qml:58
|
||||
msgid "Info"
|
||||
msgstr ""
|
||||
@ -103,6 +107,32 @@ msgstr ""
|
||||
msgid "Settings"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:15
|
||||
msgid "Git Clone Import"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:36
|
||||
msgid "Repo Url"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:44
|
||||
msgid "Git repo url"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:50
|
||||
msgid "Clone"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:68
|
||||
msgid ""
|
||||
"Importing a git repo will delete<br>any existing password store!"
|
||||
"<br>Continue ?"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/ImportGitClone.qml:78
|
||||
msgid "An error occured during git clone !"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/ImportKeyFile.qml:17
|
||||
msgid "GPG Key Import"
|
||||
msgstr ""
|
||||
@ -177,9 +207,13 @@ msgid "Password Store"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/Settings.qml:47
|
||||
msgid "Import a Password Store using Git"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/Settings.qml:51
|
||||
msgid "Import a Password Store Zip"
|
||||
msgstr ""
|
||||
|
||||
#: ../qml/pages/settings/Settings.qml:56
|
||||
#: ../qml/pages/settings/Settings.qml:60
|
||||
msgid "Warning: importing delete any exiting Password Store"
|
||||
msgstr ""
|
||||
|
@ -69,9 +69,6 @@ Component {
|
||||
id: passwordPageDecryptError
|
||||
ErrorDialog {
|
||||
textError: i18n.tr("Decryption failed !")
|
||||
onDialogClosed: {
|
||||
pageStack.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import Lomiri.Components 1.3
|
||||
import Lomiri.Components.Popups 1.3
|
||||
|
||||
Dialog {
|
||||
id: dialogSuccess
|
||||
id: dialogError
|
||||
|
||||
property string textError
|
||||
|
||||
@ -12,11 +12,11 @@ Dialog {
|
||||
title: i18n.tr("Error !")
|
||||
text: textError
|
||||
Button {
|
||||
text: i18n.tr("OK")
|
||||
text: i18n.tr("Close")
|
||||
color: LomiriColors.red
|
||||
onClicked: function () {
|
||||
dialogClosed()
|
||||
PopupUtils.close(dialogSuccess)
|
||||
PopupUtils.close(dialogError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,6 @@ Page {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
passwordStorePath = "file:" + Pass.getPasswordStore()
|
||||
passwordStorePath = "file:" + Pass.password_store
|
||||
}
|
||||
}
|
||||
|
85
qml/pages/settings/ImportGitClone.qml
Normal file
85
qml/pages/settings/ImportGitClone.qml
Normal file
@ -0,0 +1,85 @@
|
||||
import QtQuick 2.4
|
||||
import Lomiri.Components 1.3
|
||||
import Lomiri.Components.Popups 1.3
|
||||
import Git 1.0
|
||||
import Pass 1.0
|
||||
import "../headers"
|
||||
import "../../components"
|
||||
import "../../dialogs"
|
||||
|
||||
Page {
|
||||
id: importGitClonePage
|
||||
|
||||
header: StackHeader {
|
||||
id: importGitCloneHeader
|
||||
title: i18n.tr('Git Clone Import')
|
||||
}
|
||||
|
||||
Flow {
|
||||
anchors.top: importGitCloneHeader.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: units.gu(2)
|
||||
anchors.rightMargin: units.gu(2)
|
||||
spacing: units.gu(1)
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: units.gu(1)
|
||||
}
|
||||
|
||||
Text {
|
||||
id: repoUrlLabe
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
width: parent.width
|
||||
text: i18n.tr('Repo Url')
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: textFieldInput
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
width: parent.width
|
||||
placeholderText: i18n.tr('Git repo url')
|
||||
}
|
||||
|
||||
Button {
|
||||
id: buttonAdd
|
||||
width: parent.width
|
||||
text: i18n.tr('Clone')
|
||||
onClicked: {
|
||||
var ret = Git.clone(textFieldInput.text, Pass.password_store)
|
||||
if(ret) {
|
||||
pageStack.pop()
|
||||
} else {
|
||||
PopupUtils.open(importGitCloneError, importGitClonePage)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: importGitCloneValidation
|
||||
SimpleValidationDialog {
|
||||
text: i18n.tr(
|
||||
"Importing a git repo will delete<br>any existing password store!<br>Continue ?")
|
||||
onCanceled: {
|
||||
pageStack.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: importGitCloneError
|
||||
ErrorDialog {
|
||||
textError: i18n.tr("An error occured during git clone !")
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
PopupUtils.open(importGitCloneValidation, importGitClonePage)
|
||||
}
|
||||
}
|
@ -42,6 +42,10 @@ Page {
|
||||
height: units.gu(4)
|
||||
text: i18n.tr('Password Store')
|
||||
}
|
||||
PageStackLink {
|
||||
page: Qt.resolvedUrl("ImportGitClone.qml")
|
||||
text: i18n.tr('Import a Password Store using Git')
|
||||
}
|
||||
PageStackLink {
|
||||
page: Qt.resolvedUrl("ImportZip.qml")
|
||||
text: i18n.tr('Import a Password Store Zip')
|
||||
|
Loading…
x
Reference in New Issue
Block a user