1
0
mirror of https://github.com/QRouland/UTPass.git synced 2025-07-06 11:52:29 +00:00

16 Commits

Author SHA1 Message Date
399173b776 Fix style command 2025-01-10 15:28:42 +01:00
365e530efc Update repo and issues links 2025-01-10 15:01:38 +01:00
3aa99791b8 Use tmp dir during clone to keep orignal passstore in case of error 2025-01-10 14:41:04 +01:00
80a5055b78 Some minors fix 2025-01-10 13:58:46 +01:00
5e5a092da1 Initial git clone feature 2025-01-10 13:48:38 +01:00
d33932be6d Setup git libs for Pass plugin 2025-01-07 22:08:46 +01:00
7418894456 Fix import shared library libqgpgme 2025-01-07 22:07:43 +01:00
63d53caad5 Update Readme wiki links 2025-01-07 20:46:15 +01:00
62c19f8ff9 Create FUNDING.yml 2025-01-07 16:44:14 +00:00
37c481ece1 Update build : use prebuild binaries + Add libgit2 2025-01-07 14:41:48 +01:00
c6d7a025ff Fix loading password before Pass plugin init 2023-06-19 14:58:09 -04:00
cec4e7dabc Update to configuration to clickable 7 2023-06-17 21:53:54 -04:00
a9b979b011 It can be useful for people that are not really into gpg/pass to know
how to export the specficic files needed for UTPass to work properly.
2020-08-03 10:25:24 +02:00
42efea67d8 Add git plugin TG-41 closed 2019-10-07 18:18:49 +02:00
1818d3d7e8 Add libgit2 as third dependencies TG-40 2019-10-07 18:18:49 +02:00
df5321644a bump version 2019-10-07 18:18:49 +02:00
58 changed files with 979 additions and 662 deletions

View File

@ -5,8 +5,7 @@ suffix=none
--align-reference=name --align-reference=name
--convert-tabs --convert-tabs
--attach-namespaces --attach-namespaces
--max-code-length=100 --max-code-length=120
--max-instatement-indent=120
--pad-header --pad-header
--pad-oper --pad-oper
--lineend=linux --lineend=linux

2
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,2 @@
ko_fi: qrouland # Replace with a single Ko-fi username

13
.gitignore vendored
View File

@ -1,5 +1,6 @@
# Builds dirs # Builds dirs
build* build*
.cache
# IDE & Devs tools # IDE & Devs tools
.clickable .clickable
@ -10,13 +11,7 @@ build*
*.kdev4 *.kdev4
*swp *swp
scripts scripts
CMakeLists.txt.*
# Third parties ouput dir # venv
libs/third/local venv
# desktop
desktop
# Test (Not Ready yet !)
tests

30
.gitmodules vendored
View File

@ -1,30 +0,0 @@
[submodule "third/gpgme"]
path = libs/gpg/gpgme
url = https://github.com/gpg/gpgme
[submodule "third/libassuan"]
path = libs/gpg/libassuan
url = https://github.com/gpg/libassuan
[submodule "third/libgpg-error"]
path = libs/gpg/libgpg-error
url = https://github.com/gpg/libgpg-error
[submodule "third/gnupg"]
path = libs/gpg/gnupg
url = https://github.com/gpg/gnupg
[submodule "libs/utils/quazip"]
path = libs/quazip
url = https://github.com/stachenov/quazip
[submodule "libs/gpg/gpgme"]
path = libs/gpg/gpgme
url = https://github.com/gpg/gpgme
[submodule "libs/gpg/libassuan"]
path = libs/gpg/libassuan
url = https://github.com/gpg/libassuan
[submodule "libs/gpg/libgpg-error"]
path = libs/gpg/libgpg-error
url = https://github.com/gpg/libgpg-error
[submodule "libs/gpg/gnupg"]
path = libs/gpg/gnupg
url = https://github.com/gpg/gnupg
[submodule "libs/quazip"]
path = libs/quazip
url = https://github.com/stachenov/quazip

View File

@ -3,6 +3,10 @@ cmake_minimum_required(VERSION 3.5.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
endif()
execute_process( execute_process(
COMMAND dpkg-architecture -qDEB_HOST_ARCH COMMAND dpkg-architecture -qDEB_HOST_ARCH
OUTPUT_VARIABLE CLICK_ARCH OUTPUT_VARIABLE CLICK_ARCH
@ -28,10 +32,11 @@ set(PROJECT_NAME "UTPass")
set(FULL_PROJECT_NAME "utpass.qrouland") set(FULL_PROJECT_NAME "utpass.qrouland")
set(CMAKE_INSTALL_PREFIX /) set(CMAKE_INSTALL_PREFIX /)
set(DATA_DIR /) set(DATA_DIR /)
set(BIN_DIR ${DATA_DIR}lib/bin)
set(DESKTOP_FILE_NAME ${PROJECT_NAME}.desktop) 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) qt5_use_modules(${PROJECT_NAME} Gui Qml Quick)
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
@ -41,20 +46,13 @@ configure_file(${CMAKE_CURRENT_BINARY_DIR}/manifest.json ${CMAKE_CURRENT_BINARY_
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json DESTINATION ${CMAKE_INSTALL_PREFIX}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json DESTINATION ${CMAKE_INSTALL_PREFIX})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest_.json DESTINATION ${DATA_DIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest_.json DESTINATION ${DATA_DIR})
#install(DIRECTORY desktop DESTINATION ${DATA_DIR})
install(FILES ${PROJECT_NAME}.apparmor DESTINATION ${DATA_DIR}) install(FILES ${PROJECT_NAME}.apparmor DESTINATION ${DATA_DIR})
install(FILES ${PROJECT_NAME}.contenthub DESTINATION ${DATA_DIR}) install(FILES ${PROJECT_NAME}.contenthub DESTINATION ${DATA_DIR})
install(FILES LICENSE DESTINATION ${DATA_DIR}) install(FILES LICENSE DESTINATION ${DATA_DIR})
install(DIRECTORY qml DESTINATION ${DATA_DIR}) install(DIRECTORY qml DESTINATION ${DATA_DIR})
install(DIRECTORY assets DESTINATION ${DATA_DIR}) install(DIRECTORY assets DESTINATION ${DATA_DIR})
file(GLOB_RECURSE BIN_FILES
"build/${ARCH_TRIPLET}/gpg/local/bin/*")
install(
FILES ${BIN_FILES}
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
DESTINATION ${BIN_DIR}
)
# Translations # Translations
file(GLOB_RECURSE I18N_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/po qml/*.qml qml/*.js) file(GLOB_RECURSE I18N_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/po qml/*.qml qml/*.js)
@ -81,4 +79,3 @@ add_subdirectory(po)
add_subdirectory(plugins) add_subdirectory(plugins)
add_custom_target(${PROJECT_NAME}_FILES ALL SOURCES ${PROJECT_SRC_FILES}) add_custom_target(${PROJECT_NAME}_FILES ALL SOURCES ${PROJECT_SRC_FILES})

View File

@ -8,19 +8,48 @@ UTPass is avalaible on the [OpenStore](open-store.io)
[![OpenStore](https://open-store.io/badges/en_US.png)](https://open-store.io/app/utpass.qrouland) [![OpenStore](https://open-store.io/badges/en_US.png)](https://open-store.io/app/utpass.qrouland)
## Build & Tests
See [Build & Tests wiki page](https://taiga.rdrive.ovh/project/utpass/wiki/build-tests)
## Contributing & Issues
See [Contributing wiki page](https://taiga.rdrive.ovh/project/utpass/wiki/contributing)
## Features ## Features
The goal is to be closest possible of the features offer by [ZX2C4s pass command line application](https://www.passwordstore.org/). The goal is to be closest possible of the features offer by [ZX2C4s pass command line application](https://www.passwordstore.org/).
See [Features wiki page](https://taiga.rdrive.ovh/project/utpass/wiki/contributing) for details. See [Features wiki page](https://taiga.rdrive.ovh/project/utpass/wiki/contributing) for details.
## Export/Import
Assuming that there are already passwords in another device using [ZX2C4s pass command line application](https://www.passwordstore.org/) and, therefore, that [gpg keys](https://gnupg.org/) have been previously generated for encryption purposes, these may be helpful commands:
Export gpg private keys in order to decrypt passwords:
```
gpg --output keys.gpg --export-secret-keys
```
Export passwords, assuming they reside in *.password-store* folder:
```
zip passwords.zip -r .password-store/
```
Both files have the correct format for UTPass to import them and work as intended. It is highly recommended to remove them after imported to **UTPass**.
## Build & Tests
See [Build & Tests wiki page](https://github.com/QRouland/UTPass/wiki/Build-&-Tests)
## Contributing & Issues
See [Contributing wiki page](https://github.com/QRouland/UTPass/wiki/Contributing)
## Useful Links
Some useful links related to UTPass development :
* [Ubports](https://ubports.com/) : Ubuntu Touch Community
* [ZX2C4s pass command line application](https://www.passwordstore.org/) : the standard unix password manager.
* [Clickable](https://github.com/bhdouglass/clickable) : Compile, build, and deploy Ubuntu Touch click packages
* [GnuPG](https://gnupg.org/): The GNU Privacy Guard
* [Gpgme](https://www.gnupg.org/software/gpgme/index.html) : GnuPG Made Easy (GPGME) is a library designed to make access to GnuPG easier for applications
## License ## License
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
@ -37,12 +66,3 @@ See [Features wiki page](https://taiga.rdrive.ovh/project/utpass/wiki/contributi
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
## Useful Links
Some useful links related to UTPass development :
* [Ubports](https://ubports.com/) : Ubuntu Touch Community
* [ZX2C4s pass command line application](https://www.passwordstore.org/) : the standard unix password manager.
* [Clickable](https://github.com/bhdouglass/clickable) : Compile, build, and deploy Ubuntu Touch click packages
* [Gpgme](https://www.gnupg.org/software/gpgme/index.html) : GnuPG Made Easy (GPGME) is a library designed to make access to GnuPG easier for applications

View File

@ -1,6 +1,7 @@
{ {
"policy_groups": [ "policy_groups": [
"content_exchange" "content_exchange",
"networking"
], ],
"policy_version": 16.04 "policy_version": 20.04
} }

View File

@ -4,4 +4,4 @@ Exec=UTPass
Icon=assets/logo.svg Icon=assets/logo.svg
Terminal=false Terminal=false
Type=Application Type=Application
X-Ubuntu-Touch=true X-Lomiri-Touch=true

View File

@ -1,22 +0,0 @@
{
"template": "cmake",
"kill": "UTPass",
"scripts": {
"style": "echo 'Astyle :' && astyle --options=.astylerc main.cpp && astyle --options=.astylerc --recursive 'plugins/*.cpp,*.h' && echo 'QmlFmt :' && qmlfmt -l tests && qmlfmt -w tests && qmlfmt -l qml && qmlfmt -w qml"
},
"libraries": {
"gpg": {
"template": "cmake",
"make_jobs": 4,
"dependencies_build": [
"texinfo",
"gpgsm",
"bison"
]
},
"quazip": {
"template": "cmake",
"make_jobs": 4
}
}
}

34
clickable.yaml Normal file
View File

@ -0,0 +1,34 @@
clickable_minimum_required: 8
builder: cmake
kill: UTPass
scripts:
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'
dependencies_target:
- libgpgmepp-dev
- libgpgme-dev
- libgit2-dev
- libquazip5-dev
- gpg
install_lib:
- "libgpg-error.so.0.28.0"
- "libassuan.so*"
- "libgpgme.so*"
- "libgpgmepp.so*"
- "libqgpgme.so*"
- "libgit2.so*"
- "libquazip5.so*"
- "libmbedtls.so*"
- "libmbedx509.so*"
- "libmbedcrypto.so*"
- "libhttp_parser.so*"
- "libssh2.so*"
install_bin:
- "gpg"

View File

@ -1,68 +0,0 @@
cmake_minimum_required(VERSION 3.5.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
include(${CMAKE_ROOT}/Modules/ExternalProject.cmake)
execute_process(
COMMAND dpkg-architecture -qDEB_HOST_MULTIARCH
OUTPUT_VARIABLE ARCH_TRIPLET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process (
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/clean.sh ${ARCH_TRIPLET}
)
set(EXTERNAL_LIBS "${CMAKE_CURRENT_BINARY_DIR}/local/")
set(THIRD_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
set(LIBGPGERROR_PATH "${THIRD_PATH}/libgpg-error")
set(LIBASSUAN_PATH "${THIRD_PATH}/libassuan")
set(LIBGPGME_PATH "${THIRD_PATH}/gpgme")
set(GNUPG_PATH "${THIRD_PATH}/gnupg")
ExternalProject_Add(
LibGpgError
INSTALL_DIR ${EXTERNAL_LIBS}
DOWNLOAD_COMMAND ""
SOURCE_DIR ${LIBGPGERROR_PATH}
CONFIGURE_COMMAND <SOURCE_DIR>/autogen.sh && <SOURCE_DIR>/configure --prefix=${EXTERNAL_LIBS} --enable-static=yes --enable-shared=no --with-pic=yes --enable-maintainer-mode --host ${ARCH_TRIPLET} --disable-doc --disable-dependency-tracking
BUILD_IN_SOURCE 1
BUILD_COMMAND make
INSTALL_COMMAND make install
)
ExternalProject_Add(
LibGpgAssuan
DEPENDS LibGpgError
INSTALL_DIR ${EXTERNAL_LIBS}
DOWNLOAD_COMMAND ""
SOURCE_DIR ${LIBASSUAN_PATH}
CONFIGURE_COMMAND <SOURCE_DIR>/autogen.sh && <SOURCE_DIR>/configure --prefix=${EXTERNAL_LIBS} --enable-static=yes --enable-shared=no --with-pic=yes --enable-maintainer-mode --with-libgpg-error-prefix=${EXTERNAL_LIBS} --host ${ARCH_TRIPLET} --disable-doc --disable-dependency-tracking
BUILD_IN_SOURCE 1
BUILD_COMMAND make
INSTALL_COMMAND make install
)
ExternalProject_Add(
LibGpgme
DEPENDS LibGpgError LibGpgAssuan
INSTALL_DIR ${EXTERNAL_LIBS}
DOWNLOAD_COMMAND ""
SOURCE_DIR ${LIBGPGME_PATH}
CONFIGURE_COMMAND <SOURCE_DIR>/autogen.sh && <SOURCE_DIR>/configure --enable-languages=cpp,qt --enable-static=yes --enable-shared=no --with-pic=yes --prefix=${EXTERNAL_LIBS} --enable-maintainer-mode --with-libgpg-error-prefix=${EXTERNAL_LIBS} --with-libassuan-prefix=${EXTERNAL_LIBS} --host ${ARCH_TRIPLET} --disable-doc --disable-largefile --disable-dependency-tracking
BUILD_IN_SOURCE 1
BUILD_COMMAND make
INSTALL_COMMAND make install
)
ExternalProject_Add(
Gnupg
DEPENDS LibGpgError LibGpgAssuan
INSTALL_DIR ${EXTERNAL_LIBS}
DOWNLOAD_COMMAND ""
SOURCE_DIR ${GNUPG_PATH}
CONFIGURE_COMMAND <SOURCE_DIR>/autogen.sh && <SOURCE_DIR>/configure --prefix=${EXTERNAL_LIBS} --with-libgpg-error-prefix=${EXTERNAL_LIBS} --with-libassuan-prefix=${EXTERNAL_LIBS} --enable-maintainer-mode --with-libassuan-prefix=${EXTERNAL_LIBS} --host ${ARCH_TRIPLET} --disable-doc --disable-dependency-tracking
BUILD_IN_SOURCE 1
BUILD_COMMAND make
INSTALL_COMMAND make install
)

View File

@ -1,14 +0,0 @@
#!/bin/bash
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
if [ ! -z "$1" ] && [ -d $SCRIPTPATH/../../build/$1/gpg ]; then
rm -rf $SCRIPTPATH/../../build/$1/gpg
fi
git submodule update --init --recursive
for LIB in $SCRIPTPATH/*/
do
echo $LIB
cd $LIB && git clean -xdf && git reset --hard HEAD
done

Submodule libs/gpg/gnupg deleted from 8ae6a246be

Submodule libs/gpg/gpgme deleted from ea11c2a13c

Submodule libs/quazip deleted from 4df6c7412e

View File

@ -10,7 +10,7 @@
"content-hub": "UTPass.contenthub" "content-hub": "UTPass.contenthub"
} }
}, },
"version": "0.0.2", "version": "0.0.3-dev",
"maintainer": "Quentin Rouland <quentin@qrouland.com>", "maintainer": "Quentin Rouland <quentin@qrouland.com>",
"framework" : "ubuntu-sdk-16.04" "framework" : "ubuntu-sdk-20.04"
} }

View File

@ -1,2 +1,3 @@
add_subdirectory(Git)
add_subdirectory(Pass) add_subdirectory(Pass)
add_subdirectory(Utils) add_subdirectory(Utils)

View 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}/)

34
plugins/Git/git.cpp Normal file
View File

@ -0,0 +1,34 @@
#include <QUrl>
#include <QtCore/QDir>
#include <QDebug>
#include <QStandardPaths>
#include "git.h"
#include "libgit.h"
bool Git::clone(QString url, QString destination_dir_path)
{
qInfo() << "Cloning " << url << " to destination " << destination_dir_path;
QDir tmp_dir(QStandardPaths::writableLocation(
QStandardPaths::CacheLocation).append("/clone"));
tmp_dir.removeRecursively();
tmp_dir.mkpath(".");
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
if (ret) {
qDebug() << "Removing password_store " << destination_dir_path;
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();
return ret ;
}

20
plugins/Git/git.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef GIT_H
#define GIT_H
#include <QUrl>
#include <QObject>
class Git : public QObject
{
Q_OBJECT
public:
Git() = default;
~Git() override = default;
Q_INVOKABLE bool clone(QString url, QString path);
// Q_INVOKABLE bool update(QUrl url, QString path);
};
#endif

52
plugins/Git/libgit.cpp Normal file
View File

@ -0,0 +1,52 @@
#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)
{
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
View 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
View 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
View 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
View File

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

View File

@ -26,29 +26,26 @@ add_library(${PLUGIN} MODULE ${SRC})
set_target_properties(${PLUGIN} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGIN}) set_target_properties(${PLUGIN} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGIN})
qt5_use_modules(${PLUGIN} Qml Quick DBus) qt5_use_modules(${PLUGIN} Qml Quick DBus)
set(EXTERNAL_LIBS "${CMAKE_SOURCE_DIR}/build/${ARCH_TRIPLET}/gpg/local/")
INCLUDE_DIRECTORIES(${EXTERNAL_LIBS}/include) add_library(gpgerror SHARED IMPORTED)
set_property(TARGET gpgerror PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libgpg-error.so.0.28.0")
add_library(GpgError STATIC IMPORTED) add_library(libassuan SHARED IMPORTED)
set_property(TARGET GpgError PROPERTY IMPORTED_LOCATION "${EXTERNAL_LIBS}/lib/libgpg-error.a") set_property(TARGET libassuan PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libassuan.so")
add_library(GpgAssuan STATIC IMPORTED) add_library(libgpgme SHARED IMPORTED)
set_property(TARGET GpgAssuan PROPERTY IMPORTED_LOCATION "${EXTERNAL_LIBS}/lib/libassuan.a") set_property(TARGET libgpgme PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libgpgme.so")
add_library(Gpgme STATIC IMPORTED) add_library(libgpgmepp SHARED IMPORTED)
set_property(TARGET Gpgme PROPERTY IMPORTED_LOCATION "${EXTERNAL_LIBS}/lib/libgpgme.a") set_property(TARGET libgpgmepp PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libgpgmepp.so")
add_library(Gpgmepp STATIC IMPORTED) add_library(libqgpgme SHARED IMPORTED)
set_property(TARGET Gpgmepp PROPERTY IMPORTED_LOCATION "${EXTERNAL_LIBS}/lib/libgpgmepp.a") set_property(TARGET libqgpgme PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libqgpgme.so")
add_library(QGpgme STATIC IMPORTED)
set_property(TARGET QGpgme PROPERTY IMPORTED_LOCATION "${EXTERNAL_LIBS}/lib/libqgpgme.a")
target_link_libraries(${PLUGIN} QGpgme Gpgmepp Gpgme GpgAssuan GpgError) target_link_libraries(${PLUGIN} gpgerror libassuan libgpgme libgpgmepp libqgpgme)
set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}") set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}")
install(TARGETS ${PLUGIN} DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/) install(TARGETS ${PLUGIN} DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/)
install(FILES qmldir DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/) install(FILES qmldir DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/)

View File

@ -4,7 +4,6 @@
#include <QDir> #include <QDir>
#include <QtCore/QStandardPaths> #include <QtCore/QStandardPaths>
#include <gpgme.h> #include <gpgme.h>
#include <gpgme++/data.h> #include <gpgme++/data.h>
#include <gpgme++/global.h> #include <gpgme++/global.h>
@ -24,8 +23,8 @@
#include <qgpgme/changeownertrustjob.h> #include <qgpgme/changeownertrustjob.h>
#include "gpg.h" #include "gpg.h"
#include "pass.h"
#include "passphraseprovider.h" #include "passphraseprovider.h"
#include "qprocess.h"
@ -37,8 +36,6 @@ Gpg::Gpg()
{ {
m_window = nullptr; m_window = nullptr;
initializeLibrary();
Gpg::initGpgConfig(); Gpg::initGpgConfig();
auto error = checkEngine(OpenPGP); auto error = checkEngine(OpenPGP);
@ -66,15 +63,33 @@ QString Gpg::initGpgHome()
} }
QString Gpg::findCommandPath(const QString &command)
{
// Retrieve the PATH environment variable
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString pathEnv = env.value("PATH");
// Split the PATH by colon
QStringList pathDirs = pathEnv.split(":", QString::SkipEmptyParts);
// Check each directory in the PATH
foreach (const QString &dir, pathDirs) {
QFileInfo fileInfo(QDir(dir).filePath(command));
// If the file exists and is executable, return the path
if (fileInfo.exists() && fileInfo.isExecutable()) {
return fileInfo.absoluteFilePath();
}
}
return QString::null;
}
QString Gpg::initGpgExec() QString Gpg::initGpgExec()
{ {
QString path = QDir::currentPath().append("/lib/bin/gpg"); QString path = findCommandPath("gpg");
QFileInfo file(path); if (path.isNull()) {
if (!file.isFile()) { qFatal("No valid gpg exec found !");
qFatal("GNUPGEXEC file not found !");
}
if (!file.isExecutable()) {
qFatal("GNUPGEXEC file not executable !");
} }
return path; return path;
} }
@ -82,20 +97,30 @@ QString Gpg::initGpgExec()
void Gpg::initGpgConfig() void Gpg::initGpgConfig()
{ {
auto home = initGpgHome(); initializeLibrary();
auto exec = initGpgExec(); gpgme_set_global_flag("disable-gpgconf", "1");
QString home = initGpgHome();
qDebug() << "Gpg home is " << home;
QString exec = initGpgExec();
qDebug() << "Gpg exec is " << exec;
QFile agentConf(home + QStringLiteral("/gpg-agent.conf")); QFile agentConf(home + QStringLiteral("/gpg-agent.conf"));
agentConf.remove(); agentConf.remove();
agentConf.open(QIODevice::WriteOnly); agentConf.open(QIODevice::WriteOnly);
agentConf.write("allow-loopback-pinentry"); agentConf.write("allow-loopback-pinentry\n");
agentConf.close(); agentConf.close();
gpgme_set_engine_info ( auto err = gpgme_set_engine_info (
GPGME_PROTOCOL_OpenPGP, GPGME_PROTOCOL_OpenPGP,
exec.toLocal8Bit().data(), exec.toLocal8Bit().data(),
home.toLocal8Bit().data() home.toLocal8Bit().data()
); );
if (err != GPG_ERR_NO_ERROR) {
qDebug() << "Error code : " << err;
qDebug() << "Error str : " << gpg_strerror(err);
qFatal("GPGME set engine info failed !");
}
} }

View File

@ -13,15 +13,15 @@ class Gpg
{ {
private: private:
Gpg(); Gpg();
QObject *m_window; QObject *m_window;
QString findCommandPath(const QString &command);
QString initGpgHome(); QString initGpgHome();
QString initGpgExec(); QString initGpgExec();
void initGpgConfig(); void initGpgConfig();
public: public:
~Gpg();
static std::shared_ptr<Gpg> instance() static std::shared_ptr<Gpg> instance()
{ {
static std::shared_ptr<Gpg> s{new Gpg}; static std::shared_ptr<Gpg> s{new Gpg};

View File

@ -4,7 +4,6 @@
#include "pass.h" #include "pass.h"
#include "gpg.h" #include "gpg.h"
#include "passphraseprovider.h"
#include "passkeymodel.h" #include "passkeymodel.h"
@ -18,49 +17,48 @@ void Pass::init(QObject *window)
if (!window) { if (!window) {
qFatal("window is invalid. Abording."); qFatal("window is invalid. Abording.");
} }
Gpg::instance()->setWindow(window); Gpg::instance()->setWindow(window);
QDir dir(m_password_store); QDir dir(m_password_store);
if (!dir.exists()) if (!dir.exists()) {
dir.mkpath("."); dir.mkpath(".");
qDebug() << "Password Store is :" << m_password_store; }
qInfo() << "Password Store is :" << m_password_store;
} }
void Pass::decrypt(QUrl url) void Pass::decrypt(QUrl url)
{ {
qDebug() << "Start decrypting"; qInfo() << "Decrypting";
auto decrypt_ret = Gpg::instance()->decryptFromFile(url.toLocalFile()); auto decrypt_ret = Gpg::instance()->decryptFromFile(url.toLocalFile());
if (decrypt_ret.first) { if (decrypt_ret.first) {
qDebug() << "Decrypt Failed"; qInfo() << "Decrypt Failed";
emit decryptFailed(); emit decryptFailed();
} else if (decrypt_ret.second.isNull()) { } else if (decrypt_ret.second.isNull()) {
qDebug() << "Decrypt Canceled"; qInfo() << "Decrypt Canceled";
emit decryptCanceled(); emit decryptCanceled();
} else { } else {
qDebug() << "Decrypt OK"; qInfo() << "Decrypt OK";
emit decrypted(decrypt_ret.second); emit decrypted(decrypt_ret.second);
} }
} }
bool Pass::gpgDeleteKeyId(QString id) bool Pass::gpgDeleteKeyId(QString id)
{ {
qDebug() << "Start deleting Key id " << id; qInfo() << "Deleting Key id " << id;
return !Gpg::instance()->deleteKeyId(id); return !Gpg::instance()->deleteKeyId(id);
} }
bool Pass::gpgImportKeyFromFile(QUrl url) bool Pass::gpgImportKeyFromFile(QUrl url)
{ {
qDebug() << "Start importing Key from " << url; qInfo() << "Importing Key from " << url;
return !Gpg::instance()->importKeysFromFile(url.toLocalFile()); return !Gpg::instance()->importKeysFromFile(url.toLocalFile());
} }
QVariant Pass::gpgGetAllKeysModel() QVariant Pass::gpgGetAllKeysModel()
{ {
qInfo() << "Getting all key form gpg ";
return QVariant::fromValue(PassKeyModel::keysToPassKeyQObjectList( return QVariant::fromValue(PassKeyModel::keysToPassKeyQObjectList(
Gpg::instance()->getAllKeys().second)); Gpg::instance()->getAllKeys().second));
} }
QString Pass::getPasswordStore()
{
return m_password_store;
}

View File

@ -9,6 +9,9 @@
class Pass : public QObject class Pass : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString password_store READ password_store)
private:
QString m_password_store; QString m_password_store;
signals: signals:
@ -16,13 +19,16 @@ signals:
void decryptCanceled(); void decryptCanceled();
void decryptFailed(); void decryptFailed();
public: public:
Pass(); Pass();
~Pass() override = default; ~Pass() override = default;
QString password_store() const
{
return m_password_store;
}
Q_INVOKABLE void init(QObject *window); Q_INVOKABLE void init(QObject *window);
Q_INVOKABLE QString getPasswordStore();
Q_INVOKABLE void decrypt(QUrl url); Q_INVOKABLE void decrypt(QUrl url);
Q_INVOKABLE bool gpgDeleteKeyId(QString id); Q_INVOKABLE bool gpgDeleteKeyId(QString id);
Q_INVOKABLE bool gpgImportKeyFromFile(QUrl url); Q_INVOKABLE bool gpgImportKeyFromFile(QUrl url);

View File

@ -7,7 +7,6 @@
#include <QEventLoop> #include <QEventLoop>
#include <QSemaphore> #include <QSemaphore>
#include <gpgme++/interfaces/passphraseprovider.h> #include <gpgme++/interfaces/passphraseprovider.h>
#include "passphraseprovider.h"
#include "gpg.h" #include "gpg.h"

View File

@ -23,15 +23,10 @@ add_library(${PLUGIN} MODULE ${SRC})
set_target_properties(${PLUGIN} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGIN}) set_target_properties(${PLUGIN} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGIN})
qt5_use_modules(${PLUGIN} Qml Quick DBus) qt5_use_modules(${PLUGIN} Qml Quick DBus)
set(EXTERNAL_LIBS "${CMAKE_SOURCE_DIR}/build/${ARCH_TRIPLET}/quazip/install/") add_library(libquazip5 SHARED IMPORTED)
set_property(TARGET libquazip5 PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libquazip5.so")
INCLUDE_DIRECTORIES(${EXTERNAL_LIBS}/include)
add_library(quazip STATIC IMPORTED)
set_property(TARGET quazip PROPERTY IMPORTED_LOCATION "${EXTERNAL_LIBS}/lib/libquazip5.a")
target_link_libraries(${PLUGIN} quazip)
target_link_libraries(${PLUGIN} libquazip5)
set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}") set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}")

View File

@ -7,8 +7,6 @@
#include "utils.h" #include "utils.h"
Utils::Utils() {};
bool Utils::unzip(QUrl zip_url, QString dir_out_path) bool Utils::unzip(QUrl zip_url, QString dir_out_path)
{ {
auto tmp_dir_path = QStandardPaths::writableLocation( auto tmp_dir_path = QStandardPaths::writableLocation(

View File

@ -10,7 +10,7 @@ class Utils : public QObject
Q_OBJECT Q_OBJECT
public: public:
Utils(); Utils() = default;
~Utils() override = default; ~Utils() override = default;
Q_INVOKABLE bool unzip(QUrl zip_url, QString dir_out); Q_INVOKABLE bool unzip(QUrl zip_url, QString dir_out);

View File

@ -1,5 +1,5 @@
# UTPass # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the utpass.qrouland package. # This file is distributed under the same license as the utpass.qrouland package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
# #
@ -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: 2019-09-21 14:01+0000\n" "POT-Creation-Date: 2025-01-10 14:39+0100\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"
@ -37,8 +37,8 @@ msgstr ""
msgid "Error !" msgid "Error !"
msgstr "" msgstr ""
#: ../qml/dialogs/ErrorDialog.qml:15 ../qml/dialogs/SuccessDialog.qml:15 #: ../qml/dialogs/ErrorDialog.qml:15
msgid "OK" msgid "Close"
msgstr "" msgstr ""
#: ../qml/dialogs/PassphraseDialog.qml:7 #: ../qml/dialogs/PassphraseDialog.qml:7
@ -57,20 +57,11 @@ msgstr ""
msgid "Success !" msgid "Success !"
msgstr "" msgstr ""
#: ../qml/pages/headers/MainHeader.qml:8 ../qml/pages/headers/StackHeader.qml:8 #: ../qml/dialogs/SuccessDialog.qml:15
#: UTPass.desktop.in.h:1 msgid "OK"
msgid "UTPass"
msgstr "" msgstr ""
#: ../qml/pages/headers/MainHeader.qml:23 #: ../qml/pages/Info.qml:11 ../qml/pages/headers/MainHeader.qml:58
msgid "Search"
msgstr ""
#: ../qml/pages/headers/MainHeader.qml:51 ../qml/pages/settings/Settings.qml:14
msgid "Settings"
msgstr ""
#: ../qml/pages/headers/MainHeader.qml:58 ../qml/pages/Info.qml:11
msgid "Info" msgid "Info"
msgstr "" msgstr ""
@ -103,6 +94,50 @@ 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 zip in the settings"
msgstr "" msgstr ""
#: ../qml/pages/headers/MainHeader.qml:8 ../qml/pages/headers/StackHeader.qml:8
#: UTPass.desktop.in.h:1
msgid "UTPass"
msgstr ""
#: ../qml/pages/headers/MainHeader.qml:23
msgid "Search"
msgstr ""
#: ../qml/pages/headers/MainHeader.qml:51 ../qml/pages/settings/Settings.qml:14
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/ImportGitClone.qml:85
#: ../qml/pages/settings/ImportZip.qml:89
msgid "Password store sucessfully imported !"
msgstr ""
#: ../qml/pages/settings/ImportKeyFile.qml:17 #: ../qml/pages/settings/ImportKeyFile.qml:17
msgid "GPG Key Import" msgid "GPG Key Import"
msgstr "" msgstr ""
@ -128,10 +163,6 @@ msgstr ""
msgid "Password store import failed !" msgid "Password store import failed !"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportZip.qml:89
msgid "Password store sucessfully imported !"
msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:16 #: ../qml/pages/settings/InfoKeys.qml:16
msgid "Info Keys" msgid "Info Keys"
msgstr "" msgstr ""
@ -177,9 +208,13 @@ msgid "Password Store"
msgstr "" msgstr ""
#: ../qml/pages/settings/Settings.qml:47 #: ../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" msgid "Import a Password Store Zip"
msgstr "" msgstr ""
#: ../qml/pages/settings/Settings.qml:56 #: ../qml/pages/settings/Settings.qml:60
msgid "Warning: importing delete any exiting Password Store" msgid "Warning: importing delete any exiting Password Store"
msgstr "" msgstr ""

View File

@ -1,50 +1,46 @@
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import Pass 1.0
import QtQuick 2.4 import QtQuick 2.4
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import Ubuntu.Components 1.3
import Ubuntu.Components.Popups 1.3
import Pass 1.0
import "dialogs" import "dialogs"
MainView { MainView {
id: root id: root
objectName: "mainView"
applicationName: "utpass.qrouland"
automaticOrientation: false
width: units.gu(48)
height: units.gu(80)
signal responsePassphraseDialog(bool canceled, string passphrase) signal responsePassphraseDialog(bool canceled, string passphrase)
function initPass(rootView) { function initPass(rootView) {
Pass.init(rootView) Pass.init(rootView);
pageStack.push(Qt.resolvedUrl("pages/PasswordList.qml"));
} }
function callPassphraseDialog(useridHint, description, previousWasBad) { function callPassphraseDialog(useridHint, description, previousWasBad) {
//TODO use parameters to impove passphrase dialog //TODO use parameters to impove passphrase dialog
var passphraseDialog = PopupUtils.open( var passphraseDialog = PopupUtils.open(Qt.resolvedUrl("dialogs/PassphraseDialog.qml"));
Qt.resolvedUrl("dialogs/PassphraseDialog.qml")) passphraseDialog.activateFocus();
passphraseDialog.activateFocus() var validated = function validated(passphrase) {
responsePassphraseDialog(false, passphrase);
var validated = function (passphrase) { };
responsePassphraseDialog(false, passphrase) var canceled = function canceled() {
responsePassphraseDialog(true, "");
};
passphraseDialog.validated.connect(validated);
passphraseDialog.canceled.connect(canceled);
} }
var canceled = function () { objectName: "mainView"
responsePassphraseDialog(true, "") applicationName: "utpass.qrouland"
} automaticOrientation: false
width: units.gu(48)
passphraseDialog.validated.connect(validated) height: units.gu(80)
passphraseDialog.canceled.connect(canceled)
}
PageStack { PageStack {
id: pageStack id: pageStack
anchors.fill: parent
anchors.fill: parent
Component.onCompleted: { Component.onCompleted: {
pageStack.push(Qt.resolvedUrl("pages/PasswordList.qml"))
} }
} }
} }

View File

@ -1,18 +1,18 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import "../styles" import "../styles"
import Lomiri.Components 1.3
import QtQuick 2.4
Item { Item {
id: copyText id: copyText
property string text
property string text
property bool commonBorder: true property bool commonBorder: true
property int lBorderwidth: 0 property int lBorderwidth: 0
property int rBorderwidth: 0 property int rBorderwidth: 0
property int tBorderwidth: 0 property int tBorderwidth: 0
property int bBorderwidth: 0 property int bBorderwidth: 0
property int commonBorderWidth: 0 property int commonBorderWidth: 0
property string borderColor: UbuntuColors.warmGrey property string borderColor: LomiriColors.warmGrey
width: parent.width width: parent.width
height: units.gu(6) height: units.gu(6)
@ -33,26 +33,27 @@ Item {
anchors.rightMargin: units.gu(2) anchors.rightMargin: units.gu(2)
height: units.gu(4) height: units.gu(4)
name: "edit-copy" name: "edit-copy"
color: UbuntuColors.orange color: LomiriColors.orange
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onPressed: { onPressed: {
parent.color = UbuntuColors.warmGrey parent.color = LomiriColors.warmGrey;
} }
onClicked: { onClicked: {
var mimeData = Clipboard.newData() var mimeData = Clipboard.newData();
mimeData.text = copyText.text mimeData.text = copyText.text;
Clipboard.push(mimeData) Clipboard.push(mimeData);
} }
onReleased: { onReleased: {
parent.color = theme.palette.normal.background parent.color = theme.palette.normal.background;
} }
} }
CustomBorder { CustomBorder {
id: cb id: cb
commonBorder: copyText.commonBorder commonBorder: copyText.commonBorder
lBorderwidth: copyText.lBorderwidth lBorderwidth: copyText.lBorderwidth
rBorderwidth: copyText.rBorderwidth rBorderwidth: copyText.rBorderwidth
@ -60,5 +61,7 @@ Item {
bBorderwidth: copyText.bBorderwidth bBorderwidth: copyText.bBorderwidth
borderColor: copyText.borderColor borderColor: copyText.borderColor
} }
} }
} }

View File

@ -1,20 +1,19 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import "../styles" import "../styles"
import Lomiri.Components 1.3
import QtQuick 2.4
Item { Item {
id: externalLink id: externalLink
property string url property string url
property string text property string text
property bool commonBorder: true property bool commonBorder: true
property int lBorderwidth: 0 property int lBorderwidth: 0
property int rBorderwidth: 0 property int rBorderwidth: 0
property int tBorderwidth: 0 property int tBorderwidth: 0
property int bBorderwidth: 0 property int bBorderwidth: 0
property int commonBorderWidth: 0 property int commonBorderWidth: 0
property string borderColor: UbuntuColors.warmGrey property string borderColor: LomiriColors.warmGrey
width: parent.width width: parent.width
height: units.gu(6) height: units.gu(6)
@ -36,18 +35,19 @@ Item {
width: units.gu(4) width: units.gu(4)
height: units.gu(4) height: units.gu(4)
name: "go-next" name: "go-next"
color: UbuntuColors.orange color: LomiriColors.orange
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
Qt.openUrlExternally(externalLink.url) Qt.openUrlExternally(externalLink.url);
} }
} }
CustomBorder { CustomBorder {
id: cb id: cb
commonBorder: externalLink.commonBorder commonBorder: externalLink.commonBorder
lBorderwidth: externalLink.lBorderwidth lBorderwidth: externalLink.lBorderwidth
rBorderwidth: externalLink.rBorderwidth rBorderwidth: externalLink.rBorderwidth
@ -55,5 +55,7 @@ Item {
bBorderwidth: externalLink.bBorderwidth bBorderwidth: externalLink.bBorderwidth
borderColor: externalLink.borderColor borderColor: externalLink.borderColor
} }
} }
} }

View File

@ -1,13 +1,14 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Components.Popups 1.3
import Pass 1.0
import "../styles"
import "../dialogs" import "../dialogs"
import "../styles"
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import Pass 1.0
import QtQuick 2.4
Component { Component {
Rectangle { Rectangle {
id: fileDir id: fileDir
property string activePasswordName property string activePasswordName
anchors.right: parent.right anchors.right: parent.right
@ -27,31 +28,27 @@ Component {
anchors.rightMargin: units.gu(2) anchors.rightMargin: units.gu(2)
height: units.gu(4) height: units.gu(4)
name: fileIsDir ? "go-next" : "lock" name: fileIsDir ? "go-next" : "lock"
color: UbuntuColors.orange color: LomiriColors.orange
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
if (fileIsDir) { if (fileIsDir) {
folderModel.folder = folderModel.folder + "/" + fileName folderModel.folder = folderModel.folder + "/" + fileName;
backAction.visible = true backAction.visible = true;
} else { } else {
fileDir.activePasswordName = fileBaseName fileDir.activePasswordName = fileBaseName;
Pass.onDecrypted.connect(function(text) { Pass.onDecrypted.connect(function(text) {
pageStack.push(Qt.resolvedUrl("../pages/Password.qml"), pageStack.push(Qt.resolvedUrl("../pages/Password.qml"), {
{
"plainText": text, "plainText": text,
"title": fileDir.activePasswordName "title": fileDir.activePasswordName
}) });
}) });
Pass.onDecryptFailed.connect(function() { Pass.onDecryptFailed.connect(function() {
PopupUtils.open(passwordPageDecryptError) PopupUtils.open(passwordPageDecryptError);
}) });
Pass.decrypt(folderModel.folder + "/" + fileName);
Pass.decrypt(folderModel.folder + "/" + fileName)
} }
} }
} }
@ -62,17 +59,18 @@ Component {
rBorderwidth: 0 rBorderwidth: 0
tBorderwidth: 0 tBorderwidth: 0
bBorderwidth: 1 bBorderwidth: 1
borderColor: UbuntuColors.warmGrey borderColor: LomiriColors.warmGrey
} }
Component { Component {
id: passwordPageDecryptError id: passwordPageDecryptError
ErrorDialog { ErrorDialog {
textError: i18n.tr("Decryption failed !") textError: i18n.tr("Decryption failed !")
onDialogClosed: {
pageStack.pop()
}
} }
} }
} }
} }

View File

@ -1,23 +1,21 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import "../styles" import "../styles"
import Lomiri.Components 1.3
import QtQuick 2.4
Item { Item {
id: pageStackLink id: pageStackLink
property string page property string page
property var params: { property var params: {
} }
property string text property string text
property bool commonBorder: true property bool commonBorder: true
property int lBorderwidth: 0 property int lBorderwidth: 0
property int rBorderwidth: 0 property int rBorderwidth: 0
property int tBorderwidth: 0 property int tBorderwidth: 0
property int bBorderwidth: 0 property int bBorderwidth: 0
property int commonBorderWidth: 0 property int commonBorderWidth: 0
property string borderColor: UbuntuColors.warmGrey property string borderColor: LomiriColors.warmGrey
width: parent.width width: parent.width
height: units.gu(6) height: units.gu(6)
@ -39,18 +37,19 @@ Item {
width: units.gu(4) width: units.gu(4)
height: units.gu(4) height: units.gu(4)
name: "go-next" name: "go-next"
color: UbuntuColors.orange color: LomiriColors.orange
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
pageStack.push(page, params) pageStack.push(page, params);
} }
} }
CustomBorder { CustomBorder {
id: cb id: cb
commonBorder: pageStackLink.commonBorder commonBorder: pageStackLink.commonBorder
lBorderwidth: pageStackLink.lBorderwidth lBorderwidth: pageStackLink.lBorderwidth
rBorderwidth: pageStackLink.rBorderwidth rBorderwidth: pageStackLink.rBorderwidth
@ -58,5 +57,7 @@ Item {
bBorderwidth: pageStackLink.bBorderwidth bBorderwidth: pageStackLink.bBorderwidth
borderColor: pageStackLink.borderColor borderColor: pageStackLink.borderColor
} }
} }
} }

View File

@ -1,6 +1,6 @@
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import QtQuick 2.4 import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Components.Popups 1.3
Dialog { Dialog {
id: doubleValidationDialog id: doubleValidationDialog
@ -9,8 +9,8 @@ Dialog {
property string text1 property string text1
property string text2 property string text2
signal doubleValidated signal doubleValidated()
signal canceled signal canceled()
Text { Text {
visible: nb_validation == 0 visible: nb_validation == 0
@ -26,27 +26,28 @@ Dialog {
Button { Button {
text: i18n.tr("Ok") text: i18n.tr("Ok")
color: UbuntuColors.green color: LomiriColors.green
onClicked: { onClicked: {
if (nb_validation == 1) { if (nb_validation == 1) {
nb_validation = 0 nb_validation = 0;
doubleValidated() doubleValidated();
PopupUtils.close(doubleValidationDialog) PopupUtils.close(doubleValidationDialog);
} else { } else {
nb_validation += 1 nb_validation += 1;
} }
} }
} }
Button { Button {
id: cancelButton id: cancelButton
text: i18n.tr("Cancel") text: i18n.tr("Cancel")
color: UbuntuColors.red color: LomiriColors.red
onClicked: { onClicked: {
nb_validation = 0 nb_validation = 0;
canceled() canceled();
PopupUtils.close(doubleValidationDialog) PopupUtils.close(doubleValidationDialog);
} }
} }
} }

View File

@ -1,22 +1,24 @@
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import QtQuick 2.4 import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Components.Popups 1.3
Dialog { Dialog {
id: dialogSuccess id: dialogError
property string textError property string textError
signal dialogClosed signal dialogClosed()
title: i18n.tr("Error !") title: i18n.tr("Error !")
text: textError text: textError
Button { Button {
text: i18n.tr("OK") text: i18n.tr("Close")
color: UbuntuColors.red color: LomiriColors.red
onClicked: function() { onClicked: function() {
dialogClosed() dialogClosed();
PopupUtils.close(dialogSuccess) PopupUtils.close(dialogError);
} }
} }
} }

View File

@ -1,25 +1,25 @@
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import QtQuick 2.4 import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Components.Popups 1.3
Dialog { Dialog {
id: passphraseProvider id: passphraseProvider
title: i18n.tr("Authentication required")
text: i18n.tr("Enter passphrase:")
signal validated(string passphrase) signal validated(string passphrase)
signal canceled signal canceled()
function activateFocus() { function activateFocus() {
passphraseField.forceActiveFocus() passphraseField.forceActiveFocus();
} }
title: i18n.tr("Authentication required")
text: i18n.tr("Enter passphrase:")
TextField { TextField {
id: passphraseField id: passphraseField
placeholderText: i18n.tr("passphrase") placeholderText: i18n.tr("passphrase")
echoMode: TextInput.Password echoMode: TextInput.Password
onAccepted: okButton.clicked(text) onAccepted: okButton.clicked(text)
} }
@ -27,24 +27,23 @@ Dialog {
id: okButton id: okButton
text: i18n.tr("Ok") text: i18n.tr("Ok")
color: UbuntuColors.green color: LomiriColors.green
onClicked: { onClicked: {
validated(passphraseField.text) validated(passphraseField.text);
passphraseField.text = "" passphraseField.text = "";
PopupUtils.close(passphraseProvider) PopupUtils.close(passphraseProvider);
} }
} }
Button { Button {
id: cancelButton id: cancelButton
text: i18n.tr("Cancel") text: i18n.tr("Cancel")
color: LomiriColors.red
color: UbuntuColors.red
onClicked: { onClicked: {
canceled() canceled();
PopupUtils.close(passphraseProvider) PopupUtils.close(passphraseProvider);
} }
} }
} }

View File

@ -1,14 +1,14 @@
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import QtQuick 2.4 import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Components.Popups 1.3
Dialog { Dialog {
id: doubleValidationDialog id: doubleValidationDialog
property string text property string text
signal validated signal validated()
signal canceled signal canceled()
Text { Text {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
@ -17,21 +17,22 @@ Dialog {
Button { Button {
text: i18n.tr("Ok") text: i18n.tr("Ok")
color: UbuntuColors.green color: LomiriColors.green
onClicked: { onClicked: {
validated() validated();
PopupUtils.close(doubleValidationDialog) PopupUtils.close(doubleValidationDialog);
} }
} }
Button { Button {
id: cancelButton id: cancelButton
text: i18n.tr("Cancel") text: i18n.tr("Cancel")
color: UbuntuColors.red color: LomiriColors.red
onClicked: { onClicked: {
canceled() canceled();
PopupUtils.close(doubleValidationDialog) PopupUtils.close(doubleValidationDialog);
} }
} }
} }

View File

@ -1,22 +1,24 @@
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import QtQuick 2.4 import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Components.Popups 1.3
Dialog { Dialog {
id: dialogSuccess id: dialogSuccess
property string textSuccess property string textSuccess
signal dialogClosed signal dialogClosed()
title: i18n.tr("Success !") title: i18n.tr("Success !")
text: textSuccess text: textSuccess
Button { Button {
text: i18n.tr("OK") text: i18n.tr("OK")
color: UbuntuColors.green color: LomiriColors.green
onClicked: function() { onClicked: function() {
dialogClosed() dialogClosed();
PopupUtils.close(dialogSuccess) PopupUtils.close(dialogSuccess);
} }
} }
} }

View File

@ -1,14 +1,19 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import "headers"
import "../components" import "../components"
import Lomiri.Components 1.3
import QtQuick 2.4
import "headers"
Page { Page {
id: infoPage id: infoPage
header: StackHeader { Component.onCompleted: {
id: infoHeader var xhr = new XMLHttpRequest();
title: i18n.tr('Info') xhr.open("GET", "../../manifest_.json", false);
xhr.send();
var mJson = JSON.parse(xhr.responseText);
manifestTitle.text = "<b>" + mJson.title + "</b>";
manifestVersion.text = mJson.version + "<br>" + mJson.framework + "@" + mJson.architecture;
manifestMaintener.text = mJson.maintainer;
} }
Flow { Flow {
@ -24,6 +29,7 @@ Page {
Text { Text {
id: manifestTitle id: manifestTitle
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
width: parent.width width: parent.width
@ -35,12 +41,14 @@ Page {
Rectangle { Rectangle {
width: parent.width width: parent.width
height: units.gu(12) height: units.gu(12)
Image { Image {
source: "../../assets/logo.svg" source: "../../assets/logo.svg"
width: units.gu(12) width: units.gu(12)
height: units.gu(12) height: units.gu(12)
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
} }
Text { Text {
@ -54,6 +62,7 @@ Page {
Text { Text {
id: manifestVersion id: manifestVersion
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
width: parent.width width: parent.width
height: units.gu(4) height: units.gu(4)
@ -72,12 +81,14 @@ Page {
Text { Text {
id: manifestMaintener id: manifestMaintener
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
width: parent.width width: parent.width
height: units.gu(2) height: units.gu(2)
fontSizeMode: Text.Fit fontSizeMode: Text.Fit
font.pixelSize: 72 font.pixelSize: 72
} }
} }
Flow { Flow {
@ -85,14 +96,17 @@ Page {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
ExternalLink { ExternalLink {
url: "https://taiga.rdrive.ovh/project/utpass/issues" url: "https://github.com/QRouland/UTPass/issues"
text: i18n.tr("Suggest improvement(s) or report a bug(s)") text: i18n.tr("Suggest improvement(s) or report a bug(s)")
} }
ExternalLink { ExternalLink {
url: "https://git.rdrive.ovh/QRouland/UTPass" url: "https://github.com/QRouland/UTPass"
text: i18n.tr("Access to the source code") text: i18n.tr("Access to the source code")
} }
Text { Text {
width: parent.width width: parent.width
height: units.gu(2) height: units.gu(2)
@ -100,17 +114,13 @@ Page {
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: i18n.tr("Released under the terms of the GNU GPL v3") text: i18n.tr("Released under the terms of the GNU GPL v3")
} }
} }
Component.onCompleted: { header: StackHeader {
var xhr = new XMLHttpRequest() id: infoHeader
xhr.open("GET", "../../manifest_.json", false)
xhr.send()
var mJson = JSON.parse(xhr.responseText) title: i18n.tr('Info')
}
manifestTitle.text = "<b>" + mJson.title + "</b>"
manifestVersion.text = mJson.version + "<br>" + mJson.framework + "@" + mJson.architecture
manifestMaintener.text = mJson.maintainer
}
} }

View File

@ -1,6 +1,6 @@
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import QtQuick 2.4 import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Components.Popups 1.3
import "headers" import "headers"
Page { Page {
@ -10,38 +10,15 @@ Page {
property string plainText property string plainText
property var objects property var objects
header: PageHeader { Component.onCompleted: {
id: passwordPageHeader var text_split = passwordPage.plainText.split('\n');
width: parent.width var component = Qt.createComponent("../components/CopyText.qml");
height: units.gu(6) for (var i = 0; i < text_split.length; i++) {
title: passwordPage.title if (text_split[i]) {
var object = component.createObject(container);
contents: Item { object.text = text_split[i];
height: parent.height
width: parent.width
Label {
id: labelTitle
text: passwordPage.title
anchors.verticalCenter: parent.verticalCenter
} }
} }
leadingActionBar.height: units.gu(4)
leadingActionBar.actions: [
Action {
id: backAction
iconName: "back"
text: "Back"
onTriggered: {
passwordPage.plainText = ""
for (var object in objects) {
object.text = ""
object.destroy()
}
pageStack.pop()
}
}
]
} }
Rectangle { Rectangle {
@ -52,18 +29,49 @@ Page {
Flow { Flow {
id: container id: container
anchors.fill: parent anchors.fill: parent
} }
} }
Component.onCompleted: { header: PageHeader {
var text_split = passwordPage.plainText.split('\n') id: passwordPageHeader
var component = Qt.createComponent("../components/CopyText.qml")
for (var i = 0; i < text_split.length; i++) { width: parent.width
if (text_split[i]) { height: units.gu(6)
var object = component.createObject(container) title: passwordPage.title
object.text = text_split[i] leadingActionBar.height: units.gu(4)
leadingActionBar.actions: [
Action {
id: backAction
iconName: "back"
text: "Back"
onTriggered: {
passwordPage.plainText = "";
for (var object in objects) {
object.text = "";
object.destroy();
}
pageStack.pop();
} }
} }
]
contents: Item {
height: parent.height
width: parent.width
Label {
id: labelTitle
text: passwordPage.title
anchors.verticalCenter: parent.verticalCenter
} }
}
}
} }

View File

@ -1,8 +1,8 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import Qt.labs.folderlistmodel 2.1
import Pass 1.0
import "../components" import "../components"
import Lomiri.Components 1.3
import Pass 1.0
import Qt.labs.folderlistmodel 2.1
import QtQuick 2.4
import "headers" import "headers"
Page { Page {
@ -11,25 +11,8 @@ Page {
property string passwordStorePath property string passwordStorePath
anchors.fill: parent anchors.fill: parent
Component.onCompleted: {
header: MainHeader { passwordStorePath = "file:" + Pass.password_store;
id: passwordListHeader
leadingActionBar.height: units.gu(4)
leadingActionBar.actions: [
Action {
id: backAction
iconName: "back"
text: i18n.tr("Back")
visible: false
onTriggered: {
folderModel.folder = folderModel.parentFolder
if (folderModel.rootFolder === folderModel.folder) {
backAction.visible = false
}
}
}
]
} }
Rectangle { Rectangle {
@ -38,13 +21,14 @@ Page {
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
visible: folderModel.count == 0 visible: folderModel.count == 0
Text { Text {
text: i18n.tr( text: i18n.tr("No password found<br>You can import a password store zip in the settings")
"No password found<br>You can import a password store 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
} }
} }
ListView { ListView {
@ -56,17 +40,38 @@ Page {
model: FolderListModel { model: FolderListModel {
id: folderModel id: folderModel
nameFilters: ["*.gpg"] nameFilters: ["*.gpg"]
rootFolder: passwordStorePath rootFolder: passwordStorePath
folder: passwordStorePath folder: passwordStorePath
showDirs: true showDirs: true
} }
delegate: FileDir { delegate: FileDir {
id: fileDelegate id: fileDelegate
} }
} }
Component.onCompleted: { header: MainHeader {
passwordStorePath = "file:" + Pass.getPasswordStore() id: passwordListHeader
leadingActionBar.height: units.gu(4)
leadingActionBar.actions: [
Action {
id: backAction
iconName: "back"
text: i18n.tr("Back")
visible: false
onTriggered: {
folderModel.folder = folderModel.parentFolder;
if (folderModel.rootFolder === folderModel.folder)
backAction.visible = false;
} }
} }
]
}
}

View File

@ -1,40 +1,15 @@
import Lomiri.Components 1.3
import QtQuick 2.4 import QtQuick 2.4
import Ubuntu.Components 1.3
PageHeader { PageHeader {
id: mainHeader id: mainHeader
width: parent.width width: parent.width
height: units.gu(6) height: units.gu(6)
title: i18n.tr("UTPass") title: i18n.tr("UTPass")
contents: Item {
height: parent.height
width: parent.width
Label {
id: labelTitle
text: mainHeader.title
anchors.verticalCenter: parent.verticalCenter
visible: true
}
TextField {
id: searchBar
anchors.right: parent.right
anchors.left: parent.left
placeholderText: i18n.tr("Search")
height: units.gu(4)
visible: false
anchors.verticalCenter: parent.verticalCenter
onFocusChanged: {
}
}
}
trailingActionBar.height: units.gu(4) trailingActionBar.height: units.gu(4)
trailingActionBar.numberOfSlots: 2 trailingActionBar.numberOfSlots: 2
trailingActionBar.actions: [ trailingActionBar.actions: [
/*Action { TODO /*Action { TODO
iconName: "search" iconName: "search"
text: i18n.tr("Search") text: i18n.tr("Search")
@ -50,15 +25,43 @@ PageHeader {
iconName: "settings" iconName: "settings"
text: i18n.tr("Settings") text: i18n.tr("Settings")
onTriggered: { onTriggered: {
pageStack.push(Qt.resolvedUrl("../settings/Settings.qml")) pageStack.push(Qt.resolvedUrl("../settings/Settings.qml"));
} }
}, },
Action { Action {
iconName: "info" iconName: "info"
text: i18n.tr("Info") text: i18n.tr("Info")
onTriggered: { onTriggered: {
pageStack.push(Qt.resolvedUrl("../Info.qml")) pageStack.push(Qt.resolvedUrl("../Info.qml"));
} }
} }
] ]
contents: Item {
height: parent.height
width: parent.width
Label {
id: labelTitle
text: mainHeader.title
anchors.verticalCenter: parent.verticalCenter
visible: true
}
TextField {
id: searchBar
anchors.right: parent.right
anchors.left: parent.left
placeholderText: i18n.tr("Search")
height: units.gu(4)
visible: false
anchors.verticalCenter: parent.verticalCenter
onFocusChanged: {
}
}
}
} }

View File

@ -1,31 +1,36 @@
import Lomiri.Components 1.3
import QtQuick 2.4 import QtQuick 2.4
import Ubuntu.Components 1.3
PageHeader { PageHeader {
id: stackHeader id: stackHeader
width: parent.width width: parent.width
height: units.gu(6) height: units.gu(6)
title: i18n.tr("UTPass") title: i18n.tr("UTPass")
contents: Item {
height: parent.height
width: parent.width
Label {
id: labelTitle
text: stackHeader.title
anchors.verticalCenter: parent.verticalCenter
}
}
leadingActionBar.height: units.gu(4) leadingActionBar.height: units.gu(4)
leadingActionBar.actions: [ leadingActionBar.actions: [
Action { Action {
id: backAction id: backAction
iconName: "back" iconName: "back"
text: "Back" text: "Back"
onTriggered: { onTriggered: {
pageStack.pop() pageStack.pop();
} }
} }
] ]
contents: Item {
height: parent.height
width: parent.width
Label {
id: labelTitle
text: stackHeader.title
anchors.verticalCenter: parent.verticalCenter
}
}
} }

View File

@ -0,0 +1,104 @@
import "../../components"
import "../../dialogs"
import "../headers"
import Git 1.0
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import Pass 1.0
import QtQuick 2.4
Page {
id: importGitClonePage
Component.onCompleted: {
PopupUtils.open(importGitCloneValidation, importGitClonePage);
}
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)
PopupUtils.open(dialogImportGitCloneSuccess);
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 {
id: dialogImportGitCloneSuccess
SuccessDialog {
textSuccess: i18n.tr("Password store sucessfully imported !")
onDialogClosed: {
pageStack.pop();
pageStack.pop();
}
}
}
header: StackHeader {
id: importGitCloneHeader
title: i18n.tr('Git Clone Import')
}
}

View File

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

View File

@ -1,99 +1,97 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Content 1.3
import Ubuntu.Components.Popups 1.3
import Pass 1.0
import Utils 1.0
import "../headers"
import "../../dialogs" import "../../dialogs"
import "../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 { Page {
id: importZipPage id: importZipPage
property var activeTransfer property var activeTransfer
header: StackHeader { Component.onCompleted: {
id: importZipHeader PopupUtils.open(importZipPageImportValidation, importZipPage);
title: i18n.tr("Zip Password Store Import")
} }
ContentPeerPicker { ContentPeerPicker {
anchors.top: importZipHeader.bottom anchors.top: importZipHeader.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.topMargin: importZipPage.header.height anchors.topMargin: importZipPage.header.height
width: parent.width width: parent.width
visible: parent.visible visible: parent.visible
showTitle: false showTitle: false
contentType: ContentType.Text contentType: ContentType.Text
handler: ContentHandler.Source handler: ContentHandler.Source
onPeerSelected: { onPeerSelected: {
peer.selectionType = ContentTransfer.Single peer.selectionType = ContentTransfer.Single;
importZipPage.activeTransfer = peer.request() importZipPage.activeTransfer = peer.request();
importZipPage.activeTransfer.stateChanged.connect(function() { importZipPage.activeTransfer.stateChanged.connect(function() {
if (importZipPage.activeTransfer.state === ContentTransfer.Charged) { if (importZipPage.activeTransfer.state === ContentTransfer.Charged) {
console.log("Charged") console.log("Charged");
console.log(importZipPage.activeTransfer.items[0].url) console.log(importZipPage.activeTransfer.items[0].url);
var status = Utils.unzip(importZipPage.activeTransfer.items[0].url, Pass.getPasswordStore());
var status = Utils.unzip( Utils.rmFile(importZipPage.activeTransfer.items[0].url);
importZipPage.activeTransfer.items[0].url, if (status)
Pass.getPasswordStore()) PopupUtils.open(dialogImportZipPageSuccess);
else
Utils.rmFile(importZipPage.activeTransfer.items[0].url) PopupUtils.open(dialogImportZipPageError);
importZipPage.activeTransfer = null;
if (status) {
PopupUtils.open(dialogImportZipPageSuccess)
} else {
PopupUtils.open(dialogImportZipPageError)
} }
importZipPage.activeTransfer = null });
} }
})
}
onCancelPressed: { onCancelPressed: {
pageStack.pop() pageStack.pop();
} }
} }
ContentTransferHint { ContentTransferHint {
id: transferHint id: transferHint
anchors.fill: parent anchors.fill: parent
activeTransfer: importZipPage.activeTransfer activeTransfer: importZipPage.activeTransfer
} }
Component { Component {
id: importZipPageImportValidation id: importZipPageImportValidation
SimpleValidationDialog { SimpleValidationDialog {
text: i18n.tr( text: i18n.tr("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 ?")
onCanceled: { onCanceled: {
pageStack.pop() pageStack.pop();
} }
} }
} }
Component { Component {
id: dialogImportZipPageError id: dialogImportZipPageError
ErrorDialog { ErrorDialog {
textError: i18n.tr("Password store import failed !") textError: i18n.tr("Password store import failed !")
} }
} }
Component { Component {
id: dialogImportZipPageSuccess id: dialogImportZipPageSuccess
SuccessDialog { SuccessDialog {
textSuccess: i18n.tr("Password store sucessfully imported !") textSuccess: i18n.tr("Password store sucessfully imported !")
onDialogClosed: { onDialogClosed: {
pageStack.pop() pageStack.pop();
} pageStack.pop();
} }
} }
Component.onCompleted: {
PopupUtils.open(importZipPageImportValidation, importZipPage)
} }
header: StackHeader {
id: importZipHeader
title: i18n.tr("Zip Password Store Import")
}
} }

View File

@ -1,28 +1,23 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Components.Popups 1.3
import Pass 1.0
import "../headers"
import "../../components" import "../../components"
import "../../dialogs" import "../../dialogs"
import "../headers"
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import Pass 1.0
import QtQuick 2.4
Page { Page {
id: infoKeysPage id: infoKeysPage
property string currentKey property string currentKey
header: StackHeader {
id: infoKeysHeader
title: i18n.tr('Info Keys')
}
ListView { ListView {
id: infoKeysListView id: infoKeysListView
anchors.top: infoKeysHeader.bottom anchors.top: infoKeysHeader.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
model: Pass.gpgGetAllKeysModel() model: Pass.gpgGetAllKeysModel()
delegate: Grid { delegate: Grid {
@ -38,6 +33,7 @@ Page {
Text { Text {
id: uidKey id: uidKey
width: parent.width width: parent.width
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
@ -46,11 +42,12 @@ Page {
Button { Button {
id: buttonDeleteKey id: buttonDeleteKey
text: i18n.tr("Delete this key") text: i18n.tr("Delete this key")
color: UbuntuColors.red color: LomiriColors.red
onClicked: { onClicked: {
infoKeysPage.currentKey = model.modelData.uid infoKeysPage.currentKey = model.modelData.uid;
PopupUtils.open(infoKeysPageDeleteValidation, infoKeysPage) PopupUtils.open(infoKeysPageDeleteValidation, infoKeysPage);
} }
} }
@ -58,43 +55,53 @@ Page {
width: parent.width width: parent.width
height: units.gu(1) height: units.gu(1)
} }
} }
} }
Component { Component {
id: infoKeysPageDeleteValidation id: infoKeysPageDeleteValidation
DoubleValidationDialog { DoubleValidationDialog {
text1: i18n.tr( text1: i18n.tr("You're are about to delete<br>%1<br>Continue ?").arg(infoKeysPage.currentKey)
"You're are about to delete<br>%1<br>Continue ?").arg( text2: i18n.tr("%1<br>will be definitively removed.<br>Continue ?").arg(infoKeysPage.currentKey)
infoKeysPage.currentKey)
text2: i18n.tr(
"%1<br>will be definitively removed.<br>Continue ?").arg(
infoKeysPage.currentKey)
onDoubleValidated: { onDoubleValidated: {
var status = Pass.gpgDeleteKeyId(infoKeysPage.currentKey) var status = Pass.gpgDeleteKeyId(infoKeysPage.currentKey);
if (status) { if (status)
PopupUtils.open(infoKeysPageDeleteSuccess) PopupUtils.open(infoKeysPageDeleteSuccess);
} else { else
PopupUtils.open(infoKeysPageDeleteError) PopupUtils.open(infoKeysPageDeleteError);
}
} }
} }
} }
Component { Component {
id: infoKeysPageDeleteError id: infoKeysPageDeleteError
ErrorDialog { ErrorDialog {
textError: i18n.tr("Key removal failed !") textError: i18n.tr("Key removal failed !")
} }
} }
Component { Component {
id: infoKeysPageDeleteSuccess id: infoKeysPageDeleteSuccess
SuccessDialog { SuccessDialog {
textSuccess: i18n.tr("Key successfully deleted !") textSuccess: i18n.tr("Key successfully deleted !")
onDialogClosed: { onDialogClosed: {
infoKeysListView.model = Pass.gpgGetAllKeysModel() infoKeysListView.model = Pass.gpgGetAllKeysModel();
} }
} }
} }
header: StackHeader {
id: infoKeysHeader
title: i18n.tr('Info Keys')
}
} }

View File

@ -1,19 +1,14 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import Pass 1.0
import "../headers"
import "../../components" import "../../components"
import "../headers"
import Lomiri.Components 1.3
import Pass 1.0
import QtQuick 2.4
Page { Page {
id: settingsPage id: settingsPage
property string gpgKeyId: "" property string gpgKeyId: ""
header: StackHeader {
id: settingsHeader
title: i18n.tr('Settings')
}
Flow { Flow {
anchors.top: settingsHeader.bottom anchors.top: settingsHeader.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
@ -27,14 +22,17 @@ Page {
height: units.gu(4) height: units.gu(4)
text: i18n.tr('GPG') text: i18n.tr('GPG')
} }
PageStackLink { PageStackLink {
page: Qt.resolvedUrl("ImportKeyFile.qml") page: Qt.resolvedUrl("ImportKeyFile.qml")
text: i18n.tr('Import a GPG key file') text: i18n.tr('Import a GPG key file')
} }
PageStackLink { PageStackLink {
page: Qt.resolvedUrl("InfoKeys.qml") page: Qt.resolvedUrl("InfoKeys.qml")
text: i18n.tr('Show GPG keys') text: i18n.tr('Show GPG keys')
} }
Text { Text {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
@ -42,18 +40,32 @@ Page {
height: units.gu(4) height: units.gu(4)
text: i18n.tr('Password Store') text: i18n.tr('Password Store')
} }
PageStackLink {
page: Qt.resolvedUrl("ImportGitClone.qml")
text: i18n.tr('Import a Password Store using Git')
}
PageStackLink { PageStackLink {
page: Qt.resolvedUrl("ImportZip.qml") page: Qt.resolvedUrl("ImportZip.qml")
text: i18n.tr('Import a Password Store Zip') text: i18n.tr('Import a Password Store Zip')
} }
Text { Text {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
width: parent.width width: parent.width
height: units.gu(4) height: units.gu(4)
color: UbuntuColors.red color: LomiriColors.red
text: i18n.tr( text: i18n.tr('Warning: importing delete any exiting Password Store')
'Warning: importing delete any exiting Password Store')
} }
} }
header: StackHeader {
id: settingsHeader
title: i18n.tr('Settings')
}
} }

View File

@ -4,18 +4,14 @@ import QtQuick 2.4
Rectangle { Rectangle {
property bool commonBorder: true property bool commonBorder: true
property int lBorderwidth: 1 property int lBorderwidth: 1
property int rBorderwidth: 1 property int rBorderwidth: 1
property int tBorderwidth: 1 property int tBorderwidth: 1
property int bBorderwidth: 1 property int bBorderwidth: 1
property int commonBorderWidth: 1 property int commonBorderWidth: 1
z: -1
property string borderColor: "white" property string borderColor: "white"
z: -1
color: borderColor color: borderColor
anchors { anchors {
@ -23,10 +19,10 @@ Rectangle {
right: parent.right right: parent.right
top: parent.top top: parent.top
bottom: parent.bottom bottom: parent.bottom
topMargin: commonBorder ? -commonBorderWidth : -tBorderwidth topMargin: commonBorder ? -commonBorderWidth : -tBorderwidth
bottomMargin: commonBorder ? -commonBorderWidth : -bBorderwidth bottomMargin: commonBorder ? -commonBorderWidth : -bBorderwidth
leftMargin: commonBorder ? -commonBorderWidth : -lBorderwidth leftMargin: commonBorder ? -commonBorderWidth : -lBorderwidth
rightMargin: commonBorder ? -commonBorderWidth : -rBorderwidth rightMargin: commonBorder ? -commonBorderWidth : -rBorderwidth
} }
} }