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

Compare commits

...

No commits in common. "5ab87a395dee80d7de227b118364bff370fc11c2" and "37c481ece1d7a75eecfd96e319e57b5b572b5f94" have entirely different histories.

80 changed files with 2538 additions and 808 deletions

View File

@ -1,5 +1,4 @@
suffix=none
recursive
--style=kr
--indent=spaces=4
--align-pointer=name

View File

@ -1,38 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

7
.gitignore vendored
View File

@ -1,5 +1,6 @@
# Builds dirs
build*
.cache
# IDE & Devs tools
.clickable
@ -9,6 +10,8 @@ build*
.codelite
*.kdev4
*swp
scripts
CMakeLists.txt.*
# Third parties ouput dir
third/local
# venv
venv

12
.gitmodules vendored
View File

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

View File

@ -3,11 +3,6 @@ cmake_minimum_required(VERSION 3.5.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
option(TEST_RUNNER "Run Test" OFF)
if(${TEST_RUNNER})
add_definitions(-DTEST_RUNNER)
endif()
execute_process(
COMMAND dpkg-architecture -qDEB_HOST_ARCH
OUTPUT_VARIABLE CLICK_ARCH
@ -20,7 +15,6 @@ execute_process(
OUTPUT_STRIP_TRAILING_WHITESPACE
)
find_package(Qt5Core)
find_package(Qt5Qml)
find_package(Qt5Quick)
@ -29,42 +23,40 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# Automatically create moc files
set(CMAKE_AUTOMOC ON)
set(QT_IMPORTS_DIR "lib/${ARCH_TRIPLET}")
set(PROJECT_NAME "UTPass")
set(FULL_PROJECT_NAME "utpass.qrouland")
set(CMAKE_INSTALL_PREFIX /)
set(DATA_DIR /)
set(BIN_DIR ${DATA_DIR}lib/${ARCH_TRIPLET}/bin)
# set(BIN_DIR ${DATA_DIR}lib/bin)
set(DESKTOP_FILE_NAME ${PROJECT_NAME}.desktop)
add_executable(${PROJECT_NAME} main.cpp)
if(${TEST_RUNNER})
find_package(Qt5QuickTest)
qt5_use_modules(${PROJECT_NAME} Gui Qml Quick QuickTest)
else()
qt5_use_modules(${PROJECT_NAME} Gui Qml Quick)
endif()
qt5_use_modules(${PROJECT_NAME} Gui Qml Quick)
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
configure_file(manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/manifest.json)
configure_file(${CMAKE_CURRENT_BINARY_DIR}/manifest.json ${CMAKE_CURRENT_BINARY_DIR}/manifest_.json COPYONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json DESTINATION ${CMAKE_INSTALL_PREFIX})
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}.contenthub DESTINATION ${DATA_DIR})
install(FILES LICENSE DESTINATION ${DATA_DIR})
install(DIRECTORY qml DESTINATION ${DATA_DIR})
install(DIRECTORY assets DESTINATION ${DATA_DIR})
file(GLOB_RECURSE BIN_FILES
"third/local/${ARCH_TRIPLET}/bin/*")
install(
FILES ${BIN_FILES}
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
DESTINATION ${BIN_DIR}
)
if(${TEST_RUNNER})
install(DIRECTORY tests DESTINATION ${DATA_DIR})
endif()
# file(GLOB_RECURSE BIN_FILES
# "/usr/bin/gpg*"
# )
# install(
# FILES ${BIN_FILES}
# PERMISSIONS OWNER_EXECUTE OWNER_READ GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
# DESTINATION ${BIN_DIR}
# )
# Translations
file(GLOB_RECURSE I18N_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/po qml/*.qml qml/*.js)
@ -91,4 +83,3 @@ add_subdirectory(po)
add_subdirectory(plugins)
add_custom_target(${PROJECT_NAME}_FILES ALL SOURCES ${PROJECT_SRC_FILES})

View File

@ -1,79 +0,0 @@
# Features
## Pass
- [ ] pass init [--path=subfolder,-p subfolder] gpg-id...
Initialize new password storage and use gpg-id for encryption.
Selectively reencrypt existing passwords using new gpg-id.
- [ ] Interactive dialog to init a new password storage
- [ ] Support subfolder
- [ ] Support reencrypt
---
- [x] pass [ls] [subfolder]
List passwords.
- [x] UI allowing to navigate through the password store showing the available passwords
---
- [ ] pass find pass-names...
List passwords that match pass-names
- [ ] Search bar allowing searchs by pass-names
---
- [ ] pass [show] [--clip[=line-number],-c[line-number]] pass-name
Show existing password and optionally put it on the clipboard.
If put on the clipboard, it will be cleared in 45 seconds.
- [ ] Click on a pass show the password
- [ ] Add option to put the password to the clipboard
- [ ] Clearing clipboard after 45 secs
- [ ] Line number option ???
---
- [ ] pass grep search-string
Search for password files containing search-string when decrypted.
- [ ] TBD
---
- [ ] pass insert [--echo,-e | --multiline,-m] [--force,-f] pass-name
Insert new password. Optionally, echo the password back to the console
during entry. Or, optionally, the entry may be multiline. Prompt before
overwriting existing password unless forced.
- [ ] TBD
---
- [ ] pass edit pass-name
Insert a new password or edit an existing password using editor.
- [ ] TBD
---
- [ ] pass generate [--no-symbols,-n] [--clip,-c] [--in-place,-i | --force,-f] pass-name [pass-length]
Generate a new password of pass-length (or 25 if unspecified) with optionally no symbols.
Optionally put it on the clipboard and clear board after 45 seconds.
Prompt before overwriting existing password unless forced.
Optionally replace only the first line of an existing file with a new password.
- [ ] TBD
---
- [ ] pass rm [--recursive,-r] [--force,-f] pass-name
Remove existing password or directory, optionally forcefully.
- [ ] TBD
---
- [ ] pass mv [--force,-f] old-path new-path
Renames or moves old-path to new-path, optionally forcefully, selectively reencrypting.
- [ ] TBD
---
- [ ] pass cp [--force,-f] old-path new-path
Copies old-path to new-path, optionally forcefully, selectively reencrypting.
- [ ] TBD
---
- [ ] pass git git-command-args...
If the password store is a git repository, execute a git command
specified by git-command-args.
- [ ] TBD
---
- [ ] pass help
Show this text.
- [ ] TBD
---
- [ ] pass version
Show version information.
- [ ] TBD
---
## Gpg
TODO

View File

@ -2,47 +2,42 @@
A Ubuntu Touch password management app aiming to be compatible with [ZX2C4s pass command line application](https://www.passwordstore.org/) the standard unix password manager.
# Build & Tests
## Installation
# Building
UTPass is avalaible on the [OpenStore](open-store.io)
* Install [clickable](https://github.com/bhdouglass/clickable).
* Clone this repo : ```git clone --recursive https://github.com/qrouland/UTPass```
* Move to app directory: ```cd UTPass```
* Build third parties : ```clickable third_build```
* Build & Run the app : ```clickable```
[![OpenStore](https://open-store.io/badges/en_US.png)](https://open-store.io/app/utpass.qrouland)
For more options/details see the [clickable documentation](http://clickable.bhdouglass.com/en/latest/index.html)
## Build & Tests
## Custom clickable command
* ```clickable third_build ``` : build third dependencies for arm architecture
* ```clickable third_build_d ``` : build third dependencies for amd64 architecture
* ```clickable third_clean ``` : clean third parties
* ```clickable style ``` : reformat the code (Required [astyle](https://astyle.sourceforge.net) & [qmlfmt](https://github.com/jesperhh/qmlfmt) to be installed)
See [Build & Tests wiki page](https://taiga.rdrive.ovh/project/utpass/wiki/build-tests)
## Testing
## Contributing & Issues
To switch to the tests build you need to add the following arguments to the build command : -DTEST_RUNNER=ON.
See [Contributing wiki page](https://taiga.rdrive.ovh/project/utpass/wiki/contributing)
To do so with clickable you need to use the following commands:
* Set CLICKABLE_BUILD_ARGS environnment variable : ```export CLICKABLE_BUILD_ARGS='-DTEST_RUNNER=ON'```
* Build & Run the tests ```clickable ```
To comeback to the standart app build :
* Unset CLICKABLE_BUILD_ARGS environnment variable ```unset CLICKABLE_BUILD_ARGS```
# Contributing
Any contributions are welcome using the github issue & pull request system.
Please respect the code style format by running ```clickable style``` before committing.
# Features
## Features
The goal is to be closest possible of the features offer by [ZX2C4s pass command line application](https://www.passwordstore.org/).
See to the FEATURES.MD file for details.
See [Features wiki page](https://taiga.rdrive.ovh/project/utpass/wiki/contributing) for details.
# License
## 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**.
## License
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
@ -60,10 +55,11 @@ See to the FEATURES.MD file for details.
along with this program. If not, see <http://www.gnu.org/licenses/>.
# Useful Links
## Useful Links
Some useful links related to UTpass development :
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

View File

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

5
UTPass.contenthub Normal file
View File

@ -0,0 +1,5 @@
{
"source": [
"text"
]
}

View File

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

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,16 +0,0 @@
{
"template": "cmake",
"kill": "UTPass",
"scripts": {
"third_build": "clickable run 'cd third && ./clean.sh && mkdir build && cd build && cmake .. && make'",
"third_build_d": "clickable run 'cd third && ./clean.sh && mkdir build && cd build && cmake .. && make' --arch amd64 ",
"third_clean": "cd third && rm -rf local && ./clean.sh",
"style": "astyle --options=.astylerc 'plugins/*.cpp,*.h' && qmlfmt -w tests && qmlfmt -w qml"
},
"dependencies_build": [
"texinfo",
"gpgsm",
"bison"
],
"dependencies_target": []
}

28
clickable.yaml Normal file
View File

@ -0,0 +1,28 @@
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 'QmlFmt :' &&
qmlfmt -l tests && qmlfmt -w tests && qmlfmt -l qml && qmlfmt -w qml
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.7"
- "libgit2.so"
- "libquazip5.so"
install_bin:
- "gpg"

View File

@ -6,13 +6,8 @@
#include <QtQml>
#ifdef TEST_RUNNER
#include <QtQuickTest/quicktest.h>
#endif
int main(int argc, char *argv[])
{
#ifndef TEST_RUNNER
qDebug() << "Starting app from main.cpp";
new QGuiApplication(argc, argv);
@ -20,12 +15,12 @@ int main(int argc, char *argv[])
auto *view = new QQuickView();
view->setSource(QUrl(QStringLiteral("qml/Main.qml")));
view->setResizeMode(QQuickView::SizeRootObjectToView);
view->show();
QObject *mainView = view->findChild<QObject *>("mainView");
QMetaObject::invokeMethod(
mainView, "initPass",
Q_ARG(QVariant, QVariant::fromValue(mainView))
);
return QGuiApplication::exec();
#else
qDebug() << "Starting tests from main.cpp";
return quick_test_main(argc, argv, "Tests", "tests/unit");
#endif
}

View File

@ -6,10 +6,11 @@
"hooks": {
"UTPass": {
"apparmor": "UTPass.apparmor",
"desktop": "UTPass.desktop"
"desktop": "UTPass.desktop",
"content-hub": "UTPass.contenthub"
}
},
"version": "0.0.1",
"version": "0.0.3-dev",
"maintainer": "Quentin Rouland <quentin@qrouland.com>",
"framework" : "ubuntu-sdk-16.04"
"framework" : "ubuntu-sdk-20.04"
}

View File

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

View File

@ -4,8 +4,11 @@ set(PLUGIN "Pass")
set(
SRC
plugin.cpp
git.cpp
pass.cpp
gpg.cpp
passkeymodel.h
passphraseprovider.h
)
set(CMAKE_AUTOMOC ON)
@ -24,30 +27,29 @@ add_library(${PLUGIN} MODULE ${SRC})
set_target_properties(${PLUGIN} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGIN})
qt5_use_modules(${PLUGIN} Qml Quick DBus)
set(EXTERNAL_LIBS "${CMAKE_SOURCE_DIR}/third/local/${ARCH_TRIPLET}")
set(THIRD_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
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)
set_property(TARGET GpgError PROPERTY IMPORTED_LOCATION "${EXTERNAL_LIBS}/lib/libgpg-error.a")
add_library(libassuan SHARED IMPORTED)
set_property(TARGET libassuan PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libassuan.so")
add_library(GpgAssuan STATIC IMPORTED)
set_property(TARGET GpgAssuan PROPERTY IMPORTED_LOCATION "${EXTERNAL_LIBS}/lib/libassuan.a")
add_library(libgpgme SHARED IMPORTED)
set_property(TARGET libgpgme PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libgpgme.so")
add_library(Gpgme STATIC IMPORTED)
set_property(TARGET Gpgme PROPERTY IMPORTED_LOCATION "${EXTERNAL_LIBS}/lib/libgpgme.a")
add_library(libgpgmepp SHARED IMPORTED)
set_property(TARGET libgpgmepp PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libgpgmepp.so")
add_library(Gpgmepp STATIC IMPORTED)
set_property(TARGET Gpgmepp PROPERTY IMPORTED_LOCATION "${EXTERNAL_LIBS}/lib/libgpgmepp.a")
add_library(libqgpgme SHARED IMPORTED)
set_property(TARGET libqgpgme PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libqgpgme.so.7")
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)
add_library(libgit2 SHARED IMPORTED)
set_property(TARGET libgit2 PROPERTY IMPORTED_LOCATION "/usr/lib/${ARCH_TRIPLET}/libgit2.so")
target_link_libraries(${PLUGIN} gpgerror libassuan libgpgme libgpgmepp libgit2)
set(QT_IMPORTS_DIR "/lib/${ARCH_TRIPLET}")
install(TARGETS ${PLUGIN} DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/)
install(FILES qmldir DESTINATION ${QT_IMPORTS_DIR}/${PLUGIN}/)

26
plugins/Pass/git.cpp Normal file
View File

@ -0,0 +1,26 @@
#include <QDebug>
#include <QUrl>
extern "C" {
#include <git2.h>
}
#include "git.h"
Git::Git()
{
git_libgit2_init();
}
Git::~Git() {
git_libgit2_shutdown();
}
bool Git::clone(QString url)
{
return false;
}

27
plugins/Pass/git.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef GIT_H
#define GIT_H
#include <QObject>
#include <QUrl>
#include <memory>
class Git
{
private:
Git();
public:
~Git();
static std::shared_ptr<Git> instance()
{
static std::shared_ptr<Git> s{new Git};
return s;
}
Git(Git const &) = delete;
void operator=(Git const &) = delete;
bool clone(QString url);
};
#endif

View File

@ -1,172 +1,294 @@
#include <memory>
#include <QDebug>
#include <QFile>
#include <QDir>
#include <QtCore/QStandardPaths>
#include <memory>
#include <gpgme.h>
#include <gpgme++/data.h>
#include <gpgme++/global.h>
#include <gpgme++/context.h>
#include <gpgme++/engineinfo.h>
#include <gpgme++/keylistresult.h>
#include <gpgme++/importresult.h>
#include <gpgme++/encryptionresult.h>
#include <gpgme++/decryptionresult.h>
#include <qgpgme/importjob.h>
#include <qgpgme/deletejob.h>
#include <qgpgme/decryptjob.h>
#include <qgpgme/encryptjob.h>
#include <qgpgme/protocol.h>
#include <qgpgme/keylistjob.h>
#include <qgpgme/changeownertrustjob.h>
#include "gpg.h"
#include "gpgme++/global.h"
#include "gpgme++/context.h"
#include "gpgme++/engineinfo.h"
#include "qgpgme/protocol.h"
#include "qgpgme/keylistjob.h"
#include "gpgme++/keylistresult.h"
#include "qgpgme/importjob.h"
#include "gpgme++/importresult.h"
#include "qgpgme/decryptjob.h"
#include "qgpgme/encryptjob.h"
#include "passphraseprovider.h"
#include "qprocess.h"
using namespace GpgME;
using namespace QGpgME;
Gpg::Gpg()
{
auto error = initializeLibrary(OpenPGP);
m_window = nullptr;
Gpg::initGpgConfig();
auto error = checkEngine(OpenPGP);
if (error) {
qDebug() << "Code Error : " << error.code();
qDebug() << "Error str : " << error.asString();
qFatal("GpgME init fail");
qFatal("GNUPG Engine check Fail");
}
setGpghome();
error = checkEngine(OpenPGP);
if (error) {
qDebug() << "Code Error : " << error.code();
qDebug() << "Error str : " << error.asString();
qFatal("Engine check Fail");
}
qDebug() << "GpgME Engine Version :" << engineInfo(OpenPGP).version();
qDebug() << "GNUPG Engine Version is :" << engineInfo(OpenPGP).version();
qDebug() << "GNUPG Executable is :" << engineInfo(OpenPGP).fileName();
qDebug() << "GNUPG Home is :" << engineInfo(OpenPGP).homeDirectory();
}
bool Gpg::setGpghome(QString path)
QString Gpg::initGpgHome()
{
QFileInfo file(path);
if (file.isFile()) {
qWarning() << "Not a directory GNUPGHOME not change";
return false;
}
if (file.isDir() and !file.isWritable()) {
qWarning() << "Not a writable directory GNUPGHOME not change";
return false;
}
QString path = QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation).append("/.gpghome");
QDir dir(path);
if (!dir.exists()) {
dir.mkpath(".");
}
m_gpghome = dir;
qputenv("GNUPGHOME", m_gpghome.absolutePath().toStdString().c_str());
qDebug() << "GNUPGHOME is :" << qgetenv("GNUPGHOME");
return path;
}
QString Gpg::decrypt(const QByteArray cipherText)
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()
{
/*
auto decJob = openpgp()->decryptJob();
auto ctx = DecryptJob::context(decJob);
QString path = findCommandPath("gpg");
if (path.isNull()) {
qFatal("No valid gpg exec found !");
}
return path;
}
TestPassphraseProvider provider;
ctx->setPassphraseProvider(&provider);
void Gpg::initGpgConfig()
{
initializeLibrary();
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"));
agentConf.remove();
agentConf.open(QIODevice::WriteOnly);
agentConf.write("allow-loopback-pinentry\n");
agentConf.close();
auto err = gpgme_set_engine_info (
GPGME_PROTOCOL_OpenPGP,
exec.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 !");
}
}
QPair<Error, QString> Gpg::decrypt(QByteArray cipherText)
{
auto job = openpgp()->decryptJob();
auto ctx = DecryptJob::context(job);
auto provider = new UTPassphraseProvider;
ctx->setPassphraseProvider(provider);
ctx->setPinentryMode(Context::PinentryLoopback);
QByteArray plainText;
decJob->exec(cipherText, plainText);
QByteArray plain_text;
auto decResult = job->exec(cipherText, plain_text);
return QString::fromUtf8(plainText);*/
delete job;
if (decResult.error()) {
qWarning() << "something gone wrong on decrypt";
qDebug() << "Code Error : " << decResult.error().code();
qDebug() << "Error str : " << decResult.error().asString();
}
return QPair<Error, QString>(decResult.error(), QString::fromUtf8(plain_text));
}
QString Gpg::decryptFromFile(QString path)
QPair<Error, QString> Gpg::decryptFromFile(QString path)
{
qDebug() << "Decrypt from " << path;
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Can't open the File";
return nullptr;
return QPair<Error, QString>(Error(), QString());;
}
QByteArray plainText = file.readAll();
return decrypt(plainText);
QByteArray cipherText = file.readAll();
file.close();
return decrypt(cipherText);
}
QByteArray Gpg::encrypt(QString str, QString uid, bool ascii_armor, bool text_mode)
QPair<Error, QByteArray> Gpg::encrypt(QString str, QString uid, bool ascii_armor, bool text_mode)
{
qDebug() << "Encrypt to QByteArray";
auto keys = getKeys(uid);
if (keys.first) {
return QPair<Error, QByteArray>(keys.first, QByteArray());
}
auto job = std::unique_ptr<EncryptJob>(openpgp()->encryptJob(ascii_armor, text_mode));
auto job = openpgp()
->encryptJob(
ascii_armor,
text_mode
);
QByteArray cipherText;
//auto result = job->exec(keys, str.toUtf8(), Context::AlwaysTrust, cipherText);
return cipherText;
auto result = job->exec(keys.second, str.toUtf8(), Context::AlwaysTrust, cipherText);
qDebug() << "Encrypted to QByteArray";
return QPair<Error, QByteArray>(result.error(), cipherText);
}
bool Gpg::encryptToFile(QString str, QString path, const QString uid, bool ascii_armor,
bool text_mode)
Error Gpg::encryptToFile(QString str, QString path, QString uid, bool ascii_armor,
bool text_mode)
{
qDebug() << "Encrypt to file " << path;
qDebug() << "Encrypting to file " << path;
QFile file(path);
if (!file.open(QIODevice::WriteOnly)) {
qWarning() << "Can't open the file to write it" ;
return false;
return Error();
}
file.write(encrypt(str, uid, ascii_armor, text_mode));
return true;
auto encrypt_ret = encrypt(str, uid, ascii_armor, text_mode);
if (encrypt_ret.first) {
file.write(encrypt_ret.second);
}
qDebug() << "Encrypting to file " << path;
return encrypt_ret.first;
}
std::vector<Key> Gpg::getKeys(QString pattern_uid, bool remote, bool include_sigs, bool validate)
QPair<Error, std::vector< GpgME::Key >> Gpg::getAllKeys ( bool remote, const bool include_sigs,
bool validate )
{
qDebug() << "Getting the key " << pattern_uid;
auto *job = openpgp()->keyListJob(remote, include_sigs, validate);
return getKeys(QString(""), remote, include_sigs, validate);
}
QPair<Error, std::vector<Key>> Gpg::getKeys(QString pattern_uid, bool remote, bool include_sigs,
bool validate)
{
qDebug() << "Getting the keys " << pattern_uid;
auto job = std::unique_ptr<KeyListJob>(openpgp()->keyListJob(remote, include_sigs, validate));
std::vector<Key> keys;
auto result = job->exec(QStringList() << pattern_uid, false, keys);
delete job;
return keys;
qDebug() << "Got the keys " << pattern_uid;
return QPair<Error, std::vector< Key >>(result.error(), keys);
}
QStringList Gpg::getAllKeysId(bool remote, bool include_sigs, bool validate)
QPair<Error, Key> Gpg::getKey(QString uid, bool remote, bool include_sigs, bool validate)
{
qDebug() << "Show all available key";
auto job = openpgp()->keyListJob(remote, remote, validate);
std::vector<Key> keys;
auto result = job->exec(QStringList(""), false, keys);
delete job;
qDebug() << "Getting the key " << uid;
auto keys = getKeys(uid, remote, include_sigs, validate);
if (keys.empty()) {
qDebug() << "No key found";
return QStringList();
if (keys.first or keys.second.size() != 1) {
qWarning() << "Bad id";
return QPair<Error, Key>(keys.first, Key::null);
}
auto r = QStringList();
for (const auto &key : keys) {
r.append(QLatin1String(key.keyID()));
qDebug() << "Key" << QLatin1String(key.keyID());
}
return r;
qDebug() << "Got the key " << uid;
return QPair<Error, Key>(keys.first, keys.second.front());
}
bool Gpg::importKeyFromFile(QString path)
Error Gpg::importKeysFromFile(QString path)
{
qDebug() << "Importing the key file" << path;
qDebug() << "Decrypt from " << path;
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Can't open the File";
return false;
return Error();
}
auto job = openpgp()->importJob();
auto ctx = ImportJob::context(job);
auto provider = new UTPassphraseProvider;
ctx->setPassphraseProvider(provider);
ctx->setPinentryMode(Context::PinentryLoopback);
auto result = job->exec(file.readAll());
delete job;
qDebug() << "numImported" << result.numImported();
qDebug() << "numSecretKeysImported" << result.numSecretKeysImported();
qDebug() << "numSecretKeysConsidered" << result.numSecretKeysConsidered();
qDebug() << "numSecretKeysUnchanged" << result.numSecretKeysUnchanged();
qDebug() << "numUnchanged" << result.numUnchanged();
file.close();
delete job;
delete provider;
if (result.error()) {
qWarning() << "Import go wrong";
return false;
qDebug() << "Code Error : " << result.error().code();
qDebug() << "Error str : " << result.error().asString();
}
return result.imports().size() == 1;
qDebug() << "Imported the key file" << path;
return result.error();
}
Error Gpg::deleteKeyId(QString uid)
{
qDebug() << "Deleting key id " << uid;
auto key = getKey(uid);
if (key.first) {
return key.first;
}
auto ctx = std::unique_ptr<Context>(Context::createForProtocol(OpenPGP));
auto err = ctx->deleteKey(key.second, true);
if (err) {
qWarning() << "Delete go wrong";
qDebug() << "Code Error : " << err.code();
qDebug() << "Error str : " << err.asString();
return err;
}
qDebug() << "Deleted key id" << uid;
return err;
}

View File

@ -2,16 +2,27 @@
#define GPG_H
#include <memory>
#include "gpgme++/key.h"
#include <QQuickWindow>
#include <gpgme++/context.h>
#include <qgpgme/changeownertrustjob.h>
using namespace GpgME;
class Gpg
{
private:
Gpg();
QDir m_gpghome;
QObject *m_window;
QString findCommandPath(const QString &command);
QString initGpgHome();
QString initGpgExec();
void initGpgConfig();
public:
~Gpg();
static std::shared_ptr<Gpg> instance()
{
static std::shared_ptr<Gpg> s{new Gpg};
@ -20,19 +31,32 @@ public:
Gpg(Gpg const &) = delete;
void operator=(Gpg const &) = delete;
void setWindow(QObject *window)
{
m_window = window;
};
QString decrypt(QByteArray plainText);
QString decryptFromFile(QString path);
QByteArray encrypt(QString str, QString uid, bool ascii_armor = true, bool text_mode = true);
bool encryptToFile(QString str, QString path, const QString uid, bool ascii_armor = true,
bool text_mode = true);
bool importKeyFromFile(QString path);
std::vector<GpgME::Key> getKeys(QString pattern_uid, bool remote = false, bool include_sigs = false,
bool validate = false);
QStringList getAllKeysId(bool remote = false, bool include_sigs = false, bool validate = false);
QObject *getWindow()
{
return m_window;
};
bool setGpghome(QString path = QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation).append("/gpghome"));
QPair< Error, std::vector< Key > > getAllKeys(bool remote = false, bool include_sigs = {}, bool
validate = false);
QPair<Error, std::vector<Key>> getKeys( QString pattern_uid, bool remote = false,
bool include_sigs = false,
bool validate = false);
QPair<Error, Key> getKey( QString uid, bool remote = false, bool include_sigs = false,
bool validate = false);
QPair<Error, QString> decrypt( QByteArray cipherText);
QPair<Error, QString> decryptFromFile( QString path);
QPair<Error, QByteArray> encrypt( QString str, QString uid, bool ascii_armor = true,
bool text_mode = true);
Error encryptToFile( QString str, QString path, QString uid, bool ascii_armor = true,
bool text_mode = true);
Error importKeysFromFile( QString path);
Error deleteKeyId( QString uid);
};
#endif

View File

@ -1,33 +1,74 @@
#include <QDebug>
#include <QFile>
#include <QUrl>
#include <QtCore/QStandardPaths>
#include <QtCore/QDir>
#include "pass.h"
#include "git.h"
#include "gpg.h"
#include "passkeymodel.h"
Pass::Pass()
Pass::Pass(): m_password_store (QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation).append("/.password-store"))
{}
void Pass::init(QObject *window)
{
m_password_store = QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation).append("/.password-store");
if (!window) {
qFatal("window is invalid. Abording.");
}
Gpg::instance()->setWindow(window);
QDir dir(m_password_store);
if (!dir.exists())
dir.mkpath(".");
qDebug() << "Password Store is :" << m_password_store;
qInfo() << "Password Store is :" << m_password_store;
}
bool Pass::gpgImportKeyFromFile(QString path)
void Pass::decrypt(QUrl url)
{
return Gpg::instance()->importKeyFromFile(path);
qInfo() << "Decrypting";
auto decrypt_ret = Gpg::instance()->decryptFromFile(url.toLocalFile());
if (decrypt_ret.first) {
qInfo() << "Decrypt Failed";
emit decryptFailed();
} else if (decrypt_ret.second.isNull()) {
qInfo() << "Decrypt Canceled";
emit decryptCanceled();
} else {
qInfo() << "Decrypt OK";
emit decrypted(decrypt_ret.second);
}
}
QStringList Pass::gpgListAllKeys()
bool Pass::gpgDeleteKeyId(QString id)
{
return Gpg::instance()->getAllKeysId();
qInfo() << "Deleting Key id " << id;
return !Gpg::instance()->deleteKeyId(id);
}
bool Pass::gpgSetGpghome(QString path)
bool Pass::gpgImportKeyFromFile(QUrl url)
{
return Gpg::instance()->setGpghome(path);
qInfo() << "Importing Key from " << url;
return !Gpg::instance()->importKeysFromFile(url.toLocalFile());
}
QVariant Pass::gpgGetAllKeysModel()
{
qInfo() << "Getting all key form gpg ";
return QVariant::fromValue(PassKeyModel::keysToPassKeyQObjectList(
Gpg::instance()->getAllKeys().second));
}
QString Pass::getPasswordStore()
{
return m_password_store;
}
bool Pass::gitClone(QString url)
{
qInfo() << "Cloning . password_store from " << url;
return Git::instance()->clone(url);
}

View File

@ -2,19 +2,32 @@
#define PASS_H
#include <QObject>
#include <memory>
#include <QUrl>
#include <QVariant>
class Pass : public QObject
{
Q_OBJECT
QString m_password_store;
signals:
void decrypted(QString text);
void decryptCanceled();
void decryptFailed();
public:
Pass();
~Pass() override = default;
Q_INVOKABLE bool gpgImportKeyFromFile(QString path);
Q_INVOKABLE QStringList gpgListAllKeys();
Q_INVOKABLE bool gpgSetGpghome(QString path);
Q_INVOKABLE void init(QObject *window);
Q_INVOKABLE QString getPasswordStore();
Q_INVOKABLE void decrypt(QUrl url);
Q_INVOKABLE bool gpgDeleteKeyId(QString id);
Q_INVOKABLE bool gpgImportKeyFromFile(QUrl url);
Q_INVOKABLE QVariant gpgGetAllKeysModel();
Q_INVOKABLE bool gitClone(QString url);
};
#endif

View File

@ -0,0 +1,74 @@
#ifndef PASSKEYMODEL_H
#define PASSKEYMODEL_H
#include <QObject>
#include <gpgme++/key.h>
using namespace GpgME;
class PassKeyModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QString uid READ uid WRITE setUid NOTIFY uidChanged MEMBER m_uid)
Q_PROPERTY(bool secret READ secret WRITE setSecret NOTIFY secretChanged MEMBER m_secret)
Q_PROPERTY(bool expired READ expired WRITE setExpired NOTIFY expiredChanged MEMBER m_expired)
QString m_uid;
bool m_secret;
bool m_expired;
public:
PassKeyModel(QString uid, bool secret, bool expired):
m_uid(uid),
m_secret(secret),
m_expired(expired)
{};
PassKeyModel(Key key):
PassKeyModel(QString::fromUtf8(key.keyID()), key.hasSecret(), key.isExpired())
{};
static QList<QObject *> keysToPassKeyQObjectList(std::vector<Key> keys)
{
QList<QObject *> r;
std::for_each(keys.begin(), keys.end(), [&r](Key k) {
r.append(new PassKeyModel(k));
});
return r;
};
QString uid() const
{
return m_uid;
};
bool secret() const
{
return m_secret;
};
bool expired() const
{
return m_expired;
};
void setUid(QString uid)
{
m_uid = uid;
emit uidChanged(uid);
}
void setSecret(bool secret)
{
m_secret = secret;
emit secretChanged(secret);
}
void setExpired(bool expired)
{
m_expired = expired;
emit expiredChanged(expired);
}
signals:
void uidChanged(QString);
void secretChanged(bool);
void expiredChanged(bool);
};
#endif

View File

@ -0,0 +1,88 @@
#ifndef UTPASSPHRASEPROVIDER_H
#define UTPASSPHRASEPROVIDER_H
#include <stdio.h>
#include <QObject>
#include <QQmlProperty>
#include <QEventLoop>
#include <QSemaphore>
#include <gpgme++/interfaces/passphraseprovider.h>
#include "passphraseprovider.h"
#include "gpg.h"
class UTPassphraseProvider : public QObject, public PassphraseProvider
{
Q_OBJECT
private:
std::unique_ptr<QEventLoop> m_loop;
std::unique_ptr<QSemaphore> m_sem;
char *m_passphrase;
bool m_canceled;
public slots:
void handleResponse(bool canceled, QString p)
{
if (!canceled)
gpgrt_asprintf(&m_passphrase, "%s", p.toUtf8().constData());
else
m_canceled = true;
m_loop->quit();
};
public:
UTPassphraseProvider():
m_loop(std::unique_ptr<QEventLoop>(new QEventLoop)),
m_sem(std::unique_ptr<QSemaphore>(new QSemaphore(1))),
m_passphrase(nullptr),
m_canceled(false)
{}
char *getPassphrase( const char *useridHint,
const char *description,
bool previousWasBad,
bool &canceled ) Q_DECL_OVERRIDE {
if (!m_sem->tryAcquire(1, 3000))
{
qWarning() << "Cannot acquire UTPassphraseProvider semaphore.";
canceled = true;
return nullptr;
}
m_passphrase = nullptr;
m_canceled = false;
qDebug() << "Call the QML Dialog Passphrase Provider";
QMetaObject::invokeMethod(
Gpg::instance()->getWindow(), "callPassphraseDialog",
Q_ARG(QVariant, useridHint),
Q_ARG(QVariant, description),
Q_ARG(QVariant, previousWasBad)
);
qDebug() << "Waiting for response";
QObject::connect(
Gpg::instance()->getWindow(), SIGNAL(responsePassphraseDialog(bool, QString)),
this, SLOT(handleResponse(bool, QString))
);
m_loop->exec();
qDebug() << "Prepare Returns";
char *ret;
gpgrt_asprintf(&ret, "%s", m_passphrase);
canceled = m_canceled;
qDebug() << "Clean";
if (m_passphrase)
{
free(m_passphrase);
}
m_canceled = false;
m_sem->release(1);
return ret;
};
};
#endif

View File

@ -0,0 +1,30 @@
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(PLUGIN "Utils")
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}/)

10
plugins/Utils/plugin.cpp Normal file
View File

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

16
plugins/Utils/plugin.h Normal file
View File

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

2
plugins/Utils/qmldir Normal file
View File

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

62
plugins/Utils/utils.cpp Normal file
View File

@ -0,0 +1,62 @@
#include <QFile>
#include <QDir>
#include <QUrl>
#include <QtCore/QStandardPaths>
#include <quazip5/JlCompress.h>
#include "utils.h"
Utils::Utils() {};
bool Utils::unzip(QUrl zip_url, QString dir_out_path)
{
auto tmp_dir_path = QStandardPaths::writableLocation(
QStandardPaths::CacheLocation).append("/unzip");
QDir tmp_dir(tmp_dir_path);
tmp_dir.removeRecursively();
tmp_dir.mkpath(".");
qDebug() << "Temp dir path is " << tmp_dir_path;
auto status = !JlCompress::extractDir(
zip_url.toLocalFile(),
tmp_dir_path
).isEmpty();
if (!status) {
tmp_dir.removeRecursively();
return false;
}
qDebug() << "Guessing if it should remove a single root folder";
QStringList files_in_tmp_dir = tmp_dir.entryList(QDir::AllEntries | QDir::Hidden |
QDir::NoDotAndDotDot);
auto dir_import_path =
files_in_tmp_dir.length() == 1 ?
tmp_dir_path.append("/" + files_in_tmp_dir.first()) : tmp_dir_path;
qDebug() << "Final imported tmp path dir is " << dir_import_path;
qDebug() << "Removing destination";
QDir dir_out(dir_out_path);
dir_out.removeRecursively();
qDebug() << "Moving zip content to destination";
QDir dir;
qDebug() << dir_import_path << " to " << dir_out_path;
auto ret = dir.rename(dir_import_path, dir_out_path);
tmp_dir.removeRecursively();;
return ret;
}
bool Utils::rmFile(QUrl file_url)
{
return QFile::remove(file_url.toLocalFile());
}
bool Utils::rmDir(QUrl dir_url)
{
QDir dir(dir_url.toLocalFile());
return dir.removeRecursively();
}

21
plugins/Utils/utils.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef UTILS_H
#define UTILS_H
#include <QObject>
#include <QUrl>
#include <QQuickWindow>
class Utils : public QObject
{
Q_OBJECT
public:
Utils();
~Utils() override = default;
Q_INVOKABLE bool unzip(QUrl zip_url, QString dir_out);
Q_INVOKABLE bool rmFile(QUrl file_url);
Q_INVOKABLE bool rmDir(QUrl dir_url);
};
#endif

View File

@ -31,3 +31,4 @@ foreach(PO_FILE ${PO_FILES})
DESTINATION ${INSTALL_DIR}
RENAME ${DOMAIN}.mo)
endforeach(PO_FILE)

190
po/ca.po Normal file
View File

@ -0,0 +1,190 @@
# UTPass
# Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
# This file is distributed under the same license as the utpass.qrouland package.
# Joan CiberSheep <cibersheep@gmail.com>, 2019.
msgid ""
msgstr ""
"Project-Id-Version: utpass.qrouland\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-09-21 14:01+0000\n"
"PO-Revision-Date: 2019-09-30 08:53+0000\n"
"Last-Translator: Joan CiberSheep <cibersheep@gmail.com>\n"
"Language-Team: Catalan <https://translate-ut.org/projects/utpass/utpass/ca/>"
"\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 3.8\n"
#: ../qml/components/FileDir.qml:71
msgid "Decryption failed !"
msgstr "Ha fallat la desencriptació"
#: ../qml/dialogs/DoubleValidationDialog.qml:28
#: ../qml/dialogs/PassphraseDialog.qml:29
#: ../qml/dialogs/SimpleValidationDialog.qml:19
msgid "Ok"
msgstr "D'acord"
#: ../qml/dialogs/DoubleValidationDialog.qml:44
#: ../qml/dialogs/PassphraseDialog.qml:41
#: ../qml/dialogs/SimpleValidationDialog.qml:30
msgid "Cancel"
msgstr "Cancel·la"
#: ../qml/dialogs/ErrorDialog.qml:12
msgid "Error !"
msgstr "Error"
#: ../qml/dialogs/ErrorDialog.qml:15 ../qml/dialogs/SuccessDialog.qml:15
msgid "OK"
msgstr "D'acord"
#: ../qml/dialogs/PassphraseDialog.qml:7
msgid "Authentication required"
msgstr "Es requereix autenticació"
#: ../qml/dialogs/PassphraseDialog.qml:8
msgid "Enter passphrase:"
msgstr "Entreu la frase de pas:"
#: ../qml/dialogs/PassphraseDialog.qml:20
msgid "passphrase"
msgstr "frase de pas"
#: ../qml/dialogs/SuccessDialog.qml:12
msgid "Success !"
msgstr "Èxit"
#: ../qml/pages/headers/MainHeader.qml:8 ../qml/pages/headers/StackHeader.qml:8
#: UTPass.desktop.in.h:1
msgid "UTPass"
msgstr "UTPass"
#: ../qml/pages/headers/MainHeader.qml:23
msgid "Search"
msgstr "Cerca"
#: ../qml/pages/headers/MainHeader.qml:51 ../qml/pages/settings/Settings.qml:14
msgid "Settings"
msgstr "Paràmetres"
#: ../qml/pages/headers/MainHeader.qml:58 ../qml/pages/Info.qml:11
msgid "Info"
msgstr "Informació"
#: ../qml/pages/Info.qml:50
msgid "<b>Version</b>"
msgstr "<b>Versió</b>"
#: ../qml/pages/Info.qml:68
msgid "<b>Maintainer</>"
msgstr "<b>Manteniment</>"
#: ../qml/pages/Info.qml:90
msgid "Suggest improvement(s) or report a bug(s)"
msgstr "Suggeriu millores o informeu d'un error"
#: ../qml/pages/Info.qml:94
msgid "Access to the source code"
msgstr "Accediu al codi font"
#: ../qml/pages/Info.qml:101
msgid "Released under the terms of the GNU GPL v3"
msgstr "Publicada sota els termes de la GNU GPL v3"
#: ../qml/pages/PasswordList.qml:23
msgid "Back"
msgstr "Enrere"
#: ../qml/pages/PasswordList.qml:43
msgid ""
"No password found<br>You can import a password store zip in the settings"
msgstr ""
"No s'ha trobat cap contrasenya<br>Podeu un importar un zip de contrasenyes a "
"la configuració"
#: ../qml/pages/settings/ImportKeyFile.qml:17
msgid "GPG Key Import"
msgstr "Importa clau GPG"
#: ../qml/pages/settings/ImportKeyFile.qml:69
msgid "Key import failed !"
msgstr "Ha fallat la importació de la clau"
#: ../qml/pages/settings/ImportKeyFile.qml:76
msgid "Key successfully imported !"
msgstr "S'ha importat la clau amb èxit"
#: ../qml/pages/settings/ImportZip.qml:17
msgid "Zip Password Store Import"
msgstr "Importa zip de contrasenyes"
#: ../qml/pages/settings/ImportZip.qml:72
msgid ""
"Importing a new zip will delete<br>any existing password store!<br>Continue ?"
msgstr ""
"A l'Importar un nou zip s'eliminarà<br>qualsevol contrasenya desada "
"anteriorment<br>Voleu continuar ?"
#: ../qml/pages/settings/ImportZip.qml:82
msgid "Password store import failed !"
msgstr "Ha fallat la importació de contrasenyes"
#: ../qml/pages/settings/ImportZip.qml:89
msgid "Password store sucessfully imported !"
msgstr "S'han importat les contrasenyes amb èxit"
#: ../qml/pages/settings/InfoKeys.qml:16
msgid "Info Keys"
msgstr "Informació de la clau"
#: ../qml/pages/settings/InfoKeys.qml:44
msgid "Key id : %1"
msgstr "Identificació de la clau: %1"
#: ../qml/pages/settings/InfoKeys.qml:49
msgid "Delete this key"
msgstr "Elimina aquesta clau"
#: ../qml/pages/settings/InfoKeys.qml:68
msgid "You're are about to delete<br>%1<br>Continue ?"
msgstr "Esteu a punt d'eliminar<br>%1<br>Voleu continuar?"
#: ../qml/pages/settings/InfoKeys.qml:71
msgid "%1<br>will be definitively removed.<br>Continue ?"
msgstr "%1<br>s'eliminarà definitivament.<br>Voleu continuar?"
#: ../qml/pages/settings/InfoKeys.qml:87
msgid "Key removal failed !"
msgstr "Ha fallat l'eliminació de la clau"
#: ../qml/pages/settings/InfoKeys.qml:94
msgid "Key successfully deleted !"
msgstr "S'ha eliminat la clau amb èxit"
#: ../qml/pages/settings/Settings.qml:28
msgid "GPG"
msgstr "GPG"
#: ../qml/pages/settings/Settings.qml:32
msgid "Import a GPG key file"
msgstr "Importa un fitxer de clau GPG"
#: ../qml/pages/settings/Settings.qml:36
msgid "Show GPG keys"
msgstr "Mostra les claus GPG"
#: ../qml/pages/settings/Settings.qml:43
msgid "Password Store"
msgstr "Contrasenyes desades"
#: ../qml/pages/settings/Settings.qml:47
msgid "Import a Password Store Zip"
msgstr "Importa un zip de contrasenyes"
#: ../qml/pages/settings/Settings.qml:56
msgid "Warning: importing delete any exiting Password Store"
msgstr "Alertau: s'eliminarà qualsevol contrasenya desada a l'importar"

193
po/es.po Normal file
View File

@ -0,0 +1,193 @@
# UTPass
# Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
# This file is distributed under the same license as the utpass.qrouland package.
# Advocatux <advocatux@airpost.net>, 2019.
# Reda <redxxiii@zaclys.net>, 2019.
msgid ""
msgstr ""
"Project-Id-Version: utpass.qrouland\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-09-21 14:01+0000\n"
"PO-Revision-Date: 2019-09-30 08:53+0000\n"
"Last-Translator: Advocatux <advocatux@airpost.net>\n"
"Language-Team: Spanish <https://translate-ut.org/projects/utpass/utpass/es/>"
"\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 3.8\n"
#: ../qml/components/FileDir.qml:71
msgid "Decryption failed !"
msgstr "¡Falló el descifrado!"
#: ../qml/dialogs/DoubleValidationDialog.qml:28
#: ../qml/dialogs/PassphraseDialog.qml:29
#: ../qml/dialogs/SimpleValidationDialog.qml:19
msgid "Ok"
msgstr "Aceptar"
#: ../qml/dialogs/DoubleValidationDialog.qml:44
#: ../qml/dialogs/PassphraseDialog.qml:41
#: ../qml/dialogs/SimpleValidationDialog.qml:30
msgid "Cancel"
msgstr "Cancelar"
#: ../qml/dialogs/ErrorDialog.qml:12
msgid "Error !"
msgstr "¡Error!"
#: ../qml/dialogs/ErrorDialog.qml:15 ../qml/dialogs/SuccessDialog.qml:15
msgid "OK"
msgstr "Aceptar"
#: ../qml/dialogs/PassphraseDialog.qml:7
msgid "Authentication required"
msgstr "Se requiere autentificación"
#: ../qml/dialogs/PassphraseDialog.qml:8
msgid "Enter passphrase:"
msgstr "Introducir contraseña:"
#: ../qml/dialogs/PassphraseDialog.qml:20
msgid "passphrase"
msgstr "contraseña"
#: ../qml/dialogs/SuccessDialog.qml:12
msgid "Success !"
msgstr "¡Correcto!"
#: ../qml/pages/headers/MainHeader.qml:8 ../qml/pages/headers/StackHeader.qml:8
#: UTPass.desktop.in.h:1
msgid "UTPass"
msgstr "UTPass"
#: ../qml/pages/headers/MainHeader.qml:23
msgid "Search"
msgstr "Buscar"
#: ../qml/pages/headers/MainHeader.qml:51 ../qml/pages/settings/Settings.qml:14
msgid "Settings"
msgstr "Configuración"
#: ../qml/pages/headers/MainHeader.qml:58 ../qml/pages/Info.qml:11
msgid "Info"
msgstr "Información"
#: ../qml/pages/Info.qml:50
msgid "<b>Version</b>"
msgstr "<b>Versión</b>"
#: ../qml/pages/Info.qml:68
msgid "<b>Maintainer</>"
msgstr "<b>Mantenedor</b>"
#: ../qml/pages/Info.qml:90
msgid "Suggest improvement(s) or report a bug(s)"
msgstr "Sugerir mejora(s) o reportar problema(s)"
#: ../qml/pages/Info.qml:94
msgid "Access to the source code"
msgstr "Acceso al código fuente"
#: ../qml/pages/Info.qml:101
msgid "Released under the terms of the GNU GPL v3"
msgstr "Publicado bajo los términos de la GNU GPL v3"
#: ../qml/pages/PasswordList.qml:23
msgid "Back"
msgstr "Atrás"
#: ../qml/pages/PasswordList.qml:43
msgid ""
"No password found<br>You can import a password store zip in the settings"
msgstr ""
"No se han encontrado contraseñas<br>Puede importar un archivo zip de "
"almacenamiento de contraseñas en la configuración"
#: ../qml/pages/settings/ImportKeyFile.qml:17
msgid "GPG Key Import"
msgstr "Importar clave GPG"
#: ../qml/pages/settings/ImportKeyFile.qml:69
msgid "Key import failed !"
msgstr "¡Falló la importación de la clave!"
#: ../qml/pages/settings/ImportKeyFile.qml:76
msgid "Key successfully imported !"
msgstr "¡Clave importada correctamente!"
#: ../qml/pages/settings/ImportZip.qml:17
msgid "Zip Password Store Import"
msgstr "Importar zip de almacenamiento de contraseñas"
#: ../qml/pages/settings/ImportZip.qml:72
msgid ""
"Importing a new zip will delete<br>any existing password store!<br>Continue ?"
msgstr ""
"¡La importación de un nuevo zip borrará<br>cualquier contraseña "
"almacenada!<br>¿Continuar?"
#: ../qml/pages/settings/ImportZip.qml:82
msgid "Password store import failed !"
msgstr "¡Falló la importación del archivo de contraseñas!"
#: ../qml/pages/settings/ImportZip.qml:89
msgid "Password store sucessfully imported !"
msgstr ""
"¡La importación del archivo de contraseñas se ha realizado correctamente!"
#: ../qml/pages/settings/InfoKeys.qml:16
msgid "Info Keys"
msgstr "Información de las claves"
#: ../qml/pages/settings/InfoKeys.qml:44
msgid "Key id : %1"
msgstr "Identificador de clave: %1"
#: ../qml/pages/settings/InfoKeys.qml:49
msgid "Delete this key"
msgstr "Eliminar esta clave"
#: ../qml/pages/settings/InfoKeys.qml:68
msgid "You're are about to delete<br>%1<br>Continue ?"
msgstr "Está a punto de eliminar<br>%1<br>¿Continuar?"
#: ../qml/pages/settings/InfoKeys.qml:71
msgid "%1<br>will be definitively removed.<br>Continue ?"
msgstr "1%<br>será eliminada definitivamente.<br>¿Continuar?"
#: ../qml/pages/settings/InfoKeys.qml:87
msgid "Key removal failed !"
msgstr "¡Falló la eliminación de la clave!"
#: ../qml/pages/settings/InfoKeys.qml:94
msgid "Key successfully deleted !"
msgstr "¡La clave ha sido eliminada correctamente!"
#: ../qml/pages/settings/Settings.qml:28
msgid "GPG"
msgstr "GPG"
#: ../qml/pages/settings/Settings.qml:32
msgid "Import a GPG key file"
msgstr "Importar un archivo de clave GPG"
#: ../qml/pages/settings/Settings.qml:36
msgid "Show GPG keys"
msgstr "Mostrar las claves GPG"
#: ../qml/pages/settings/Settings.qml:43
msgid "Password Store"
msgstr "Archivo de contraseñas"
#: ../qml/pages/settings/Settings.qml:47
msgid "Import a Password Store Zip"
msgstr "Importar un archivo Zip de contraseñas"
#: ../qml/pages/settings/Settings.qml:56
msgid "Warning: importing delete any exiting Password Store"
msgstr ""
"Advertencia: Importar elimina cualquier archivo de contraseñas existente"

191
po/fr.po Normal file
View File

@ -0,0 +1,191 @@
# UTPass
# Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
# This file is distributed under the same license as the utpass.qrouland package.
# Anne17 <>anneonyme017@netcourrier.com>, 2019.
# Quentin Rouland <quentin@qrouland.com>, 2019.
# Reda <redxxiii@zaclys.net>, 2019.
msgid ""
msgstr ""
"Project-Id-Version: utpass.qrouland\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-09-21 14:01+0000\n"
"PO-Revision-Date: 2019-10-05 17:01+0000\n"
"Last-Translator: Reda <redxxiii@zaclys.net>\n"
"Language-Team: French <https://translate-ut.org/projects/utpass/utpass/fr/>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 3.8\n"
#: ../qml/components/FileDir.qml:71
msgid "Decryption failed !"
msgstr "Échec du déchiffrement !"
#: ../qml/dialogs/DoubleValidationDialog.qml:28
#: ../qml/dialogs/PassphraseDialog.qml:29
#: ../qml/dialogs/SimpleValidationDialog.qml:19
msgid "Ok"
msgstr "Valider"
#: ../qml/dialogs/DoubleValidationDialog.qml:44
#: ../qml/dialogs/PassphraseDialog.qml:41
#: ../qml/dialogs/SimpleValidationDialog.qml:30
msgid "Cancel"
msgstr "Annuler"
#: ../qml/dialogs/ErrorDialog.qml:12
msgid "Error !"
msgstr "Erreur !"
#: ../qml/dialogs/ErrorDialog.qml:15 ../qml/dialogs/SuccessDialog.qml:15
msgid "OK"
msgstr "Valider"
#: ../qml/dialogs/PassphraseDialog.qml:7
msgid "Authentication required"
msgstr "Authentification nécessaire"
#: ../qml/dialogs/PassphraseDialog.qml:8
msgid "Enter passphrase:"
msgstr "Saisissez votre mot de passe :"
#: ../qml/dialogs/PassphraseDialog.qml:20
msgid "passphrase"
msgstr "Mot de passe"
#: ../qml/dialogs/SuccessDialog.qml:12
msgid "Success !"
msgstr "Réussite !"
#: ../qml/pages/headers/MainHeader.qml:8 ../qml/pages/headers/StackHeader.qml:8
#: UTPass.desktop.in.h:1
msgid "UTPass"
msgstr "UTPass"
#: ../qml/pages/headers/MainHeader.qml:23
msgid "Search"
msgstr "Rechercher"
#: ../qml/pages/headers/MainHeader.qml:51 ../qml/pages/settings/Settings.qml:14
msgid "Settings"
msgstr "Paramètres"
#: ../qml/pages/headers/MainHeader.qml:58 ../qml/pages/Info.qml:11
msgid "Info"
msgstr "Infos"
#: ../qml/pages/Info.qml:50
msgid "<b>Version</b>"
msgstr "<b>Version</b>"
#: ../qml/pages/Info.qml:68
msgid "<b>Maintainer</>"
msgstr "<b>Mainteneur</>"
#: ../qml/pages/Info.qml:90
msgid "Suggest improvement(s) or report a bug(s)"
msgstr "Suggérer des améliorations ou signaler des problèmes"
#: ../qml/pages/Info.qml:94
msgid "Access to the source code"
msgstr "Accéder au code source"
#: ../qml/pages/Info.qml:101
msgid "Released under the terms of the GNU GPL v3"
msgstr "Distribuée sous les termes de la GNU GPL v3"
#: ../qml/pages/PasswordList.qml:23
msgid "Back"
msgstr "Retour"
#: ../qml/pages/PasswordList.qml:43
msgid ""
"No password found<br>You can import a password store zip in the settings"
msgstr ""
"Aucun mot de passe trouvé<br>Vous pouvez importer un fichier zip de stockage "
"de mots de passe dans les paramètres"
#: ../qml/pages/settings/ImportKeyFile.qml:17
msgid "GPG Key Import"
msgstr "Importation de clé GPG"
#: ../qml/pages/settings/ImportKeyFile.qml:69
msgid "Key import failed !"
msgstr "L'importation de la clé a échoué !"
#: ../qml/pages/settings/ImportKeyFile.qml:76
msgid "Key successfully imported !"
msgstr "Clé importée avec succès !"
#: ../qml/pages/settings/ImportZip.qml:17
msgid "Zip Password Store Import"
msgstr "Importation d'un fichier zip de mots de passe"
#: ../qml/pages/settings/ImportZip.qml:72
msgid ""
"Importing a new zip will delete<br>any existing password store!<br>Continue ?"
msgstr ""
"L'importation d'un nouveau zip supprimera<br>tout mot de passe stocké!<br>"
"Continuer ?"
#: ../qml/pages/settings/ImportZip.qml:82
msgid "Password store import failed !"
msgstr "L'importation du fichier de mots de passe a échoué !"
#: ../qml/pages/settings/ImportZip.qml:89
msgid "Password store sucessfully imported !"
msgstr "L'importation du fichier de mots de passe a réussi !"
#: ../qml/pages/settings/InfoKeys.qml:16
msgid "Info Keys"
msgstr "Informations sur les clés"
#: ../qml/pages/settings/InfoKeys.qml:44
msgid "Key id : %1"
msgstr "Identifiant de la clé : %1"
#: ../qml/pages/settings/InfoKeys.qml:49
msgid "Delete this key"
msgstr "Supprimer cette clé"
#: ../qml/pages/settings/InfoKeys.qml:68
msgid "You're are about to delete<br>%1<br>Continue ?"
msgstr "Vous êtes sur le point de supprimer<br>%1<br>Voulez-vous continuer ?"
#: ../qml/pages/settings/InfoKeys.qml:71
msgid "%1<br>will be definitively removed.<br>Continue ?"
msgstr "%1<br>sera définitivement supprimée.<br>Voulez-vous continuer ?"
#: ../qml/pages/settings/InfoKeys.qml:87
msgid "Key removal failed !"
msgstr "La suppression de clé a échoué !"
#: ../qml/pages/settings/InfoKeys.qml:94
msgid "Key successfully deleted !"
msgstr "La clé a été supprimée avec succès !"
#: ../qml/pages/settings/Settings.qml:28
msgid "GPG"
msgstr "GPG"
#: ../qml/pages/settings/Settings.qml:32
msgid "Import a GPG key file"
msgstr "Importer un fichier de clés GPG"
#: ../qml/pages/settings/Settings.qml:36
msgid "Show GPG keys"
msgstr "Afficher les clés GPG"
#: ../qml/pages/settings/Settings.qml:43
msgid "Password Store"
msgstr "Fichier de mots de passe"
#: ../qml/pages/settings/Settings.qml:47
msgid "Import a Password Store Zip"
msgstr "Importer un fichier Zip de mots de passe"
#: ../qml/pages/settings/Settings.qml:56
msgid "Warning: importing delete any exiting Password Store"
msgstr "Attention : l'importation supprime les fichiers précédents"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: utpass.qrouland\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-03-23 19:50+0000\n"
"POT-Creation-Date: 2025-01-07 13:36+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,16 +17,77 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: ../qml/pages/PasswordList.qml:16
#: ../qml/components/FileDir.qml:71
msgid "Decryption failed !"
msgstr ""
#: ../qml/dialogs/DoubleValidationDialog.qml:28
#: ../qml/dialogs/PassphraseDialog.qml:29
#: ../qml/dialogs/SimpleValidationDialog.qml:19
msgid "Ok"
msgstr ""
#: ../qml/dialogs/DoubleValidationDialog.qml:44
#: ../qml/dialogs/PassphraseDialog.qml:41
#: ../qml/dialogs/SimpleValidationDialog.qml:30
msgid "Cancel"
msgstr ""
#: ../qml/dialogs/ErrorDialog.qml:12
msgid "Error !"
msgstr ""
#: ../qml/dialogs/ErrorDialog.qml:15 ../qml/dialogs/SuccessDialog.qml:15
msgid "OK"
msgstr ""
#: ../qml/dialogs/PassphraseDialog.qml:7
msgid "Authentication required"
msgstr ""
#: ../qml/dialogs/PassphraseDialog.qml:8
msgid "Enter passphrase:"
msgstr ""
#: ../qml/dialogs/PassphraseDialog.qml:20
msgid "passphrase"
msgstr ""
#: ../qml/dialogs/SuccessDialog.qml:12
msgid "Success !"
msgstr ""
#: ../qml/pages/Info.qml:11 ../qml/pages/headers/MainHeader.qml:58
msgid "Info"
msgstr ""
#: ../qml/pages/Info.qml:50
msgid "<b>Version</b>"
msgstr ""
#: ../qml/pages/Info.qml:68
msgid "<b>Maintainer</>"
msgstr ""
#: ../qml/pages/Info.qml:90
msgid "Suggest improvement(s) or report a bug(s)"
msgstr ""
#: ../qml/pages/Info.qml:94
msgid "Access to the source code"
msgstr ""
#: ../qml/pages/Info.qml:101
msgid "Released under the terms of the GNU GPL v3"
msgstr ""
#: ../qml/pages/PasswordList.qml:23
msgid "Back"
msgstr ""
#: ../qml/pages/PasswordList.qml:38
msgid "No password found in the current folder"
msgstr ""
#: ../qml/pages/Settings.qml:8 ../qml/pages/headers/MainHeader.qml:49
msgid "Settings"
#: ../qml/pages/PasswordList.qml:43
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
@ -35,34 +96,90 @@ msgid "UTPass"
msgstr ""
#: ../qml/pages/headers/MainHeader.qml:23
#: ../qml/pages/headers/MainHeader.qml:38
msgid "Search"
msgstr ""
#: ../qml/pages/headers/MainHeader.qml:56 ../qml/pages/Info.qml:10
msgid "Info"
#: ../qml/pages/headers/MainHeader.qml:51 ../qml/pages/settings/Settings.qml:14
msgid "Settings"
msgstr ""
#: ../qml/pages/Info.qml:31
msgid "<b><font size=\"6\">%1</font></b>"
#: ../qml/pages/settings/ImportKeyFile.qml:17
msgid "GPG Key Import"
msgstr ""
#: ../qml/pages/Info.qml:47
msgid "<font size=\"4\">Maintainer<br>%1</font>"
#: ../qml/pages/settings/ImportKeyFile.qml:69
msgid "Key import failed !"
msgstr ""
#: ../qml/pages/Info.qml:53
msgid "<font size=\"4\">Version<br>%1</font><br>%2@%3"
#: ../qml/pages/settings/ImportKeyFile.qml:76
msgid "Key successfully imported !"
msgstr ""
#: ../qml/pages/Info.qml:64
msgid "Suggest improvement(s) or report a bug(s)"
#: ../qml/pages/settings/ImportZip.qml:17
msgid "Zip Password Store Import"
msgstr ""
#: ../qml/pages/Info.qml:68
msgid "Access to the source code"
#: ../qml/pages/settings/ImportZip.qml:72
msgid ""
"Importing a new zip will delete<br>any existing password store!<br>Continue ?"
msgstr ""
#: ../qml/pages/Info.qml:75
msgid "<font size=\"2\">Released under the terms of the GNU GPL v3</font>"
#: ../qml/pages/settings/ImportZip.qml:82
msgid "Password store import failed !"
msgstr ""
#: ../qml/pages/settings/ImportZip.qml:89
msgid "Password store sucessfully imported !"
msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:16
msgid "Info Keys"
msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:44
msgid "Key id : %1"
msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:49
msgid "Delete this key"
msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:68
msgid "You're are about to delete<br>%1<br>Continue ?"
msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:71
msgid "%1<br>will be definitively removed.<br>Continue ?"
msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:87
msgid "Key removal failed !"
msgstr ""
#: ../qml/pages/settings/InfoKeys.qml:94
msgid "Key successfully deleted !"
msgstr ""
#: ../qml/pages/settings/Settings.qml:28
msgid "GPG"
msgstr ""
#: ../qml/pages/settings/Settings.qml:32
msgid "Import a GPG key file"
msgstr ""
#: ../qml/pages/settings/Settings.qml:36
msgid "Show GPG keys"
msgstr ""
#: ../qml/pages/settings/Settings.qml:43
msgid "Password Store"
msgstr ""
#: ../qml/pages/settings/Settings.qml:47
msgid "Import a Password Store Zip"
msgstr ""
#: ../qml/pages/settings/Settings.qml:56
msgid "Warning: importing delete any exiting Password Store"
msgstr ""

View File

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

View File

@ -0,0 +1,64 @@
import QtQuick 2.4
import Lomiri.Components 1.3
import "../styles"
Item {
id: copyText
property string text
property bool commonBorder: true
property int lBorderwidth: 0
property int rBorderwidth: 0
property int tBorderwidth: 0
property int bBorderwidth: 0
property int commonBorderWidth: 0
property string borderColor: LomiriColors.warmGrey
width: parent.width
height: units.gu(6)
Rectangle {
anchors.fill: parent
Text {
text: copyText.text
anchors.left: parent.left
anchors.leftMargin: units.gu(2)
anchors.verticalCenter: parent.verticalCenter
}
Icon {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: units.gu(2)
height: units.gu(4)
name: "edit-copy"
color: LomiriColors.orange
}
MouseArea {
anchors.fill: parent
onPressed: {
parent.color = LomiriColors.warmGrey
}
onClicked: {
var mimeData = Clipboard.newData()
mimeData.text = copyText.text
Clipboard.push(mimeData)
}
onReleased: {
parent.color = theme.palette.normal.background
}
}
CustomBorder {
id: cb
commonBorder: copyText.commonBorder
lBorderwidth: copyText.lBorderwidth
rBorderwidth: copyText.rBorderwidth
tBorderwidth: copyText.tBorderwidth
bBorderwidth: copyText.bBorderwidth
borderColor: copyText.borderColor
}
}
}

View File

@ -1,8 +1,10 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import Lomiri.Components 1.3
import "../styles"
Item {
id: externalLink
property string url
property string text
@ -12,46 +14,46 @@ Item {
property int tBorderwidth: 0
property int bBorderwidth: 0
property int commonBorderWidth: 0
property string borderColor: UbuntuColors.warmGrey
property string borderColor: LomiriColors.warmGrey
width: parent.width
height: units.gu(6)
Rectangle {
width: parent.width
height: parent.height
anchors.fill: parent
Text {
text: parent.parent.text
text: externalLink.text
anchors.left: parent.left
anchors.leftMargin: units.gu(1)
anchors.leftMargin: units.gu(2)
anchors.verticalCenter: parent.verticalCenter
}
Icon {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: units.gu(2)
width: units.gu(4)
height: units.gu(4)
name: "go-next"
color: Theme.raisin_black
color: LomiriColors.orange
}
MouseArea {
anchors.fill: parent
onClicked: {
Qt.openUrlExternally(parent.parent.url)
Qt.openUrlExternally(externalLink.url)
}
}
CustomBorder {
id: cb
commonBorder: parent.parent.commonBorder
lBorderwidth: parent.parent.lBorderwidth
rBorderwidth: parent.parent.rBorderwidth
tBorderwidth: parent.parent.tBorderwidth
bBorderwidth: parent.parent.bBorderwidth
borderColor: parent.parent.borderColor
commonBorder: externalLink.commonBorder
lBorderwidth: externalLink.lBorderwidth
rBorderwidth: externalLink.rBorderwidth
tBorderwidth: externalLink.tBorderwidth
bBorderwidth: externalLink.bBorderwidth
borderColor: externalLink.borderColor
}
}
}

View File

@ -1,26 +1,33 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import Pass 1.0
import "../styles"
import "../dialogs"
Component {
Rectangle {
width: parent.width
id: fileDir
property string activePasswordName
anchors.right: parent.right
anchors.left: parent.left
height: units.gu(5)
Text {
text: fileBaseName
anchors.left: parent.left
anchors.leftMargin: units.gu(1)
anchors.leftMargin: units.gu(2)
anchors.verticalCenter: parent.verticalCenter
}
Icon {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
width: units.gu(4)
anchors.rightMargin: units.gu(2)
height: units.gu(4)
name: fileIsDir ? "go-next" : "lock"
color: Theme.raisin_black
color: LomiriColors.orange
}
MouseArea {
@ -29,6 +36,22 @@ Component {
if (fileIsDir) {
folderModel.folder = folderModel.folder + "/" + fileName
backAction.visible = true
} else {
fileDir.activePasswordName = fileBaseName
Pass.onDecrypted.connect(function (text) {
pageStack.push(Qt.resolvedUrl("../pages/Password.qml"),
{
"plainText": text,
"title": fileDir.activePasswordName
})
})
Pass.onDecryptFailed.connect(function () {
PopupUtils.open(passwordPageDecryptError)
})
Pass.decrypt(folderModel.folder + "/" + fileName)
}
}
}
@ -39,7 +62,17 @@ Component {
rBorderwidth: 0
tBorderwidth: 0
bBorderwidth: 1
borderColor: UbuntuColors.warmGrey
borderColor: LomiriColors.warmGrey
}
Component {
id: passwordPageDecryptError
ErrorDialog {
textError: i18n.tr("Decryption failed !")
onDialogClosed: {
pageStack.pop()
}
}
}
}
}

View File

@ -0,0 +1,62 @@
import QtQuick 2.4
import Lomiri.Components 1.3
import "../styles"
Item {
id: pageStackLink
property string page
property var params: {
}
property string text
property bool commonBorder: true
property int lBorderwidth: 0
property int rBorderwidth: 0
property int tBorderwidth: 0
property int bBorderwidth: 0
property int commonBorderWidth: 0
property string borderColor: LomiriColors.warmGrey
width: parent.width
height: units.gu(6)
Rectangle {
anchors.fill: parent
Text {
text: pageStackLink.text
anchors.left: parent.left
anchors.leftMargin: units.gu(2)
anchors.verticalCenter: parent.verticalCenter
}
Icon {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: units.gu(2)
width: units.gu(4)
height: units.gu(4)
name: "go-next"
color: LomiriColors.orange
}
MouseArea {
anchors.fill: parent
onClicked: {
pageStack.push(page, params)
}
}
CustomBorder {
id: cb
commonBorder: pageStackLink.commonBorder
lBorderwidth: pageStackLink.lBorderwidth
rBorderwidth: pageStackLink.rBorderwidth
tBorderwidth: pageStackLink.tBorderwidth
bBorderwidth: pageStackLink.bBorderwidth
borderColor: pageStackLink.borderColor
}
}
}

View File

@ -1,2 +0,0 @@
FileDir 1.0 FileDir.qml
Link 1.0 Link.qml

View File

@ -0,0 +1,52 @@
import QtQuick 2.4
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
Dialog {
id: doubleValidationDialog
property int nb_validation: 0
property string text1
property string text2
signal doubleValidated
signal canceled
Text {
visible: nb_validation == 0
horizontalAlignment: Text.AlignHCenter
text: text1
}
Text {
visible: nb_validation == 1
horizontalAlignment: Text.AlignHCenter
text: text2
}
Button {
text: i18n.tr("Ok")
color: LomiriColors.green
onClicked: {
if (nb_validation == 1) {
nb_validation = 0
doubleValidated()
PopupUtils.close(doubleValidationDialog)
} else {
nb_validation += 1
}
}
}
Button {
id: cancelButton
text: i18n.tr("Cancel")
color: LomiriColors.red
onClicked: {
nb_validation = 0
canceled()
PopupUtils.close(doubleValidationDialog)
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,31 +0,0 @@
pragma Singleton
import QtQuick 2.4
Item {
id: manifest
property string name: ""
property string description: ""
property string architecture: ""
property string title: ""
property string version: ""
property string maintainer: ""
property string framework: ""
Component.onCompleted: {
var xhr = new XMLHttpRequest
xhr.open("GET", "../../manifest.json")
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
var mJson = JSON.parse(xhr.responseText)
manifest.name = mJson.name
manifest.description = mJson.description
manifest.architecture = mJson.architecture
manifest.title = mJson.title
manifest.version = mJson.version
manifest.maintainer = mJson.maintainer
manifest.framework = mJson.framework
}
}
xhr.send()
}
}

View File

@ -1,5 +0,0 @@
pragma Singleton
import QtQuick 2.4
Item {
}

View File

@ -1,2 +0,0 @@
singleton PasswordStore 1.0 PasswordStore.qml
singleton Manifest 1.0 Manifest.qml

View File

@ -1,84 +1,116 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import Lomiri.Components 1.3
import "headers"
import "../components"
import "../models"
Page {
id: infoPage
header: StackHeader {
id: infoHeader
title: i18n.tr('Info')
}
Rectangle {
Flow {
anchors.top: infoHeader.bottom
anchors.bottom: parent.bottom
width: parent.width
color: "#FFF"
anchors.right: parent.right
anchors.left: parent.left
spacing: units.gu(3)
Flow {
spacing: units.gu(3)
anchors.fill: parent
Rectangle {
width: parent.width
height: units.gu(1)
}
Text {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: parent.width
height: units.gu(4)
text: i18n.tr('<b><font size="6">%1</font></b>').arg(
Manifest.title)
}
Rectangle {
width: parent.width
Rectangle {
width: parent.width
height: units.gu(1)
}
Text {
id: manifestTitle
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: parent.width
height: units.gu(8)
fontSizeMode: Text.Fit
font.pixelSize: 144
}
Rectangle {
width: parent.width
height: units.gu(12)
Image {
source: "../../assets/logo.svg"
width: units.gu(12)
height: units.gu(12)
Image {
source: "../../assets/logo.svg"
width: units.gu(12)
height: units.gu(12)
anchors.horizontalCenter: parent.horizontalCenter
}
}
Text {
horizontalAlignment: Text.AlignHCenter
width: parent.width
height: units.gu(6)
text: i18n.tr('<font size="4">Maintainer<br>%1</font>').arg(
Manifest.maintainer)
}
Text {
horizontalAlignment: Text.AlignHCenter
width: parent.width
height: units.gu(6)
text: i18n.tr(
'<font size="4">Version<br>%1</font><br>%2@%3').arg(
Manifest.version).arg(Manifest.framework).arg(
Manifest.architecture)
anchors.horizontalCenter: parent.horizontalCenter
}
}
Flow {
spacing: 2
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
Link {
url: "https://github.com/QRouland/UTPass/issues"
text: i18n.tr('Suggest improvement(s) or report a bug(s)')
}
Link {
url: "https://github.com/QRouland/UTPass"
text: i18n.tr('Access to the source code')
}
Text {
width: parent.width
height: units.gu(3)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: i18n.tr(
'<font size="2">Released under the terms of the GNU GPL v3</font>')
}
Text {
horizontalAlignment: Text.AlignHCenter
width: parent.width
height: units.gu(3)
text: i18n.tr("<b>Version</b>")
fontSizeMode: Text.Fit
font.pixelSize: 72
}
Text {
id: manifestVersion
horizontalAlignment: Text.AlignHCenter
width: parent.width
height: units.gu(4)
fontSizeMode: Text.Fit
font.pixelSize: 72
}
Text {
horizontalAlignment: Text.AlignHCenter
width: parent.width
height: units.gu(3)
text: i18n.tr("<b>Maintainer</>")
fontSizeMode: Text.Fit
font.pixelSize: 72
}
Text {
id: manifestMaintener
horizontalAlignment: Text.AlignHCenter
width: parent.width
height: units.gu(2)
fontSizeMode: Text.Fit
font.pixelSize: 72
}
}
Flow {
spacing: 2
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
ExternalLink {
url: "https://taiga.rdrive.ovh/project/utpass/issues"
text: i18n.tr("Suggest improvement(s) or report a bug(s)")
}
ExternalLink {
url: "https://git.rdrive.ovh/QRouland/UTPass"
text: i18n.tr("Access to the source code")
}
Text {
width: parent.width
height: units.gu(2)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: i18n.tr("Released under the terms of the GNU GPL v3")
}
}
Component.onCompleted: {
var xhr = new XMLHttpRequest()
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
}
}

69
qml/pages/Password.qml Normal file
View File

@ -0,0 +1,69 @@
import QtQuick 2.4
import Lomiri.Components 1.3
import Lomiri.Components.Popups 1.3
import "headers"
Page {
id: passwordPage
property string title
property string plainText
property var objects
header: PageHeader {
id: passwordPageHeader
width: parent.width
height: units.gu(6)
title: passwordPage.title
contents: Item {
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 {
anchors.top: passwordPageHeader.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
Flow {
id: container
anchors.fill: parent
}
}
Component.onCompleted: {
var text_split = passwordPage.plainText.split('\n')
var component = Qt.createComponent("../components/CopyText.qml")
for (var i = 0; i < text_split.length; i++) {
if (text_split[i]) {
var object = component.createObject(container)
object.text = text_split[i]
}
}
}
}

View File

@ -1,12 +1,19 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import Lomiri.Components 1.3
import Qt.labs.folderlistmodel 2.1
import Pass 1.0
import "../components"
import "headers"
Page {
id: passwordListPage
property string passwordStorePath
anchors.fill: parent
header: MainHeader {
flickable: nav
id: passwordListHeader
leadingActionBar.height: units.gu(4)
leadingActionBar.actions: [
@ -25,34 +32,41 @@ Page {
]
}
Flickable {
id: nav
height: parent.height
width: parent.width
Rectangle {
width: parent.width
visible: folderModel.count == 0
height: units.gu(5)
Text {
text: i18n.tr("No password found in the current folder")
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
}
ListView {
anchors.fill: parent
spacing: 1
model: FolderListModel {
id: folderModel
nameFilters: ["*.gpg"]
rootFolder: "file:password-store"
folder: "file:password-store"
}
delegate: FileDir {
id: fileDelegate
}
Rectangle {
anchors.top: passwordListHeader.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
visible: folderModel.count == 0
Text {
text: i18n.tr(
"No password found<br>You can import a password store zip in the settings")
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignHCenter
}
}
ListView {
anchors.top: passwordListHeader.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
spacing: 1
model: FolderListModel {
id: folderModel
nameFilters: ["*.gpg"]
rootFolder: passwordStorePath
folder: passwordStorePath
showDirs: true
}
delegate: FileDir {
id: fileDelegate
}
}
Component.onCompleted: {
passwordStorePath = "file:" + Pass.getPasswordStore()
}
}

View File

@ -1,28 +0,0 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import "headers"
Page {
header: StackHeader {
id: settingsHeader
title: i18n.tr('Settings')
}
Rectangle {
anchors.top: settingsHeader.bottom
anchors.bottom: parent.bottom
width: parent.width
color: "#FFF"
Flow {
spacing: 1
anchors.fill: parent
Text {
horizontalAlignment: Text.AlignHCenter
width: parent.width
height: units.gu(6)
text: "Settings"
}
}
}
}

View File

@ -1,5 +1,5 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import Lomiri.Components 1.3
PageHeader {
id: mainHeader
@ -33,7 +33,9 @@ PageHeader {
trailingActionBar.height: units.gu(4)
trailingActionBar.numberOfSlots: 2
trailingActionBar.actions: [
Action {
/*Action { TODO
iconName: "search"
text: i18n.tr("Search")
onTriggered: {
@ -43,12 +45,12 @@ PageHeader {
searchBar.focus = true
}
}
},
},*/
Action {
iconName: "settings"
text: i18n.tr("Settings")
onTriggered: {
pageStack.push(Qt.resolvedUrl("../Settings.qml"))
pageStack.push(Qt.resolvedUrl("../settings/Settings.qml"))
}
},
Action {

View File

@ -1,5 +1,5 @@
import QtQuick 2.4
import Ubuntu.Components 1.3
import Lomiri.Components 1.3
PageHeader {
id: stackHeader

View File

@ -1,2 +0,0 @@
MainHeader 1.0 MainHeader.qml
StackHeader 1.0 StackHeader.qml

View File

@ -1,4 +0,0 @@
Info 1.0 Info.qml
PassordList 1.0 Password.qml
Settings 1.0 Settings.qml
UTPassPage 1.0 UTPassPage.qml

View File

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

View File

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

View File

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

View File

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

View File

@ -1,10 +0,0 @@
pragma Singleton
import QtQuick 2.4
Item {
readonly property color claret: "#77172A"
readonly property color raisin_black: "#AE2B25"
readonly property color steel_blue: "#462C98"
readonly property color twilight_lavender: "#754888"
readonly property color eerie_black: "#191716"
}

View File

@ -1,2 +0,0 @@
CustomBorder 1.0 CustomBorder.qml
singleton Theme 1.0 Theme.qml

BIN
screens/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
screens/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
screens/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
screens/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
screens/5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

View File

@ -1 +0,0 @@
This not a key file

View File

@ -1,30 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBFyNdOEBCADl2oWeYkmVBDWoWgZdkpbV5VRJJFATLsu5aHBuQO/C1mn2RlL2
jIpIzI5mwviAw9RN0KnLdHvp3n3JkJPZ8tB3Sk9SD8qhr6ae2DbIpySMscYC9+Go
t0mrGyB3w+Y5etfZ/1dRNx6/vYaWYIG6bKfJettt/zLJcjpkIKcrN4OKyN2wXz3y
EiAiJvMntdgLslURl93RyNuVR6UaE4TchtDqRc2KvXAxrf6NUYd4KxvUgUd0TFPs
s3SRs+cAcRmTzxv/c40sBw3z0B9rBB7T7oPgGUA6NhErvBwpF9MLN+6ucZ1HHLLH
dmCd7q2OT7wZ9L6zILmKvJcK13V4FyO9zOALABEBAAG0I1Rlc3QgKFRlc3QgZ3Bn
IGtleSkgPHRlc3RAdGVzdC5vcmc+iQFOBBMBCAA4FiEE6JXydyCXAQnkfMmTuV1W
R67EDnIFAlyNdOECGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQuV1WR67E
DnIchAgAvV5q4/Hktlu3RIgo8KkGksMOS5XhJrr6fZ8bUgqpwL3oEfZ3Se5aS7yN
5M7NT8foB2zK2moBICMYpxBxQoGjxFosv94FqX9+XMiRc2Di6MwLwKkWfu0HoPEi
e701iTo53r6K84TIKNrRsKyg6C/pRqNNwSp1YcvG11eUnG5teZMcb1xsMfx4O2/s
mcrySo0ZjAfYnh2poxf4yy9xTryPrDnaY/EFj+4uBMLH8jG3QQiAH1N6wHhi/vwj
FaaaBtRxcVU/obGDg2LHTVxItv81xzSbLf8JdIGOKjwFed+DjaoSlEzPnuaEZf/M
7mE6fiGbIhFgUlwEGomptZDC1fg3M7kBDQRcjXThAQgAmuSsbRoLfiSoij5CWiP4
UUvhIEt5d4KkMRRvuWXkJo4FWs2tmNWIb1tiXuKhX+puLjP06LwfEyNT1jz75pgO
tSQ0Yz55Hn25CWOcyWF/iIoIjjw3WhQ0a59Ajk8tVdVrTEhlcQ+m7dH1igyMO1vv
iH1eTu+TXqWDF1+oYTZH0iTMYreCNbz2RcFHZQKdWK8GI1DE/qeKLHf+XYGTVQH4
fRnGaX7T5DdnklHKVGi4iILOKn5aofTIg14roS9yfDMK6vmNr7BkzqAe9+WfYC0K
TU3hX1z5SrjnYnBb531MaaCotUEI3DbNeoNsuH3Hx0WLHR1Q55Hh+KAxhMUKTR4P
uwARAQABiQE2BBgBCAAgFiEE6JXydyCXAQnkfMmTuV1WR67EDnIFAlyNdOECGwwA
CgkQuV1WR67EDnKjKwgA3yexUAoTe9sDRKO710MSWhPAn3DZ8qMo8EqmNegG86PO
/mD6BPKo9503pqGGXYoFBcqsmFX07uvy0evCsqO15xuDWwOhNX5fm2LeSsNEkhhC
2wvJVQPdekj9KmOrRRRcr6DlR0Yl7+BJX1+zF8tYwtU4tiY+bCOVRoa1KvTXUwcy
sRTQ9xWguCP8Ai1GyZS0P8lEU0nCS2KrgU/XKQVW7o2OtBiywJbmVCDw15vIq3kN
akRrU5DvYCelUjjzgj+HC3MEE5fV4UsuFLKw3QMmekzFfa6OagRb/FYYZ5ZL+tGI
cf2W57AJOHpgYvxqrY5M1UfKLf8kCYPt3AG0XiD5mw==
=OHyE
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -1,39 +0,0 @@
import QtTest 1.0
import Ubuntu.Test 1.0
import Pass 1.0
UbuntuTestCase {
name: "GpgTests"
function initTestCase() {
Pass.gpgSetGpghome("tests/tmp/gnuhome")
}
function test_empty_gnuhome() {
var listKeys = Pass.gpgListAllKeys()
verify(listKeys.length == 0)
}
function test_import_key_form_file_data() {
return [{
"tag": "public1.key",
"path": "tests/unit/assets/public1.key",
"answer": true
}, {
"tag": "private1.key",
"path": "tests/unit/assets/private1.key",
"answer": true
}, {
"tag": "bad path",
"path": "this/is/a/bad/path",
"answer": false
}, {
"tag": "bad key",
"path": "tests/unit/assets/not.key",
"answer": false
}]
}
function test_import_key_form_file(data) {
compare(Pass.gpgImportKeyFromFile(data.path), data.answer)
}
}

View File

@ -1,65 +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
)
set(EXTERNAL_LIBS "${CMAKE_SOURCE_DIR}/local/${ARCH_TRIPLET}")
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
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
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
BUILD_IN_SOURCE 1
BUILD_COMMAND make
INSTALL_COMMAND make install
)
ExternalProject_Add(
Gnupg
INSTALL_DIR ${EXTERNAL_LIBS}
DOWNLOAD_COMMAND ""
SOURCE_DIR ${GNUPG_PATH}
CONFIGURE_COMMAND <SOURCE_DIR>/autogen.sh && <SOURCE_DIR>/configure --prefix=${EXTERNAL_LIBS} --enable-maintainer-mode --host ${ARCH_TRIPLET}
BUILD_IN_SOURCE 1
BUILD_COMMAND make
INSTALL_COMMAND make install
)

View File

@ -1,13 +0,0 @@
#!/bin/sh
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
cd $SCRIPTPATH && rm -rf build
git submodule update --init --recursive
for LIB in "gnupg" "gpgme" "libassuan" "libgpg-error"
do
echo $LIB
cd $SCRIPTPATH/$LIB && git clean -xdf && git reset --hard HEAD
done
rm -rf $SCRIPTPATH/../local

@ -1 +0,0 @@
Subproject commit 8ae6a246bef5b5eb0684e9fb1c933a4f8441dadd

@ -1 +0,0 @@
Subproject commit 1aff2512d846ea640d400caa31c20c40230b3b04

@ -1 +0,0 @@
Subproject commit 4de3154ea6e6e89e34760b7b9e0eed5123bb81f9

@ -1 +0,0 @@
Subproject commit 2421afddf6ae5a245e6dd1a59779bd26bf225253