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

Compare commits

...

4 Commits

Author SHA1 Message Date
b022e30a89 Fix Cmake issue 2025-01-13 18:26:48 +01:00
063f66e99a Some cleanup 2025-01-13 18:11:16 +01:00
6ac11e2da7 Add initial support for http git clone with authentification 2025-01-13 17:59:08 +01:00
46145241fc Setup tests 2025-01-13 10:51:27 +01:00
32 changed files with 425 additions and 103 deletions

View File

@ -35,9 +35,19 @@ set(DATA_DIR /)
set(DESKTOP_FILE_NAME ${PROJECT_NAME}.desktop) set(DESKTOP_FILE_NAME ${PROJECT_NAME}.desktop)
add_executable(${PROJECT_NAME} main.cpp if(NOT TESTS_PATH)
qml/pages/settings/ImportGitClone.qml) set(TESTS_PATH "./tests")
qt5_use_modules(${PROJECT_NAME} Gui Qml Quick) endif()
configure_file(main.in.cpp main.cpp)
add_executable(${PROJECT_NAME} main.cpp)
qt5_use_modules(${PROJECT_NAME} Gui Qml Quick QuickTest)
if(TESTS_RUNNER)
qt5_use_modules(${PROJECT_NAME} QuickTest)
endif()
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
@ -77,5 +87,9 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE_NAME} DESTINATION ${DAT
add_subdirectory(po) add_subdirectory(po)
add_subdirectory(plugins) add_subdirectory(plugins)
if(TESTS_RUNNER)
add_subdirectory(tests/plugins)
endif()
add_custom_target(${PROJECT_NAME}_FILES ALL SOURCES ${PROJECT_SRC_FILES}) add_custom_target(${PROJECT_NAME}_FILES ALL SOURCES ${PROJECT_SRC_FILES})

View File

@ -4,7 +4,7 @@ kill: UTPass
scripts: scripts:
style: >- style: >-
echo 'Astyle :' && astyle --options=.astylerc main.cpp && astyle --options=.astylerc --recursive 'plugins/*.cpp,*.h' && echo 'Running QmlFormat' && find . -name "*.qml" -exec qmlformat -i {} \; && echo 'Success' echo 'Running Astyle :' && astyle --options=.astylerc --recursive '*.cpp,*.h' --exclude=build && echo 'Running QmlFormat' && find . -name "*.qml" -exec qmlformat -i {} \; && echo 'Success'

View File

@ -6,6 +6,10 @@
#include <QtQml> #include <QtQml>
#ifdef TEST_RUNNER
#include <QtQuickTest/quicktest.h>
#endif
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
qDebug() << "Starting app from main.cpp"; qDebug() << "Starting app from main.cpp";
@ -13,6 +17,7 @@ int main(int argc, char *argv[])
QGuiApplication::setApplicationName("utpass.qrouland"); QGuiApplication::setApplicationName("utpass.qrouland");
#ifndef TEST_RUNNER
auto *view = new QQuickView(); auto *view = new QQuickView();
view->setSource(QUrl(QStringLiteral("qml/Main.qml"))); view->setSource(QUrl(QStringLiteral("qml/Main.qml")));
view->setResizeMode(QQuickView::SizeRootObjectToView); view->setResizeMode(QQuickView::SizeRootObjectToView);
@ -23,4 +28,7 @@ int main(int argc, char *argv[])
Q_ARG(QVariant, QVariant::fromValue(mainView)) Q_ARG(QVariant, QVariant::fromValue(mainView))
); );
return QGuiApplication::exec(); return QGuiApplication::exec();
#else
return quick_test_main(argc, argv, "@TESTS_PATH@", "@TESTS_PATH@");
#endif
} }

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(PLUGIN "Git")
set( set(
@ -6,7 +6,7 @@ set(
plugin.cpp plugin.cpp
libgit.cpp libgit.cpp
git.cpp git.cpp
utils.h
) )
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)

View File

@ -3,32 +3,77 @@
#include <QDebug> #include <QDebug>
#include <QStandardPaths> #include <QStandardPaths>
#include "git.h" #include "git.h"
#include "libgit.h" #include "libgit.h"
#include "utils.h"
bool Git::clone(QString url, QString destination_dir_path) 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(); tmp_dir.removeRecursively();
tmp_dir.mkpath(".");
qDebug() << "Temp dir path is " << tmp_dir.absolutePath(); qDebug() << "Temp dir path is " << tmp_dir.absolutePath();
return tmp_dir;
}
bool Git::clone_tear_down(QDir tmp_dir)
{
return 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(); qDebug() << "Cloning " << url << " to tmp dir " << tmp_dir.absolutePath();
auto ret = LibGit::instance()->clone(url, tmp_dir.absolutePath()); // TODO Better error handling auto ret = LibGit::instance()->clone(url, tmp_dir.absolutePath()); // TODO Better error handling
if (ret) { if (ret) {
qDebug() << "Removing password_store " << destination_dir_path; this->move_to_destination(path, tmp_dir);
QDir destination_dir(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();
this->clone_tear_down(tmp_dir);
LibGit::instance()->set_mode(Unset());
return ret ; 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 <QUrl>
#include <QObject> #include <QObject>
#include <QtCore/QDir>
#include "libgit.h"
class Git : public QObject class Git : public QObject
{ {
Q_OBJECT 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: public:
Git() = default; Git() = default;
~Git() override = 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); // Q_INVOKABLE bool update(QUrl url, QString path);
}; };

View File

@ -1,10 +1,13 @@
#include <QUrl> #include <QUrl>
#include <QDebug> #include <QDebug>
#include <type_traits>
extern "C" { extern "C" {
#include <git2.h> #include <git2.h>
} }
#include "libgit.h" #include "libgit.h"
#include "utils.h"
@ -18,35 +21,69 @@ LibGit::~LibGit()
git_libgit2_shutdown(); 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, int LibGit::credentials_cb(git_cred **out, const char *url, const char *username_from_url,
unsigned int allowed_types, void *payload) unsigned int allowed_types, void *payload)
{ {
int error; // TODO : More precise Error Handling for UI
const char *user, *pass; auto instance = LibGit::instance();
auto v = overload {
/* [](const Unset & x)
* 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 qDebug() << "credentials_cb : Unset ";
* to know it was an error from the application instead of libgit2. qWarning() << "credentials_cb : callback should never be call for Unset ";
*/ return (int) GIT_EUSER;
// if ((error = ask_user(&user, &pass, url, username_from_url, allowed_types)) < 0) { },
// store_error(error); [](const HTTP & x)
// return GIT_EUSER; {
// } qDebug() << "credentials_cb : HTTP ";
// user = "user"; qWarning() << "credentials_cb : callback should never be call for HTTP ";
// pass = "pass"; return (int) GIT_EUSER;
// return git_cred_userpass_plaintext_new(out, user, pass); },
return 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) bool LibGit::clone(QString url, QString path)
{ {
git_repository *repo = NULL; git_repository *repo = NULL;
git_clone_options opts = GIT_CLONE_OPTIONS_INIT; git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
opts.fetch_opts.callbacks.credentials = *credentials_cb; opts.fetch_opts.callbacks.credentials = *credentials_cb;
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) {
qDebug() << git_error_last()->message;
}
if (repo) { 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 == 0; // TODO Clean error handling to return specifics errors for the ui
return ret;
} }

View File

@ -3,19 +3,32 @@
#include <QObject> #include <QObject>
#include <QUrl> #include <QUrl>
#include <git2/clone.h>
extern "C" { extern "C" {
#include <git2/transport.h> #include <git2/transport.h>
} }
#include <memory> #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 class LibGit
{ {
private: private:
LibGit(); LibGit();
mode_type mode;
static int credentials_cb(git_cred **out, const char *url, const char *username_from_url, static int credentials_cb(git_cred **out, const char *url, const char *username_from_url,
unsigned int allowed_types, void *payload); unsigned int allowed_types, void *payload);
public: public:
~LibGit(); ~LibGit();
static std::shared_ptr<LibGit> instance() static std::shared_ptr<LibGit> instance()
@ -27,6 +40,7 @@ public:
void operator=(LibGit const &) = delete; void operator=(LibGit const &) = delete;
bool clone(QString url, QString path); bool clone(QString url, QString path);
void set_mode(mode_type type);
}; };
#endif #endif

View File

@ -1,10 +1,13 @@
#include <QtQml> #include <QtQml>
#include <cstring>
#include "plugin.h" #include "plugin.h"
#include "git.h" #include "git.h"
void GitPlugin::registerTypes(const char *uri) void GitPlugin::registerTypes(const char *uri)
{ {
//@uri Git //@uri Git
qmlRegisterSingletonType<Git>(uri, 1, 0, "Git", [](QQmlEngine *, QJSEngine *) -> QObject * { return new Git; }); qmlRegisterSingletonType<Git>(uri, 1, 0, "Git", [](QQmlEngine *, QJSEngine *) -> QObject * { return new Git; });
} }

11
plugins/Git/utils.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef UTILS_H
#define UTILS_H
template<class... Ts>
struct overload : Ts... {
using Ts::operator()...;
};
template<class... Ts>
overload(Ts...) -> overload<Ts...>;
#endif // UTILS_H

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 "Pass") set(PLUGIN "Pass")
set( set(

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 "Utils") set(PLUGIN "Utils")
set( set(

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-01-10 14:39+0100\n" "POT-Creation-Date: 2025-01-13 17:26+0000\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"
@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n" "Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: ../qml/components/FileDir.qml:71 #: ../qml/components/FileDir.qml:69
msgid "Decryption failed !" msgid "Decryption failed !"
msgstr "" msgstr ""
@ -37,19 +37,19 @@ msgstr ""
msgid "Error !" msgid "Error !"
msgstr "" msgstr ""
#: ../qml/dialogs/ErrorDialog.qml:15 #: ../qml/dialogs/ErrorDialog.qml:16
msgid "Close" msgid "Close"
msgstr "" msgstr ""
#: ../qml/dialogs/PassphraseDialog.qml:7 #: ../qml/dialogs/PassphraseDialog.qml:15
msgid "Authentication required" msgid "Authentication required"
msgstr "" msgstr ""
#: ../qml/dialogs/PassphraseDialog.qml:8 #: ../qml/dialogs/PassphraseDialog.qml:16
msgid "Enter passphrase:" msgid "Enter passphrase:"
msgstr "" msgstr ""
#: ../qml/dialogs/PassphraseDialog.qml:20 #: ../qml/dialogs/PassphraseDialog.qml:21
msgid "passphrase" msgid "passphrase"
msgstr "" msgstr ""
@ -57,157 +57,158 @@ msgstr ""
msgid "Success !" msgid "Success !"
msgstr "" msgstr ""
#: ../qml/dialogs/SuccessDialog.qml:15 #: ../qml/dialogs/SuccessDialog.qml:16
msgid "OK" msgid "OK"
msgstr "" msgstr ""
#: ../qml/pages/Info.qml:11 ../qml/pages/headers/MainHeader.qml:58 #: ../qml/pages/Info.qml:58
msgid "Info"
msgstr ""
#: ../qml/pages/Info.qml:50
msgid "<b>Version</b>" msgid "<b>Version</b>"
msgstr "" msgstr ""
#: ../qml/pages/Info.qml:68 #: ../qml/pages/Info.qml:77
msgid "<b>Maintainer</>" msgid "<b>Maintainer</>"
msgstr "" msgstr ""
#: ../qml/pages/Info.qml:90 #: ../qml/pages/Info.qml:102
msgid "Suggest improvement(s) or report a bug(s)" msgid "Suggest improvement(s) or report a bug(s)"
msgstr "" msgstr ""
#: ../qml/pages/Info.qml:94 #: ../qml/pages/Info.qml:107
msgid "Access to the source code" msgid "Access to the source code"
msgstr "" msgstr ""
#: ../qml/pages/Info.qml:101 #: ../qml/pages/Info.qml:115
msgid "Released under the terms of the GNU GPL v3" msgid "Released under the terms of the GNU GPL v3"
msgstr "" msgstr ""
#: ../qml/pages/PasswordList.qml:23 #: ../qml/pages/Info.qml:123 ../qml/pages/headers/MainHeader.qml:33
msgid "Info"
msgstr ""
#: ../qml/pages/PasswordList.qml:26
msgid ""
"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
msgid "Back" msgid "Back"
msgstr "" msgstr ""
#: ../qml/pages/PasswordList.qml:43 #: ../qml/pages/headers/MainHeader.qml:9 ../qml/pages/headers/StackHeader.qml:9
msgid ""
"No password found<br>You can import a password store zip in the settings"
msgstr ""
#: ../qml/pages/headers/MainHeader.qml:8 ../qml/pages/headers/StackHeader.qml:8
#: UTPass.desktop.in.h:1 #: UTPass.desktop.in.h:1
msgid "UTPass" msgid "UTPass"
msgstr "" msgstr ""
#: ../qml/pages/headers/MainHeader.qml:23 #: ../qml/pages/headers/MainHeader.qml:26 ../qml/pages/settings/Settings.qml:68
msgid "Search"
msgstr ""
#: ../qml/pages/headers/MainHeader.qml:51 ../qml/pages/settings/Settings.qml:14
msgid "Settings" msgid "Settings"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportGitClone.qml:15 #: ../qml/pages/headers/MainHeader.qml:57
msgid "Git Clone Import" msgid "Search"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportGitClone.qml:36 #: ../qml/pages/settings/ImportGitClone.qml:36
msgid "Repo Url" msgid "Repo Url"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportGitClone.qml:44 #: ../qml/pages/settings/ImportGitClone.qml:53
msgid "Git repo url" msgid "Password"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportGitClone.qml:50 #: ../qml/pages/settings/ImportGitClone.qml:69
msgid "Clone" msgid "Clone"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportGitClone.qml:68 #: ../qml/pages/settings/ImportGitClone.qml:89
msgid "" msgid ""
"Importing a git repo will delete<br>any existing password store!" "Importing a git repo will delete<br>any existing password store!"
"<br>Continue ?" "<br>Continue ?"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportGitClone.qml:78 #: ../qml/pages/settings/ImportGitClone.qml:101
msgid "An error occured during git clone !" msgid "An error occured during git clone !"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportGitClone.qml:85 #: ../qml/pages/settings/ImportGitClone.qml:110
#: ../qml/pages/settings/ImportZip.qml:89 #: ../qml/pages/settings/ImportZip.qml:82
msgid "Password store sucessfully imported !" msgid "Password store sucessfully imported !"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportKeyFile.qml:17 #: ../qml/pages/settings/ImportGitClone.qml:122
msgid "GPG Key Import" msgid "Git Clone Import"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportKeyFile.qml:69 #: ../qml/pages/settings/ImportKeyFile.qml:57
msgid "Key import failed !" msgid "Key import failed !"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportKeyFile.qml:76 #: ../qml/pages/settings/ImportKeyFile.qml:66
msgid "Key successfully imported !" msgid "Key successfully imported !"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportZip.qml:17 #: ../qml/pages/settings/ImportKeyFile.qml:77
msgid "Zip Password Store Import" msgid "GPG Key Import"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportZip.qml:72 #: ../qml/pages/settings/ImportZip.qml:61
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:82 #: ../qml/pages/settings/ImportZip.qml:73
msgid "Password store import failed !" msgid "Password store import failed !"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:16 #: ../qml/pages/settings/ImportZip.qml:94
msgid "Info Keys" msgid "Zip Password Store Import"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:44 #: ../qml/pages/settings/InfoKeys.qml:40
msgid "Key id : %1" msgid "Key id : %1"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:49 #: ../qml/pages/settings/InfoKeys.qml:46
msgid "Delete this key" msgid "Delete this key"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:68 #: ../qml/pages/settings/InfoKeys.qml:67
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:71 #: ../qml/pages/settings/InfoKeys.qml:68
msgid "%1<br>will be definitively removed.<br>Continue ?" msgid "%1<br>will be definitively removed.<br>Continue ?"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:87 #: ../qml/pages/settings/InfoKeys.qml:84
msgid "Key removal failed !" msgid "Key removal failed !"
msgstr "" msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:94 #: ../qml/pages/settings/InfoKeys.qml:93
msgid "Key successfully deleted !" msgid "Key successfully deleted !"
msgstr "" msgstr ""
#: ../qml/pages/settings/Settings.qml:28 #: ../qml/pages/settings/InfoKeys.qml:104
msgid "Info Keys"
msgstr ""
#: ../qml/pages/settings/Settings.qml:23
msgid "GPG" msgid "GPG"
msgstr "" msgstr ""
#: ../qml/pages/settings/Settings.qml:32 #: ../qml/pages/settings/Settings.qml:28
msgid "Import a GPG key file" msgid "Import a GPG key file"
msgstr "" msgstr ""
#: ../qml/pages/settings/Settings.qml:36 #: ../qml/pages/settings/Settings.qml:33
msgid "Show GPG keys" msgid "Show GPG keys"
msgstr "" msgstr ""
#: ../qml/pages/settings/Settings.qml:43 #: ../qml/pages/settings/Settings.qml:41
msgid "Password Store" msgid "Password Store"
msgstr "" msgstr ""
#: ../qml/pages/settings/Settings.qml:47 #: ../qml/pages/settings/Settings.qml:46
msgid "Import a Password Store using Git" msgid "Import a Password Store using Git"
msgstr "" msgstr ""

View File

@ -23,7 +23,7 @@ Page {
visible: folderModel.count == 0 visible: folderModel.count == 0
Text { 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.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter

View File

@ -28,7 +28,7 @@ Page {
} }
Text { Text {
id: repoUrlLabe id: repoUrlLabel
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
@ -37,12 +37,29 @@ Page {
} }
TextField { TextField {
id: textFieldInput id: repoUrlInput
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
width: parent.width 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 { Button {
@ -51,7 +68,11 @@ Page {
width: parent.width width: parent.width
text: i18n.tr('Clone') text: i18n.tr('Clone')
onClicked: { 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) if (ret)
PopupUtils.open(dialogImportGitCloneSuccess); PopupUtils.open(dialogImportGitCloneSuccess);
else else

BIN
tests/assets/archive.zip Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
utpasspassphrase

Binary file not shown.

View File

@ -0,0 +1 @@
*.gpg diff=gpg

View File

@ -0,0 +1 @@
UTPass Test

View File

View File

@ -0,0 +1 @@
└^ШзАщн8m@%f#▄≥┌б╧┌пмnW▐[qЬ╜┴Xз&ч>&MO`0жБ@ o▀▓(М≤R▒╖└+-В┌щ╧ 'ZHБ╗╖╤лEЗfКцJ╧Nxаь⌠8РтE ⌠з│W/°<┐-И7л# oJ╛dЭ≥7^т?аыHЫ4²H9└`kОdеwg╨d©╓Р9╣лА·ё▒x╫│╧Ж

View File

@ -0,0 +1 @@
add_subdirectory(TestsUtils)

View File

@ -0,0 +1,29 @@
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(PLUGIN "TestsUtils")
set(
SRC
plugin.cpp
utils.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)
set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}")
install(TARGETS ${PLUGIN} DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/)
install(FILES qmldir DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/)

View File

@ -0,0 +1,10 @@
#include <QtQml>
#include "plugin.h"
#include "utils.h"
void TestsUtilsPlugin::registerTypes(const char *uri)
{
//@uri TestUtils
qmlRegisterSingletonType<TestsUtilsPlugin>(uri, 1, 0, "TestUtils", [](QQmlEngine *, QJSEngine *) -> QObject * { return new TestsUtils; });
}

View File

@ -0,0 +1,16 @@
#ifndef TESTSUTILSPLUGIN_H
#define TESTSUTILSPLUGIN_H
#include <QQmlExtensionPlugin>
class TestsUtilsPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID
"org.qt-project.Qt.QQmlExtensionInterface")
public:
void registerTypes(const char *uri) override;
};
#endif

View File

@ -0,0 +1,2 @@
module TestUtils
plugin TestUtils

View File

@ -0,0 +1,38 @@
#include <QFile>
#include <QDir>
#include <QUrl>
#include <QUuid>
#include <QtCore/QStandardPaths>
#include <quazip5/JlCompress.h>
#include "utils.h"
QString TestsUtils::getTempPath()
{
qFatal("yp");
// Get the system's temporary directory
QString tempDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
qDebug() << "TempDir : " << tempDir;
// Generate a unique UUID
QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
// Create a new directory using the generated UUID
QString newTempDir = tempDir + "/" + uuid;
QDir dir;
if (!dir.exists(newTempDir)) {
// Create the directory
if (dir.mkpath(newTempDir)) {
return newTempDir; // Return the path if successful
} else {
return "Failed to create directory"; // Return an error message
}
} else {
return newTempDir; // If the directory already exists, return its path
}
}

View File

@ -0,0 +1,19 @@
#ifndef TESTSUTILS_H
#define TESTSUTILS_H
#include <QObject>
#include <QUrl>
#include <QQuickWindow>
class TestsUtils : public QObject
{
Q_OBJECT
public:
TestsUtils() = default;
~TestsUtils() override = default;
Q_INVOKABLE QString getTempPath();
};
#endif

11
tests/unit/tst_git.qml Normal file
View File

@ -0,0 +1,11 @@
import Git 1.0
import QtQuick 2.9
import QtTest 1.2
TestCase {
function test_git_clone() {
verify(Git.clone("", ""));
}
name: "git"
}

11
tests/unit/tst_pass.qml Normal file
View File

@ -0,0 +1,11 @@
import Git 1.0
import QtQuick 2.9
import QtTest 1.2
TestCase {
function test_git_clone() {
verify(Git.clone("", ""));
}
name: "git"
}

15
tests/unit/tst_utils.qml Normal file
View File

@ -0,0 +1,15 @@
import QtQuick 2.9
import QtTest 1.2
import TestUtils 1.0
import Utils 1.0
TestCase {
function test_unzip() {
var tempPath = TestUtils.getTempPath() + "/password-store";
var zipUrl = Qt.resolvedUrl("../assets/archive.zip");
var r = Utils.unzip(zipUrl, tempPath);
verify(r, "Unzip return an error %1".arg(zipUrl));
}
name: "utils"
}