├── .gitignore ├── .gitmodules ├── .qmake.conf ├── .travis.yml ├── 3rdparty ├── 3rdparty.pro ├── QR-Code-generator │ ├── QR-Code-generator.pri │ └── QR-Code-generator.pro ├── cryptopp │ ├── cryptopp.pri │ └── cryptopp.pro └── openssl │ ├── armv7 │ ├── libcrypto.so │ └── libssl.so │ └── x86 │ ├── libcrypto.so │ └── libssl.so ├── Dockerfile ├── KeepassTransfer.pro ├── LICENSE ├── README.md ├── appveyor.yml ├── ci ├── appveyor_postbuild.bat ├── travis_init.sh └── travis_postbuild.sh ├── clients ├── clients.pro ├── core │ ├── clients_core_de.ts │ ├── clients_core_template.ts │ ├── clientscore.qrc │ ├── clienttransferservice.cpp │ ├── clienttransferservice.h │ ├── core.pro │ ├── credentialseditviewmodel.cpp │ ├── credentialseditviewmodel.h │ ├── credentialsselectionviewmodel.cpp │ ├── credentialsselectionviewmodel.h │ ├── gui_settings.xml │ ├── kpt.svg │ ├── kptclientapp.cpp │ ├── kptclientapp.h │ ├── kptrootviewmodel.cpp │ ├── kptrootviewmodel.h │ ├── kptsettingsviewmodel.cpp │ ├── kptsettingsviewmodel.h │ ├── kpxcclientimporter.cpp │ ├── kpxcclientimporter.h │ ├── passclientencryptor.cpp │ ├── passclientencryptor.h │ ├── passconnectorviewmodel.cpp │ ├── passconnectorviewmodel.h │ ├── qpmx.json │ ├── qrclientencryptor.cpp │ ├── qrclientencryptor.h │ ├── qrcodeconnectorviewmodel.cpp │ ├── qrcodeconnectorviewmodel.h │ ├── settings.xml │ ├── transferpreselectionentry.cpp │ ├── transferpreselectionentry.h │ ├── transferselectionviewmodel.cpp │ └── transferselectionviewmodel.h ├── quick │ ├── App.qml │ ├── CredentialsEditView.qml │ ├── CredentialsSelectionView.qml │ ├── KptRootDrawer.qml │ ├── PassConnectorView.qml │ ├── QrCodeConnectorView.qml │ ├── TransferPreSelectionEdit.qml │ ├── TransferSelectionView.qml │ ├── android │ │ ├── AndroidManifest.xml │ │ ├── build.gradle │ │ ├── res │ │ │ ├── drawable-hdpi │ │ │ │ └── ic_splash.9.png │ │ │ ├── drawable-mdpi │ │ │ │ └── ic_splash.9.png │ │ │ ├── drawable-xhdpi │ │ │ │ └── ic_splash.9.png │ │ │ ├── drawable-xxhdpi │ │ │ │ └── ic_splash.9.png │ │ │ ├── drawable-xxxhdpi │ │ │ │ └── ic_splash.9.png │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ └── ic_launcher.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_foreground.png │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_foreground.png │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_foreground.png │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_foreground.png │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_foreground.png │ │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ │ ├── colors.xml │ │ │ │ ├── libs.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ └── src │ │ │ ├── de │ │ │ └── skycoder42 │ │ │ │ └── kpt │ │ │ │ ├── KptActivity.java │ │ │ │ ├── TransferAccessReceiver.java │ │ │ │ └── TransferActionReceiver.java │ │ │ └── keepass2android │ ├── clientsquick.qrc │ ├── icons │ │ ├── baseline-add-24px.svg │ │ ├── baseline-lock-24px.svg │ │ ├── baseline-lock_open-24px.svg │ │ ├── baseline-menu-24px.svg │ │ ├── baseline-photo_camera-24px.svg │ │ ├── baseline-send-24px.svg │ │ ├── baseline-visibility-24px.svg │ │ ├── baseline-visibility_off-24px.svg │ │ ├── baseline-vpn_key-24px.svg │ │ └── outline-info-24px.svg │ ├── kpt_client_quick_de.ts │ ├── kpt_client_quick_template.ts │ ├── main.cpp │ ├── qpmx.json │ ├── qrcodescanner.cpp │ ├── qrcodescanner.h │ ├── qtquickcontrols2.conf │ ├── quick.pro │ ├── transferloader.cpp │ └── transferloader.h └── widgets │ ├── clientswidgets.qrc │ ├── credentialseditpage.cpp │ ├── credentialseditpage.h │ ├── credentialseditpage.ui │ ├── credentialsselectionpage.cpp │ ├── credentialsselectionpage.h │ ├── credentialsselectionpage.ui │ ├── de.skycoder42.kptransfer.desktop │ ├── icons │ ├── baseline-add-24px.svg │ ├── baseline-assignment-24px.svg │ ├── baseline-lock-24px.svg │ ├── baseline-lock_open-24px.svg │ ├── baseline-select_all-24px.svg │ ├── baseline-tab_unselected-24px.svg │ ├── baseline-visibility-24px.svg │ ├── baseline-visibility_off-24px.svg │ ├── baseline-vpn_key-24px.svg │ └── keepassxc.svg │ ├── kpt_client_template.ts │ ├── kpt_client_widgets_de.ts │ ├── kpt_client_widgets_template.ts │ ├── kptrootwizard.cpp │ ├── kptrootwizard.h │ ├── main.cpp │ ├── passconnectorpage.cpp │ ├── passconnectorpage.h │ ├── passconnectorpage.ui │ ├── qpmx.json │ ├── qrcodeconnectorpage.cpp │ ├── qrcodeconnectorpage.h │ ├── qrcodeconnectorpage.ui │ ├── transferpreselectionedit.cpp │ ├── transferpreselectionedit.h │ ├── transferselectionpage.cpp │ ├── transferselectionpage.h │ ├── transferselectionpage.ui │ └── widgets.pro ├── flatpak ├── de.skycoder42.flatpakrepo ├── de.skycoder42.kptransfer.flatpakref └── de.skycoder42.kptransfer.json ├── icon ├── external │ ├── flat │ │ ├── baseline-add-24px.svg │ │ ├── baseline-arrow_back-24px.svg │ │ ├── baseline-assignment-24px.svg │ │ ├── baseline-file_copy-24px.svg │ │ ├── baseline-lock-24px.svg │ │ ├── baseline-lock_open-24px.svg │ │ ├── baseline-menu-24px.svg │ │ ├── baseline-photo_camera-24px.svg │ │ ├── baseline-select_all-24px.svg │ │ ├── baseline-send-24px.svg │ │ ├── baseline-tab_unselected-24px.svg │ │ ├── baseline-visibility-24px.svg │ │ ├── baseline-visibility_off-24px.svg │ │ ├── baseline-vpn_key-24px.svg │ │ └── outline-info-24px.svg │ └── keepassxc.svg ├── kpt.icns ├── kpt.ico ├── kpt.svg ├── kpt_header.png ├── pngs │ ├── kpt_128.png │ ├── kpt_144.png │ ├── kpt_16.png │ ├── kpt_192.png │ ├── kpt_22.png │ ├── kpt_24.png │ ├── kpt_256.png │ ├── kpt_32.png │ ├── kpt_36.png │ ├── kpt_384.png │ ├── kpt_48.png │ ├── kpt_512.png │ ├── kpt_64.png │ ├── kpt_72.png │ └── kpt_96.png └── raw │ ├── kpt_v1.svg │ ├── kpt_v2.svg │ ├── kpt_v2_colored.svg │ ├── kpt_v2_colored_bg.svg │ ├── kpt_v3.svg │ ├── kpt_v3_colored.svg │ └── kpt_v3_colored_bg.svg ├── install.pri ├── lib ├── credential.cpp ├── credential.h ├── dataencryptor.cpp ├── dataencryptor.h ├── encrypteddata.cpp ├── encrypteddata.h ├── kptlib.cpp ├── kptlib.h ├── lib.pri ├── lib.pro ├── messages │ ├── appidentmessage.cpp │ ├── appidentmessage.h │ ├── appokmessage.cpp │ ├── appokmessage.h │ ├── clienttransfermessage.cpp │ ├── clienttransfermessage.h │ ├── errormessage.cpp │ ├── errormessage.h │ ├── serveridentmessage.cpp │ ├── serveridentmessage.h │ ├── serverokmessage.cpp │ ├── serverokmessage.h │ ├── servertransfermessage.cpp │ └── servertransfermessage.h ├── protocol.qmodel ├── qpmx.json ├── qrdata.cpp └── qrdata.h ├── readme ├── desktop.gif ├── mobile.gif └── webapp.gif ├── server ├── de.skycoder42.kptransfer.server.plist ├── dockerbuild │ ├── env_start.sh │ └── install.sh ├── kptserver-install.bat ├── kptserver.service.in ├── kptserver.socket ├── kptservice.cpp ├── kptservice.h ├── main.cpp ├── qpmx.json ├── server.pro ├── transferserver.cpp └── transferserver.h ├── update-icons.sh └── webapp ├── AboutDialog.qml ├── CredentialsView.qml ├── ErrorDialog.qml ├── MainView.qml ├── PassTabView.qml ├── QrTabView.qml ├── emjsconnector.cpp ├── emjsconnector.h ├── emjsconnector_wasm.cpp ├── icons ├── baseline-arrow_back-24px.svg ├── baseline-file_copy-24px.svg ├── baseline-visibility-24px.svg ├── baseline-visibility_off-24px.svg ├── baseline-vpn_key-24px.svg ├── kpt.svg └── outline-info-24px.svg ├── iencoder.cpp ├── iencoder.h ├── main.cpp ├── main.qml ├── passencoder.cpp ├── passencoder.h ├── qrencoder.cpp ├── qrencoder.h ├── qrimageprovider.cpp ├── qrimageprovider.h ├── qtquickcontrols2.conf ├── qwasmsettings.cpp ├── qwasmsettings.h ├── serverconnector.cpp ├── serverconnector.h ├── webapp.pro └── webapp.qrc /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | 41 | # xemacs temporary files 42 | *.flc 43 | 44 | # Vim temporary files 45 | .*.swp 46 | 47 | # Visual Studio generated files 48 | *.ib_pdb_index 49 | *.idb 50 | *.ilk 51 | *.pdb 52 | *.sln 53 | *.suo 54 | *.vcproj 55 | *vcproj.*.*.user 56 | *.ncb 57 | *.sdf 58 | *.opensdf 59 | *.vcxproj 60 | *vcxproj.* 61 | 62 | # MinGW generated files 63 | *.Debug 64 | *.Release 65 | 66 | # Python byte code 67 | *.pyc 68 | 69 | # Binaries 70 | # -------- 71 | *.dll 72 | *.exe 73 | 74 | # qpmx 75 | .qpmx-dev-cache 76 | *.tsdummy.cpp 77 | *.json.user 78 | .tsdummy.pro.dummy 79 | *_qmlcache.qrc 80 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "3rdparty/cryptopp/src"] 2 | path = 3rdparty/cryptopp/src 3 | url = https://github.com/weidai11/cryptopp 4 | [submodule "3rdparty/QR-Code-generator/src"] 5 | path = 3rdparty/QR-Code-generator/src 6 | url = https://github.com/nayuki/QR-Code-generator.git 7 | [submodule "3rdparty/keepass2android"] 8 | path = 3rdparty/keepass2android 9 | url = https://github.com/PhilippC/keepass2android.git 10 | [submodule "3rdparty/qtcsv"] 11 | path = 3rdparty/qtcsv 12 | url = https://github.com/iamantony/qtcsv 13 | [submodule "deploy"] 14 | path = deploy 15 | url = https://github.com/Skycoder42/deployment 16 | -------------------------------------------------------------------------------- /.qmake.conf: -------------------------------------------------------------------------------- 1 | VERSION = 3.0.0 2 | 3 | CONFIG += warning_clean exceptions c++14 4 | DEFINES += QT_DEPRECATED_WARNINGS QT_ASCII_CAST_WARNINGS QT_USE_QSTRINGBUILDER 5 | 6 | PROJECT_NAME = KeePass-Transfer 7 | PROJECT_TARGET = kptransfer 8 | QMAKE_TARGET_PRODUCT = "$$PROJECT_NAME" 9 | QMAKE_TARGET_COMPANY = "Skycoder42" 10 | QMAKE_TARGET_COPYRIGHT = "Felix Barz" 11 | QMAKE_TARGET_BUNDLE_PREFIX = de.skycoder42 12 | 13 | DEFINES += "PROJECT_NAME=\\\"$$PROJECT_NAME\\\"" 14 | DEFINES += "PROJECT_TARGET=\\\"$$PROJECT_TARGET\\\"" 15 | DEFINES += "VERSION=\\\"$$VERSION\\\"" 16 | DEFINES += "COMPANY=\"\\\"$$QMAKE_TARGET_COMPANY\\\"\"" 17 | DEFINES += "BUNDLE=\"\\\"$$QMAKE_TARGET_BUNDLE_PREFIX\\\"\"" 18 | DEFINES += APPID=\"\\\"$${QMAKE_TARGET_BUNDLE_PREFIX}.$${PROJECT_TARGET}\\\"\" 19 | 20 | ICON_SIZES=16 22 24 32 36 48 64 72 96 128 144 192 256 384 512 21 | 22 | wasm { 23 | CONFIG += no_clients 24 | QMAKE_LFLAGS_DEBUG += --emrun 25 | QMAKE_CXXFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 26 | QMAKE_LFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 27 | DEFINES += QT_OS_WASM 28 | } 29 | 30 | android { 31 | PREFIX = / 32 | CONFIG += no_widgets no_webapp 33 | } 34 | 35 | !wasm:CONFIG(release, debug|release): CONFIG += no_webapp 36 | 37 | SRC_ROOT_DIR=$$PWD 38 | 39 | unix:!wasm:!cross_compile:packagesExist(libcrypto++): CONFIG += system_cryptopp 40 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | services: 4 | - docker 5 | 6 | sudo: required 7 | dist: trusty 8 | osx_image: xcode10.1 9 | 10 | env: 11 | global: 12 | - QPMX_CACHE_DIR=$HOME/.qpmx-cache 13 | - QT_VER_MINOR=5.12 14 | - QT_VER=${QT_VER_MINOR}.0 15 | - EXTRA_MODULES=".skycoder42" 16 | - DOCKER_IMAGE=full 17 | - NO_TESTS=true 18 | 19 | matrix: 20 | include: 21 | - os: linux 22 | env: 23 | - PLATFORM=gcc_64 24 | - QMAKE_FLAGS="PREFIX=/deploy CONFIG+=no_quick" 25 | - os: linux 26 | env: 27 | - PLATFORM=flatpak 28 | - DOCKER_IMAGE= 29 | - DOCKER_IMAGE_BASE="base/archlinux:latest" 30 | - FLATDEP_DIR=deploy/flatpak 31 | - FLATPAK_MANIFEST=flatpak/de.skycoder42.kptransfer.json 32 | - os: linux 33 | env: 34 | - PLATFORM=emscripten 35 | - DOCKER_IMAGE=base 36 | - QMAKE_FLAGS="PREFIX=/wasm INSTALL_WWW=/wasm/www" 37 | #- os: linux 38 | #env: 39 | #- PLATFORM=android_arm64_v8a 40 | - os: linux 41 | env: 42 | - PLATFORM=android_armv7 43 | - os: linux 44 | env: 45 | - PLATFORM=android_x86 46 | - os: osx 47 | env: 48 | - PLATFORM=clang_64 49 | - QMAKE_FLAGS="PREFIX=/deploy CONFIG+=no_quick" 50 | 51 | before_install: 52 | - git clone https://github.com/Skycoder42/QtModules.git ./qtmodules-travis 53 | - travis_wait 40 ./qtmodules-travis/ci/$TRAVIS_OS_NAME/setup.sh 54 | 55 | script: 56 | - ./ci/travis_init.sh 57 | - ./qtmodules-travis/ci/$TRAVIS_OS_NAME/build.sh 58 | - if [ "$TRAVIS_OS_NAME" == "osx" ]; then ./ci/travis_postbuild.sh; fi 59 | 60 | deploy: 61 | provider: releases 62 | skip_cleanup: true 63 | api_key: 64 | secure: ultP5Os1hFNW9FXRQCNCH6zZ+TqdBAJIXkdINIVZCIPIm3Haipk7SWDUXN0ZC8w9iN3/efx7woiUTQB/euNHZXOPMVsTYfuzw/VxrOzgTnKQg/euUMvJedSf9UGW4yw6Ftm7/mR7RtrCp1nImHmnVLZqqEhbhsTc9PTcm7LC45jFnWHhOv6So1mCg1n/ckCkqZy+AIQVum25L2MPsKvMhezqoetU3g2h1KZJrEd1y5nSl1mF9YsYoIl9RUutqG5wewex7n6NXNOGdoj0eal+VtkzNRUvrJiNGsFiVbxn9oAIf72avQ2Pe4XDTwSboDnxI0uki3s2xiJ98NcDrpcgm1xiz9GgVsAp4nKXu5EGjWHKaFpkOp7bmhI9ssQQ06njwEO+E+mKaCsJxhYP5F5v5j+IxEWaS6GXtCIDQAwAgORktEY/MIZIXdYNusWgfy2yO8qJseFp4bFbfOhJO9cqcgHfp31RtdgqQdDk8T96ODd2ffz/O0czLTN7YfmCGOp2gqu5JWDwAXA/UaANBWVM+V8PD4+sRdY+R8CEN5+9LQCQxhy1RJ0naR7LANx1KK4jDgmTL/eZwx2Ch6Fk4ny13eVBh8KWqQikjmiYIwyVX8Y8o8SPfHiMhGB5YyHmQ/4j0Ih4uD6wpVwCwayAll0Noy3V6+p7WyxebzKffddZ2yI= 65 | file_glob: true 66 | file: 67 | - ./install/kptransfer-*.dmg 68 | - ./install/kptransfer-*.apk 69 | - ./install/kptransfer-*_emscripten.tar.xz 70 | - ./install/flatpak_build.tar.xz 71 | on: 72 | repo: Skycoder42/KeepassTransfer 73 | tags: true 74 | 75 | before_cache: 76 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 77 | - rm -rf $HOME/.gradle/caches/*/plugin-resolution/ 78 | - rm -rf $QPMX_CACHE_DIR/locks 79 | - rm -rf $QPMX_CACHE_DIR/tmp 80 | - sudo rm -rf flatpak-build/.flatpak-builder/build 81 | - sudo rm -rf flatpak-build/.flatpak-builder/rofiles 82 | cache: 83 | directories: 84 | - $HOME/.gradle/caches/ 85 | - $HOME/.gradle/wrapper/ 86 | - $HOME/.android/build-cache 87 | - $QPMX_CACHE_DIR 88 | - flatpak-build/.flatpak-builder 89 | -------------------------------------------------------------------------------- /3rdparty/3rdparty.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | cryptopp \ 5 | QR-Code-generator 6 | 7 | system_cryptopp: SUBDIRS -= cryptopp 8 | 9 | DISTFILES += \ 10 | cryptopp/cryptopp.pri \ 11 | QR-Code-generator/QR-Code-generator.pri 12 | 13 | QMAKE_EXTRA_TARGETS += lrelease 14 | -------------------------------------------------------------------------------- /3rdparty/QR-Code-generator/QR-Code-generator.pri: -------------------------------------------------------------------------------- 1 | OUT_ROOT = $$shadowed($$SRC_ROOT_DIR) 2 | 3 | win32:CONFIG(release, debug|release): LIBS += -L$$OUT_ROOT/3rdparty/QR-Code-generator/release/ -lqrcodegen 4 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_ROOT/3rdparty/QR-Code-generator/debug/ -lqrcodegen 5 | else:unix: LIBS += -L$$OUT_ROOT/3rdparty/QR-Code-generator/ -lqrcodegen 6 | 7 | INCLUDEPATH += $$PWD/src/cpp 8 | DEPENDPATH += $$PWD/src/cpp 9 | 10 | win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_ROOT/3rdparty/QR-Code-generator/release/libqrcodegen.a 11 | else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_ROOT/3rdparty/QR-Code-generator/debug/libqrcodegen.a 12 | else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_ROOT/3rdparty/QR-Code-generator/release/libqrcodegen.lib 13 | else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_ROOT/3rdparty/QR-Code-generator/debug/libqrcodegen.lib 14 | else:unix: PRE_TARGETDEPS += $$OUT_ROOT/3rdparty/QR-Code-generator/libqrcodegen.a 15 | -------------------------------------------------------------------------------- /3rdparty/QR-Code-generator/QR-Code-generator.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | 3 | CONFIG += staticlib 4 | CONFIG -= qt 5 | QT = 6 | 7 | TARGET = qrcodegen 8 | 9 | HEADERS += \ 10 | src/cpp/BitBuffer.hpp \ 11 | src/cpp/QrCode.hpp \ 12 | src/cpp/QrSegment.hpp 13 | 14 | SOURCES += \ 15 | src/cpp/BitBuffer.cpp \ 16 | src/cpp/QrCode.cpp \ 17 | src/cpp/QrSegment.cpp 18 | 19 | -------------------------------------------------------------------------------- /3rdparty/cryptopp/cryptopp.pri: -------------------------------------------------------------------------------- 1 | system_cryptopp { 2 | CONFIG += link_pkgconfig 3 | PKGCONFIG += libcrypto++ 4 | } else { 5 | OUT_ROOT = $$shadowed($$SRC_ROOT_DIR) 6 | 7 | win32:CONFIG(release, debug|release): LIBS += -L$$OUT_ROOT/3rdparty/cryptopp/release/ -lqtcryptopp 8 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_ROOT/3rdparty/cryptopp/debug/ -lqtcryptopp 9 | else:unix: LIBS += -L$$OUT_ROOT/3rdparty/cryptopp/ -lqtcryptopp 10 | 11 | INCLUDEPATH += $$OUT_ROOT/include 12 | DEPENDPATH += $$PWD/src 13 | 14 | win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_ROOT/3rdparty/cryptopp/release/libqtcryptopp.a 15 | else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_ROOT/3rdparty/cryptopp/debug/libqtcryptopp.a 16 | else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_ROOT/3rdparty/cryptopp/release/qtcryptopp.lib 17 | else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_ROOT/3rdparty/cryptopp/debug/qtcryptopp.lib 18 | else:unix: PRE_TARGETDEPS += $$OUT_ROOT/3rdparty/cryptopp/libqtcryptopp.a 19 | 20 | # defines: 21 | win32:!win32-g++: DEFINES += CRYPTOPP_DISABLE_ASM 22 | equals(ANDROID_TARGET_ARCH, x86): DEFINES += CRYPTOPP_DISABLE_ASM 23 | win32:cross_compile: DEFINES += NO_OS_DEPENDENCE 24 | } 25 | -------------------------------------------------------------------------------- /3rdparty/cryptopp/cryptopp.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | 3 | load(qt_build_config) 4 | CONFIG += staticlib exceptions c++14 5 | CONFIG -= qt 6 | 7 | TARGET = $$qtLibraryTarget(qtcryptopp) 8 | 9 | QMAKE_CXXFLAGS_RELEASE += "-DNDEBUG" 10 | 11 | win32:!win32-g++ { 12 | QMAKE_CXXFLAGS += /arch:AVX2 13 | DEFINES += CRYPTOPP_DISABLE_ASM #TODO reenable again later 14 | cross_compile: DEFINES += NO_OS_DEPENDENCE 15 | } else:wasm { 16 | QMAKE_CXXFLAGS += -msse4.1 -mssse3 17 | } else { 18 | # based on https://github.com/KayEss/fost-crypto/blob/master/CMakeLists.txt 19 | QMAKE_CXXFLAGS += -Wno-keyword-macro -Wno-unused-const-variable -Wno-unused-private-field 20 | 21 | !isEmpty(ANDROID_TARGET_ARCH) { 22 | message("Building for android arch $$ANDROID_TARGET_ARCH") 23 | INCLUDEPATH += $$(ANDROID_NDK_ROOT)/sources/android/cpufeatures 24 | SOURCES += $$(ANDROID_NDK_ROOT)/sources/android/cpufeatures/cpu-features.c 25 | 26 | equals(ANDROID_TARGET_ARCH, armeabi-v7a) { 27 | QMAKE_CXXFLAGS -= -mfpu=vfp 28 | QMAKE_CXXFLAGS += -mfpu=neon 29 | } else:equals(ANDROID_TARGET_ARCH, arm64-v8a) { 30 | # nothing to be done 31 | } else:equals(ANDROID_TARGET_ARCH, x86) { 32 | QMAKE_CXXFLAGS += -maes -mpclmul -msha -msse4.1 -msse4.2 -mssse3 33 | # Do this for Android builds for now as the NDK is broken 34 | DEFINES += CRYPTOPP_DISABLE_ASM 35 | warning("Disabled x86 crypto ASM") 36 | } 37 | } else { 38 | # assume "normal" x86 arch 39 | message("Building for host x86 arch") 40 | QMAKE_CXXFLAGS += -maes -mpclmul -msha -msse4.1 -msse4.2 -mssse3 41 | } 42 | } 43 | 44 | # Input 45 | HEADERS += $$files(src/*.h) 46 | 47 | SOURCES += $$files(src/*.cpp) 48 | 49 | SOURCES -= \ 50 | src/bench1.cpp \ 51 | src/bench2.cpp \ 52 | src/datatest.cpp \ 53 | src/dlltest.cpp \ 54 | src/pch.cpp \ 55 | src/regtest1.cpp \ 56 | src/regtest2.cpp \ 57 | src/regtest3.cpp \ 58 | src/test.cpp \ 59 | src/validat0.cpp \ 60 | src/validat1.cpp \ 61 | src/validat2.cpp \ 62 | src/validat3.cpp \ 63 | src/validat4.cpp \ 64 | src/TestScripts/cryptest-coverity.cpp 65 | 66 | DISTFILES += cryptopp.pri 67 | 68 | load(qt_build_paths) 69 | 70 | HEADER_INSTALL_DIR = "$$shadowed($$SRC_ROOT_DIR)/include/cryptopp" 71 | !ReleaseBuild|!DebugBuild { 72 | !mkpath($$HEADER_INSTALL_DIR):error("Failed to create cryptopp header dir: $$HEADER_INSTALL_DIR") 73 | for(hdr, HEADERS):!system($$QMAKE_QMAKE -install qinstall "$$PWD/$$hdr" "$$HEADER_INSTALL_DIR/$$basename(hdr)"):error("Failed to install header file: $$hdr") 74 | } 75 | 76 | INCLUDEPATH += "$$MODULE_BASE_OUTDIR/include" 77 | -------------------------------------------------------------------------------- /3rdparty/openssl/armv7/libcrypto.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/3rdparty/openssl/armv7/libcrypto.so -------------------------------------------------------------------------------- /3rdparty/openssl/armv7/libssl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/3rdparty/openssl/armv7/libssl.so -------------------------------------------------------------------------------- /3rdparty/openssl/x86/libcrypto.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/3rdparty/openssl/x86/libcrypto.so -------------------------------------------------------------------------------- /3rdparty/openssl/x86/libssl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/3rdparty/openssl/x86/libssl.so -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #LABEL maintainer="skycoder42.de@gmx.de" 2 | FROM debian:latest 3 | 4 | COPY . /tmp/src 5 | RUN /tmp/src/server/dockerbuild/install.sh 6 | 7 | # create env vars & ready for usage 8 | ENV KPTSERVER_CONFIG_PATH=/etc/Skycoder42/kptransfer-server.conf 9 | ENV KPTSERVER_HOST=localhost 10 | ENV KPTSERVER_PORT=27352 11 | ENV KPTSERVER_LOCAL=false 12 | ENV KPTSERVER_TIMEOUT=30000 13 | 14 | CMD ["/usr/bin/env_start.sh"] 15 | -------------------------------------------------------------------------------- /KeepassTransfer.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 3rdparty \ 5 | lib 6 | 7 | !no_server:!cross_compile: SUBDIRS += server 8 | !no_webapp: SUBDIRS += webapp 9 | !no_clients: SUBDIRS += clients 10 | 11 | lib.depends += 3rdparty 12 | webapp.depends += 3rdparty lib 13 | clients.depends += 3rdparty lib 14 | server.depends += 3rdparty lib 15 | 16 | prepareRecursiveTarget(lrelease) 17 | QMAKE_EXTRA_TARGETS += lrelease 18 | 19 | DISTFILES += \ 20 | .qmake.conf 21 | 22 | include(deploy/install.pri) 23 | 24 | !isEmpty(PREFIX):!no_bundle_deploy { 25 | win32: DEPLOY_BINS = "$$INSTALL_BINS/$${PROJECT_TARGET}-client.exe" "$$INSTALL_BINS/$${PROJECT_TARGET}-server.exe" 26 | else:mac: DEPLOY_BINS = "$$PREFIX/$${PROJECT_NAME}.app" "$$PREFIX/$${APP_PREFIX}/MacOs/$${PROJECT_TARGET}-server" 27 | else:android: DEPLOY_BINS = "$$OUT_PWD/clients/quick/android-lib$${PROJECT_TARGET}-app.so-deployment-settings.json" 28 | DEPLOY_PLUGINS += servicebackends 29 | 30 | #!no_widgets: TS_DICTIONARIES += $$PWD/gui/widgets/kptransfer.tsdict 31 | #!no_quick: TS_DICTIONARIES += $$PWD/gui/quick/kptransfer.tsdict 32 | } 33 | 34 | include(deploy/deploy.pri) 35 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: 2 | - Visual Studio 2017 3 | 4 | version: build-{build} 5 | 6 | environment: 7 | QT_VER: 5.12.0 8 | QMAKE_FLAGS: "PREFIX=/deploy CONFIG+=no_quick" 9 | PLATFORM: msvc2017_64 10 | EXTRA_MODULES: .skycoder42 11 | NO_TESTS: true 12 | 13 | install: 14 | - git submodule init 15 | - git submodule update 16 | - git clone https://github.com/Skycoder42/QtModules.git .\qtmodules-travis 17 | - .\qtmodules-travis\ci\win\setup.bat 18 | 19 | build_script: 20 | - .\qtmodules-travis\ci\win\build.bat 21 | - .\ci\appveyor_postbuild.bat 22 | 23 | artifacts: 24 | - path: install\kptransfer-*.zip 25 | 26 | deploy: 27 | provider: GitHub 28 | auth_token: 29 | secure: Cp5GRQku2ZWnKPE12NB5q11ZO0Fr5mlzdUTjnLpYJr/dki4LPVqm231edFggogy8 30 | artifact: /.*/ 31 | force_update: false 32 | on: 33 | appveyor_repo_tag: true 34 | 35 | cache: 36 | - 'C:\Users\appveyor\AppData\Local\Skycoder42\qpmx\cache -> appveyor.yml' 37 | -------------------------------------------------------------------------------- /ci/appveyor_postbuild.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | set qtplatform=%PLATFORM% 5 | for %%* in (.) do set CurrDirName=%%~nx* 6 | 7 | call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 || exit /B 1 8 | 9 | cd build-%qtplatform% 10 | nmake INSTALL_ROOT=\projects\%CurrDirName%\install deploy || exit /B 1 11 | nmake INSTALL_ROOT=\projects\%CurrDirName%\install package || exit /B 1 12 | cd .. 13 | 14 | dir /s install\ 15 | -------------------------------------------------------------------------------- /ci/travis_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | currDir=$(dirname $0) 5 | 6 | if [[ $TRAVIS_OS_NAME == "linux" ]]; then 7 | # append post build script 8 | echo "$currDir/travis_postbuild.sh" >> qtmodules-travis/ci/linux/build-docker.sh 9 | fi 10 | -------------------------------------------------------------------------------- /ci/travis_postbuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | rootdir=$(pwd) 5 | 6 | if [[ $PLATFORM == "android_"* ]]; then 7 | if [[ "$PLATFORM" == "android_arm64_v8a" ]]; then 8 | PCODE=0 9 | fi 10 | if [[ "$PLATFORM" == "android_armv7" ]]; then 11 | PCODE=1 12 | fi 13 | if [[ "$PLATFORM" == "android_x86" ]]; then 14 | PCODE=2 15 | fi 16 | 17 | sed -i "s/android:versionCode=\"\([[:digit:]]*\)\"/android:versionCode=\"\1%{pcode}\"/g" clients/quick/android/AndroidManifest.xml 18 | sed -i "s/%{pcode}/$PCODE/g" clients/quick/android/AndroidManifest.xml 19 | 20 | pushd build-$PLATFORM 21 | make INSTALL_ROOT="$rootdir/install" deploy 22 | popd 23 | else 24 | pushd build-$PLATFORM 25 | make INSTALL_ROOT="$rootdir/install" deploy 26 | make INSTALL_ROOT="$rootdir/install" package 27 | popd 28 | fi 29 | 30 | find install/ 31 | -------------------------------------------------------------------------------- /clients/clients.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | core \ 5 | widgets \ 6 | quick 7 | 8 | no_widgets: SUBDIRS -= widgets 9 | no_quick: SUBDIRS -= quick 10 | 11 | widgets.depends += core 12 | quick.depends += core 13 | 14 | prepareRecursiveTarget(lrelease) 15 | QMAKE_EXTRA_TARGETS += lrelease 16 | -------------------------------------------------------------------------------- /clients/core/clientscore.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | gui_settings.xml 4 | 5 | 6 | kpt.svg 7 | 8 | 9 | -------------------------------------------------------------------------------- /clients/core/clienttransferservice.h: -------------------------------------------------------------------------------- 1 | #ifndef CLIENTTRANSFERSERVICE_H 2 | #define CLIENTTRANSFERSERVICE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "settings.h" 20 | 21 | class IClientEncryptor 22 | { 23 | Q_DISABLE_COPY(IClientEncryptor) 24 | public: 25 | IClientEncryptor(); 26 | virtual ~IClientEncryptor(); 27 | 28 | virtual EncryptedData::DataMode mode() const = 0; 29 | virtual QUuid channelId() const = 0; 30 | virtual std::pair obtainKeys(CryptoPP::RandomNumberGenerator &rng) = 0; 31 | }; 32 | 33 | class ClientTransferService : public QObject 34 | { 35 | Q_OBJECT 36 | QTMVVM_INJECT_PROP(DataEncryptor*, encryptor, _encryptor) 37 | QTMVVM_INJECT_PROP(Settings*, settings, _settings) 38 | 39 | public: 40 | Q_INVOKABLE explicit ClientTransferService(QObject *parent = nullptr); 41 | 42 | public slots: 43 | void sendCredentials(IClientEncryptor *clientCrypt, 44 | const QList &credentials); 45 | 46 | signals: 47 | void transferCompleted(); 48 | 49 | private slots: 50 | void connected(); 51 | void disconnected(); 52 | void binaryMessageReceived(const QByteArray &message); 53 | void onSocketError(); 54 | 55 | void cryptDataReady(); 56 | void userCanceled(); 57 | 58 | private: 59 | static QThreadStorage _rngs; 60 | 61 | DataEncryptor *_encryptor = nullptr; 62 | Settings *_settings = nullptr; 63 | 64 | QWebSocket *_currentSocket = nullptr; 65 | QPointer _currentControl = nullptr; 66 | QFutureWatcher *_cryptWatcher = nullptr; 67 | IClientEncryptor *_currentCrypt = nullptr; 68 | bool _doSend = false; 69 | 70 | EncryptedData encrypt(IClientEncryptor *clientCrypt, const QList &credentials); 71 | 72 | void onServerOk(const ServerOkMessage message); 73 | void onError(const ErrorMessage &message); 74 | void onFallback(int typeId); 75 | 76 | void sendData(); 77 | }; 78 | 79 | #define IClientEncryptorIid "de.skycoder42.kpt.IClientEncryptor" 80 | Q_DECLARE_INTERFACE(IClientEncryptor, IClientEncryptorIid) 81 | 82 | #endif // CLIENTTRANSFERSERVICE_H 83 | -------------------------------------------------------------------------------- /clients/core/core.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | 3 | QT += mvvmcore websockets concurrent 4 | CONFIG += static 5 | 6 | TARGET = $${PROJECT_TARGET}-core 7 | 8 | DEFINES += QTCSV_STATIC_LIB 9 | 10 | packagesExist(libkpxcclient) { 11 | CONFIG += link_pkgconfig 12 | PKGCONFIG += libkpxcclient 13 | DEFINES += USE_KPXCCLIENT_LIB 14 | 15 | HEADERS += kpxcclientimporter.h 16 | SOURCES += kpxcclientimporter.cpp 17 | } 18 | 19 | HEADERS += \ 20 | kptclientapp.h \ 21 | credentialseditviewmodel.h \ 22 | transferselectionviewmodel.h \ 23 | kptrootviewmodel.h \ 24 | clienttransferservice.h \ 25 | qrcodeconnectorviewmodel.h \ 26 | qrclientencryptor.h \ 27 | kptsettingsviewmodel.h \ 28 | transferpreselectionentry.h \ 29 | credentialsselectionviewmodel.h \ 30 | passclientencryptor.h \ 31 | passconnectorviewmodel.h 32 | 33 | SOURCES += \ 34 | kptclientapp.cpp \ 35 | credentialseditviewmodel.cpp \ 36 | transferselectionviewmodel.cpp \ 37 | kptrootviewmodel.cpp \ 38 | clienttransferservice.cpp \ 39 | qrcodeconnectorviewmodel.cpp \ 40 | qrclientencryptor.cpp \ 41 | kptsettingsviewmodel.cpp \ 42 | transferpreselectionentry.cpp \ 43 | credentialsselectionviewmodel.cpp \ 44 | passclientencryptor.cpp \ 45 | passconnectorviewmodel.cpp 46 | 47 | SETTINGS_DEFINITIONS += \ 48 | settings.xml 49 | 50 | RESOURCES += \ 51 | clientscore.qrc 52 | 53 | TRANSLATIONS += clients_core_de.ts \ 54 | clients_core_template.ts 55 | 56 | SETTINGS_TRANSLATIONS = gui_settings.xml 57 | 58 | DISTFILES += $$TRANSLATIONS \ 59 | qpmx.json 60 | 61 | include($$SRC_ROOT_DIR/lib/lib.pri) 62 | include($$SRC_ROOT_DIR/3rdparty/qtcsv/qtcsv.pri) 63 | 64 | !ReleaseBuild:!DebugBuild:!system(qpmx -d $$shell_quote($$_PRO_FILE_PWD_) --qmake-run init $$QPMX_EXTRA_OPTIONS $$shell_quote($$QMAKE_QMAKE) $$shell_quote($$OUT_PWD)): error(qpmx initialization failed. Check the compilation log for details.) 65 | else: include($$OUT_PWD/qpmx_generated.pri) 66 | -------------------------------------------------------------------------------- /clients/core/credentialseditviewmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef CREDENTIALSEDITVIEWMODEL_H 2 | #define CREDENTIALSEDITVIEWMODEL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef USE_KPXCCLIENT_LIB 9 | class KPXCClientImporter; 10 | #endif 11 | 12 | class CredentialsEditViewModel : public QtMvvm::ViewModel 13 | { 14 | Q_OBJECT 15 | QTMVVM_CONTAINER_VM(KptRootViewModel) 16 | 17 | Q_PROPERTY(CredentialsEditViewModel::CredentialsModel* credentialsModel READ credentialsModel CONSTANT) 18 | 19 | public: 20 | static const QString paramKpxcPath; 21 | static QVariantHash params(const QString &kpxcPath); 22 | 23 | using CredentialsModel = QGenericListModel; 24 | 25 | Q_INVOKABLE explicit CredentialsEditViewModel(QObject *parent = nullptr); 26 | 27 | CredentialsModel *credentialsModel() const; 28 | 29 | Q_INVOKABLE bool commitCredentials(); 30 | 31 | public slots: 32 | void onInit(const QVariantHash ¶ms) override; 33 | 34 | void addEmptyEntry(); 35 | void importFromKPXC(); 36 | 37 | private slots: 38 | void entryImported(const QList &credentials); 39 | 40 | private: 41 | CredentialsModel *_credModel; 42 | #ifdef USE_KPXCCLIENT_LIB 43 | KPXCClientImporter *_importer; 44 | #endif 45 | 46 | void setupModel(); 47 | }; 48 | 49 | Q_DECLARE_METATYPE(CredentialsEditViewModel::CredentialsModel*) 50 | 51 | #endif // CREDENTIALSEDITVIEWMODEL_H 52 | -------------------------------------------------------------------------------- /clients/core/credentialsselectionviewmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef CREDENTIALSSELECTIONVIEWMODEL_H 2 | #define CREDENTIALSSELECTIONVIEWMODEL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "settings.h" 8 | 9 | class CredentialsSelectionViewModel : public QtMvvm::ViewModel 10 | { 11 | Q_OBJECT 12 | QTMVVM_CONTAINER_VM(KptRootViewModel) 13 | 14 | QTMVVM_INJECT_PROP(Settings*, settings, _settings) 15 | 16 | Q_PROPERTY(QStandardItemModel* credModel READ credModel CONSTANT) 17 | 18 | public: 19 | enum Roles { 20 | KeyRole = Qt::DisplayRole, 21 | IconRole = Qt::DecorationRole, 22 | SelectedRole = Qt::CheckStateRole, 23 | IconNameRole = Qt::UserRole + 1, 24 | IconPathRole 25 | }; 26 | Q_ENUM(Roles) 27 | 28 | static const QString paramCred; 29 | static QVariantHash params(const QList &creds); 30 | 31 | Q_INVOKABLE explicit CredentialsSelectionViewModel(QObject *parent = nullptr); 32 | 33 | QStandardItemModel* credModel() const; 34 | 35 | Q_INVOKABLE bool commitCredentials(); 36 | 37 | public slots: 38 | void onInit(const QVariantHash ¶ms) override; 39 | 40 | void selectAll(); 41 | void deselectAll(); 42 | 43 | private: 44 | Settings *_settings = nullptr; 45 | QList _credentials; 46 | 47 | QStandardItemModel * const _credModel; 48 | QHash _modelMap; 49 | }; 50 | 51 | #endif // CREDENTIALSSELECTIONVIEWMODEL_H 52 | -------------------------------------------------------------------------------- /clients/core/gui_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | Current Server: %1 10 | 11 | wss 12 | ws 13 | 14 | 15 | 16 | 17 | 22 | Exit app after successful transfers 23 | 24 | 29 | Send data to partner if valid data was pasted 30 | 31 | 35 | Currently has %L1 elements selected 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /clients/core/kpt.svg: -------------------------------------------------------------------------------- 1 | ../../icon/kpt.svg -------------------------------------------------------------------------------- /clients/core/kptclientapp.h: -------------------------------------------------------------------------------- 1 | #ifndef KPTCLIENTAPP_H 2 | #define KPTCLIENTAPP_H 3 | 4 | #include 5 | #include 6 | 7 | class KPTClientApp : public QtMvvm::CoreApp 8 | { 9 | Q_OBJECT 10 | 11 | public: 12 | explicit KPTClientApp(QObject *parent = nullptr); 13 | 14 | void overwriteInitCredentials(const QList &credentials); 15 | 16 | protected: 17 | void performRegistrations() override; 18 | int startApp(const QStringList &arguments) override; 19 | 20 | private: 21 | QList _initCredentials; 22 | 23 | bool readCliCredentials(const QCommandLineParser &parser); 24 | bool readJsonCredentials(QIODevice *device); 25 | bool readCsvCredentials(QIODevice *device); 26 | bool readPlainCredentials(QIODevice *device); 27 | }; 28 | 29 | #undef coreApp 30 | #define coreApp static_cast(QtMvvm::CoreApp::instance()) 31 | 32 | #endif // KPTCLIENTAPP_H 33 | -------------------------------------------------------------------------------- /clients/core/kptrootviewmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "kptrootviewmodel.h" 2 | #include 3 | #include 4 | #include "kptsettingsviewmodel.h" 5 | 6 | KptRootViewModel::KptRootViewModel(QObject *parent) : 7 | ViewModel{parent} 8 | {} 9 | 10 | void KptRootViewModel::showSettings() 11 | { 12 | show(); 13 | } 14 | 15 | void KptRootViewModel::about() 16 | { 17 | QtMvvm::about(tr("A tool to securely transfer passwords and other credentials from any " 18 | "device to a remote computer for easy access anywhere."), 19 | QStringLiteral("https://github.com/Skycoder42/KeepassTransfer"), 20 | tr("GPL-3.0"), 21 | QStringLiteral("https://github.com/Skycoder42/KeepassTransfer/blob/master/LICENSE"), 22 | {}, true, {}, 23 | tr("Attributions:")); 35 | } 36 | -------------------------------------------------------------------------------- /clients/core/kptrootviewmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef KPTROOTVIEWMODEL_H 2 | #define KPTROOTVIEWMODEL_H 3 | 4 | #include 5 | 6 | class KptRootViewModel : public QtMvvm::ViewModel 7 | { 8 | Q_OBJECT 9 | QTMVVM_SINGLETON 10 | 11 | public: 12 | Q_INVOKABLE explicit KptRootViewModel(QObject *parent = nullptr); 13 | 14 | public slots: 15 | void showSettings(); 16 | void about(); 17 | }; 18 | 19 | #endif // KPTROOTVIEWMODEL_H 20 | -------------------------------------------------------------------------------- /clients/core/kptsettingsviewmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "kptsettingsviewmodel.h" 2 | #include "settings.h" 3 | #include "transferpreselectionentry.h" 4 | 5 | KptSettingsViewModel::KptSettingsViewModel(QObject *parent) : 6 | SettingsViewModel{parent} 7 | {} 8 | 9 | QVariant KptSettingsViewModel::loadValue(const QString &key, const QVariant &defaultValue) const 10 | { 11 | if(key == QStringLiteral("transfer/preselected")) { 12 | Settings settings{accessor(), nullptr}; 13 | QVariantList presel; 14 | presel.reserve(settings.preselected.size()); 15 | for(const auto &entry : settings.preselected) 16 | presel.append(QVariant::fromValue(TransferPreSelectionEntry{entry.key, entry.selected})); 17 | return presel; 18 | } else 19 | return SettingsViewModel::loadValue(key, defaultValue); 20 | } 21 | 22 | void KptSettingsViewModel::saveValue(const QString &key, const QVariant &value) 23 | { 24 | if(key == QStringLiteral("transfer/preselected")) { 25 | Settings settings{accessor(), nullptr}; 26 | settings.preselected.reset(); 27 | for(const auto &entryVar : value.toList()) { 28 | const auto entry = entryVar.value(); 29 | auto elem = settings.preselected.push_deferred(); 30 | elem->key = entry.key; 31 | elem->selected = entry.selected; 32 | } 33 | } else 34 | return SettingsViewModel::saveValue(key, value); 35 | } 36 | 37 | void KptSettingsViewModel::resetValue(const QString &key) 38 | { 39 | if(key == QStringLiteral("transfer/preselected")) { 40 | Settings settings{accessor(), nullptr}; 41 | settings.preselected.reset(); 42 | settings.preselectedSetupDummy.get(); 43 | } else 44 | return SettingsViewModel::resetValue(key); 45 | } 46 | -------------------------------------------------------------------------------- /clients/core/kptsettingsviewmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef KPTSETTINGSVIEWMODEL_H 2 | #define KPTSETTINGSVIEWMODEL_H 3 | 4 | #include 5 | 6 | class KptSettingsViewModel : public QtMvvm::SettingsViewModel 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | Q_INVOKABLE explicit KptSettingsViewModel(QObject *parent = nullptr); 12 | 13 | QVariant loadValue(const QString &key, const QVariant &defaultValue) const override; 14 | void saveValue(const QString &key, const QVariant &value) override; 15 | void resetValue(const QString &key) override; 16 | }; 17 | 18 | #endif // KPTSETTINGSVIEWMODEL_H 19 | -------------------------------------------------------------------------------- /clients/core/kpxcclientimporter.h: -------------------------------------------------------------------------------- 1 | #ifndef KPXCCLIENTIMPORTER_H 2 | #define KPXCCLIENTIMPORTER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | class KPXCClientImporter : public QObject 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit KPXCClientImporter(QObject *parent = nullptr); 18 | 19 | public slots: 20 | void setKpxcPath(QString path); 21 | void importCredentials(); 22 | 23 | signals: 24 | void credentialsImported(const QList &credentials); 25 | 26 | private slots: 27 | void databaseOpen(); 28 | void loginsReceived(const QList &entries); 29 | void disconnected(); 30 | void onError(KPXCClient::Client::Error error, 31 | const QString &message, 32 | const QString &action, 33 | bool unrecoverable); 34 | 35 | void onCancel(); 36 | 37 | private: 38 | QString _kpxcPath; 39 | KPXCClient::Client *_client; 40 | QUrl _fetchUrl; 41 | 42 | QPointer _currentProgress; 43 | 44 | void convertEntry(const KPXCClient::Entry &entry); 45 | }; 46 | 47 | #endif // KPXCCLIENTIMPORTER_H 48 | -------------------------------------------------------------------------------- /clients/core/passclientencryptor.cpp: -------------------------------------------------------------------------------- 1 | #include "passclientencryptor.h" 2 | using namespace CryptoPP; 3 | 4 | PassClientEncryptor::PassClientEncryptor(DataEncryptor *encryptor, QObject *parent) : 5 | QObject{parent}, 6 | _encryptor{encryptor} 7 | {} 8 | 9 | EncryptedData::DataMode PassClientEncryptor::mode() const 10 | { 11 | return EncryptedData::DataMode::Password; 12 | } 13 | 14 | QUuid PassClientEncryptor::channelId() const 15 | { 16 | return _channelId; 17 | } 18 | 19 | std::pair PassClientEncryptor::obtainKeys(RandomNumberGenerator &rng) 20 | { 21 | QByteArray salt{AES::MAX_KEYLENGTH, Qt::Uninitialized}; 22 | rng.GenerateBlock(reinterpret_cast(salt.data()), 23 | static_cast(salt.size())); 24 | const auto key = _encryptor->generateSecretKey(_passphrase, salt); 25 | return std::make_pair(key, salt); 26 | } 27 | 28 | QString PassClientEncryptor::passphrase() const 29 | { 30 | return _passphrase; 31 | } 32 | 33 | void PassClientEncryptor::setChannelId(QUuid channelId) 34 | { 35 | if (_channelId == channelId) 36 | return; 37 | 38 | _channelId = std::move(channelId); 39 | emit channelIdChanged(_channelId); 40 | } 41 | 42 | void PassClientEncryptor::setPassphrase(QString passphrase) 43 | { 44 | if (_passphrase == passphrase) 45 | return; 46 | 47 | _passphrase = std::move(passphrase); 48 | emit passphraseChanged(_passphrase); 49 | } 50 | -------------------------------------------------------------------------------- /clients/core/passclientencryptor.h: -------------------------------------------------------------------------------- 1 | #ifndef PASSCLIENTENCRYPTOR_H 2 | #define PASSCLIENTENCRYPTOR_H 3 | 4 | #include 5 | #include "clienttransferservice.h" 6 | 7 | class PassClientEncryptor : public QObject, public IClientEncryptor 8 | { 9 | Q_OBJECT 10 | Q_INTERFACES(IClientEncryptor) 11 | 12 | Q_PROPERTY(QUuid channelId READ channelId WRITE setChannelId NOTIFY channelIdChanged) 13 | Q_PROPERTY(QString passphrase READ passphrase WRITE setPassphrase NOTIFY passphraseChanged) 14 | 15 | public: 16 | explicit PassClientEncryptor(DataEncryptor *encryptor, QObject *parent = nullptr); 17 | 18 | EncryptedData::DataMode mode() const override; 19 | QUuid channelId() const override; 20 | std::pair obtainKeys(CryptoPP::RandomNumberGenerator &rng) override; 21 | 22 | QString passphrase() const; 23 | 24 | public slots: 25 | void setChannelId(QUuid channelId); 26 | void setPassphrase(QString passphrase); 27 | 28 | signals: 29 | void channelIdChanged(QUuid channelId); 30 | void passphraseChanged(const QString &passphrase); 31 | 32 | private: 33 | DataEncryptor *_encryptor; 34 | QUuid _channelId; 35 | QString _passphrase; 36 | }; 37 | 38 | #endif // PASSCLIENTENCRYPTOR_H 39 | -------------------------------------------------------------------------------- /clients/core/passconnectorviewmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "passconnectorviewmodel.h" 2 | #include "transferselectionviewmodel.h" 3 | 4 | PassConnectorViewModel::PassConnectorViewModel(QObject *parent) : 5 | ViewModel{parent}, 6 | _channelIdValidator{new QRegularExpressionValidator{this}} 7 | { 8 | _channelIdValidator->setRegularExpression(QRegularExpression{ 9 | QStringLiteral(R"__(^(?:[a-zA-Z0-9+\/]{4}-){5}[a-zA-Z0-9+\/]{4}$)__"), 10 | QRegularExpression::OptimizeOnFirstUsageOption | 11 | QRegularExpression::DontCaptureOption 12 | }); 13 | } 14 | 15 | QRegularExpressionValidator *PassConnectorViewModel::channelIdValidator() const 16 | { 17 | return _channelIdValidator; 18 | } 19 | 20 | QUuid PassConnectorViewModel::channelId() const 21 | { 22 | return _passCryptor ? _passCryptor->channelId() : QUuid{}; 23 | } 24 | 25 | QString PassConnectorViewModel::channelIdStr() const 26 | { 27 | return KPTLib::uiEncodeId(channelId()); 28 | } 29 | 30 | QString PassConnectorViewModel::passphrase() const 31 | { 32 | return _passCryptor ? _passCryptor->passphrase() : QString{}; 33 | } 34 | 35 | bool PassConnectorViewModel::isValid() const 36 | { 37 | return _passCryptor && !_passCryptor->channelId().isNull(); 38 | } 39 | 40 | bool PassConnectorViewModel::transfer() 41 | { 42 | if(!isValid()) 43 | return false; 44 | 45 | _transferService->sendCredentials(_passCryptor, _credentials); 46 | return true; 47 | } 48 | 49 | void PassConnectorViewModel::generateRandomPassphrase() 50 | { 51 | QByteArray rngData{12, Qt::Uninitialized}; 52 | _rng.GenerateBlock(reinterpret_cast(rngData.data()), 53 | static_cast(rngData.size())); 54 | setPassphrase(QString::fromUtf8(rngData.toBase64(QByteArray::OmitTrailingEquals))); 55 | } 56 | 57 | void PassConnectorViewModel::onInit(const QVariantHash ¶ms) 58 | { 59 | Q_ASSERT(_transferService); 60 | Q_ASSERT(_encryptor); 61 | Q_ASSERT(_settings); 62 | connect(_transferService, &ClientTransferService::transferCompleted, 63 | this, &PassConnectorViewModel::transferDone); 64 | 65 | _passCryptor = new PassClientEncryptor{_encryptor, this}; 66 | connect(_passCryptor, &PassClientEncryptor::channelIdChanged, 67 | this, &PassConnectorViewModel::channelIdChanged); 68 | connect(_passCryptor, &PassClientEncryptor::passphraseChanged, 69 | this, &PassConnectorViewModel::passphraseChanged); 70 | 71 | _credentials = params.value(TransferSelectionViewModel::paramCred).value>(); 72 | } 73 | 74 | void PassConnectorViewModel::setChannelId(QUuid channelId) 75 | { 76 | if(_passCryptor) 77 | _passCryptor->setChannelId(channelId); 78 | } 79 | 80 | void PassConnectorViewModel::setChannelIdStr(QString channelIdStr) 81 | { 82 | setChannelId(KPTLib::uiDecodeId(std::move(channelIdStr))); 83 | } 84 | 85 | void PassConnectorViewModel::setPassphrase(QString passphrase) 86 | { 87 | if(_passCryptor) 88 | _passCryptor->setPassphrase(std::move(passphrase)); 89 | } 90 | 91 | void PassConnectorViewModel::transferDone() 92 | { 93 | if(_settings->transfer.exit) 94 | QCoreApplication::quit(); 95 | } 96 | -------------------------------------------------------------------------------- /clients/core/passconnectorviewmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef PASSCONNECTORVIEWMODEL_H 2 | #define PASSCONNECTORVIEWMODEL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "passclientencryptor.h" 9 | 10 | class PassConnectorViewModel : public QtMvvm::ViewModel 11 | { 12 | Q_OBJECT 13 | QTMVVM_CONTAINER_VM(KptRootViewModel) 14 | 15 | QTMVVM_INJECT_PROP(DataEncryptor*, encryptor, _encryptor) 16 | QTMVVM_INJECT_PROP(Settings*, settings, _settings) 17 | QTMVVM_INJECT_PROP(ClientTransferService*, transferService, _transferService) 18 | 19 | Q_PROPERTY(QRegularExpressionValidator* channelIdValidator READ channelIdValidator CONSTANT) 20 | 21 | Q_PROPERTY(QString channelIdStr READ channelIdStr WRITE setChannelIdStr NOTIFY channelIdChanged) 22 | Q_PROPERTY(QUuid channelId READ channelId WRITE setChannelId NOTIFY channelIdChanged) 23 | Q_PROPERTY(QString passphrase READ passphrase WRITE setPassphrase NOTIFY passphraseChanged) 24 | Q_PROPERTY(bool valid READ isValid NOTIFY channelIdChanged) 25 | 26 | public: 27 | Q_INVOKABLE explicit PassConnectorViewModel(QObject *parent = nullptr); 28 | 29 | QRegularExpressionValidator* channelIdValidator() const; 30 | QUuid channelId() const; 31 | QString channelIdStr() const; 32 | QString passphrase() const; 33 | bool isValid() const; 34 | 35 | public slots: 36 | bool transfer(); 37 | void generateRandomPassphrase(); 38 | 39 | void onInit(const QVariantHash ¶ms) override; 40 | 41 | void setChannelId(QUuid channelId); 42 | void setChannelIdStr(QString channelIdStr); 43 | void setPassphrase(QString passphrase); 44 | 45 | signals: 46 | void channelIdChanged(); 47 | void passphraseChanged(const QString &passphrase); 48 | 49 | private slots: 50 | void transferDone(); 51 | 52 | private: 53 | CryptoPP::AutoSeededRandomPool _rng; 54 | 55 | DataEncryptor *_encryptor = nullptr; 56 | Settings *_settings = nullptr; 57 | ClientTransferService *_transferService = nullptr; 58 | PassClientEncryptor *_passCryptor = nullptr; 59 | QRegularExpressionValidator* _channelIdValidator; 60 | 61 | QList _credentials; 62 | }; 63 | 64 | #endif // PASSCONNECTORVIEWMODEL_H 65 | -------------------------------------------------------------------------------- /clients/core/qpmx.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | { 4 | "package": "de.skycoder42.qobjectlistmodel", 5 | "provider": "qpm", 6 | "version": "2.1.0" 7 | } 8 | ], 9 | "license": { 10 | "file": "", 11 | "name": "" 12 | }, 13 | "prcFile": "", 14 | "priFile": "", 15 | "priIncludes": [ 16 | ], 17 | "publishers": { 18 | }, 19 | "qbsFile": "", 20 | "source": false 21 | } 22 | -------------------------------------------------------------------------------- /clients/core/qrclientencryptor.cpp: -------------------------------------------------------------------------------- 1 | #include "qrclientencryptor.h" 2 | using namespace CryptoPP; 3 | 4 | QrClientEncryptor::QrClientEncryptor(DataEncryptor *encryptor, QObject *parent) : 5 | QObject{parent}, 6 | _encryptor{encryptor} 7 | { 8 | Q_ASSERT(_encryptor); 9 | } 10 | 11 | EncryptedData::DataMode QrClientEncryptor::mode() const 12 | { 13 | return EncryptedData::DataMode::QrCode; 14 | } 15 | 16 | QUuid QrClientEncryptor::channelId() const 17 | { 18 | return _qrData.channelId; 19 | } 20 | 21 | std::pair QrClientEncryptor::obtainKeys(RandomNumberGenerator &rng) 22 | { 23 | SecByteBlock secKey{AES::MAX_KEYLENGTH}; 24 | rng.GenerateBlock(secKey, secKey.size()); 25 | const auto pubKey = _encryptor->deserializePublicKey(rng, _qrData.pubKey); 26 | auto keyData = _encryptor->encryptSecretKey(rng, secKey, pubKey); 27 | return std::make_pair(std::move(secKey), std::move(keyData)); 28 | } 29 | 30 | QrData QrClientEncryptor::qrData() const 31 | { 32 | return _qrData; 33 | } 34 | 35 | void QrClientEncryptor::setQrData(QrData qrData) 36 | { 37 | _qrData = std::move(qrData); 38 | } 39 | -------------------------------------------------------------------------------- /clients/core/qrclientencryptor.h: -------------------------------------------------------------------------------- 1 | #ifndef QRCLIENTENCRYPTOR_H 2 | #define QRCLIENTENCRYPTOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "clienttransferservice.h" 8 | 9 | class QrClientEncryptor : public QObject, public IClientEncryptor 10 | { 11 | Q_OBJECT 12 | Q_INTERFACES(IClientEncryptor) 13 | 14 | Q_PROPERTY(QrData qrData READ qrData WRITE setQrData) 15 | 16 | public: 17 | explicit QrClientEncryptor(DataEncryptor *encryptor, QObject *parent = nullptr); 18 | 19 | EncryptedData::DataMode mode() const override; 20 | QUuid channelId() const override; 21 | std::pair obtainKeys(CryptoPP::RandomNumberGenerator &rng) override; 22 | 23 | QrData qrData() const; 24 | 25 | public slots: 26 | void setQrData(QrData qrData); 27 | 28 | private: 29 | const DataEncryptor *_encryptor; 30 | QrData _qrData; 31 | }; 32 | 33 | #endif // QRCLIENTENCRYPTOR_H 34 | -------------------------------------------------------------------------------- /clients/core/qrcodeconnectorviewmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "qrcodeconnectorviewmodel.h" 2 | #include "transferselectionviewmodel.h" 3 | 4 | QrCodeConnectorViewModel::QrCodeConnectorViewModel(QObject *parent) : 5 | ViewModel{parent} 6 | {} 7 | 8 | QString QrCodeConnectorViewModel::qrData() const 9 | { 10 | return _qrRawData; 11 | } 12 | 13 | bool QrCodeConnectorViewModel::isValid() const 14 | { 15 | return _qrCryptor->qrData().isValid(); 16 | } 17 | 18 | bool QrCodeConnectorViewModel::doPasteTransfer() const 19 | { 20 | return isValid() && _settings->transfer.commit; 21 | } 22 | 23 | ClientTransferService *QrCodeConnectorViewModel::transferService() const 24 | { 25 | return _transferService; 26 | } 27 | 28 | bool QrCodeConnectorViewModel::transfer() 29 | { 30 | if(!isValid()) 31 | return false; 32 | 33 | _transferService->sendCredentials(_qrCryptor, _credentials); 34 | return true; 35 | } 36 | 37 | void QrCodeConnectorViewModel::onInit(const QVariantHash ¶ms) 38 | { 39 | Q_ASSERT(_transferService); 40 | Q_ASSERT(_encryptor); 41 | Q_ASSERT(_settings); 42 | connect(_transferService, &ClientTransferService::transferCompleted, 43 | this, &QrCodeConnectorViewModel::transferDone); 44 | 45 | _qrCryptor = new QrClientEncryptor{_encryptor, this}; 46 | 47 | _credentials = params.value(TransferSelectionViewModel::paramCred).value>(); 48 | } 49 | 50 | void QrCodeConnectorViewModel::setQrData(QString qrData) 51 | { 52 | if (_qrRawData == qrData) 53 | return; 54 | 55 | _qrRawData = std::move(qrData); 56 | _qrCryptor->setQrData(KPTLib::decode(_qrRawData.trimmed().toUtf8(), true)); 57 | emit qrDataChanged({}); 58 | } 59 | 60 | void QrCodeConnectorViewModel::transferDone() 61 | { 62 | if(_settings->transfer.exit) 63 | QCoreApplication::quit(); 64 | } 65 | -------------------------------------------------------------------------------- /clients/core/qrcodeconnectorviewmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef QRCODECONNECTORVIEWMODEL_H 2 | #define QRCODECONNECTORVIEWMODEL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "clienttransferservice.h" 9 | #include "qrclientencryptor.h" 10 | #include "settings.h" 11 | 12 | class QrCodeConnectorViewModel : public QtMvvm::ViewModel 13 | { 14 | Q_OBJECT 15 | QTMVVM_CONTAINER_VM(KptRootViewModel) 16 | 17 | QTMVVM_INJECT_PROP(DataEncryptor*, encryptor, _encryptor) 18 | QTMVVM_INJECT_PROP(Settings*, settings, _settings) 19 | QTMVVM_INJECT_PROP(ClientTransferService*, transferService, _transferService) 20 | 21 | Q_PROPERTY(QString qrData READ qrData WRITE setQrData NOTIFY qrDataChanged) 22 | Q_PROPERTY(bool valid READ isValid NOTIFY qrDataChanged) 23 | Q_PROPERTY(bool pasteTransfer READ doPasteTransfer NOTIFY qrDataChanged) 24 | 25 | public: 26 | Q_INVOKABLE explicit QrCodeConnectorViewModel(QObject *parent = nullptr); 27 | 28 | QString qrData() const; 29 | bool isValid() const; 30 | bool doPasteTransfer() const; 31 | 32 | ClientTransferService* transferService() const; 33 | 34 | public slots: 35 | bool transfer(); 36 | 37 | void onInit(const QVariantHash ¶ms) override; 38 | 39 | void setQrData(QString qrData); 40 | 41 | signals: 42 | void qrDataChanged(QPrivateSignal); 43 | 44 | private slots: 45 | void transferDone(); 46 | 47 | private: 48 | DataEncryptor *_encryptor = nullptr; 49 | Settings *_settings = nullptr; 50 | ClientTransferService *_transferService = nullptr; 51 | QrClientEncryptor *_qrCryptor = nullptr; 52 | 53 | QList _credentials; 54 | QString _qrRawData; 55 | }; 56 | 57 | #endif // QRCODECONNECTORVIEWMODEL_H 58 | -------------------------------------------------------------------------------- /clients/core/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | QUrl 4 | 5 | 6 | 7 | gui_settings.xml 8 | 9 | 10 | 12 | 15 | 16 | 17 | 18 | [&](){ 19 | if(!preselected.isSet()) { 20 | QStringList standardFields { 21 | QStringLiteral("Title"), 22 | QStringLiteral("UserName"), 23 | QStringLiteral("Password"), 24 | QStringLiteral("URL"), 25 | QStringLiteral("Notes") 26 | }; 27 | for(const auto &field : standardFields) { 28 | auto entry = preselected.push_deferred(); 29 | entry->key = field; 30 | entry->selected = true; 31 | } 32 | } 33 | return false; 34 | }() 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /clients/core/transferpreselectionentry.cpp: -------------------------------------------------------------------------------- 1 | #include "transferpreselectionentry.h" 2 | -------------------------------------------------------------------------------- /clients/core/transferpreselectionentry.h: -------------------------------------------------------------------------------- 1 | #ifndef TRANSFERPRESELECTIONENTRY_H 2 | #define TRANSFERPRESELECTIONENTRY_H 3 | 4 | #include 5 | #include 6 | 7 | struct TransferPreSelectionEntry 8 | { 9 | Q_GADGET 10 | 11 | Q_PROPERTY(QString key MEMBER key) 12 | Q_PROPERTY(bool selected MEMBER selected) 13 | 14 | public: 15 | QString key; 16 | bool selected = false; 17 | }; 18 | 19 | Q_DECLARE_METATYPE(TransferPreSelectionEntry) 20 | Q_DECLARE_TYPEINFO(TransferPreSelectionEntry, Q_MOVABLE_TYPE); 21 | 22 | #endif // TRANSFERPRESELECTIONENTRY_H 23 | -------------------------------------------------------------------------------- /clients/core/transferselectionviewmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "transferselectionviewmodel.h" 2 | #include "qrcodeconnectorviewmodel.h" 3 | #include "passconnectorviewmodel.h" 4 | #include 5 | 6 | const QString TransferSelectionViewModel::paramCred = QStringLiteral("credentials"); 7 | 8 | QVariantHash TransferSelectionViewModel::params(const QList &creds) 9 | { 10 | return { 11 | {paramCred, QVariant::fromValue(creds)} 12 | }; 13 | } 14 | 15 | TransferSelectionViewModel::TransferSelectionViewModel(QObject *parent) : 16 | ViewModel{parent}, 17 | _modeModel{new QStandardItemModel{0, 1, this}} 18 | { 19 | auto qrItem = new QStandardItem{tr("QR-Code")}; 20 | qrItem->setToolTip(tr("Take a foto (or enter the contents) of a QR-Code with key data.")); 21 | _modeModel->appendRow(qrItem); 22 | 23 | auto passItem = new QStandardItem{tr("Passphrase")}; 24 | passItem->setToolTip(tr("Choose a password and enter it here and on the target.")); 25 | _modeModel->appendRow(passItem); 26 | } 27 | 28 | QStandardItemModel *TransferSelectionViewModel::modeModel() const 29 | { 30 | return _modeModel; 31 | } 32 | 33 | bool TransferSelectionViewModel::startTransfer(int index) 34 | { 35 | switch (index) { 36 | case 0: //qrItem 37 | show(params(_credentials)); 38 | return true; 39 | case 1: //passItem 40 | show(params(_credentials)); 41 | return true; 42 | default: 43 | qWarning() << "Unknown index" << index; 44 | return false; 45 | } 46 | } 47 | 48 | bool TransferSelectionViewModel::startTransfer(const QModelIndex &index) 49 | { 50 | if(_modeModel->checkIndex(index, QStandardItemModel::CheckIndexOption::IndexIsValid)) 51 | return startTransfer(index.row()); 52 | else 53 | return false; 54 | } 55 | 56 | void TransferSelectionViewModel::onInit(const QVariantHash ¶ms) 57 | { 58 | _credentials = params.value(paramCred).value>(); 59 | } 60 | -------------------------------------------------------------------------------- /clients/core/transferselectionviewmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef TRANSFERSELECTIONVIEWMODEL_H 2 | #define TRANSFERSELECTIONVIEWMODEL_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | class TransferSelectionViewModel : public QtMvvm::ViewModel 10 | { 11 | Q_OBJECT 12 | QTMVVM_CONTAINER_VM(KptRootViewModel) 13 | 14 | Q_PROPERTY(QStandardItemModel* modeModel READ modeModel CONSTANT) 15 | 16 | public: 17 | static const QString paramCred; 18 | static QVariantHash params(const QList &creds); 19 | 20 | Q_INVOKABLE explicit TransferSelectionViewModel(QObject *parent = nullptr); 21 | 22 | QStandardItemModel* modeModel() const; 23 | 24 | Q_INVOKABLE bool startTransfer(int index); 25 | bool startTransfer(const QModelIndex &index); 26 | 27 | public slots: 28 | void onInit(const QVariantHash ¶ms) override; 29 | 30 | private: 31 | QStandardItemModel * const _modeModel; 32 | QList _credentials; 33 | }; 34 | 35 | #endif // TRANSFERSELECTIONVIEWMODEL_H 36 | -------------------------------------------------------------------------------- /clients/quick/App.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import de.skycoder42.QtMvvm.Quick 1.1 3 | 4 | QtMvvmApp { 5 | id: rootApp 6 | rootOnlyDrawer: false 7 | } 8 | -------------------------------------------------------------------------------- /clients/quick/CredentialsEditView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import QtQuick.Controls 2.4 3 | import QtQuick.Layouts 1.3 4 | import de.skycoder42.QtMvvm.Core 1.1 5 | import de.skycoder42.QtMvvm.Quick 1.1 6 | import de.skycoder42.kpt 1.0 7 | 8 | Page { 9 | property CredentialsEditViewModel viewModel: null 10 | 11 | header: ContrastToolBar { 12 | RowLayout { 13 | anchors.fill: parent 14 | spacing: 0 15 | 16 | ActionButton { 17 | icon.name: "open-menu-symbolic" 18 | icon.source: "qrc:/icons/menu.svg" 19 | onClicked: QuickPresenter.toggleDrawer() 20 | } 21 | 22 | ToolBarLabel { 23 | text: qsTr("Enter Credentials") 24 | Layout.fillWidth: true 25 | } 26 | 27 | ActionButton { 28 | text: qsTr("Send") 29 | display: ToolButton.TextBesideIcon 30 | icon.name: "mail-send" 31 | icon.source: "qrc:/icons/send.svg" 32 | onClicked: viewModel.commitCredentials() 33 | } 34 | } 35 | } 36 | 37 | PresenterProgress {} 38 | 39 | ScrollView { 40 | id: scrollView 41 | anchors.fill: parent 42 | 43 | ListView { 44 | id: listView 45 | 46 | model: viewModel.credentialsModel 47 | 48 | delegate: ItemDelegate { 49 | width: scrollView.width 50 | 51 | contentItem: RowLayout { 52 | TextField { 53 | id: keyField 54 | placeholderText: qsTr("Key") 55 | text: key 56 | onTextEdited: key = text 57 | } 58 | 59 | TextField { 60 | id: valueField 61 | Layout.fillWidth: true 62 | placeholderText: qsTr("Value") 63 | text: value 64 | onTextEdited: value = text 65 | echoMode: confButton.checked ? TextField.Password : TextField.Normal 66 | } 67 | 68 | ToolButton { 69 | id: confButton 70 | flat: true 71 | checkable: true 72 | icon.name: checked ? "lock" : "unlock" 73 | icon.source: checked ? "qrc:/icons/locked.svg" : "qrc:/icons/unlocked.svg" 74 | checked: confidential 75 | onCheckedChanged: confidential = checked 76 | 77 | ToolTip.visible: pressed 78 | ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval 79 | ToolTip.text: checked ? qsTr("Condfidential") : qsTr("Common") 80 | } 81 | } 82 | } 83 | 84 | footer: Item { 85 | height: addButton.height + 2 * addButton.anchors.margins 86 | width: scrollView.width 87 | } 88 | } 89 | } 90 | 91 | RoundActionButton { 92 | id: addButton 93 | anchors.right: parent.right 94 | anchors.bottom: parent.bottom 95 | anchors.margins: 16 96 | 97 | icon.name: "list-add" 98 | icon.source: "qrc:/icons/add.svg" 99 | text: qsTr("Add entry") 100 | 101 | onClicked: viewModel.addEmptyEntry() 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /clients/quick/CredentialsSelectionView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import QtQuick.Controls 2.4 3 | import QtQuick.Layouts 1.3 4 | import de.skycoder42.QtMvvm.Core 1.1 5 | import de.skycoder42.QtMvvm.Quick 1.1 6 | import de.skycoder42.kpt 1.0 7 | 8 | Page { 9 | property CredentialsSelectionViewModel viewModel: null 10 | 11 | header: ContrastToolBar { 12 | RowLayout { 13 | anchors.fill: parent 14 | spacing: 0 15 | 16 | ActionButton { 17 | icon.name: "open-menu-symbolic" 18 | icon.source: "qrc:/icons/menu.svg" 19 | onClicked: QuickPresenter.toggleDrawer() 20 | } 21 | 22 | ToolBarLabel { 23 | text: qsTr("Select Credentials") 24 | Layout.fillWidth: true 25 | } 26 | 27 | ActionButton { 28 | text: qsTr("Send") 29 | display: ToolButton.TextBesideIcon 30 | icon.name: "mail-send" 31 | icon.source: "qrc:/icons/send.svg" 32 | onClicked: viewModel.commitCredentials() 33 | } 34 | 35 | MenuButton { 36 | MenuItem { 37 | text: qsTr("Select all") 38 | onClicked: viewModel.selectAll() 39 | } 40 | 41 | MenuItem { 42 | text: qsTr("Deselect all") 43 | onClicked: viewModel.deselectAll() 44 | } 45 | } 46 | } 47 | } 48 | 49 | PresenterProgress {} 50 | 51 | ScrollView { 52 | id: scrollView 53 | anchors.fill: parent 54 | 55 | ListView { 56 | id: listView 57 | 58 | model: viewModel.credModel 59 | 60 | delegate: CheckDelegate { 61 | width: scrollView.width 62 | text: key 63 | icon.name: iconName 64 | icon.source: iconPath 65 | checkable: true 66 | checkState: selected 67 | onCheckStateChanged: selected = checkState 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /clients/quick/KptRootDrawer.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import QtQuick.Controls 2.4 3 | import QtQuick.Controls.Material 2.4 4 | import QtQuick.Layouts 1.3 5 | import de.skycoder42.QtMvvm.Core 1.1 6 | import de.skycoder42.QtMvvm.Quick 1.1 7 | import de.skycoder42.kpt 1.0 8 | 9 | ColumnLayout { 10 | id: rootDrawer 11 | property KptRootViewModel viewModel: null 12 | property Drawer drawer: null 13 | 14 | anchors.fill: parent 15 | spacing: 0 16 | 17 | ColorHelper { 18 | id: helper 19 | } 20 | 21 | Rectangle { 22 | id: headerRect 23 | Layout.fillWidth: true 24 | Layout.preferredHeight: width * 0.666 25 | color: QuickPresenter.currentStyle == "Material" ? Material.primary : helper.highlight 26 | 27 | ColumnLayout { 28 | anchors.fill: parent 29 | 30 | TintIcon { 31 | Layout.alignment: Qt.AlignCenter 32 | icon.source: "qrc:/icons/main.svg" 33 | icon.color: Material.accent 34 | icon.width: parent.height * 0.666 35 | icon.height: parent.height * 0.666 36 | } 37 | 38 | ToolBarLabel { 39 | Layout.fillWidth: true 40 | Layout.bottomMargin: 8 41 | text: Qt.application.displayName 42 | } 43 | } 44 | } 45 | 46 | ItemDelegate { 47 | Layout.fillWidth: true 48 | display: Button.TextBesideIcon 49 | icon.name: "settings-configure" 50 | icon.source: "qrc:/de/skycoder42/qtmvvm/icons/settings.svg" 51 | text: qsTr("Settings") 52 | onClicked: { 53 | viewModel.showSettings(); 54 | drawer.close(); 55 | } 56 | } 57 | 58 | MenuSeparator { 59 | Layout.fillWidth: true 60 | topPadding: 0 61 | bottomPadding: 0 62 | } 63 | 64 | ItemDelegate { 65 | Layout.fillWidth: true 66 | display: Button.TextBesideIcon 67 | icon.name: "help-about" 68 | icon.source: "qrc:/icons/about.svg" 69 | text: qsTr("About this App") 70 | onClicked: viewModel.about() 71 | } 72 | 73 | MenuSeparator { 74 | Layout.fillWidth: true 75 | topPadding: 0 76 | bottomPadding: 0 77 | } 78 | 79 | Item { 80 | id: spacer 81 | Layout.fillHeight: true 82 | Layout.fillWidth: true 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /clients/quick/PassConnectorView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import QtQuick.Controls 2.4 3 | import QtQuick.Controls.Material 2.4 4 | import QtQuick.Layouts 1.3 5 | import de.skycoder42.QtMvvm.Core 1.1 6 | import de.skycoder42.QtMvvm.Quick 1.1 7 | import de.skycoder42.kpt 1.0 8 | 9 | Page { 10 | id: passView 11 | property PassConnectorViewModel viewModel: null 12 | 13 | header: ContrastToolBar { 14 | height: headerLayout.implicitHeight 15 | 16 | RowLayout { 17 | id: headerLayout 18 | anchors.fill: parent 19 | spacing: 0 20 | 21 | ActionButton { 22 | icon.name: "open-menu-symbolic" 23 | icon.source: "qrc:/icons/menu.svg" 24 | onClicked: QuickPresenter.toggleDrawer() 25 | } 26 | 27 | ToolBarLabel { 28 | text: qsTr("Passphrase Transfer") 29 | Layout.fillWidth: true 30 | Layout.preferredHeight: 56 31 | } 32 | 33 | ActionButton { 34 | text: qsTr("Send") 35 | display: ToolButton.TextBesideIcon 36 | enabled: viewModel.valid 37 | icon.name: "mail-send" 38 | icon.source: "qrc:/icons/send.svg" 39 | onClicked: viewModel.transfer() 40 | } 41 | } 42 | } 43 | 44 | PresenterProgress {} 45 | 46 | Pane { 47 | anchors.fill: parent 48 | GridLayout { 49 | anchors.fill: parent 50 | columns: 4 51 | 52 | DecorLabel { 53 | Layout.fillWidth: true 54 | text: qsTr("Channel-ID:") 55 | edit: channelIdField 56 | } 57 | 58 | Label { 59 | Layout.fillWidth: true 60 | Layout.columnSpan: 3 61 | text: viewModel.valid ? qsTr("Channel-ID is valid") : qsTr("Channel-ID is invalid") 62 | font.italic: true 63 | color: viewModel.valid ? "green" : "red" 64 | } 65 | 66 | TextField { 67 | id: channelIdField 68 | Layout.fillWidth: true 69 | Layout.columnSpan: 4 70 | validator: viewModel.channelIdValidator 71 | 72 | MvvmBinding { 73 | viewModel: passView.viewModel 74 | viewModelProperty: "channelIdStr" 75 | view: channelIdField 76 | viewProperty: "text" 77 | type: MvvmBinding.OneWayToViewModel 78 | } 79 | } 80 | 81 | DecorLabel { 82 | Layout.fillWidth: true 83 | Layout.columnSpan: 4 84 | text: qsTr("Passphrase:") 85 | edit: passphraseField 86 | } 87 | 88 | TextField { 89 | id: passphraseField 90 | Layout.fillWidth: true 91 | Layout.columnSpan: 2 92 | selectByMouse: true 93 | echoMode: visButton.checked ? TextField.Normal : TextField.Password 94 | 95 | MvvmBinding { 96 | viewModel: passView.viewModel 97 | viewModelProperty: "passphrase" 98 | view: passphraseField 99 | viewProperty: "text" 100 | viewChangeSignal: "editingFinished()" 101 | } 102 | } 103 | 104 | ActionButton { 105 | id: visButton 106 | flat: true 107 | checkable: true 108 | icon.name: checked ? "show_table_column" : "hide_table_column" 109 | icon.source: checked ? "qrc:/icons/show.svg" : "qrc:/icons/hide.svg" 110 | text: qsTr("Toggle the visibility of the password") 111 | checked: false 112 | } 113 | 114 | ActionButton { 115 | id: generateButton 116 | flat: true 117 | icon.name: "password-generate" 118 | icon.source: "qrc:/icons/key.svg" 119 | text: qsTr("Generate a new, 16 character password") 120 | 121 | onClicked: viewModel.generateRandomPassphrase() 122 | } 123 | 124 | Item { 125 | Layout.columnSpan: 4 126 | Layout.fillHeight: true 127 | Layout.fillWidth: true 128 | } 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /clients/quick/QrCodeConnectorView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import QtQuick.Controls 2.4 3 | import QtQuick.Controls.Material 2.4 4 | import QtQuick.Layouts 1.3 5 | import de.skycoder42.QtMvvm.Core 1.1 6 | import de.skycoder42.QtMvvm.Quick 1.1 7 | import de.skycoder42.kpt 1.0 8 | 9 | Page { 10 | id: qrView 11 | property QrCodeConnectorViewModel viewModel: null 12 | 13 | function closeAction() { 14 | if(scanner.scanning) { 15 | scanner.scanning = false; 16 | return true; 17 | } else 18 | return false; 19 | } 20 | 21 | QrCodeScanner { 22 | id: scanner 23 | 24 | property bool scanning: false 25 | 26 | onScanResultReady: { 27 | scanning = (scanResult == ""); 28 | codeArea.text = scanResult 29 | //if(viewModel.valid) //NOTE bug in 5.12.0 -> reenable in 5.12.1 30 | // viewModel.transfer(); 31 | } 32 | 33 | function startScan() { 34 | scanning = true; 35 | initiateScan(); 36 | } 37 | } 38 | 39 | header: ContrastToolBar { 40 | height: headerLayout.implicitHeight 41 | 42 | RowLayout { 43 | id: headerLayout 44 | anchors.fill: parent 45 | spacing: 0 46 | 47 | ActionButton { 48 | icon.name: "open-menu-symbolic" 49 | icon.source: "qrc:/icons/menu.svg" 50 | onClicked: QuickPresenter.toggleDrawer() 51 | } 52 | 53 | ToolBarLabel { 54 | text: qsTr("QR-Code Transfer") 55 | Layout.fillWidth: true 56 | Layout.preferredHeight: 56 57 | } 58 | 59 | ActionButton { 60 | id: scanButton 61 | visible: scanner.canScan 62 | text: qsTr("Take another image") 63 | icon.name: "camera-photo" 64 | icon.source: "qrc:/icons/camera.svg" 65 | onClicked: scanner.startScan() 66 | } 67 | 68 | ActionButton { 69 | text: qsTr("Send") 70 | display: ToolButton.TextBesideIcon 71 | enabled: viewModel.valid 72 | icon.name: "mail-send" 73 | icon.source: "qrc:/icons/send.svg" 74 | onClicked: viewModel.transfer() 75 | } 76 | } 77 | } 78 | 79 | Component.onCompleted: { 80 | if(scanner.canScan) 81 | scanner.startScan(); 82 | } 83 | 84 | PresenterProgress {} 85 | 86 | Pane { 87 | anchors.fill: parent 88 | GridLayout { 89 | anchors.fill: parent 90 | columns: 2 91 | 92 | ScrollView { 93 | id: textScroller 94 | Layout.fillWidth: true 95 | Layout.fillHeight: true 96 | Layout.columnSpan: 2 97 | 98 | Flickable { 99 | TextArea.flickable: TextArea { 100 | id: codeArea 101 | selectByMouse: true 102 | selectByKeyboard: true 103 | wrapMode: TextArea.WrapAnywhere 104 | textFormat: TextEdit.PlainText 105 | placeholderText: qsTr("Scan a QR-Code or paste the\npublic key data here to continue.") 106 | 107 | MvvmBinding { 108 | viewModel: qrView.viewModel 109 | viewModelProperty: "qrData" 110 | view: codeArea 111 | viewProperty: "text" 112 | type: MvvmBinding.OneWayToViewModel 113 | } 114 | } 115 | } 116 | } 117 | 118 | Label { 119 | Layout.fillWidth: true 120 | text: viewModel.valid ? qsTr("Content is valid") : qsTr("Content is invalid") 121 | font.italic: true 122 | color: viewModel.valid ? "green" : "red" 123 | } 124 | 125 | Button { 126 | id: pasteBtn 127 | text: qsTr("Paste") 128 | onClicked: { 129 | codeArea.clear(); 130 | codeArea.paste(); 131 | if(viewModel.pasteTransfer) 132 | viewModel.transfer(); 133 | } 134 | } 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /clients/quick/TransferPreSelectionEdit.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import QtQuick.Controls 2.4 3 | 4 | ScrollView { 5 | id: preSelView 6 | 7 | property var inputValue 8 | 9 | implicitHeight: dummyDelegate.height * (elementList.model ? elementList.model.length : 1) 10 | 11 | ListView { 12 | id: elementList 13 | model: preSelView.inputValue 14 | 15 | CheckDelegate { 16 | id: dummyDelegate 17 | visible: false 18 | text: "dummy" 19 | } 20 | 21 | delegate: CheckDelegate { 22 | id: delegate 23 | width: preSelView.width 24 | text: modelData.key 25 | checked: modelData.selected 26 | onCheckedChanged: inputValue[index].selected = delegate.checked 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /clients/quick/TransferSelectionView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import QtQuick.Controls 2.4 3 | import QtQuick.Layouts 1.3 4 | import de.skycoder42.QtMvvm.Core 1.1 5 | import de.skycoder42.QtMvvm.Quick 1.1 6 | import de.skycoder42.kpt 1.0 7 | 8 | Page { 9 | id: mainView 10 | property TransferSelectionViewModel viewModel: null 11 | 12 | header: ContrastToolBar { 13 | RowLayout { 14 | anchors.fill: parent 15 | spacing: 0 16 | 17 | ActionButton { 18 | icon.name: "open-menu-symbolic" 19 | icon.source: "qrc:/icons/menu.svg" 20 | onClicked: QuickPresenter.toggleDrawer() 21 | } 22 | 23 | ToolBarLabel { 24 | text: qsTr("Select a mode") 25 | Layout.fillWidth: true 26 | } 27 | } 28 | } 29 | 30 | PresenterProgress {} 31 | 32 | ScrollView { 33 | id: scrollView 34 | anchors.fill: parent 35 | 36 | ListView { 37 | id: listView 38 | 39 | model: viewModel.modeModel 40 | 41 | delegate: ItemDelegate { 42 | width: scrollView.width 43 | 44 | onClicked: viewModel.startTransfer(index) 45 | 46 | Component.onCompleted: height = Qt.binding(function(){ return grid.implicitHeight + padding; }) 47 | 48 | contentItem: GridLayout { 49 | id: grid 50 | rows: 2 51 | columns: 2 52 | columnSpacing: 16 53 | 54 | Label { 55 | id: titleLabel 56 | text: edit 57 | Layout.row: 0 58 | Layout.column: 0 59 | font.bold: true 60 | elide: Label.ElideRight 61 | Layout.fillWidth: true 62 | } 63 | 64 | Label { 65 | id: textLabel 66 | Layout.row: 1 67 | Layout.column: 0 68 | text: toolTip 69 | wrapMode: Text.WordWrap 70 | Layout.fillWidth: true 71 | } 72 | 73 | TintIcon { 74 | id: openIcon 75 | icon.source: "qrc:/de/skycoder42/qtmvvm/quick/icons/ic_chevron_right.svg" 76 | Layout.row: 0 77 | Layout.column: 2 78 | Layout.rowSpan: 2 79 | Layout.fillHeight: true 80 | Layout.preferredWidth: implicitWidth 81 | Layout.preferredHeight: implicitHeight 82 | Layout.alignment: Qt.AlignVCenter | Qt.AlignRight 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /clients/quick/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.2.0' 9 | } 10 | } 11 | 12 | repositories { 13 | google() 14 | jcenter() 15 | } 16 | 17 | apply plugin: 'com.android.application' 18 | 19 | dependencies { 20 | implementation fileTree(dir: 'libs', include: ['*.jar']) 21 | compile "com.android.support:support-compat:+" 22 | compile "com.google.zxing:android-integration:+" 23 | } 24 | 25 | android { 26 | /******************************************************* 27 | * The following variables: 28 | * - androidBuildToolsVersion, 29 | * - androidCompileSdkVersion 30 | * - qt5AndroidDir - holds the path to qt android files 31 | * needed to build any Qt application 32 | * on Android. 33 | * 34 | * are defined in gradle.properties file. This file is 35 | * updated by QtCreator and androiddeployqt tools. 36 | * Changing them manually might break the compilation! 37 | *******************************************************/ 38 | 39 | compileSdkVersion androidCompileSdkVersion.toInteger() 40 | 41 | buildToolsVersion androidBuildToolsVersion 42 | 43 | sourceSets { 44 | main { 45 | manifest.srcFile 'AndroidManifest.xml' 46 | java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java'] 47 | aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl'] 48 | res.srcDirs = [qt5AndroidDir + '/res', 'res'] 49 | resources.srcDirs = ['src'] 50 | renderscript.srcDirs = ['src'] 51 | assets.srcDirs = ['assets'] 52 | jniLibs.srcDirs = ['libs'] 53 | } 54 | } 55 | 56 | lintOptions { 57 | abortOnError false 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /clients/quick/android/res/drawable-hdpi/ic_splash.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/clients/quick/android/res/drawable-hdpi/ic_splash.9.png -------------------------------------------------------------------------------- /clients/quick/android/res/drawable-mdpi/ic_splash.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/clients/quick/android/res/drawable-mdpi/ic_splash.9.png -------------------------------------------------------------------------------- /clients/quick/android/res/drawable-xhdpi/ic_splash.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/clients/quick/android/res/drawable-xhdpi/ic_splash.9.png -------------------------------------------------------------------------------- /clients/quick/android/res/drawable-xxhdpi/ic_splash.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/clients/quick/android/res/drawable-xxhdpi/ic_splash.9.png -------------------------------------------------------------------------------- /clients/quick/android/res/drawable-xxxhdpi/ic_splash.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/clients/quick/android/res/drawable-xxxhdpi/ic_splash.9.png -------------------------------------------------------------------------------- /clients/quick/android/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /clients/quick/android/res/mipmap-hdpi/ic_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/clients/quick/android/res/mipmap-hdpi/ic_foreground.png -------------------------------------------------------------------------------- /clients/quick/android/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- 1 | ../../../../../icon/pngs/kpt_72.png -------------------------------------------------------------------------------- /clients/quick/android/res/mipmap-mdpi/ic_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/clients/quick/android/res/mipmap-mdpi/ic_foreground.png -------------------------------------------------------------------------------- /clients/quick/android/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- 1 | ../../../../../icon/pngs/kpt_48.png -------------------------------------------------------------------------------- /clients/quick/android/res/mipmap-xhdpi/ic_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/clients/quick/android/res/mipmap-xhdpi/ic_foreground.png -------------------------------------------------------------------------------- /clients/quick/android/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- 1 | ../../../../../icon/pngs/kpt_96.png -------------------------------------------------------------------------------- /clients/quick/android/res/mipmap-xxhdpi/ic_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/clients/quick/android/res/mipmap-xxhdpi/ic_foreground.png -------------------------------------------------------------------------------- /clients/quick/android/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- 1 | ../../../../../icon/pngs/kpt_144.png -------------------------------------------------------------------------------- /clients/quick/android/res/mipmap-xxxhdpi/ic_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/clients/quick/android/res/mipmap-xxxhdpi/ic_foreground.png -------------------------------------------------------------------------------- /clients/quick/android/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- 1 | ../../../../../icon/pngs/kpt_192.png -------------------------------------------------------------------------------- /clients/quick/android/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #8bc34a 4 | 5 | -------------------------------------------------------------------------------- /clients/quick/android/res/values/libs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | https://download.qt.io/ministro/android/qt5/qt-5.9 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /clients/quick/android/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | KeePass-Transfer 4 | 5 | 6 | @string/app_name 7 | A Plugin to transfer password entries to the browser in a secure manner 8 | Felix Barz 9 | Transfer Entry 10 | 11 | -------------------------------------------------------------------------------- /clients/quick/android/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | -------------------------------------------------------------------------------- /clients/quick/android/src/de/skycoder42/kpt/KptActivity.java: -------------------------------------------------------------------------------- 1 | package de.skycoder42.kpt; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.ArrayList; 6 | import java.util.Map; 7 | import java.util.HashMap; 8 | 9 | import android.content.Intent; 10 | 11 | import android.os.Bundle; 12 | 13 | import org.qtproject.qt5.android.bindings.QtActivity; 14 | 15 | import com.google.zxing.integration.android.IntentIntegrator; 16 | import com.google.zxing.integration.android.IntentResult; 17 | 18 | public class KptActivity extends QtActivity { 19 | public static final String DataEntriesExtra = "de.skycoder42.kpt.KptActivity.DataEntriesExtra"; 20 | public static final String GuardedEntriesExtra = "de.skycoder42.kpt.KptActivity.GuardedEntriesExtra"; 21 | 22 | public static class KptEntry { 23 | public String key; 24 | public String value; 25 | public boolean guarded; 26 | 27 | public KptEntry(String key, String value, boolean guarded) { 28 | this.key = key; 29 | this.value = value; 30 | this.guarded = guarded; 31 | } 32 | } 33 | 34 | private ArrayList _cachedFields; 35 | private synchronized void setTransferEntries(ArrayList entries) { 36 | _cachedFields = entries; 37 | } 38 | 39 | private native void reportScanResult(String result); 40 | 41 | public void startQrScan() { 42 | IntentIntegrator integrator = new IntentIntegrator(this); 43 | integrator.addExtra("SAVE_HISTORY", false); 44 | integrator.initiateScan(IntentIntegrator.QR_CODE_TYPES); 45 | } 46 | 47 | public synchronized List getLastTransferEntries() { 48 | return _cachedFields; 49 | } 50 | 51 | @Override 52 | public void onCreate(Bundle savedInstanceState) { 53 | Intent intent = getIntent(); 54 | if(intent != null && intent.hasExtra(DataEntriesExtra) && intent.hasExtra(GuardedEntriesExtra)) { 55 | HashMap entries = (HashMap)intent.getSerializableExtra(DataEntriesExtra); 56 | List guarded = Arrays.asList(intent.getStringArrayExtra(GuardedEntriesExtra)); 57 | ArrayList fields = new ArrayList<>(entries.size()); 58 | for (Map.Entry entry : entries.entrySet()) { 59 | fields.add(new KptEntry( 60 | entry.getKey(), 61 | entry.getValue(), 62 | guarded.contains(entry.getKey()))); 63 | } 64 | setTransferEntries(fields); 65 | } else 66 | setTransferEntries(null); 67 | super.onCreate(savedInstanceState); 68 | } 69 | 70 | @Override 71 | public void onActivityResult(int requestCode, int resultCode, Intent intent) { 72 | IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent); 73 | if (scanResult != null) 74 | reportScanResult(scanResult.getContents()); 75 | else 76 | super.onActivityResult(requestCode, resultCode, intent); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /clients/quick/android/src/de/skycoder42/kpt/TransferAccessReceiver.java: -------------------------------------------------------------------------------- 1 | package de.skycoder42.kpt; 2 | 3 | import java.util.ArrayList; 4 | 5 | import keepass2android.pluginsdk.PluginAccessBroadcastReceiver; 6 | import keepass2android.pluginsdk.Strings; 7 | 8 | public class TransferAccessReceiver extends PluginAccessBroadcastReceiver { 9 | @Override 10 | public ArrayList getScopes() { 11 | ArrayList scopes = new ArrayList(); 12 | scopes.add(Strings.SCOPE_CURRENT_ENTRY); 13 | scopes.add(Strings.SCOPE_QUERY_CREDENTIALS); 14 | return scopes; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /clients/quick/android/src/de/skycoder42/kpt/TransferActionReceiver.java: -------------------------------------------------------------------------------- 1 | package de.skycoder42.kpt; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | 6 | import android.os.Bundle; 7 | 8 | import android.util.Log; 9 | 10 | import org.json.JSONArray; 11 | import org.json.JSONException; 12 | 13 | import keepass2android.pluginsdk.PluginActionBroadcastReceiver; 14 | import keepass2android.pluginsdk.PluginAccessException; 15 | import keepass2android.pluginsdk.Strings; 16 | 17 | public class TransferActionReceiver extends PluginActionBroadcastReceiver { 18 | private Intent _currentIntent; 19 | 20 | @Override 21 | protected void openEntry(OpenEntryAction oe) { 22 | try { 23 | oe.addEntryAction(oe.getContext().getString(R.string.action_entry), 24 | R.mipmap.ic_foreground, 25 | new Bundle()); 26 | } catch (PluginAccessException e) { 27 | Log.getStackTraceString(e); 28 | } 29 | } 30 | 31 | @Override 32 | protected void actionSelected(ActionSelectedAction actionSelected) { 33 | Intent intent = new Intent(actionSelected.getContext(), KptActivity.class); 34 | 35 | intent.putExtra(KptActivity.DataEntriesExtra, actionSelected.getEntryFields()); 36 | 37 | String[] protFields = actionSelected.getProtectedFieldsList(); 38 | if (protFields == null) {//in case it was fixed -> only if not successful (see https://github.com/PhilippC/keepass2android/issues/627) 39 | try { 40 | JSONArray fieldData = new JSONArray(_currentIntent.getStringExtra(Strings.EXTRA_PROTECTED_FIELDS_LIST)); 41 | protFields = new String[fieldData.length()]; 42 | for(int i = 0; i < fieldData.length(); i++) 43 | protFields[i] = fieldData.getString(i); 44 | } catch(JSONException e) { 45 | Log.getStackTraceString(e); 46 | protFields = new String[0]; 47 | } 48 | } 49 | intent.putExtra(KptActivity.GuardedEntriesExtra, protFields); 50 | 51 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 52 | actionSelected.getContext().startActivity(intent); 53 | } 54 | 55 | @Override 56 | public void onReceive(Context context, Intent intent) { 57 | _currentIntent = intent; 58 | super.onReceive(context, intent); 59 | _currentIntent = null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /clients/quick/android/src/keepass2android: -------------------------------------------------------------------------------- 1 | ../../../../3rdparty/keepass2android/src/java/Keepass2AndroidPluginSDK2/app/src/main/java/keepass2android -------------------------------------------------------------------------------- /clients/quick/clientsquick.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | App.qml 4 | qtquickcontrols2.conf 5 | 6 | 7 | CredentialsEditView.qml 8 | TransferSelectionView.qml 9 | KptRootDrawer.qml 10 | QrCodeConnectorView.qml 11 | CredentialsSelectionView.qml 12 | PassConnectorView.qml 13 | 14 | 15 | icons/baseline-send-24px.svg 16 | icons/baseline-add-24px.svg 17 | icons/baseline-lock-24px.svg 18 | icons/baseline-lock_open-24px.svg 19 | icons/baseline-menu-24px.svg 20 | icons/outline-info-24px.svg 21 | icons/baseline-photo_camera-24px.svg 22 | icons/baseline-visibility_off-24px.svg 23 | icons/baseline-visibility-24px.svg 24 | icons/baseline-vpn_key-24px.svg 25 | 26 | 27 | TransferPreSelectionEdit.qml 28 | 29 | 30 | -------------------------------------------------------------------------------- /clients/quick/icons/baseline-add-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-add-24px.svg -------------------------------------------------------------------------------- /clients/quick/icons/baseline-lock-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-lock-24px.svg -------------------------------------------------------------------------------- /clients/quick/icons/baseline-lock_open-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-lock_open-24px.svg -------------------------------------------------------------------------------- /clients/quick/icons/baseline-menu-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-menu-24px.svg -------------------------------------------------------------------------------- /clients/quick/icons/baseline-photo_camera-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-photo_camera-24px.svg -------------------------------------------------------------------------------- /clients/quick/icons/baseline-send-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-send-24px.svg -------------------------------------------------------------------------------- /clients/quick/icons/baseline-visibility-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-visibility-24px.svg -------------------------------------------------------------------------------- /clients/quick/icons/baseline-visibility_off-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-visibility_off-24px.svg -------------------------------------------------------------------------------- /clients/quick/icons/baseline-vpn_key-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-vpn_key-24px.svg -------------------------------------------------------------------------------- /clients/quick/icons/outline-info-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/outline-info-24px.svg -------------------------------------------------------------------------------- /clients/quick/kpt_client_quick_de.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /clients/quick/kpt_client_quick_template.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /clients/quick/qpmx.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [], 3 | "license": { 4 | "file": "", 5 | "name": "" 6 | }, 7 | "prcFile": "", 8 | "priFile": "", 9 | "priIncludes": [ 10 | "../core" 11 | ], 12 | "publishers": { 13 | }, 14 | "qbsFile": "", 15 | "source": false 16 | } 17 | -------------------------------------------------------------------------------- /clients/quick/qrcodescanner.cpp: -------------------------------------------------------------------------------- 1 | #include "qrcodescanner.h" 2 | #include 3 | #include 4 | #include 5 | #ifdef Q_OS_ANDROID 6 | #include 7 | #include 8 | #endif 9 | 10 | QPointer QrCodeScanner::_instance; 11 | 12 | QrCodeScanner::QrCodeScanner(QObject *parent) : 13 | QObject{parent} 14 | { 15 | Q_ASSERT(!_instance); 16 | _instance = this; 17 | } 18 | 19 | QrCodeScanner *QrCodeScanner::instance() 20 | { 21 | return _instance; 22 | } 23 | 24 | bool QrCodeScanner::canScan() const 25 | { 26 | #ifdef Q_OS_ANDROID 27 | return true; 28 | #else 29 | return false; 30 | #endif 31 | } 32 | 33 | QString QrCodeScanner::pasteData() 34 | { 35 | const auto cp = QGuiApplication::clipboard(); 36 | return cp->text(); 37 | } 38 | 39 | void QrCodeScanner::initiateScan() 40 | { 41 | #ifdef Q_OS_ANDROID 42 | QtAndroid::runOnAndroidThread([](){ 43 | auto activity = QtAndroid::androidActivity(); 44 | activity.callMethod("startQrScan"); 45 | }); 46 | #else 47 | Q_UNIMPLEMENTED(); 48 | #endif 49 | } 50 | 51 | #ifdef Q_OS_ANDROID 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | JNIEXPORT void JNICALL Java_de_skycoder42_kpt_KptActivity_reportScanResult(JNIEnv*, jobject, jstring result) 58 | { 59 | const auto instance = QrCodeScanner::instance(); 60 | if(instance) { 61 | QMetaObject::invokeMethod(instance, "scanResultReady", Qt::QueuedConnection, 62 | Q_ARG(QString, QAndroidJniObject::fromLocalRef(result).toString())); 63 | } else 64 | qWarning() << "Received QR-Scanresult, but no QrCodeScanner instance is available to report the result to"; 65 | } 66 | 67 | #ifdef __cplusplus 68 | } 69 | #endif 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /clients/quick/qrcodescanner.h: -------------------------------------------------------------------------------- 1 | #ifndef QRCODESCANNER_H 2 | #define QRCODESCANNER_H 3 | 4 | #include 5 | #include 6 | 7 | class QrCodeScanner : public QObject 8 | { 9 | Q_OBJECT 10 | 11 | Q_PROPERTY(bool canScan READ canScan CONSTANT) 12 | 13 | public: 14 | explicit QrCodeScanner(QObject *parent = nullptr); 15 | 16 | static QrCodeScanner *instance(); 17 | 18 | bool canScan() const; 19 | 20 | Q_INVOKABLE QString pasteData(); 21 | 22 | public slots: 23 | void initiateScan(); 24 | 25 | signals: 26 | void scanResultReady(const QString &scanResult); 27 | 28 | private: 29 | static QPointer _instance; 30 | }; 31 | 32 | #endif // QRCODESCANNER_H 33 | -------------------------------------------------------------------------------- /clients/quick/qtquickcontrols2.conf: -------------------------------------------------------------------------------- 1 | [Controls] 2 | Style=Material 3 | 4 | [Material] 5 | Theme=System 6 | Primary=#8BC34A 7 | PrimaryDark=#689F38 8 | Accent=#7C4DFF 9 | -------------------------------------------------------------------------------- /clients/quick/quick.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT += quick mvvmquick websockets concurrent 4 | android: QT += androidextras 5 | CONFIG(release, debug|release): CONFIG += qtquickcompiler 6 | 7 | TARGET = $${PROJECT_TARGET}-app 8 | 9 | QMAKE_TARGET_DESCRIPTION = "$$PROJECT_NAME Mobile App" 10 | RC_ICONS += ../../icon/kpt.ico 11 | ICON += ../../icon/kpt.icns 12 | 13 | DEFINES += QTCSV_STATIC_LIB 14 | 15 | HEADERS += \ 16 | qrcodescanner.h \ 17 | transferloader.h 18 | 19 | SOURCES += main.cpp \ 20 | qrcodescanner.cpp \ 21 | transferloader.cpp 22 | 23 | RESOURCES += \ 24 | clientsquick.qrc 25 | 26 | TRANSLATIONS += \ 27 | kpt_client_quick_de.ts \ 28 | kpt_client_quick_template.ts 29 | 30 | ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android 31 | 32 | DISTFILES += $$TRANSLATIONS \ 33 | qpmx.json \ 34 | android/AndroidManifest.xml \ 35 | $$files(android/src/*, true) \ 36 | $$files(android/res/*, true) \ 37 | android/build.gradle \ 38 | android/src/de/skycoder42/kpt/TransferAccessReceiver.java \ 39 | android/src/de/skycoder42/kpt/TransferActionReceiver.java 40 | 41 | include(../../deploy/install.pri) 42 | target.path = $$INSTALL_BINS 43 | qpmx_ts_target.path = $$INSTALL_TRANSLATIONS 44 | INSTALLS += target qpmx_ts_target 45 | 46 | # Link with core project 47 | win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../core/release/ -l$${PROJECT_TARGET}-core 48 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../core/debug/ -l$${PROJECT_TARGET}-core 49 | else:unix: LIBS += -L$$OUT_PWD/../core/ -l$${PROJECT_TARGET}-core 50 | 51 | INCLUDEPATH += $$PWD/../core $$OUT_PWD/../core 52 | win32:CONFIG(release, debug|release): INCLUDEPATH += $$OUT_PWD/../core/release 53 | else:win32:CONFIG(debug, debug|release): INCLUDEPATH += $$OUT_PWD/../core/debug 54 | DEPENDPATH += $$PWD/../core 55 | 56 | win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/release/lib$${PROJECT_TARGET}-core.a 57 | else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/debug/lib$${PROJECT_TARGET}-core.a 58 | else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/release/$${PROJECT_TARGET}-core.lib 59 | else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/debug/$${PROJECT_TARGET}-core.lib 60 | else:unix: PRE_TARGETDEPS += $$OUT_PWD/../core/lib$${PROJECT_TARGET}-core.a 61 | 62 | packagesExist(libkpxcclient) { 63 | CONFIG += link_pkgconfig 64 | PKGCONFIG += libkpxcclient 65 | DEFINES += USE_KPXCCLIENT_LIB 66 | } 67 | 68 | !ReleaseBuild:!DebugBuild:!system(qpmx -d $$shell_quote($$_PRO_FILE_PWD_) --qmake-run init $$QPMX_EXTRA_OPTIONS $$shell_quote($$QMAKE_QMAKE) $$shell_quote($$OUT_PWD)): error(qpmx initialization failed. Check the compilation log for details.) 69 | else: include($$OUT_PWD/qpmx_generated.pri) 70 | 71 | include($$SRC_ROOT_DIR/lib/lib.pri) 72 | 73 | contains(ANDROID_TARGET_ARCH,x86) { 74 | ANDROID_EXTRA_LIBS = \ 75 | $$PWD/../../3rdparty/openssl/x86/libcrypto.so \ 76 | $$PWD/../../3rdparty/openssl/x86/libssl.so 77 | } else:contains(ANDROID_TARGET_ARCH,armeabi-v7a) { 78 | ANDROID_EXTRA_LIBS = \ 79 | $$PWD/../../3rdparty/openssl/armv7/libcrypto.so \ 80 | $$PWD/../../3rdparty/openssl/armv7/libssl.so 81 | } 82 | -------------------------------------------------------------------------------- /clients/quick/transferloader.cpp: -------------------------------------------------------------------------------- 1 | #include "transferloader.h" 2 | #ifdef Q_OS_ANDROID 3 | #include 4 | #include 5 | #endif 6 | 7 | QList TransferLoader::loadCredentials() 8 | { 9 | #ifdef Q_OS_ANDROID 10 | auto activity = QtAndroid::androidActivity(); 11 | auto entries = activity.callObjectMethod("getLastTransferEntries", "()Ljava/util/List;"); 12 | if(entries.isValid()) { 13 | const auto size = entries.callMethod("size"); 14 | QList credentials; 15 | credentials.reserve(size); 16 | for(jint i = 0; i < size; ++i) { 17 | auto entry = entries.callObjectMethod("get", "(I)Ljava/lang/Object;", 18 | i); 19 | Credential cred; 20 | cred.setKey(entry.getObjectField("key", "Ljava/lang/String;").toString()); 21 | cred.setValue(entry.getObjectField("value", "Ljava/lang/String;").toString()); 22 | cred.setConfidential(entry.getField("guarded")); 23 | credentials.append(cred); 24 | } 25 | return credentials; 26 | } else 27 | return {}; 28 | #else 29 | return {}; 30 | #endif 31 | } 32 | -------------------------------------------------------------------------------- /clients/quick/transferloader.h: -------------------------------------------------------------------------------- 1 | #ifndef TRANSFERLOADER_H 2 | #define TRANSFERLOADER_H 3 | 4 | #include 5 | 6 | class TransferLoader 7 | { 8 | Q_DISABLE_COPY(TransferLoader) 9 | 10 | public: 11 | TransferLoader() = delete; 12 | 13 | static QList loadCredentials(); 14 | }; 15 | 16 | #endif // TRANSFERLOADER_H 17 | -------------------------------------------------------------------------------- /clients/widgets/clientswidgets.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | icons/baseline-add-24px.svg 4 | icons/baseline-lock_open-24px.svg 5 | icons/baseline-lock-24px.svg 6 | icons/baseline-visibility_off-24px.svg 7 | icons/baseline-visibility-24px.svg 8 | icons/baseline-vpn_key-24px.svg 9 | icons/baseline-select_all-24px.svg 10 | icons/baseline-tab_unselected-24px.svg 11 | icons/baseline-assignment-24px.svg 12 | icons/keepassxc.svg 13 | 14 | 15 | -------------------------------------------------------------------------------- /clients/widgets/credentialseditpage.cpp: -------------------------------------------------------------------------------- 1 | #include "credentialseditpage.h" 2 | #include "ui_credentialseditpage.h" 3 | 4 | CredentialsEditPage::CredentialsEditPage(QtMvvm::ViewModel *viewModel, QWidget *parent) : 5 | QWizardPage{parent}, 6 | _viewModel{static_cast(viewModel)}, 7 | _ui{new Ui::CredentialsEditPage{}} 8 | { 9 | _ui->setupUi(this); 10 | 11 | _ui->addButton->setDefaultAction(_ui->action_Add_Entry); 12 | _ui->importButton->setDefaultAction(_ui->actionKPXC_Import); 13 | 14 | connect(_ui->action_Add_Entry, &QAction::triggered, 15 | _viewModel, &CredentialsEditViewModel::addEmptyEntry); 16 | connect(_ui->actionKPXC_Import, &QAction::triggered, 17 | _viewModel, &CredentialsEditViewModel::importFromKPXC); 18 | 19 | _ui->tableView->addActions({ 20 | _ui->action_Add_Entry, 21 | _ui->actionKPXC_Import 22 | }); 23 | _ui->tableView->setModel(_viewModel->credentialsModel()); 24 | _ui->tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Interactive); 25 | _ui->tableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); 26 | _ui->tableView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents); 27 | 28 | #ifndef USE_KPXCCLIENT_LIB 29 | _ui->actionKPXC_Import->setEnabled(false); 30 | _ui->actionKPXC_Import->setVisible(false); 31 | #endif 32 | } 33 | 34 | CredentialsEditPage::~CredentialsEditPage() = default; 35 | 36 | bool CredentialsEditPage::validatePage() 37 | { 38 | return _viewModel->commitCredentials(); 39 | } 40 | -------------------------------------------------------------------------------- /clients/widgets/credentialseditpage.h: -------------------------------------------------------------------------------- 1 | #ifndef CREDENTIALSEDITDIALOG_H 2 | #define CREDENTIALSEDITDIALOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Ui { 9 | class CredentialsEditPage; 10 | } 11 | 12 | class CredentialsEditPage : public QWizardPage 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | Q_INVOKABLE explicit CredentialsEditPage(QtMvvm::ViewModel *viewModel, QWidget *parent = nullptr); 18 | ~CredentialsEditPage() override; 19 | 20 | bool validatePage() override; 21 | 22 | private: 23 | CredentialsEditViewModel *_viewModel; 24 | QScopedPointer _ui; 25 | }; 26 | 27 | #endif // CREDENTIALSEDITDIALOG_H 28 | -------------------------------------------------------------------------------- /clients/widgets/credentialsselectionpage.cpp: -------------------------------------------------------------------------------- 1 | #include "credentialsselectionpage.h" 2 | #include "ui_credentialsselectionpage.h" 3 | 4 | CredentialsSelectionPage::CredentialsSelectionPage(QtMvvm::ViewModel *viewModel, QWidget *parent) : 5 | QWizardPage{parent}, 6 | _viewModel{static_cast(viewModel)}, 7 | _ui{new Ui::CredentialsSelectionPage{}} 8 | { 9 | _ui->setupUi(this); 10 | _ui->selectButton->setDefaultAction(_ui->actionSelect_all); 11 | _ui->deselectButton->setDefaultAction(_ui->actionDeselect_all); 12 | _ui->listView->addActions({ 13 | _ui->actionSelect_all, 14 | _ui->actionDeselect_all 15 | }); 16 | 17 | _ui->listView->setModel(_viewModel->credModel()); 18 | connect(_ui->actionSelect_all, &QAction::triggered, 19 | _viewModel, &CredentialsSelectionViewModel::selectAll); 20 | connect(_ui->actionDeselect_all, &QAction::triggered, 21 | _viewModel, &CredentialsSelectionViewModel::deselectAll); 22 | } 23 | 24 | bool CredentialsSelectionPage::validatePage() 25 | { 26 | return _viewModel->commitCredentials(); 27 | } 28 | 29 | CredentialsSelectionPage::~CredentialsSelectionPage() = default; 30 | -------------------------------------------------------------------------------- /clients/widgets/credentialsselectionpage.h: -------------------------------------------------------------------------------- 1 | #ifndef CREDENTIALSSELECTIONPAGE_H 2 | #define CREDENTIALSSELECTIONPAGE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Ui { 9 | class CredentialsSelectionPage; 10 | } 11 | 12 | class CredentialsSelectionPage : public QWizardPage 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | Q_INVOKABLE explicit CredentialsSelectionPage(QtMvvm::ViewModel *viewModel, QWidget *parent = nullptr); 18 | ~CredentialsSelectionPage() override; 19 | 20 | bool validatePage() override; 21 | 22 | private: 23 | CredentialsSelectionViewModel *_viewModel; 24 | QScopedPointer _ui; 25 | }; 26 | 27 | #endif // CREDENTIALSSELECTIONPAGE_H 28 | -------------------------------------------------------------------------------- /clients/widgets/credentialsselectionpage.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CredentialsSelectionPage 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Select Credentials 15 | 16 | 17 | Select the credentials you want to transfer to the partner. 18 | 19 | 20 | 21 | 0 22 | 23 | 24 | 0 25 | 26 | 27 | 0 28 | 29 | 30 | 0 31 | 32 | 33 | 34 | 35 | Qt::ActionsContextMenu 36 | 37 | 38 | QAbstractItemView::NoEditTriggers 39 | 40 | 41 | true 42 | 43 | 44 | true 45 | 46 | 47 | 48 | 49 | 50 | 51 | Qt::Horizontal 52 | 53 | 54 | 55 | 349 56 | 20 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | Qt::ToolButtonFollowStyle 65 | 66 | 67 | 68 | 69 | 70 | 71 | Qt::ToolButtonFollowStyle 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | :/icons/select.svg:/icons/select.svg 80 | 81 | 82 | Select all 83 | 84 | 85 | Ctrl+A 86 | 87 | 88 | 89 | 90 | 91 | :/icons/deselect.svg:/icons/deselect.svg 92 | 93 | 94 | Deselect all 95 | 96 | 97 | Ctrl+Shift+A 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /clients/widgets/de.skycoder42.kptransfer.desktop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env xdg-open 2 | [Desktop Entry] 3 | Type=Application 4 | Version=1.1 5 | Name=KeePass-Transfer 6 | GenericName=Secure Password transfers 7 | Comment=An extension of KeePassXC to transfer entries to the browser 8 | Categories=Utility;Security;Qt; 9 | Exec=kptransfer-client 10 | Icon=de.skycoder42.kptransfer 11 | Terminal=false 12 | -------------------------------------------------------------------------------- /clients/widgets/icons/baseline-add-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-add-24px.svg -------------------------------------------------------------------------------- /clients/widgets/icons/baseline-assignment-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-assignment-24px.svg -------------------------------------------------------------------------------- /clients/widgets/icons/baseline-lock-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-lock-24px.svg -------------------------------------------------------------------------------- /clients/widgets/icons/baseline-lock_open-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-lock_open-24px.svg -------------------------------------------------------------------------------- /clients/widgets/icons/baseline-select_all-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-select_all-24px.svg -------------------------------------------------------------------------------- /clients/widgets/icons/baseline-tab_unselected-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-tab_unselected-24px.svg -------------------------------------------------------------------------------- /clients/widgets/icons/baseline-visibility-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-visibility-24px.svg -------------------------------------------------------------------------------- /clients/widgets/icons/baseline-visibility_off-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-visibility_off-24px.svg -------------------------------------------------------------------------------- /clients/widgets/icons/baseline-vpn_key-24px.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/flat/baseline-vpn_key-24px.svg -------------------------------------------------------------------------------- /clients/widgets/icons/keepassxc.svg: -------------------------------------------------------------------------------- 1 | ../../../icon/external/keepassxc.svg -------------------------------------------------------------------------------- /clients/widgets/kptrootwizard.h: -------------------------------------------------------------------------------- 1 | #ifndef KPTROOTWIZARD_H 2 | #define KPTROOTWIZARD_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class KptRootWizard : public QWizard, public QtMvvm::IPresentingView 11 | { 12 | Q_OBJECT 13 | Q_INTERFACES(QtMvvm::IPresentingView) 14 | 15 | public: 16 | Q_INVOKABLE explicit KptRootWizard(QtMvvm::ViewModel *viewModel, QWidget *parent = nullptr); 17 | 18 | bool tryPresent(QWidget *view) override; 19 | 20 | bool validateCurrentPage() override; 21 | int nextId() const override; 22 | 23 | protected: 24 | void initializePage(int id) override; 25 | void cleanupPage(int id) override; 26 | 27 | private slots: 28 | void dropPage(int id); 29 | void customAction(int button); 30 | 31 | private: 32 | KptRootViewModel *_viewModel; 33 | 34 | int _pageCounter = 0; 35 | QStack _pageStack; 36 | 37 | mutable bool _recurseBlocker = false; 38 | 39 | int topStack() const; 40 | int nextStackId() const; 41 | }; 42 | 43 | #endif // KPTROOTWIZARD_H 44 | -------------------------------------------------------------------------------- /clients/widgets/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "kptrootwizard.h" 6 | #include "credentialseditpage.h" 7 | #include "credentialsselectionpage.h" 8 | #include "transferselectionpage.h" 9 | #include "qrcodeconnectorpage.h" 10 | #include "passconnectorpage.h" 11 | #include "transferpreselectionedit.h" 12 | 13 | // Register the core app 14 | QTMVVM_REGISTER_CORE_APP(KPTClientApp) 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | QApplication a(argc, argv); 19 | 20 | QtMvvm::WidgetsPresenter::getInputWidgetFactory()->addSimpleWidget("TransferPreSelection", [](QWidget *parent){ 21 | return new TransferPreSelectionEdit{parent}; 22 | }); 23 | 24 | QtMvvm::WidgetsPresenter::registerView(); 25 | QtMvvm::WidgetsPresenter::registerView(); 26 | QtMvvm::WidgetsPresenter::registerView(); 27 | QtMvvm::WidgetsPresenter::registerView(); 28 | QtMvvm::WidgetsPresenter::registerView(); 29 | QtMvvm::WidgetsPresenter::registerView(); 30 | 31 | return a.exec(); 32 | } 33 | -------------------------------------------------------------------------------- /clients/widgets/passconnectorpage.cpp: -------------------------------------------------------------------------------- 1 | #include "passconnectorpage.h" 2 | #include "ui_passconnectorpage.h" 3 | #include 4 | 5 | PassConnectorPage::PassConnectorPage(QtMvvm::ViewModel *viewModel, QWidget *parent) : 6 | QWizardPage{parent}, 7 | _viewModel{static_cast(viewModel)}, 8 | _ui{new Ui::PassConnectorPage{}} 9 | { 10 | _ui->setupUi(this); 11 | setFinalPage(true); 12 | 13 | _ui->channelIDLineEdit->setValidator(_viewModel->channelIdValidator()); 14 | _ui->passphraseLineEdit->addAction(_ui->actionGenerate_random_passphrase, QLineEdit::TrailingPosition); 15 | _ui->passphraseLineEdit->addAction(_ui->actionToggle_passphrase_visibility, QLineEdit::TrailingPosition); 16 | 17 | connect(_ui->actionToggle_passphrase_visibility, &QAction::triggered, 18 | this, &PassConnectorPage::toggleVisible); 19 | connect(_ui->actionGenerate_random_passphrase, &QAction::triggered, 20 | _viewModel, &PassConnectorViewModel::generateRandomPassphrase); 21 | 22 | QtMvvm::bind(_viewModel, "channelIdStr", 23 | _ui->channelIDLineEdit, "text", 24 | QtMvvm::Binding::OneWayToViewModel); 25 | QtMvvm::bind(_viewModel, "passphrase", 26 | _ui->passphraseLineEdit, "text", 27 | QtMvvm::Binding::TwoWay, 28 | nullptr, 29 | "editingFinished()"); 30 | connect(_viewModel, &PassConnectorViewModel::channelIdChanged, 31 | this, &PassConnectorPage::appIdChanged); 32 | appIdChanged(); 33 | } 34 | 35 | bool PassConnectorPage::validatePage() 36 | { 37 | return _viewModel->transfer(); 38 | } 39 | 40 | bool PassConnectorPage::isComplete() const 41 | { 42 | return _viewModel->isValid(); 43 | } 44 | 45 | void PassConnectorPage::appIdChanged() 46 | { 47 | auto pal = palette(); 48 | if(_viewModel->isValid()) { 49 | _ui->statusLabel->setText(tr("Channel-ID is valid")); 50 | pal.setColor(QPalette::WindowText, Qt::darkGreen); 51 | _ui->statusLabel->setPalette(pal); 52 | } else { 53 | _ui->statusLabel->setText(tr("Channel-ID is invalid")); 54 | pal.setColor(QPalette::WindowText, Qt::darkRed); 55 | _ui->statusLabel->setPalette(pal); 56 | } 57 | emit completeChanged(); 58 | } 59 | 60 | void PassConnectorPage::toggleVisible(bool visible) 61 | { 62 | _ui->passphraseLineEdit->setEchoMode(visible ? QLineEdit::Normal : QLineEdit::Password); 63 | } 64 | 65 | PassConnectorPage::~PassConnectorPage() = default; 66 | -------------------------------------------------------------------------------- /clients/widgets/passconnectorpage.h: -------------------------------------------------------------------------------- 1 | #ifndef PASSCONNECTORPAGE_H 2 | #define PASSCONNECTORPAGE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Ui { 9 | class PassConnectorPage; 10 | } 11 | 12 | class PassConnectorPage : public QWizardPage 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | Q_INVOKABLE explicit PassConnectorPage(QtMvvm::ViewModel *viewModel, QWidget *parent = nullptr); 18 | ~PassConnectorPage(); 19 | 20 | bool validatePage() override; 21 | bool isComplete() const override; 22 | 23 | private slots: 24 | void appIdChanged(); 25 | void toggleVisible(bool visible); 26 | 27 | private: 28 | PassConnectorViewModel *_viewModel; 29 | QScopedPointer _ui; 30 | }; 31 | 32 | #endif // PASSCONNECTORPAGE_H 33 | -------------------------------------------------------------------------------- /clients/widgets/qpmx.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [], 3 | "license": { 4 | "file": "", 5 | "name": "" 6 | }, 7 | "prcFile": "", 8 | "priFile": "", 9 | "priIncludes": [ 10 | "../core" 11 | ], 12 | "publishers": { 13 | }, 14 | "qbsFile": "", 15 | "source": false 16 | } 17 | -------------------------------------------------------------------------------- /clients/widgets/qrcodeconnectorpage.cpp: -------------------------------------------------------------------------------- 1 | #include "qrcodeconnectorpage.h" 2 | #include "ui_qrcodeconnectorpage.h" 3 | 4 | QrCodeConnectorPage::QrCodeConnectorPage(QtMvvm::ViewModel *viewModel, QWidget *parent) : 5 | QWizardPage{parent}, 6 | _viewModel{static_cast(viewModel)}, 7 | _ui{new Ui::QrCodeConnectorPage{}} 8 | { 9 | _ui->setupUi(this); 10 | setFinalPage(true); 11 | 12 | _ui->pasteButton->setDefaultAction(_ui->actionPaste); 13 | 14 | connect(_ui->actionPaste, &QAction::triggered, 15 | this, &QrCodeConnectorPage::pasteQrData); 16 | connect(_ui->plainTextEdit, &QPlainTextEdit::textChanged, 17 | _viewModel, [this](){ 18 | _viewModel->setQrData(_ui->plainTextEdit->toPlainText()); 19 | }); 20 | connect(_viewModel, &QrCodeConnectorViewModel::qrDataChanged, 21 | this, &QrCodeConnectorPage::qrDataChanged); 22 | } 23 | 24 | bool QrCodeConnectorPage::validatePage() 25 | { 26 | return _viewModel->transfer(); 27 | } 28 | 29 | bool QrCodeConnectorPage::isComplete() const 30 | { 31 | return _viewModel->isValid(); 32 | } 33 | 34 | void QrCodeConnectorPage::pasteQrData() 35 | { 36 | _ui->plainTextEdit->selectAll(); 37 | _ui->plainTextEdit->paste(); 38 | if(_viewModel->doPasteTransfer()) 39 | _viewModel->transfer(); 40 | } 41 | 42 | void QrCodeConnectorPage::qrDataChanged() 43 | { 44 | auto pal = palette(); 45 | if(_viewModel->isValid()) { 46 | _ui->statusLabel->setText(tr("Content is valid")); 47 | pal.setColor(QPalette::WindowText, Qt::darkGreen); 48 | _ui->statusLabel->setPalette(pal); 49 | } else { 50 | _ui->statusLabel->setText(tr("Content is invalid")); 51 | pal.setColor(QPalette::WindowText, Qt::darkRed); 52 | _ui->statusLabel->setPalette(pal); 53 | } 54 | emit completeChanged(); 55 | } 56 | 57 | QrCodeConnectorPage::~QrCodeConnectorPage() = default; 58 | -------------------------------------------------------------------------------- /clients/widgets/qrcodeconnectorpage.h: -------------------------------------------------------------------------------- 1 | #ifndef QRCODECONNECTORPAGE_H 2 | #define QRCODECONNECTORPAGE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Ui { 9 | class QrCodeConnectorPage; 10 | } 11 | 12 | class QrCodeConnectorPage : public QWizardPage 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | Q_INVOKABLE explicit QrCodeConnectorPage(QtMvvm::ViewModel *viewModel, QWidget *parent = nullptr); 18 | ~QrCodeConnectorPage(); 19 | 20 | bool validatePage() override; 21 | bool isComplete() const override; 22 | 23 | private slots: 24 | void pasteQrData(); 25 | void qrDataChanged(); 26 | 27 | private: 28 | QrCodeConnectorViewModel *_viewModel; 29 | QScopedPointer _ui; 30 | }; 31 | 32 | #endif // QRCODECONNECTORPAGE_H 33 | -------------------------------------------------------------------------------- /clients/widgets/qrcodeconnectorpage.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | QrCodeConnectorPage 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | QR-Code Transfer 15 | 16 | 17 | Paste the QR-Code data that you obtained from the partner here. Visit https://kpt.skycoder42.de to obtain the data. 18 | 19 | 20 | 21 | 0 22 | 23 | 24 | 0 25 | 26 | 27 | 0 28 | 29 | 30 | 0 31 | 32 | 33 | 34 | 35 | Qt::ToolButtonFollowStyle 36 | 37 | 38 | 39 | 40 | 41 | 42 | true 43 | 44 | 45 | true 46 | 47 | 48 | Paste the QR-Code data here to continue 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | :/icons/copy.svg:/icons/copy.svg 64 | 65 | 66 | Paste 67 | 68 | 69 | Paste Qr-Code-Data from the clipboard 70 | 71 | 72 | Ctrl+Shift+V 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /clients/widgets/transferpreselectionedit.cpp: -------------------------------------------------------------------------------- 1 | #include "transferpreselectionedit.h" 2 | #include 3 | #include 4 | 5 | TransferPreSelectionEdit::TransferPreSelectionEdit(QWidget *parent) : 6 | QListWidget{parent} 7 | { 8 | connect(this, &TransferPreSelectionEdit::itemChanged, 9 | this, &TransferPreSelectionEdit::updateElements); 10 | } 11 | 12 | QVariantList TransferPreSelectionEdit::elements() const 13 | { 14 | QVariantList elements; 15 | elements.reserve(_elements.size()); 16 | for(const auto &element : _elements) 17 | elements.append(QVariant::fromValue(element)); 18 | return elements; 19 | } 20 | 21 | void TransferPreSelectionEdit::setElements(const QVariantList &elements) 22 | { 23 | _elements.clear(); 24 | _elements.reserve(elements.size()); 25 | for(const auto &element : elements) 26 | _elements.append(element.value()); 27 | 28 | clear(); 29 | _blockUpdate = true; 30 | for(const auto &element : qAsConst(_elements)) { 31 | auto item = new QListWidgetItem{this}; 32 | item->setText(element.key); 33 | item->setCheckState(element.selected ? Qt::Checked : Qt::Unchecked); 34 | item->setFlags((item->flags() | Qt::ItemIsUserCheckable) & ~Qt::ItemIsEditable); 35 | } 36 | _blockUpdate = false; 37 | 38 | emit elementsChanged(); 39 | } 40 | 41 | void TransferPreSelectionEdit::updateElements(QListWidgetItem *item) 42 | { 43 | if(_blockUpdate) 44 | return; 45 | 46 | for(auto &element : _elements) { 47 | if(element.key == item->text()) { 48 | element.selected = (item->checkState() != Qt::Unchecked); 49 | emit elementsChanged(); 50 | return; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /clients/widgets/transferpreselectionedit.h: -------------------------------------------------------------------------------- 1 | #ifndef TRANSFERPRESELECTIONEDIT_H 2 | #define TRANSFERPRESELECTIONEDIT_H 3 | 4 | #include "transferpreselectionentry.h" 5 | #include 6 | 7 | class TransferPreSelectionEdit : public QListWidget 8 | { 9 | Q_OBJECT 10 | 11 | Q_PROPERTY(QVariantList elements READ elements WRITE setElements NOTIFY elementsChanged USER true) 12 | 13 | public: 14 | explicit TransferPreSelectionEdit(QWidget *parent = nullptr); 15 | 16 | QVariantList elements() const; 17 | 18 | public slots: 19 | void setElements(const QVariantList &elements); 20 | 21 | signals: 22 | void elementsChanged(); 23 | 24 | private slots: 25 | void updateElements(QListWidgetItem *item); 26 | 27 | private: 28 | QList _elements; 29 | bool _blockUpdate = false; 30 | }; 31 | 32 | #endif // TRANSFERPRESELECTIONEDIT_H 33 | -------------------------------------------------------------------------------- /clients/widgets/transferselectionpage.cpp: -------------------------------------------------------------------------------- 1 | #include "transferselectionpage.h" 2 | #include "ui_transferselectionpage.h" 3 | 4 | TransferSelectionPage::TransferSelectionPage(QtMvvm::ViewModel *viewModel, QWidget *parent) : 5 | QWizardPage{parent}, 6 | _viewModel{static_cast(viewModel)}, 7 | _ui{new Ui::TransferSelectionPage{}} 8 | { 9 | _ui->setupUi(this); 10 | _ui->listView->setModel(_viewModel->modeModel()); 11 | _ui->listView->selectionModel()->select(_viewModel->modeModel()->index(0, 0), 12 | QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current); 13 | } 14 | 15 | bool TransferSelectionPage::validatePage() 16 | { 17 | return _viewModel->startTransfer(_ui->listView->currentIndex()); 18 | } 19 | 20 | TransferSelectionPage::~TransferSelectionPage() = default; 21 | -------------------------------------------------------------------------------- /clients/widgets/transferselectionpage.h: -------------------------------------------------------------------------------- 1 | #ifndef TRANSFERSELECTIONPAGE_H 2 | #define TRANSFERSELECTIONPAGE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Ui { 9 | class TransferSelectionPage; 10 | } 11 | 12 | class TransferSelectionPage : public QWizardPage 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | Q_INVOKABLE explicit TransferSelectionPage(QtMvvm::ViewModel *viewModel, QWidget *parent = nullptr); 18 | ~TransferSelectionPage() override; 19 | 20 | bool validatePage() override; 21 | 22 | private: 23 | TransferSelectionViewModel *_viewModel; 24 | QScopedPointer _ui; 25 | }; 26 | 27 | #endif // TRANSFERSELECTIONPAGE_H 28 | -------------------------------------------------------------------------------- /clients/widgets/transferselectionpage.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | TransferSelectionPage 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Select a mode 15 | 16 | 17 | Select which backend you want to use to connect to the target and send the credentials. 18 | 19 | 20 | 21 | 0 22 | 23 | 24 | 0 25 | 26 | 27 | 0 28 | 29 | 30 | 0 31 | 32 | 33 | 34 | 35 | QAbstractItemView::NoEditTriggers 36 | 37 | 38 | true 39 | 40 | 41 | false 42 | 43 | 44 | true 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /flatpak/de.skycoder42.flatpakrepo: -------------------------------------------------------------------------------- 1 | [Flatpak Repo] 2 | Title=Skycoder42 Flatpak Repository 3 | Url=https://install.skycoder42.de/flatpak/ 4 | Homepage=https://github.com/Skycoder42 5 | Comment=Flatpak repository where I host my own applications 6 | Description=Flatpak repository where I host my own applications 7 | Icon=https://install.skycoder42.de/flatpak-repo-icon.png 8 | GPGKey=mQINBFugvTgBEAC5U2IW3HYPowVJSxxn0+VGDq+Uf3DXmSDQTKczzGPsRn3URP7ZhGzBB7pZARoawQSyFM3fstWyKwytcVsAZ543RwlW48w31dw7ssmJhvVn0dhLFr2yQYwC1/W9d2rralq5/IL6B81ckmB+vl7yJOSgqGlLHQFnCxljyG6fxTQp+aKlJRWcS1a37TRj9Kn4ULFXRut3RXC4cPZBblq3W3cZQq5G/74JLrqNS6nRkTBhxP/U9E+nk6vgNGp1sinSlevFJ+r4rVbM/7y5YcfpP6YAtrFtsCIbxFmZcOR9kO7E5b1swG1VBoB6ZA5xWmC2VTwfxHyr1WbvOvTmfZx994Qow5vHVp3aWsx3Yge/n0qGWYgx0g/xe11TB1blGd4l8cNRmmkgbhkil1TMEk7AWK6SFNKGqR6oyDerIALhuoMRzTe9H5drm1EC9YdNkPzMyoQvP2V8OXu4JBhAJU5gFZ1ziDFh935DehGaJutzx5An/veAzMTefpyNbYb7hi4ugXZsBLrR/jES0xxPFjow+KuhazI7KwErkYYWb4ICZR1f9nR2qOpX0aCt4nidlnvlOY1pByiTXe5FykyjCGXYtVrU97nR0rERfD9cfzrjaCSs2AOtSlRjwOgQNlERuEZYl7BeGqvegJRZz2qkBVSwfgStGSCCxxjfddz/mD0VFaXQ+QARAQABtEJTa3ljb2RlcjQyIChGbGF0cGFrIHJlcG9zaXRvcnkgc2lnbmluZyBrZXkpIDxza3ljb2RlcjQyLmRlQGdteC5kZT6JAk4EEwEIADgWIQTL1nR7/OQFBPJAtqpTqf2Zk29CDQUCW6C9OAIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRBTqf2Zk29CDZ/dD/9ynZxYB5PWfQJETT5TU00NrPYx0/tzI/3QVdmsB/bN2v8yx4apd5oMYem+AgBmaDDeMgQosLzdM8OW43UzjoORtkevT+gTMWQtm1cMQWf4+yt2ar0jZcXyznBO2Lg/TUB1sOguu9xqbEuP6RVOKD1I66gIJZdeFQzSxAwbXJ87AtehZDieVCr+0T9ITCamVG5WQEB1DiGC0iaTTLu4V3ia8YvEBivZmYamo3hFtUZuTima0LJdjvRGSxVEP3mwcPBLLJd0qIW4DSaa/haq+5+oKwQ1cJZa/O2zJtHE28TbtoqOR9FJu9vh/jNfEh03xjGrHpEMeKekSMZUs9PwJqNGoeZAxz81qqyNp7Cr4oeeEmOFcmq14uKsAEPmIeEVrIOzyaQiLB4WnyCgk/h85dXkyt0j0SAEEz21OJCm+ovs2y0oQ8zl/ew50ccInUCKRpbI1Jyr2dn/oofaLF87RiSgtDKMh1XTcp3ZEV9HweNoesOvZRnAzgumre6Yrl1o3M+O68erLYEKpFQa5C8W3JI/O5s6H/LVIwR9f58llTPCh+P/+VUpZg8rK9iYjt8qUuX6LL3MKsiQgbZ67gNQNdfPRjtqda/oPeiKNOoHmk3h+Hfp2ZjJOcaZM+jBPTUcblMO7ovZ266MhbjIwmQTO1NFldTv/NnFsQeRgNFwr5nbPbkCDQRboL04ARAAwxBQiY0ia8uWqv63P+5C9TQWZzlnQQxlfOzAqPVaSUvMi4B8O7WeIIekYFw5tGHlYZHRP/ngVG7lG/Qzl6zBqcKbQwmciESQ2eFT6pg1PcjVaBcG5W824QBzBDGhEGhRWDecQQ2hoKVjH+stdz0DZeW0es8FoVQA65iUgOxkr/qVJ4Fn81ppnx8499nbXxUUJwwgcYvFpTSc6/C9SwWpLUUUW9H4afvTdBO2estauyhpApHpkPeDF/acg9NT7yij2htYn1XTcvnZN1BN7R6jh2+uY27urq8dD5iv8hsjVIeGAWJJNs8aDcUMcUZhz/k94ofai0A4ZICIqyKwi78jpY+JrfheqisLf7izik6fd9ObJzoilOx37/JNEOLFqNRnzAlTwmqcloLgTYNZkcG1Qnjvj2OT71rbiYiNDsXsntsOMIvequMFbCxA5nvFsAVgL3weP/HeD1ZUCKr/CXdbnrIQ0Kjd7sv5uWtVEkas/2bJo1XgECshxcesh0xzzwuMiqoiuM8OHO29jMJYqghPJR+4gD4m1S2RInk4wb70UO3yeA8c9Tm7pUgG1Ixiz7EkDQwZD8axQtNH+V9uXPhu8BuJr9nJrv6TxPpe+ELt63Q+88Z73hf99z0IQvW0+NihYn9+P0ahwlQt0s7tVJNEHpI3jlJg1+NMQRP2UIkABX0AEQEAAYkCNgQYAQgAIBYhBMvWdHv85AUE8kC2qlOp/ZmTb0INBQJboL04AhsMAAoJEFOp/ZmTb0INwI0QAJy0l0/EsF86Y9fShaB3LJjklOpDCAa61aJg8XCLpoBeyOgJ8hHU6SnIef1nZBGtqgbIzZV02XTFLYhbOTt2XPVH4VZ6sTJ53Pfpve0p/z59b33JhsamDUvdK/u6AOomspOYazcpiDRsCh1F0Lh+9X3BmQR8tjvtIa+NLy9/y1YY5KtjOBn6fb+zALBz5/sa3Ps83UczTDSIiqSxA1kEwKqJn9oQ9fDBJ3Oyh8ZoWxNbD9KgwUl7KBywQLsvJvTrxe8QiAibMrEr9GXLAjBTSfiOcf8nHv+F6h/1IaqLJ4gx9/36uZv4DkDcDO5OlX7AAzaJUkqX9mpjqU1lqVbE3ROvC1wAo8WAZ1jzeiqepzbTRACfhqT+1BvUiS6n+5zXX2IiMvCAd1fa7XfmRqw76UA//EB/TG2ly3823o6+z4UHSYqNNVR+vVuyU3dqQadNsWAaeoxMwVRilYYjxsgL2PVGTdF57pT71bXDF4r4ttuatG6sUnfSitZpTog3zMEaJ6gsiRI6I1fuAwY6WSUiCOuaVb1aNPGWE/UGd7rBzL/mincIhMhF//+Sh1gXBeJ4jo1V+e5OYjVizJETnD6UWt4J/YGUA/RvCKkjKsM929CG9jrY9dPwVZ7zJ/bXRzurVUzKpFygAO2SCV4E0h2VIvprojsTphs5df9ZRwCobbzH 9 | -------------------------------------------------------------------------------- /flatpak/de.skycoder42.kptransfer.flatpakref: -------------------------------------------------------------------------------- 1 | [Flatpak Ref] 2 | Title=KeePass-Transfer 3 | Name=de.skycoder42.kptransfer 4 | Branch=stable 5 | Url=https://install.skycoder42.de/flatpak/ 6 | IsRuntime=False 7 | GPGKey=mQINBFugvTgBEAC5U2IW3HYPowVJSxxn0+VGDq+Uf3DXmSDQTKczzGPsRn3URP7ZhGzBB7pZARoawQSyFM3fstWyKwytcVsAZ543RwlW48w31dw7ssmJhvVn0dhLFr2yQYwC1/W9d2rralq5/IL6B81ckmB+vl7yJOSgqGlLHQFnCxljyG6fxTQp+aKlJRWcS1a37TRj9Kn4ULFXRut3RXC4cPZBblq3W3cZQq5G/74JLrqNS6nRkTBhxP/U9E+nk6vgNGp1sinSlevFJ+r4rVbM/7y5YcfpP6YAtrFtsCIbxFmZcOR9kO7E5b1swG1VBoB6ZA5xWmC2VTwfxHyr1WbvOvTmfZx994Qow5vHVp3aWsx3Yge/n0qGWYgx0g/xe11TB1blGd4l8cNRmmkgbhkil1TMEk7AWK6SFNKGqR6oyDerIALhuoMRzTe9H5drm1EC9YdNkPzMyoQvP2V8OXu4JBhAJU5gFZ1ziDFh935DehGaJutzx5An/veAzMTefpyNbYb7hi4ugXZsBLrR/jES0xxPFjow+KuhazI7KwErkYYWb4ICZR1f9nR2qOpX0aCt4nidlnvlOY1pByiTXe5FykyjCGXYtVrU97nR0rERfD9cfzrjaCSs2AOtSlRjwOgQNlERuEZYl7BeGqvegJRZz2qkBVSwfgStGSCCxxjfddz/mD0VFaXQ+QARAQABtEJTa3ljb2RlcjQyIChGbGF0cGFrIHJlcG9zaXRvcnkgc2lnbmluZyBrZXkpIDxza3ljb2RlcjQyLmRlQGdteC5kZT6JAk4EEwEIADgWIQTL1nR7/OQFBPJAtqpTqf2Zk29CDQUCW6C9OAIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRBTqf2Zk29CDZ/dD/9ynZxYB5PWfQJETT5TU00NrPYx0/tzI/3QVdmsB/bN2v8yx4apd5oMYem+AgBmaDDeMgQosLzdM8OW43UzjoORtkevT+gTMWQtm1cMQWf4+yt2ar0jZcXyznBO2Lg/TUB1sOguu9xqbEuP6RVOKD1I66gIJZdeFQzSxAwbXJ87AtehZDieVCr+0T9ITCamVG5WQEB1DiGC0iaTTLu4V3ia8YvEBivZmYamo3hFtUZuTima0LJdjvRGSxVEP3mwcPBLLJd0qIW4DSaa/haq+5+oKwQ1cJZa/O2zJtHE28TbtoqOR9FJu9vh/jNfEh03xjGrHpEMeKekSMZUs9PwJqNGoeZAxz81qqyNp7Cr4oeeEmOFcmq14uKsAEPmIeEVrIOzyaQiLB4WnyCgk/h85dXkyt0j0SAEEz21OJCm+ovs2y0oQ8zl/ew50ccInUCKRpbI1Jyr2dn/oofaLF87RiSgtDKMh1XTcp3ZEV9HweNoesOvZRnAzgumre6Yrl1o3M+O68erLYEKpFQa5C8W3JI/O5s6H/LVIwR9f58llTPCh+P/+VUpZg8rK9iYjt8qUuX6LL3MKsiQgbZ67gNQNdfPRjtqda/oPeiKNOoHmk3h+Hfp2ZjJOcaZM+jBPTUcblMO7ovZ266MhbjIwmQTO1NFldTv/NnFsQeRgNFwr5nbPbkCDQRboL04ARAAwxBQiY0ia8uWqv63P+5C9TQWZzlnQQxlfOzAqPVaSUvMi4B8O7WeIIekYFw5tGHlYZHRP/ngVG7lG/Qzl6zBqcKbQwmciESQ2eFT6pg1PcjVaBcG5W824QBzBDGhEGhRWDecQQ2hoKVjH+stdz0DZeW0es8FoVQA65iUgOxkr/qVJ4Fn81ppnx8499nbXxUUJwwgcYvFpTSc6/C9SwWpLUUUW9H4afvTdBO2estauyhpApHpkPeDF/acg9NT7yij2htYn1XTcvnZN1BN7R6jh2+uY27urq8dD5iv8hsjVIeGAWJJNs8aDcUMcUZhz/k94ofai0A4ZICIqyKwi78jpY+JrfheqisLf7izik6fd9ObJzoilOx37/JNEOLFqNRnzAlTwmqcloLgTYNZkcG1Qnjvj2OT71rbiYiNDsXsntsOMIvequMFbCxA5nvFsAVgL3weP/HeD1ZUCKr/CXdbnrIQ0Kjd7sv5uWtVEkas/2bJo1XgECshxcesh0xzzwuMiqoiuM8OHO29jMJYqghPJR+4gD4m1S2RInk4wb70UO3yeA8c9Tm7pUgG1Ixiz7EkDQwZD8axQtNH+V9uXPhu8BuJr9nJrv6TxPpe+ELt63Q+88Z73hf99z0IQvW0+NihYn9+P0ahwlQt0s7tVJNEHpI3jlJg1+NMQRP2UIkABX0AEQEAAYkCNgQYAQgAIBYhBMvWdHv85AUE8kC2qlOp/ZmTb0INBQJboL04AhsMAAoJEFOp/ZmTb0INwI0QAJy0l0/EsF86Y9fShaB3LJjklOpDCAa61aJg8XCLpoBeyOgJ8hHU6SnIef1nZBGtqgbIzZV02XTFLYhbOTt2XPVH4VZ6sTJ53Pfpve0p/z59b33JhsamDUvdK/u6AOomspOYazcpiDRsCh1F0Lh+9X3BmQR8tjvtIa+NLy9/y1YY5KtjOBn6fb+zALBz5/sa3Ps83UczTDSIiqSxA1kEwKqJn9oQ9fDBJ3Oyh8ZoWxNbD9KgwUl7KBywQLsvJvTrxe8QiAibMrEr9GXLAjBTSfiOcf8nHv+F6h/1IaqLJ4gx9/36uZv4DkDcDO5OlX7AAzaJUkqX9mpjqU1lqVbE3ROvC1wAo8WAZ1jzeiqepzbTRACfhqT+1BvUiS6n+5zXX2IiMvCAd1fa7XfmRqw76UA//EB/TG2ly3823o6+z4UHSYqNNVR+vVuyU3dqQadNsWAaeoxMwVRilYYjxsgL2PVGTdF57pT71bXDF4r4ttuatG6sUnfSitZpTog3zMEaJ6gsiRI6I1fuAwY6WSUiCOuaVb1aNPGWE/UGd7rBzL/mincIhMhF//+Sh1gXBeJ4jo1V+e5OYjVizJETnD6UWt4J/YGUA/RvCKkjKsM929CG9jrY9dPwVZ7zJ/bXRzurVUzKpFygAO2SCV4E0h2VIvprojsTphs5df9ZRwCobbzH 8 | -------------------------------------------------------------------------------- /flatpak/de.skycoder42.kptransfer.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "de.skycoder42.kptransfer", 3 | "branch": "master", 4 | "runtime": "org.kde.Platform", 5 | "runtime-version": "5.12", 6 | "sdk": "org.kde.Sdk", 7 | "command": "kptransfer-client", 8 | "finish-args": [ 9 | "--share=ipc", 10 | "--socket=fallback-x11", 11 | "--socket=wayland", 12 | "--share=network" 13 | ], 14 | "build-options": { 15 | "env": { 16 | "QMAKEPATH": "/app/lib", 17 | "QT_PLUGIN_PATH": "/app/lib/plugins" 18 | } 19 | }, 20 | 21 | "depends": [ 22 | "cryptopp", 23 | "qpmx", 24 | "qtservice", 25 | "qtmvvm-nods", 26 | "libkpxcclient" 27 | ], 28 | 29 | "modules": [ 30 | "../deploy/flatpak/flatdep-modules.json", 31 | { 32 | "name": "kptransfer", 33 | "buildsystem": "qmake", 34 | "build-options": { 35 | "env": { 36 | "QPMX_CACHE_DIR": "/app/.qpmx" 37 | }, 38 | "build-args": [ "--share=network" ] 39 | }, 40 | "config-opts": [ 41 | "CONFIG+=no_quick", 42 | "CONFIG+=no_server", 43 | "CONFIG+=no_auto_lupdate", 44 | "CONFIG+=auto_lrelease", 45 | "CONFIG+=no_bundle_deploy", 46 | "CONFIG+=system_cryptopp", 47 | "DEFINES+=FLATPAK_BUILD" 48 | ], 49 | "sources": [ 50 | { 51 | "type": "dir", 52 | "path": ".." 53 | } 54 | ], 55 | "cleanup": [ 56 | "/.qpmx", 57 | "*_template.qm" 58 | ] 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-add-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-arrow_back-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-assignment-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-file_copy-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-lock-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-lock_open-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-menu-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-photo_camera-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-select_all-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-send-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-tab_unselected-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-visibility-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-visibility_off-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/baseline-vpn_key-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/external/flat/outline-info-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon/kpt.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/kpt.icns -------------------------------------------------------------------------------- /icon/kpt.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/kpt.ico -------------------------------------------------------------------------------- /icon/kpt.svg: -------------------------------------------------------------------------------- 1 | raw/kpt_v3_colored.svg -------------------------------------------------------------------------------- /icon/kpt_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/kpt_header.png -------------------------------------------------------------------------------- /icon/pngs/kpt_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_128.png -------------------------------------------------------------------------------- /icon/pngs/kpt_144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_144.png -------------------------------------------------------------------------------- /icon/pngs/kpt_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_16.png -------------------------------------------------------------------------------- /icon/pngs/kpt_192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_192.png -------------------------------------------------------------------------------- /icon/pngs/kpt_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_22.png -------------------------------------------------------------------------------- /icon/pngs/kpt_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_24.png -------------------------------------------------------------------------------- /icon/pngs/kpt_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_256.png -------------------------------------------------------------------------------- /icon/pngs/kpt_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_32.png -------------------------------------------------------------------------------- /icon/pngs/kpt_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_36.png -------------------------------------------------------------------------------- /icon/pngs/kpt_384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_384.png -------------------------------------------------------------------------------- /icon/pngs/kpt_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_48.png -------------------------------------------------------------------------------- /icon/pngs/kpt_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_512.png -------------------------------------------------------------------------------- /icon/pngs/kpt_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_64.png -------------------------------------------------------------------------------- /icon/pngs/kpt_72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_72.png -------------------------------------------------------------------------------- /icon/pngs/kpt_96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/icon/pngs/kpt_96.png -------------------------------------------------------------------------------- /install.pri: -------------------------------------------------------------------------------- 1 | # installing 2 | isEmpty(PREFIX) { 3 | PREFIX = $$[QT_INSTALL_PREFIX] 4 | isEmpty(INSTALL_BINS): INSTALL_BINS = $$[QT_INSTALL_BINS] 5 | isEmpty(INSTALL_APPS): INSTALL_APPS = $$INSTALL_BINS 6 | isEmpty(INSTALL_LIBS): INSTALL_LIBS = $$[QT_INSTALL_LIBS] 7 | isEmpty(INSTALL_HEADERS): INSTALL_HEADERS = $$[QT_INSTALL_HEADERS] 8 | isEmpty(INSTALL_PLUGINS): INSTALL_PLUGINS = $$[QT_INSTALL_PLUGINS] 9 | isEmpty(INSTALL_TRANSLATIONS): INSTALL_TRANSLATIONS = $$[QT_INSTALL_TRANSLATIONS] 10 | isEmpty(INSTALL_SHARE): INSTALL_SHARE = $${PREFIX}/share 11 | CONFIG += no_deploy_qt_qm 12 | } else:!no_bundle_deploy:mac { 13 | APP_PREFIX = $${PROJECT_NAME}.app/Contents 14 | isEmpty(INSTALL_APPS): INSTALL_APPS = $${PREFIX}/.app-tmp 15 | isEmpty(INSTALL_BINS): INSTALL_BINS = $${PREFIX}/$${APP_PREFIX}/MacOS 16 | isEmpty(INSTALL_LIBS): INSTALL_LIBS = $${PREFIX}/$${APP_PREFIX}/Frameworks 17 | isEmpty(INSTALL_HEADERS): INSTALL_HEADERS = $${PREFIX}/$${APP_PREFIX}/Headers 18 | isEmpty(INSTALL_PLUGINS): INSTALL_PLUGINS = $${PREFIX}/$${APP_PREFIX}/PlugIns 19 | isEmpty(INSTALL_TRANSLATIONS): INSTALL_TRANSLATIONS = $${PREFIX}/$${APP_PREFIX}/Resources/translations 20 | isEmpty(INSTALL_SHARE): INSTALL_SHARE = $${PREFIX}/$${APP_PREFIX}/Resources 21 | } else { 22 | # bins 23 | !no_bundle_deploy:win32:isEmpty(INSTALL_BINS): INSTALL_BINS = $$PREFIX 24 | isEmpty(INSTALL_BINS): INSTALL_BINS = $${PREFIX}/bin 25 | isEmpty(INSTALL_APPS): INSTALL_APPS = $$INSTALL_BINS 26 | 27 | # libs 28 | !no_bundle_deploy:win32:isEmpty(INSTALL_LIBS): INSTALL_LIBS = $$INSTALL_BINS 29 | else:isEmpty(INSTALL_LIBS): INSTALL_LIBS = $${PREFIX}/lib 30 | 31 | # headers 32 | isEmpty(INSTALL_HEADERS): INSTALL_HEADERS = $${PREFIX}/include 33 | 34 | # plugins 35 | !no_bundle_deploy:win32:isEmpty(INSTALL_PLUGINS): INSTALL_PLUGINS = $$INSTALL_BINS 36 | else:isEmpty(INSTALL_PLUGINS): INSTALL_PLUGINS = $${PREFIX}/plugins 37 | 38 | # translations 39 | !no_bundle_deploy:android:isEmpty(INSTALL_TRANSLATIONS): INSTALL_TRANSLATIONS = /assets/translations 40 | else:isEmpty(INSTALL_TRANSLATIONS): INSTALL_TRANSLATIONS = $${PREFIX}/translations 41 | 42 | # share 43 | isEmpty(INSTALL_SHARE): INSTALL_SHARE = $${PREFIX}/share 44 | } 45 | 46 | auto_lrelease: PRE_TARGETDEPS += lrelease 47 | android: CONFIG += no_headers_install 48 | -------------------------------------------------------------------------------- /lib/credential.cpp: -------------------------------------------------------------------------------- 1 | #include "credential.h" 2 | 3 | class CredentialData : public QSharedData 4 | { 5 | public: 6 | CredentialData(QString &&key, QString &&value, bool confidential) : 7 | key{std::move(key)}, 8 | value{std::move(value)}, 9 | confidential{confidential} 10 | {} 11 | CredentialData(const CredentialData &other) = default; 12 | 13 | QString key; 14 | QString value; 15 | bool confidential; 16 | }; 17 | 18 | Credential::Credential(QString key, QString value, bool confidential) : 19 | d{new CredentialData{std::move(key), std::move(value), confidential}} 20 | {} 21 | 22 | void Credential::filterOutEmpty(QList &credentials) 23 | { 24 | for(auto it = credentials.begin(); it != credentials.end();) { 25 | if(it->isValid()) 26 | ++it; 27 | else 28 | it = credentials.erase(it); 29 | } 30 | } 31 | 32 | bool Credential::isValid() const 33 | { 34 | return !d->key.isEmpty(); 35 | } 36 | 37 | Credential::operator bool() const 38 | { 39 | return isValid(); 40 | } 41 | 42 | bool Credential::operator!() const 43 | { 44 | return !isValid(); 45 | } 46 | 47 | Credential::Credential(const Credential &other) = default; 48 | 49 | Credential::Credential(Credential &&other) noexcept = default; 50 | 51 | Credential &Credential::operator=(const Credential &other) = default; 52 | 53 | Credential &Credential::operator=(Credential &&other) noexcept = default; 54 | 55 | Credential::~Credential() = default; 56 | 57 | QString Credential::key() const 58 | { 59 | return d->key; 60 | } 61 | 62 | QString Credential::value() const 63 | { 64 | return d->value; 65 | } 66 | 67 | bool Credential::confidential() const 68 | { 69 | return d->confidential; 70 | } 71 | 72 | void Credential::setKey(QString key) 73 | { 74 | d->key = std::move(key); 75 | } 76 | 77 | void Credential::setValue(QString value) 78 | { 79 | d->value = std::move(value); 80 | } 81 | 82 | void Credential::setConfidential(bool confidential) 83 | { 84 | d->confidential = confidential; 85 | } 86 | 87 | bool Credential::operator==(const Credential &other) const 88 | { 89 | return d == other.d || ( 90 | d->key == other.d->key && 91 | d->value == other.d->value && 92 | d->confidential == other.d->confidential); 93 | } 94 | 95 | bool Credential::operator!=(const Credential &other) const 96 | { 97 | return d != other.d && ( 98 | d->key != other.d->key || 99 | d->value != other.d->value || 100 | d->confidential != other.d->confidential); 101 | } 102 | 103 | QDataStream &operator<<(QDataStream &stream, const Credential &credential) 104 | { 105 | stream << credential.d->key 106 | << credential.d->value 107 | << credential.d->confidential; 108 | return stream; 109 | } 110 | 111 | QDataStream &operator>>(QDataStream &stream, Credential &credential) 112 | { 113 | stream >> credential.d->key 114 | >> credential.d->value 115 | >> credential.d->confidential; 116 | return stream; 117 | } 118 | 119 | QDebug operator<<(QDebug stream, const Credential &credential) 120 | { 121 | QDebugStateSaver state{stream}; 122 | stream.nospace().noquote() << "{" 123 | << credential.key() << ": " 124 | << (credential.confidential() ? 125 | QString{credential.value().size(), QLatin1Char('*')} : 126 | credential.value()) 127 | << "}"; 128 | return stream; 129 | } 130 | -------------------------------------------------------------------------------- /lib/credential.h: -------------------------------------------------------------------------------- 1 | #ifndef CREDENTIAL_H 2 | #define CREDENTIAL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class CredentialData; 10 | class Credential 11 | { 12 | Q_GADGET 13 | 14 | Q_PROPERTY(bool valid READ isValid STORED false) 15 | 16 | Q_PROPERTY(QString key READ key WRITE setKey USER true) 17 | Q_PROPERTY(QString value READ value WRITE setValue) 18 | Q_PROPERTY(bool confidential READ confidential WRITE setConfidential) 19 | 20 | public: 21 | Credential(QString key = {}, QString value = {}, bool confidential = false); 22 | Credential(const Credential &other); 23 | Credential(Credential &&other) noexcept; 24 | Credential &operator=(const Credential &other); 25 | Credential &operator=(Credential &&other) noexcept; 26 | ~Credential(); 27 | 28 | static void filterOutEmpty(QList &credentials); 29 | 30 | bool isValid() const; 31 | explicit operator bool() const; 32 | bool operator!() const; 33 | 34 | QString key() const; 35 | QString value() const; 36 | bool confidential() const; 37 | 38 | void setKey(QString key); 39 | void setValue(QString value); 40 | void setConfidential(bool confidential); 41 | 42 | bool operator==(const Credential &other) const; 43 | bool operator!=(const Credential &other) const; 44 | 45 | private: 46 | friend QDataStream &operator<<(QDataStream &stream, const Credential &credential); 47 | friend QDataStream &operator>>(QDataStream &stream, Credential &credential); 48 | 49 | QSharedDataPointer d; 50 | }; 51 | 52 | QDataStream &operator<<(QDataStream &stream, const Credential &credential); 53 | QDataStream &operator>>(QDataStream &stream, Credential &credential); 54 | 55 | QDebug operator<<(QDebug stream, const Credential &credential); 56 | 57 | Q_DECLARE_METATYPE(Credential) 58 | Q_DECLARE_TYPEINFO(Credential, Q_MOVABLE_TYPE); 59 | 60 | #endif // CREDENTIAL_H 61 | -------------------------------------------------------------------------------- /lib/dataencryptor.h: -------------------------------------------------------------------------------- 1 | #ifndef DATAENCRYPTOR_H 2 | #define DATAENCRYPTOR_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class DataEncryptor : public QObject 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | enum class ECCCurve { 18 | secp128r1, 19 | secp256r1, 20 | secp128r2, 21 | secp256k1, 22 | brainpoolP256r1, 23 | brainpoolP512r1 24 | }; 25 | Q_ENUM(ECCCurve) 26 | 27 | Q_INVOKABLE explicit DataEncryptor(QObject *parent = nullptr); 28 | 29 | // symmetric encryption 30 | QByteArray encryptSymmetric(const QByteArray &plain, 31 | const CryptoPP::SecByteBlock &key, 32 | const QByteArray &iv) const; 33 | QByteArray decryptSymmetric(const QByteArray &cipher, 34 | const CryptoPP::SecByteBlock &key, 35 | const QByteArray &iv) const; 36 | 37 | // pw-based key generation 38 | CryptoPP::SecByteBlock generateSecretKey(const QString &password, const QByteArray &salt) const; 39 | 40 | // asymmetric key encryption 41 | QSharedPointer generateAsymKey(CryptoPP::RandomNumberGenerator &rng, 42 | ECCCurve curve) const; 43 | 44 | QByteArray serializePublicKey(const CryptoPP::X509PublicKey &pubKey) const; 45 | inline QByteArray serializePublicKey(const QSharedPointer &pubKey) const { 46 | return serializePublicKey(*(pubKey.data())); 47 | } 48 | QByteArray serializePublicKey(const CryptoPP::PKCS8PrivateKey &privKey) const; 49 | inline QByteArray serializePublicKey(const QSharedPointer &privKey) const { 50 | return serializePublicKey(*(privKey.data())); 51 | } 52 | QSharedPointer deserializePublicKey(CryptoPP::RandomNumberGenerator &rng, 53 | const QByteArray &data) const; 54 | 55 | QByteArray encryptSecretKey(CryptoPP::RandomNumberGenerator &rng, 56 | const CryptoPP::SecByteBlock &secKey, 57 | const CryptoPP::X509PublicKey &pubKey) const; 58 | inline QByteArray encryptSecretKey(CryptoPP::RandomNumberGenerator &rng, 59 | const CryptoPP::SecByteBlock &secKey, 60 | const QSharedPointer &pubKey) const { 61 | return encryptSecretKey(rng, secKey, *(pubKey.data())); 62 | } 63 | 64 | CryptoPP::SecByteBlock decryptSecretKey(CryptoPP::RandomNumberGenerator &rng, 65 | const QByteArray &data, 66 | const CryptoPP::PKCS8PrivateKey &privKey) const; 67 | inline CryptoPP::SecByteBlock decryptSecretKey(CryptoPP::RandomNumberGenerator &rng, 68 | const QByteArray &data, 69 | const QSharedPointer &privKey) const { 70 | return decryptSecretKey(rng, data, *(privKey.data())); 71 | } 72 | 73 | private: 74 | CryptoPP::OID curveOid(ECCCurve curve) const; 75 | }; 76 | 77 | #endif // DATAENCRYPTOR_H 78 | -------------------------------------------------------------------------------- /lib/encrypteddata.cpp: -------------------------------------------------------------------------------- 1 | #include "encrypteddata.h" 2 | 3 | bool EncryptedData::operator==(const EncryptedData &other) const 4 | { 5 | return mode == other.mode && 6 | keyInfo == other.keyInfo && 7 | iv == other.iv && 8 | data == other.data; 9 | } 10 | 11 | bool EncryptedData::operator!=(const EncryptedData &other) const 12 | { 13 | return mode != other.mode || 14 | keyInfo != other.keyInfo || 15 | iv != other.iv || 16 | data != other.data; 17 | } 18 | 19 | QDataStream &operator<<(QDataStream &stream, const EncryptedData &data) 20 | { 21 | stream << static_cast(data.mode) 22 | << data.keyInfo 23 | << data.iv 24 | << data.data; 25 | return stream; 26 | } 27 | 28 | QDataStream &operator>>(QDataStream &stream, EncryptedData &data) 29 | { 30 | static_assert(sizeof(EncryptedData::DataMode) == sizeof(int), "EncryptedData::DataMode must be an int-enum"); 31 | stream >> (*reinterpret_cast(&data.mode)) 32 | >> data.keyInfo 33 | >> data.iv 34 | >> data.data; 35 | return stream; 36 | } 37 | -------------------------------------------------------------------------------- /lib/encrypteddata.h: -------------------------------------------------------------------------------- 1 | #ifndef ENCRYPTEDDATA_H 2 | #define ENCRYPTEDDATA_H 3 | 4 | #include 5 | #include 6 | 7 | class EncryptedData 8 | { 9 | Q_GADGET 10 | 11 | Q_PROPERTY(DataMode mode MEMBER mode) 12 | Q_PROPERTY(QByteArray keyInfo MEMBER keyInfo) 13 | Q_PROPERTY(QByteArray iv MEMBER iv) 14 | Q_PROPERTY(QByteArray data MEMBER data) 15 | 16 | public: 17 | enum class DataMode : int { 18 | QrCode, 19 | Password 20 | }; 21 | Q_ENUM(DataMode) 22 | 23 | DataMode mode; 24 | QByteArray keyInfo; 25 | QByteArray iv; 26 | QByteArray data; 27 | 28 | bool operator==(const EncryptedData &other) const; 29 | bool operator!=(const EncryptedData &other) const; 30 | }; 31 | 32 | QDataStream &operator<<(QDataStream &stream, const EncryptedData &data); 33 | QDataStream &operator>>(QDataStream &stream, EncryptedData &data); 34 | 35 | inline uint qHash(EncryptedData::DataMode key, uint seed) { 36 | return qHash(static_cast(key), seed); 37 | } 38 | 39 | Q_DECLARE_METATYPE(EncryptedData) 40 | Q_DECLARE_TYPEINFO(EncryptedData, Q_MOVABLE_TYPE); 41 | 42 | #endif // ENCRYPTEDDATA_H 43 | -------------------------------------------------------------------------------- /lib/lib.pri: -------------------------------------------------------------------------------- 1 | OUT_ROOT = $$shadowed($$SRC_ROOT_DIR) 2 | 3 | win32:CONFIG(release, debug|release): LIBS += -L$$OUT_ROOT/lib/release/ -lkptransfer 4 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_ROOT/lib/debug/ -lkptransfer 5 | else:unix: LIBS += -L$$OUT_ROOT/lib/ -lkptransfer 6 | 7 | INCLUDEPATH += $$PWD 8 | DEPENDPATH += $$PWD 9 | 10 | win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_ROOT/lib/release/libkptransfer.a 11 | else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_ROOT/lib/debug/libkptransfer.a 12 | else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_ROOT/lib/release/kptransfer.lib 13 | else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_ROOT/lib/debug/kptransfer.lib 14 | else:unix: PRE_TARGETDEPS += $$OUT_ROOT/lib/libkptransfer.a 15 | 16 | include($$SRC_ROOT_DIR/3rdparty/cryptopp/cryptopp.pri) 17 | -------------------------------------------------------------------------------- /lib/lib.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | 3 | QT = core 4 | CONFIG += staticlib 5 | 6 | TARGET = $$PROJECT_TARGET 7 | 8 | HEADERS += \ 9 | kptlib.h \ 10 | messages/appidentmessage.h \ 11 | messages/serveridentmessage.h \ 12 | messages/errormessage.h \ 13 | messages/clienttransfermessage.h \ 14 | messages/servertransfermessage.h \ 15 | messages/appokmessage.h \ 16 | messages/serverokmessage.h \ 17 | dataencryptor.h \ 18 | encrypteddata.h \ 19 | credential.h \ 20 | qrdata.h 21 | 22 | SOURCES += \ 23 | kptlib.cpp \ 24 | messages/appidentmessage.cpp \ 25 | messages/serveridentmessage.cpp \ 26 | messages/errormessage.cpp \ 27 | messages/clienttransfermessage.cpp \ 28 | messages/servertransfermessage.cpp \ 29 | messages/appokmessage.cpp \ 30 | messages/serverokmessage.cpp \ 31 | dataencryptor.cpp \ 32 | encrypteddata.cpp \ 33 | credential.cpp \ 34 | qrdata.cpp 35 | 36 | DISTFILES += \ 37 | protocol.qmodel \ 38 | qpmx.json 39 | 40 | include($$SRC_ROOT_DIR/3rdparty/cryptopp/cryptopp.pri) 41 | 42 | !ReleaseBuild:!DebugBuild:!system(qpmx -d $$shell_quote($$_PRO_FILE_PWD_) --qmake-run init $$QPMX_EXTRA_OPTIONS $$shell_quote($$QMAKE_QMAKE) $$shell_quote($$OUT_PWD)): error(qpmx initialization failed. Check the compilation log for details.) 43 | else: include($$OUT_PWD/qpmx_generated.pri) 44 | -------------------------------------------------------------------------------- /lib/messages/appidentmessage.cpp: -------------------------------------------------------------------------------- 1 | #include "appidentmessage.h" 2 | -------------------------------------------------------------------------------- /lib/messages/appidentmessage.h: -------------------------------------------------------------------------------- 1 | #ifndef APPIDENTMESSAGE_H 2 | #define APPIDENTMESSAGE_H 3 | 4 | #include 5 | #include "kptlib.h" 6 | 7 | class AppIdentMessage 8 | { 9 | Q_GADGET 10 | 11 | Q_PROPERTY(quint32 version MEMBER version) 12 | 13 | public: 14 | quint32 version = KPTLib::ProtocolVersion; 15 | }; 16 | 17 | Q_DECLARE_METATYPE(AppIdentMessage) 18 | Q_DECLARE_TYPEINFO(AppIdentMessage, Q_MOVABLE_TYPE); 19 | 20 | #endif // APPIDENTMESSAGE_H 21 | -------------------------------------------------------------------------------- /lib/messages/appokmessage.cpp: -------------------------------------------------------------------------------- 1 | #include "appokmessage.h" 2 | -------------------------------------------------------------------------------- /lib/messages/appokmessage.h: -------------------------------------------------------------------------------- 1 | #ifndef APPOKMESSAGE_H 2 | #define APPOKMESSAGE_H 3 | 4 | #include 5 | #include "kptlib.h" 6 | 7 | class AppOkMessage 8 | { 9 | Q_GADGET 10 | 11 | public: 12 | }; 13 | 14 | Q_DECLARE_METATYPE(AppOkMessage) 15 | Q_DECLARE_TYPEINFO(AppOkMessage, Q_MOVABLE_TYPE); 16 | 17 | #endif // APPOKMESSAGE_H 18 | -------------------------------------------------------------------------------- /lib/messages/clienttransfermessage.cpp: -------------------------------------------------------------------------------- 1 | #include "clienttransfermessage.h" 2 | -------------------------------------------------------------------------------- /lib/messages/clienttransfermessage.h: -------------------------------------------------------------------------------- 1 | #ifndef CLIENTTRANSFERMESSAGE_H 2 | #define CLIENTTRANSFERMESSAGE_H 3 | 4 | #include 5 | #include 6 | #include "kptlib.h" 7 | #include "encrypteddata.h" 8 | 9 | class ClientTransferMessage 10 | { 11 | Q_GADGET 12 | 13 | Q_PROPERTY(quint32 version MEMBER version) 14 | Q_PROPERTY(QUuid channelId MEMBER channelId) 15 | Q_PROPERTY(EncryptedData data MEMBER data) 16 | 17 | public: 18 | quint32 version = KPTLib::ProtocolVersion; 19 | QUuid channelId; 20 | EncryptedData data; 21 | }; 22 | 23 | Q_DECLARE_METATYPE(ClientTransferMessage) 24 | Q_DECLARE_TYPEINFO(ClientTransferMessage, Q_MOVABLE_TYPE); 25 | 26 | #endif // CLIENTTRANSFERMESSAGE_H 27 | -------------------------------------------------------------------------------- /lib/messages/errormessage.cpp: -------------------------------------------------------------------------------- 1 | #include "errormessage.h" 2 | -------------------------------------------------------------------------------- /lib/messages/errormessage.h: -------------------------------------------------------------------------------- 1 | #ifndef ERRORMESSAGE_H 2 | #define ERRORMESSAGE_H 3 | 4 | #include 5 | #include "kptlib.h" 6 | 7 | class ErrorMessage 8 | { 9 | Q_GADGET 10 | 11 | Q_PROPERTY(QString message MEMBER message) 12 | 13 | public: 14 | QString message; 15 | }; 16 | 17 | Q_DECLARE_METATYPE(ErrorMessage) 18 | Q_DECLARE_TYPEINFO(ErrorMessage, Q_MOVABLE_TYPE); 19 | 20 | #endif // ERRORMESSAGE_H 21 | -------------------------------------------------------------------------------- /lib/messages/serveridentmessage.cpp: -------------------------------------------------------------------------------- 1 | #include "serveridentmessage.h" 2 | -------------------------------------------------------------------------------- /lib/messages/serveridentmessage.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVERIDENTMESSAGE_H 2 | #define SERVERIDENTMESSAGE_H 3 | 4 | #include 5 | #include 6 | #include "kptlib.h" 7 | 8 | class ServerIdentMessage 9 | { 10 | Q_GADGET 11 | 12 | Q_PROPERTY(QUuid channelId MEMBER channelId) 13 | 14 | public: 15 | QUuid channelId; 16 | }; 17 | 18 | Q_DECLARE_METATYPE(ServerIdentMessage) 19 | Q_DECLARE_TYPEINFO(ServerIdentMessage, Q_MOVABLE_TYPE); 20 | 21 | #endif // SERVERIDENTMESSAGE_H 22 | -------------------------------------------------------------------------------- /lib/messages/serverokmessage.cpp: -------------------------------------------------------------------------------- 1 | #include "serverokmessage.h" 2 | -------------------------------------------------------------------------------- /lib/messages/serverokmessage.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVEROKMESSAGE_H 2 | #define SERVEROKMESSAGE_H 3 | 4 | #include 5 | #include "kptlib.h" 6 | 7 | class ServerOkMessage 8 | { 9 | Q_GADGET 10 | 11 | public: 12 | }; 13 | 14 | Q_DECLARE_METATYPE(ServerOkMessage) 15 | Q_DECLARE_TYPEINFO(ServerOkMessage, Q_MOVABLE_TYPE); 16 | 17 | #endif // SERVEROKMESSAGE_H 18 | -------------------------------------------------------------------------------- /lib/messages/servertransfermessage.cpp: -------------------------------------------------------------------------------- 1 | #include "servertransfermessage.h" 2 | -------------------------------------------------------------------------------- /lib/messages/servertransfermessage.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVERTRANSFERMESSAGE_H 2 | #define SERVERTRANSFERMESSAGE_H 3 | 4 | #include 5 | #include "kptlib.h" 6 | #include "encrypteddata.h" 7 | 8 | class ServerTransferMessage 9 | { 10 | Q_GADGET 11 | 12 | Q_PROPERTY(EncryptedData data MEMBER data) 13 | 14 | public: 15 | EncryptedData data; 16 | }; 17 | 18 | Q_DECLARE_METATYPE(ServerTransferMessage) 19 | Q_DECLARE_TYPEINFO(ServerTransferMessage, Q_MOVABLE_TYPE); 20 | 21 | #endif // SERVERTRANSFERMESSAGE_H 22 | -------------------------------------------------------------------------------- /lib/qpmx.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | { 4 | "package": "de.skycoder42.cryptoqq", 5 | "provider": "qpm", 6 | "version": "1.1.1" 7 | } 8 | ], 9 | "license": { 10 | "file": "", 11 | "name": "" 12 | }, 13 | "prcFile": "", 14 | "priFile": "", 15 | "priIncludes": [ 16 | ], 17 | "publishers": { 18 | }, 19 | "qbsFile": "", 20 | "source": true 21 | } 22 | -------------------------------------------------------------------------------- /lib/qrdata.cpp: -------------------------------------------------------------------------------- 1 | #include "qrdata.h" 2 | 3 | QDataStream &operator<<(QDataStream &stream, const QrData &data) 4 | { 5 | stream << data.channelId 6 | << data.pubKey 7 | << data.calcChecksum(); 8 | return stream; 9 | } 10 | 11 | QDataStream &operator>>(QDataStream &stream, QrData &data) 12 | { 13 | stream.startTransaction(); 14 | quint16 checksum; 15 | stream >> data.channelId 16 | >> data.pubKey 17 | >> checksum; 18 | if(stream.status() != QDataStream::Ok) 19 | stream.rollbackTransaction(); 20 | else if(checksum != data.calcChecksum()) 21 | stream.abortTransaction(); 22 | else 23 | stream.commitTransaction(); 24 | return stream; 25 | } 26 | 27 | bool QrData::isValid() const 28 | { 29 | return !channelId.isNull() && !pubKey.isEmpty(); 30 | } 31 | 32 | QrData::operator bool() const 33 | { 34 | return isValid(); 35 | } 36 | 37 | bool QrData::operator!() const 38 | { 39 | return !isValid(); 40 | } 41 | 42 | quint16 QrData::calcChecksum() const 43 | { 44 | const QByteArray checksumData = channelId.toRfc4122() + pubKey; 45 | return qChecksum(checksumData.data(), static_cast(checksumData.size())); 46 | } 47 | -------------------------------------------------------------------------------- /lib/qrdata.h: -------------------------------------------------------------------------------- 1 | #ifndef QRDATA_H 2 | #define QRDATA_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class QrData 9 | { 10 | Q_GADGET 11 | 12 | Q_PROPERTY(QUuid channelId MEMBER channelId) 13 | Q_PROPERTY(QByteArray pubKey MEMBER pubKey) 14 | 15 | Q_PROPERTY(bool valid READ isValid STORED false) 16 | 17 | public: 18 | QUuid channelId; 19 | QByteArray pubKey; 20 | 21 | bool isValid() const; 22 | explicit operator bool() const; 23 | bool operator!() const; 24 | 25 | private: 26 | friend QDataStream &operator<<(QDataStream &stream, const QrData &data); 27 | friend QDataStream &operator>>(QDataStream &stream, QrData &data); 28 | 29 | quint16 calcChecksum() const; 30 | }; 31 | 32 | QDataStream &operator<<(QDataStream &stream, const QrData &data); 33 | QDataStream &operator>>(QDataStream &stream, QrData &data); 34 | 35 | Q_DECLARE_METATYPE(QrData) 36 | Q_DECLARE_TYPEINFO(QrData, Q_MOVABLE_TYPE); 37 | 38 | #endif // QRDATA_H 39 | -------------------------------------------------------------------------------- /readme/desktop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/readme/desktop.gif -------------------------------------------------------------------------------- /readme/mobile.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/readme/mobile.gif -------------------------------------------------------------------------------- /readme/webapp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/KeepassTransfer/7ba18abfaa0f3f372e57fda96cbe3b67fa69cb95/readme/webapp.gif -------------------------------------------------------------------------------- /server/de.skycoder42.kptransfer.server.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | de.skycoder42.kptransfer.server 7 | ProgramArguments 8 | 9 | ~/Applications/KeePass-Transfer.app/Contents/MacOs/kptransfer-server 10 | --backend 11 | launchd 12 | 13 | RunAtLoad 14 | false 15 | Sockets 16 | 17 | Listeners 18 | 19 | SockServiceName 20 | 27352 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /server/dockerbuild/env_start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "[server]" > $KPTSERVER_CONFIG_PATH 4 | echo "host=$KPTSERVER_HOST" >> $KPTSERVER_CONFIG_PATH 5 | echo "port=$KPTSERVER_PORT" >> $KPTSERVER_CONFIG_PATH 6 | echo "local=$KPTSERVER_LOCAL" >> $KPTSERVER_CONFIG_PATH 7 | echo "timeout=$KPTSERVER_TIMEOUT" >> $KPTSERVER_CONFIG_PATH 8 | 9 | exec /usr/bin/kptransfer-server 10 | -------------------------------------------------------------------------------- /server/dockerbuild/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | export MAKEFLAGS=-j$(nproc) 5 | export QPMX_CACHE_DIR=/tmp/qpmx-cache 6 | 7 | KPT_NAME=kptransfer-server 8 | QT_VERSION_TAG=v5.12.0 9 | MAIN_DEP="libssl1.1 zlib1g libdbus-1-3 libc6 libglib2.0-0 libudev1 libpcre2-16-0 libpq5 libdouble-conversion1 libicu57 libinput10 ca-certificates" 10 | DEV_DEP="openssl libssl-dev zlib1g-dev dbus libdbus-1-dev libc6-dev libglib2.0-dev libudev-dev libdouble-conversion-dev libicu-dev libpcre2-dev libpq-dev libinput-dev make gcc g++ curl python3 git perl gawk" 11 | 12 | if [ ! -d "/tmp/src/.git" ]; then 13 | echo "Failed to find .git directory - not supported!" 14 | exit 1 15 | fi 16 | 17 | apt-get -qq update 18 | apt-get -qq install --no-install-recommends $MAIN_DEP $DEV_DEP 19 | 20 | # get QPM 21 | curl -O https://www.qpm.io/download/v0.11.0/linux_386/qpm 22 | install -m 755 ./qpm /usr/local/bin/ 23 | 24 | mkdir /tmp/sysbuild 25 | cd /tmp/sysbuild 26 | 27 | # build qt 28 | git clone --depth 1 https://code.qt.io/qt/qt5.git ./qt5 --branch $QT_VERSION_TAG 29 | cd qt5 30 | ./init-repository --module-subset="qtbase,qtwebsockets,qttools" 31 | _qt5_prefix=/usr/lib/qt5 32 | _qt5_datadir=/usr/share/qt5 33 | ./configure -confirm-license -opensource \ 34 | -prefix /usr \ 35 | -archdatadir "$_qt5_prefix" \ 36 | -datadir "$_qt5_prefix" \ 37 | -importdir "$_qt5_prefix"/imports \ 38 | -libexecdir "$_qt5_prefix"/libexec \ 39 | -plugindir "$_qt5_prefix"/plugins \ 40 | -translationdir "$_qt5_datadir"/translations \ 41 | -sysconfdir /etc/xdg \ 42 | -release -reduce-exports \ 43 | -make libs -make tools \ 44 | -glib \ 45 | -no-rpath \ 46 | -no-separate-debug-info \ 47 | -no-pch \ 48 | -openssl-linked \ 49 | -plugin-sql-psql \ 50 | -dbus-linked \ 51 | -system-pcre \ 52 | -system-zlib \ 53 | -no-reduce-relocations \ 54 | -no-gui -no-widgets -no-feature-accessibility -no-feature-dom 55 | make > /dev/null 56 | make install 57 | cd .. 58 | 59 | # build json serializer, qpmx, qtservice 60 | for repo in QtJsonSerializer qpmx QtService; do 61 | git clone https://github.com/Skycoder42/$repo.git ./$repo 62 | cd $repo 63 | latesttag=$(git describe --tags --abbrev=0) 64 | echo checking out ${latesttag} 65 | git checkout ${latesttag} 66 | 67 | if [[ "$repo" == "qpmx" ]]; then 68 | git submodule init 69 | git submodule update 70 | fi 71 | 72 | if [[ -f src/imports/imports.pro ]]; then 73 | echo "SUBDIRS -= imports" >> src/src.pro 74 | fi 75 | 76 | qmake 77 | make > /dev/null || (cat /tmp/qpmx-*/*; exit 1) 78 | make install 79 | cd .. 80 | done 81 | 82 | # build keepass transfer server 83 | cd /tmp/src 84 | qmake "PREFIX=/usr" "CONFIG+=no_clients" "CONFIG+=no_webapp" 85 | make 86 | make install 87 | 88 | #create special symlinks, dirs and move the env script 89 | mkdir -p /etc/Skycoder42 90 | mv /tmp/src/server/dockerbuild/env_start.sh /usr/bin/ 91 | 92 | # test if working 93 | /usr/bin/$KPT_NAME --version 94 | 95 | # remove unused stuff 96 | apt-get -qq autoremove --purge $DEV_DEP 97 | rm -rf /tmp/* 98 | rm -rf $HOME/.cache/qpmx 99 | rm -rf /usr/local/bin/qpm 100 | 101 | # test if still working 102 | /usr/bin/$KPT_NAME --version 103 | -------------------------------------------------------------------------------- /server/kptserver-install.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | sc create server binPath= "%~dp0\kptransfer-server.exe --backend windows" start= demand displayname= "KeePass-Transfer Server Service" || exit /B 1 3 | sc description server "The KeePass-Transfer Server Application" || exit /B 1 4 | -------------------------------------------------------------------------------- /server/kptserver.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=KeePass-Transfer Service 3 | Documentation=https://github.com/Skycoder42/KeepassTransfer 4 | After=network-online.target kptservice.socket 5 | 6 | [Service] 7 | Type=notify 8 | NotifyAccess=exec 9 | ExecStart=%{INSTALL_BINS}/kptransfer-server -platform minimal --backend systemd 10 | ExecReload=%{INSTALL_BINS}/kptransfer-server -platform minimal --backend systemd reload $MAINPID 11 | ExecStop=%{INSTALL_BINS}/kptransfer-server -platform minimal --backend systemd stop $MAINPID 12 | #WatchdogSec=10 13 | Restart=on-abnormal 14 | RuntimeDirectory=kptransfer 15 | 16 | [Install] 17 | # Use the following for a system service 18 | WantedBy=multi-user.target 19 | # Use the following for a user service 20 | #WantedBy=default.target 21 | -------------------------------------------------------------------------------- /server/kptserver.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=KeePass-Transfer Service Socket 3 | Documentation=https://github.com/Skycoder42/KeepassTransfer 4 | After=network.target 5 | PartOf=kptservice.service 6 | 7 | [Socket] 8 | ListenStream=27352 9 | 10 | [Install] 11 | WantedBy=sockets.target 12 | -------------------------------------------------------------------------------- /server/kptservice.cpp: -------------------------------------------------------------------------------- 1 | #include "kptservice.h" 2 | 3 | #include 4 | 5 | KPTService::KPTService(int &argc, char **argv) : 6 | Service{argc, argv} 7 | { 8 | QCoreApplication::setApplicationName(QStringLiteral(PROJECT_TARGET)); 9 | QCoreApplication::setApplicationVersion(QStringLiteral(VERSION)); 10 | QCoreApplication::setOrganizationName(QStringLiteral(COMPANY)); 11 | QCoreApplication::setOrganizationDomain(QStringLiteral(BUNDLE)); 12 | } 13 | 14 | QtService::Service::CommandResult KPTService::onStart() 15 | { 16 | KPTLib::setup(); 17 | 18 | #ifdef Q_OS_LINUX 19 | QSettings::setPath(QSettings::NativeFormat, QSettings::SystemScope, QStringLiteral("/etc")); 20 | #endif 21 | _settings = new QSettings{this}; 22 | _settings->setFallbacksEnabled(true); 23 | 24 | _server = new TransferServer{_settings->value(QStringLiteral("server/timeout"), 30000).toLongLong(), this}; 25 | const auto hostName = _settings->value(QStringLiteral("server/host"), QStringLiteral("localhost")).toString(); 26 | auto socket = getSocket(); 27 | auto ok = false; 28 | if(socket != -1) 29 | ok = _server->startServer(hostName, socket); 30 | else { 31 | ok = _server->startServer(hostName, 32 | _settings->value(QStringLiteral("server/local"), false).toBool(), 33 | static_cast(_settings->value(QStringLiteral("server/port"), 27352).toUInt())); 34 | } 35 | if(!ok) 36 | return CommandResult::Failed; 37 | 38 | return CommandResult::Completed; 39 | } 40 | 41 | QtService::Service::CommandResult KPTService::onStop(int &exitCode) 42 | { 43 | exitCode = EXIT_SUCCESS; 44 | return CommandResult::Completed; 45 | } 46 | -------------------------------------------------------------------------------- /server/kptservice.h: -------------------------------------------------------------------------------- 1 | #ifndef KPTSERVICE_H 2 | #define KPTSERVICE_H 3 | 4 | #include 5 | #include 6 | 7 | #include "transferserver.h" 8 | 9 | class KPTService : public QtService::Service 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | explicit KPTService(int &argc, char **argv); 15 | 16 | protected: 17 | CommandResult onStart() override; 18 | CommandResult onStop(int &exitCode) override; 19 | 20 | private: 21 | QSettings *_settings = nullptr; 22 | TransferServer *_server = nullptr; 23 | }; 24 | 25 | #undef qService 26 | #define qService static_cast(QtService::Service::instance()) 27 | 28 | #endif // KPTSERVICE_H 29 | -------------------------------------------------------------------------------- /server/main.cpp: -------------------------------------------------------------------------------- 1 | #include "kptservice.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | // check if version 7 | for(auto i = 0; i < argc; i++) { 8 | if(qstrcmp(argv[i], "--version") == 0) { 9 | std::cout << VERSION << std::endl; 10 | return EXIT_SUCCESS; 11 | } 12 | } 13 | 14 | KPTService svc{argc, argv}; 15 | return svc.exec(); 16 | } 17 | -------------------------------------------------------------------------------- /server/qpmx.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | { 4 | "package": "de.skycoder42.qtcoroutines", 5 | "provider": "qpm", 6 | "version": "1.1.2" 7 | } 8 | ], 9 | "license": { 10 | "file": "", 11 | "name": "" 12 | }, 13 | "prcFile": "", 14 | "priFile": "", 15 | "priIncludes": [ 16 | ], 17 | "publishers": { 18 | }, 19 | "qbsFile": "", 20 | "source": false 21 | } 22 | -------------------------------------------------------------------------------- /server/server.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core service websockets 4 | CONFIG += c++17 console 5 | CONFIG -= app_bundle c++14 6 | 7 | TARGET = $${PROJECT_TARGET}-server 8 | 9 | QMAKE_TARGET_DESCRIPTION = "$$PROJECT_NAME Server" 10 | RC_ICONS += ../icon/kpt.ico 11 | 12 | HEADERS += \ 13 | kptservice.h \ 14 | transferserver.h 15 | 16 | SOURCES += \ 17 | main.cpp \ 18 | kptservice.cpp \ 19 | transferserver.cpp 20 | 21 | DISTFILES += \ 22 | kptserver.service.in \ 23 | kptserver.socket \ 24 | kptserver-install.bat \ 25 | de.skycoder42.kptransfer.server.plist 26 | 27 | # install 28 | include(../deploy/install.pri) 29 | 30 | win32 { 31 | install_service.files += $$PWD/kptserver-install.bat 32 | install_service.path = $$INSTALL_BINS 33 | } else:mac { 34 | install_service.files += $$PWD/de.skycoder42.kptransfer.server.plist 35 | install_service.path = $$INSTALL_SHARE/LaunchAgents 36 | } else: { 37 | create_service.target = kptserver.service 38 | create_service.depends += $$PWD/kptserver.service.in 39 | create_service.commands += sed "s:%{INSTALL_BINS}:$$INSTALL_BINS:g" $$PWD/kptserver.service.in > kptserver.service 40 | 41 | QMAKE_EXTRA_TARGETS += create_service 42 | PRE_TARGETDEPS += kptserver.service 43 | 44 | install_service.files += $$OUT_PWD/kptserver.service kptserver.socket 45 | install_service.CONFIG += no_check_exist 46 | install_service.path = $$INSTALL_LIBS/systemd/system/ 47 | } 48 | 49 | target.path = $$INSTALL_BINS 50 | qpmx_ts_target.path = $$INSTALL_TRANSLATIONS 51 | INSTALLS += target install_service qpmx_ts_target 52 | 53 | include($$SRC_ROOT_DIR/lib/lib.pri) 54 | 55 | !ReleaseBuild:!DebugBuild:!system(qpmx -d $$shell_quote($$_PRO_FILE_PWD_) --qmake-run init $$QPMX_EXTRA_OPTIONS $$shell_quote($$QMAKE_QMAKE) $$shell_quote($$OUT_PWD)): error(qpmx initialization failed. Check the compilation log for details.) 56 | else: include($$OUT_PWD/qpmx_generated.pri) 57 | -------------------------------------------------------------------------------- /server/transferserver.h: -------------------------------------------------------------------------------- 1 | #ifndef TRANSFERSERVER_H 2 | #define TRANSFERSERVER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | class TransferServer : public QObject 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | explicit TransferServer(qint64 timeout, QObject *parent = nullptr); 23 | 24 | bool startServer(const QString &serverName, int socket); 25 | bool startServer(const QString &serverName, bool localHostOnly, quint16 port); 26 | 27 | private slots: 28 | void newConnection(); 29 | 30 | void acceptError(QAbstractSocket::SocketError socketError); 31 | void serverError(QWebSocketProtocol::CloseCode closeCode); 32 | 33 | void onInvalidMessage(int typeId, QWebSocket *socket); 34 | void onInvalidMessage2(int typeId, QWebSocket *socket, QWebSocket *partnerSocket); 35 | 36 | void onAppIdent(const AppIdentMessage message, QWebSocket *socket); 37 | void onClientTransfer(ClientTransferMessage message, QWebSocket *clientSocket); 38 | void onAppOk(const AppOkMessage &message, QWebSocket *clientSocket); 39 | void onAppError(const ErrorMessage &message, QWebSocket *clientSocket); 40 | 41 | void timeout(); 42 | 43 | private: 44 | QWebSocketServer *_server = nullptr; 45 | QHash _appHash; 46 | 47 | QTimer *_timeoutTimer; 48 | const qint64 _timeout; 49 | QHash> _timeouts; 50 | 51 | void setup(); 52 | void setupCleanupConnections(QWebSocket *socket); 53 | 54 | bool verifyProtocolVersion(quint32 version, QWebSocket *socket); 55 | void closeOnTimeout(QWebSocket *socket, int timeout = 5000); 56 | }; 57 | 58 | #endif // TRANSFERSERVER_H 59 | -------------------------------------------------------------------------------- /update-icons.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | exec svgdump.py -a "$PWD/clients/quick/android/" -c "#4CAF50" --no-notify "$PWD/icon/kpt.svg" 3 | -------------------------------------------------------------------------------- /webapp/AboutDialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import QtQuick.Controls 2.4 3 | import de.skycoder42.kpt 1.0 4 | 5 | Dialog { 6 | id: errorDialog 7 | x: (appWindow.width - errorDialog.width) / 2 8 | y: (appWindow.height - errorDialog.height) / 2 9 | title: qsTr("About %1 — Version %2").arg(Qt.application.displayName).arg(Qt.application.version) 10 | standardButtons: Dialog.Ok 11 | modal: true 12 | 13 | Label { 14 | id: textLabel 15 | anchors.fill: parent 16 | text: qsTr("

A tool to securely transfer passwords and other credentials from any device to a remote computer for easy access anywhere.

17 |

Qt-Version: %1

18 |

Developed by: Skycoder42
19 | Project Website: https://github.com/Skycoder42/KeepassTransfer
20 | License: GPL-3.0

21 |

Attributions:

").arg(qtVersion) 33 | 34 | onLinkActivated: emjscon.openUrl(link) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /webapp/ErrorDialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import QtQuick.Controls 2.4 3 | import de.skycoder42.kpt 1.0 4 | 5 | Dialog { 6 | id: errorDialog 7 | x: (appWindow.width - errorDialog.width) / 2 8 | y: (appWindow.height - errorDialog.height) / 2 9 | title: qsTr("An Error occured!") 10 | standardButtons: Dialog.Ok 11 | modal: true 12 | closePolicy: Popup.CloseOnEscape 13 | 14 | property alias errorText: textLabel.text 15 | 16 | Connections { 17 | target: connector 18 | onServerError: { 19 | errorDialog.errorText = message; 20 | errorDialog.open(); 21 | } 22 | } 23 | 24 | Label { 25 | id: textLabel 26 | anchors.fill: parent 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /webapp/MainView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import QtQuick.Controls 2.4 3 | import QtQuick.Layouts 1.3 4 | import QtQuick.Controls.Material 2.4 5 | 6 | Page { 7 | id: mainView 8 | 9 | header: ToolBar { 10 | Material.background: Material.primary 11 | Material.foreground: "black" 12 | 13 | GridLayout { 14 | anchors.fill: parent 15 | columns: 2 16 | 17 | Label { 18 | Layout.preferredHeight: 56 19 | Layout.fillWidth: true 20 | text: Qt.application.displayName 21 | font.pointSize: 14 22 | font.bold: true 23 | elide: Label.ElideRight 24 | horizontalAlignment: Qt.AlignLeft 25 | verticalAlignment: Qt.AlignVCenter 26 | leftPadding: 16 27 | } 28 | 29 | ToolButton { 30 | id: aboutBtn 31 | flat: true 32 | icon.name: "help-about" 33 | icon.source: "qrc:/icons/about.svg" 34 | onClicked: aboutDialog.open() 35 | 36 | ToolTip.visible: pressed 37 | ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval 38 | ToolTip.text: qsTr("About %1").arg(Qt.application.displayName) 39 | } 40 | 41 | TabBar { 42 | id: modeBar 43 | currentIndex: modeView.currentIndex 44 | Layout.fillWidth: true 45 | Layout.columnSpan: 2 46 | 47 | TabButton { 48 | text: qsTr("QR-Code") 49 | } 50 | 51 | TabButton { 52 | text: qsTr("Password") 53 | } 54 | } 55 | } 56 | } 57 | 58 | SwipeView { 59 | id: modeView 60 | anchors.fill: parent 61 | currentIndex: modeBar.currentIndex 62 | 63 | QrTabView {} 64 | 65 | PassTabView {} 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /webapp/PassTabView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import QtQuick.Controls 2.4 3 | import QtQuick.Controls.Material 2.4 4 | import QtQuick.Layouts 1.3 5 | import Qt.labs.settings 1.0 6 | import de.skycoder42.kpt 1.0 7 | 8 | Pane { 9 | id: passView 10 | 11 | PassEncoder { 12 | id: encoder 13 | } 14 | 15 | ColumnLayout { 16 | id: contentLayout 17 | anchors.fill: parent 18 | 19 | GroupBox { 20 | id: passGroup 21 | title: qsTr("Passphrase and Identity") 22 | Layout.alignment: Qt.AlignHCenter | Qt.AlignTop 23 | Layout.preferredWidth: 500 24 | Layout.minimumWidth: 0 25 | 26 | GridLayout { 27 | anchors.fill: parent 28 | columns: 4 29 | columnSpacing: 16 30 | 31 | Label { 32 | text: qsTr("Identity:") 33 | Layout.alignment: Qt.AlignLeft 34 | } 35 | 36 | TextField { 37 | id: idField 38 | Layout.fillWidth: true 39 | Layout.columnSpan: 3 40 | readOnly: true 41 | selectByMouse: true 42 | text: connector.appIdStr 43 | } 44 | 45 | Label { 46 | text: qsTr("Passphrase:") 47 | Layout.alignment: Qt.AlignLeft 48 | } 49 | 50 | TextField { 51 | id: passField 52 | Layout.fillWidth: true 53 | selectByMouse: true 54 | echoMode: visButton.checked ? TextField.Normal : TextField.Password 55 | 56 | text: encoder.passphrase 57 | onTextEdited: encoder.passphrase = text 58 | } 59 | 60 | ToolButton { 61 | id: visButton 62 | flat: true 63 | checkable: true 64 | icon.name: checked ? "show_table_column" : "hide_table_column" 65 | icon.source: checked ? "qrc:/icons/show.svg" : "qrc:/icons/hide.svg" 66 | checked: false 67 | 68 | ToolTip.visible: pressed 69 | ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval 70 | ToolTip.text: qsTr("Toggle the visibility of the password") 71 | } 72 | 73 | ToolButton { 74 | id: generateButton 75 | flat: true 76 | icon.name: "password-generate" 77 | icon.source: "qrc:/icons/key.svg" 78 | onClicked: encoder.generateRandom() 79 | 80 | ToolTip.visible: pressed 81 | ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval 82 | ToolTip.text: qsTr("Generate a new, 16 character password") 83 | } 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /webapp/emjsconnector.cpp: -------------------------------------------------------------------------------- 1 | #include "emjsconnector.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | Q_GLOBAL_STATIC(EmJsConnector, clipInstance) 8 | 9 | EmJsConnector::EmJsConnector(QObject *parent) : 10 | QObject{parent} 11 | {} 12 | 13 | EmJsConnector *EmJsConnector::instance() 14 | { 15 | return clipInstance; 16 | } 17 | 18 | void EmJsConnector::updateClipboard(const QString &) {} 19 | 20 | QUrl EmJsConnector::getHostUrl() const 21 | { 22 | #ifdef QT_NO_DEBUG 23 | return QStringLiteral("wss://kpt.skycoder42.de/backend"); 24 | #else 25 | return QStringLiteral("ws://localhost:27352"); 26 | #endif 27 | } 28 | 29 | void EmJsConnector::setTag(const QString &) {} 30 | 31 | void EmJsConnector::openUrl(const QUrl &url) 32 | { 33 | QDesktopServices::openUrl(url); 34 | } 35 | 36 | void EmJsConnector::copyText(const QString &text) 37 | { 38 | QGuiApplication::clipboard()->setText(text); 39 | } 40 | 41 | void EmJsConnector::qtDataChanged() {} 42 | 43 | void EmJsConnector::readJsClipboard() {} 44 | -------------------------------------------------------------------------------- /webapp/emjsconnector.h: -------------------------------------------------------------------------------- 1 | #ifndef EMJSCONNECTOR_H 2 | #define EMJSCONNECTOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class EmJsConnector : public QObject 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | explicit EmJsConnector(QObject *parent = nullptr); 14 | 15 | static EmJsConnector *instance(); 16 | 17 | void updateClipboard(const QString &text); 18 | 19 | QUrl getHostUrl() const; 20 | 21 | public slots: 22 | void setTag(const QString &tag); 23 | void openUrl(const QUrl &url); 24 | 25 | void copyText(const QString &text); 26 | 27 | signals: 28 | void tagChanged(const QString &tag); 29 | 30 | private slots: 31 | void qtDataChanged(); 32 | void readJsClipboard(); 33 | 34 | private: 35 | QClipboard * const _qtClipboard = nullptr; 36 | bool _skipNext = false; 37 | }; 38 | 39 | #endif // EMJSCONNECTOR_H 40 | -------------------------------------------------------------------------------- /webapp/emjsconnector_wasm.cpp: -------------------------------------------------------------------------------- 1 | #include "emjsconnector.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | using namespace emscripten; 10 | 11 | Q_GLOBAL_STATIC(EmJsConnector, clipInstance) 12 | 13 | namespace { 14 | 15 | void onGetTextCallback(val text) { 16 | clipInstance->updateClipboard(QString::fromStdString(text.as())); 17 | } 18 | 19 | void onPopState(val event) { 20 | Q_UNUSED(event) 21 | auto location = val::global("location"); 22 | emit clipInstance->tagChanged(QString::fromStdString(location["hash"].as()).mid(1)); 23 | } 24 | 25 | } 26 | 27 | EMSCRIPTEN_BINDINGS(EmJsConnectorModule) { 28 | function("onGetTextCallback", &onGetTextCallback); 29 | function("onPopState", &onPopState); 30 | } 31 | 32 | EmJsConnector::EmJsConnector(QObject *parent) : 33 | QObject{parent}, 34 | _qtClipboard{QGuiApplication::clipboard()} 35 | { 36 | connect(_qtClipboard, &QClipboard::dataChanged, 37 | this, &EmJsConnector::qtDataChanged); 38 | 39 | auto cpTimer = new QTimer{this}; 40 | cpTimer->setTimerType(Qt::CoarseTimer); 41 | connect(cpTimer, &QTimer::timeout, 42 | this, &EmJsConnector::readJsClipboard); 43 | cpTimer->start(500); 44 | 45 | auto window = val::global("window"); 46 | window.set("onpopstate", val::module_property("onPopState")); 47 | } 48 | 49 | EmJsConnector *EmJsConnector::instance() 50 | { 51 | return clipInstance; 52 | } 53 | 54 | void EmJsConnector::updateClipboard(const QString &text) 55 | { 56 | _skipNext = true; 57 | _qtClipboard->setText(text); 58 | } 59 | 60 | QUrl EmJsConnector::getHostUrl() const 61 | { 62 | #ifdef QT_NO_DEBUG 63 | auto location = val::global("location"); 64 | return QStringLiteral("wss://%1/backend").arg(QString::fromStdString(location["host"].as())); 65 | #else 66 | return QStringLiteral("ws://localhost:27352"); 67 | #endif 68 | } 69 | 70 | void EmJsConnector::setTag(const QString &tag) 71 | { 72 | auto location = val::global("location"); 73 | location.set("hash", "#" + tag.toStdString()); 74 | } 75 | 76 | void EmJsConnector::openUrl(const QUrl &url) 77 | { 78 | auto window = val::global("window"); 79 | window.call("open", 80 | url.toString(QUrl::FullyEncoded).toStdString(), 81 | std::string{"_blank"}); 82 | } 83 | 84 | void EmJsConnector::copyText(const QString &text) 85 | { 86 | _qtClipboard->setText(text); 87 | } 88 | 89 | void EmJsConnector::qtDataChanged() 90 | { 91 | if(_skipNext) { 92 | _skipNext = false; 93 | return; 94 | } 95 | 96 | auto navigator = val::global("navigator"); 97 | auto clipboard = navigator["clipboard"]; 98 | clipboard.call("writeText", _qtClipboard->text().toStdString()); 99 | } 100 | 101 | void EmJsConnector::readJsClipboard() 102 | { 103 | auto navigator = val::global("navigator"); 104 | auto clipboard = navigator["clipboard"]; 105 | auto promise = clipboard.call("readText"); 106 | promise.call("then", val::module_property("onGetTextCallback")); 107 | } 108 | -------------------------------------------------------------------------------- /webapp/icons/baseline-arrow_back-24px.svg: -------------------------------------------------------------------------------- 1 | ../../icon/external/flat/baseline-arrow_back-24px.svg -------------------------------------------------------------------------------- /webapp/icons/baseline-file_copy-24px.svg: -------------------------------------------------------------------------------- 1 | ../../icon/external/flat/baseline-file_copy-24px.svg -------------------------------------------------------------------------------- /webapp/icons/baseline-visibility-24px.svg: -------------------------------------------------------------------------------- 1 | ../../icon/external/flat/baseline-visibility-24px.svg -------------------------------------------------------------------------------- /webapp/icons/baseline-visibility_off-24px.svg: -------------------------------------------------------------------------------- 1 | ../../icon/external/flat/baseline-visibility_off-24px.svg -------------------------------------------------------------------------------- /webapp/icons/baseline-vpn_key-24px.svg: -------------------------------------------------------------------------------- 1 | ../../icon/external/flat/baseline-vpn_key-24px.svg -------------------------------------------------------------------------------- /webapp/icons/kpt.svg: -------------------------------------------------------------------------------- 1 | ../../icon/kpt.svg -------------------------------------------------------------------------------- /webapp/icons/outline-info-24px.svg: -------------------------------------------------------------------------------- 1 | ../../icon/external/flat/outline-info-24px.svg -------------------------------------------------------------------------------- /webapp/iencoder.cpp: -------------------------------------------------------------------------------- 1 | #include "iencoder.h" 2 | #include 3 | #include 4 | using namespace CryptoPP; 5 | 6 | QHash> IEncoder::_encoders; 7 | 8 | IEncoder::IEncoder(QObject *parent) : 9 | QObject{parent}, 10 | _encryptor{new DataEncryptor{this}} 11 | {} 12 | 13 | QList IEncoder::decodeData(const EncryptedData &data) 14 | { 15 | try { 16 | auto encoder = _encoders.value(data.mode); 17 | if(!encoder) { 18 | qCritical() << "Unable to find a decoder for mode:" << data.mode; 19 | return {}; 20 | } 21 | 22 | const auto rawData = encoder->decryptData(data.keyInfo, data.iv, data.data); 23 | return KPTLib::decode>(rawData); 24 | } catch(std::exception &e) { 25 | qCritical() << "Failed to decrypt data with error:" << e.what(); 26 | return {}; 27 | } 28 | } 29 | 30 | void IEncoder::registerEncoder(EncryptedData::DataMode mode, IEncoder *encoder) 31 | { 32 | Q_ASSERT_X(!_encoders.value(mode), Q_FUNC_INFO, "Only one encoder can be registered for each mode at a time"); 33 | _encoders.insert(mode, encoder); 34 | } 35 | 36 | RandomNumberGenerator &IEncoder::rng() const 37 | { 38 | return _rng; 39 | } 40 | 41 | const DataEncryptor *IEncoder::encryptor() const 42 | { 43 | return _encryptor; 44 | } 45 | -------------------------------------------------------------------------------- /webapp/iencoder.h: -------------------------------------------------------------------------------- 1 | #ifndef IENCODER_H 2 | #define IENCODER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | class IEncoder : public QObject 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | explicit IEncoder(QObject *parent = nullptr); 20 | 21 | static QList decodeData(const EncryptedData &data); 22 | 23 | protected: 24 | static void registerEncoder(EncryptedData::DataMode mode, IEncoder *encoder); 25 | 26 | CryptoPP::RandomNumberGenerator &rng() const; 27 | const DataEncryptor *encryptor() const; 28 | 29 | virtual QByteArray decryptData(const QByteArray &keyInfo, 30 | const QByteArray &iv, 31 | const QByteArray &data) const = 0; 32 | 33 | private: 34 | static QHash> _encoders; 35 | 36 | mutable CryptoPP::AutoSeededRandomPool _rng; 37 | DataEncryptor *_encryptor; 38 | }; 39 | 40 | #endif // IENCODER_H 41 | -------------------------------------------------------------------------------- /webapp/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "qrencoder.h" 10 | #include "passencoder.h" 11 | #include "qrimageprovider.h" 12 | #include "emjsconnector.h" 13 | 14 | #ifdef QT_OS_WASM 15 | #include "qwasmsettings.h" 16 | #endif 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 21 | 22 | QGuiApplication app(argc, argv); 23 | QCoreApplication::setApplicationName(QStringLiteral(PROJECT_TARGET)); 24 | QCoreApplication::setApplicationVersion(QStringLiteral(VERSION)); 25 | QCoreApplication::setOrganizationName(QStringLiteral(COMPANY)); 26 | QCoreApplication::setOrganizationDomain(QStringLiteral(BUNDLE)); 27 | QGuiApplication::setApplicationDisplayName(QStringLiteral(PROJECT_NAME)); 28 | QGuiApplication::setWindowIcon(QIcon{QStringLiteral(":/icons/main.svg")}); 29 | 30 | #ifdef QT_OS_WASM 31 | QWasmSettings::registerFormat(); 32 | #endif 33 | 34 | KPTLib::setup(); 35 | 36 | qmlRegisterUncreatableType("de.skycoder42.kpt", 1, 0, "Credential", {}); 37 | qmlRegisterUncreatableType("de.skycoder42.kpt", 1, 0, "ServerConnector", {}); 38 | qmlRegisterUncreatableType("de.skycoder42.kpt", 1, 0, "DataEncryptor", {}); 39 | qmlRegisterType("de.skycoder42.kpt", 1, 0, "QrEncoder"); 40 | qmlRegisterType("de.skycoder42.kpt", 1, 0, "PassEncoder"); 41 | 42 | ServerConnector connector{EmJsConnector::instance()->getHostUrl()}; 43 | 44 | QQmlApplicationEngine engine; 45 | engine.addImageProvider(QStringLiteral("qrcode"), new QrImageProvider{}); 46 | engine.rootContext()->setContextProperty(QStringLiteral("connector"), &connector); 47 | engine.rootContext()->setContextProperty(QStringLiteral("emjscon"), EmJsConnector::instance()); 48 | engine.rootContext()->setContextProperty(QStringLiteral("qtVersion"), QStringLiteral(QT_VERSION_STR)); 49 | 50 | engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); 51 | if (engine.rootObjects().isEmpty()) 52 | return -1; 53 | 54 | return app.exec(); 55 | } 56 | -------------------------------------------------------------------------------- /webapp/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import QtQuick.Window 2.11 3 | import QtQuick.Controls 2.4 4 | import QtQuick.Layouts 1.3 5 | import QtQuick.Controls.Material 2.4 6 | 7 | ApplicationWindow { 8 | id: appWindow 9 | visible: true 10 | width: 960 11 | height: 720 12 | title: Qt.application.displayName 13 | 14 | StackView { 15 | id: mainStack 16 | anchors.fill: parent 17 | initialItem: MainView { 18 | } 19 | 20 | Component { 21 | id: credentialsViewComponent 22 | CredentialsView {} 23 | } 24 | 25 | onCurrentItemChanged: emjscon.setTag(mainStack.depth) 26 | 27 | Connections { 28 | target: connector 29 | onCredentialsReceived: { 30 | mainStack.push(credentialsViewComponent, { 31 | credentials: receivedCreds, 32 | idCred: entryTitle 33 | }); 34 | } 35 | } 36 | 37 | Connections { 38 | target: emjscon 39 | onTagChanged: { 40 | if(tag != "") { 41 | var index = Number(tag); 42 | if(tag < mainStack.depth) 43 | mainStack.pop(mainStack.get(index - 1, StackView.ForceLoad)); 44 | } 45 | } 46 | } 47 | } 48 | 49 | ErrorDialog {} 50 | 51 | AboutDialog { 52 | id: aboutDialog 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /webapp/passencoder.cpp: -------------------------------------------------------------------------------- 1 | #include "passencoder.h" 2 | 3 | PassEncoder::PassEncoder(QObject *parent) : 4 | IEncoder{parent} 5 | { 6 | registerEncoder(EncryptedData::DataMode::Password, this); 7 | } 8 | 9 | QString PassEncoder::passphrase() const 10 | { 11 | return _passphrase; 12 | } 13 | 14 | void PassEncoder::setPassphrase(QString passphrase) 15 | { 16 | if (_passphrase == passphrase) 17 | return; 18 | 19 | _passphrase = std::move(passphrase); 20 | emit passphraseChanged(_passphrase); 21 | } 22 | 23 | void PassEncoder::generateRandom() 24 | { 25 | QByteArray rndBlock{12, Qt::Uninitialized}; 26 | rng().GenerateBlock(reinterpret_cast(rndBlock.data()), 27 | static_cast(rndBlock.size())); 28 | setPassphrase(QString::fromUtf8(rndBlock.toBase64(QByteArray::OmitTrailingEquals))); 29 | } 30 | 31 | QByteArray PassEncoder::decryptData(const QByteArray &keyInfo, const QByteArray &iv, const QByteArray &data) const 32 | { 33 | const auto secretKey = encryptor()->generateSecretKey(_passphrase, keyInfo); 34 | return encryptor()->decryptSymmetric(data, secretKey, iv); 35 | } 36 | -------------------------------------------------------------------------------- /webapp/passencoder.h: -------------------------------------------------------------------------------- 1 | #ifndef PASSENCODER_H 2 | #define PASSENCODER_H 3 | 4 | #include "iencoder.h" 5 | #include 6 | 7 | class PassEncoder : public IEncoder 8 | { 9 | Q_OBJECT 10 | 11 | Q_PROPERTY(QString passphrase READ passphrase WRITE setPassphrase NOTIFY passphraseChanged) 12 | 13 | public: 14 | explicit PassEncoder(QObject *parent = nullptr); 15 | 16 | QString passphrase() const; 17 | 18 | public slots: 19 | void setPassphrase(QString passphrase); 20 | 21 | void generateRandom(); 22 | 23 | signals: 24 | void passphraseChanged(const QString &passphrase); 25 | 26 | protected: 27 | QByteArray decryptData(const QByteArray &keyInfo, const QByteArray &iv, const QByteArray &data) const override; 28 | 29 | private: 30 | QString _passphrase; 31 | }; 32 | 33 | #endif // PASSENCODER_H 34 | -------------------------------------------------------------------------------- /webapp/qrencoder.cpp: -------------------------------------------------------------------------------- 1 | #include "qrencoder.h" 2 | #include 3 | #include 4 | #include 5 | using namespace CryptoPP; 6 | 7 | QrEncoder::QrEncoder(QObject *parent) : 8 | IEncoder{parent} 9 | { 10 | registerEncoder(EncryptedData::DataMode::QrCode, this); 11 | } 12 | 13 | DataEncryptor::ECCCurve QrEncoder::curve() const 14 | { 15 | return _curve; 16 | } 17 | 18 | QUuid QrEncoder::channelId() const 19 | { 20 | return _channelId; 21 | } 22 | 23 | QString QrEncoder::qrData() const 24 | { 25 | try { 26 | if(!_privKey) 27 | return {}; 28 | 29 | if(_pubKey.isNull()) { 30 | _qrData.clear(); 31 | _pubKey = encryptor()->serializePublicKey(_privKey); 32 | } 33 | 34 | if(_qrData.isNull()) 35 | _qrData = QString::fromUtf8(KPTLib::encode(QrData{_channelId, _pubKey}, true)); 36 | 37 | return _qrData; 38 | } catch(std::exception &e) { 39 | qCritical() << "Failed to obtain public key from private key with error:" 40 | << e.what(); 41 | return {}; 42 | } 43 | } 44 | 45 | bool QrEncoder::isValid() const 46 | { 47 | return _privKey && !_channelId.isNull(); 48 | } 49 | 50 | void QrEncoder::classBegin() 51 | { 52 | _blocked = true; 53 | } 54 | 55 | void QrEncoder::componentComplete() 56 | { 57 | _blocked = false; 58 | recreateKeys(); 59 | } 60 | 61 | void QrEncoder::recreateKeys() 62 | { 63 | if(_blocked) 64 | return; 65 | 66 | try { 67 | //NOTE make async 68 | _privKey.clear(); 69 | _pubKey.clear(); 70 | _qrData.clear(); 71 | emit qrDataChanged({}); 72 | _privKey = encryptor()->generateAsymKey(rng(), _curve); 73 | emit qrDataChanged({}); 74 | } catch(std::exception &e) { 75 | qCritical() << "Failed to generate new private key with error:" 76 | << e.what(); 77 | } 78 | } 79 | 80 | void QrEncoder::setCurve(DataEncryptor::ECCCurve curve) 81 | { 82 | if (_curve == curve) 83 | return; 84 | 85 | _curve = curve; 86 | emit curveChanged(_curve); 87 | recreateKeys(); 88 | } 89 | 90 | void QrEncoder::setChannelId(QUuid channelId) 91 | { 92 | if (_channelId == channelId) 93 | return; 94 | 95 | _channelId = std::move(channelId); 96 | _qrData.clear(); 97 | emit qrDataChanged({}); 98 | } 99 | 100 | QByteArray QrEncoder::decryptData(const QByteArray &keyInfo, const QByteArray &iv, const QByteArray &data) const 101 | { 102 | const auto secretKey = encryptor()->decryptSecretKey(rng(), keyInfo, _privKey); 103 | return encryptor()->decryptSymmetric(data, secretKey, iv); 104 | } 105 | -------------------------------------------------------------------------------- /webapp/qrencoder.h: -------------------------------------------------------------------------------- 1 | #ifndef QRENCODER_H 2 | #define QRENCODER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class QrEncoder : public IEncoder, public QQmlParserStatus 10 | { 11 | Q_OBJECT 12 | Q_INTERFACES(QQmlParserStatus) 13 | 14 | Q_PROPERTY(DataEncryptor::ECCCurve curve READ curve WRITE setCurve NOTIFY curveChanged) 15 | 16 | Q_PROPERTY(QUuid channelId READ channelId WRITE setChannelId NOTIFY qrDataChanged) 17 | Q_PROPERTY(QString qrData READ qrData NOTIFY qrDataChanged) 18 | Q_PROPERTY(bool valid READ isValid NOTIFY qrDataChanged) 19 | 20 | public: 21 | explicit QrEncoder(QObject *parent = nullptr); 22 | 23 | DataEncryptor::ECCCurve curve() const; 24 | QUuid channelId() const; 25 | QString qrData() const; 26 | bool isValid() const; 27 | 28 | void classBegin() override; 29 | void componentComplete() override; 30 | 31 | public slots: 32 | void recreateKeys(); 33 | 34 | void setCurve(DataEncryptor::ECCCurve curve); 35 | void setChannelId(QUuid channelId); 36 | 37 | signals: 38 | void qrDataChanged(QPrivateSignal); 39 | void curveChanged(DataEncryptor::ECCCurve curve); 40 | 41 | protected: 42 | QByteArray decryptData(const QByteArray &keyInfo, const QByteArray &iv, const QByteArray &data) const override; 43 | 44 | private: 45 | DataEncryptor::ECCCurve _curve = DataEncryptor::ECCCurve::secp256r1; 46 | 47 | bool _blocked = false; 48 | QSharedPointer _privKey; 49 | QUuid _channelId; 50 | 51 | mutable QByteArray _pubKey; 52 | mutable QString _qrData; 53 | }; 54 | 55 | #endif // QRENCODER_H 56 | -------------------------------------------------------------------------------- /webapp/qrimageprovider.cpp: -------------------------------------------------------------------------------- 1 | #include "qrimageprovider.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace qrcodegen; 11 | 12 | QrImageProvider::QrImageProvider() : 13 | QQuickImageProvider{QQmlImageProviderBase::Image} 14 | {} 15 | 16 | QImage QrImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) 17 | { 18 | QUrl requestUrl{QStringLiteral("qrcode:///") + id}; 19 | const auto imageData = requestUrl.path().mid(1); 20 | const QUrlQuery params{requestUrl.query()}; 21 | const auto eccLevel = params.queryItemValue(QStringLiteral("eccLevel")); 22 | const auto border = params.hasQueryItem(QStringLiteral("border")) ? 23 | params.queryItemValue(QStringLiteral("border")).toInt() : 24 | 1; 25 | 26 | QrCode::Ecc ecc; 27 | if(eccLevel == QLatin1Char('L')) 28 | ecc = QrCode::Ecc::LOW; 29 | else if(eccLevel == QLatin1Char('M')) 30 | ecc = QrCode::Ecc::MEDIUM; 31 | else if(eccLevel == QLatin1Char('Q')) 32 | ecc = QrCode::Ecc::QUARTILE; 33 | else if(eccLevel == QLatin1Char('H')) 34 | ecc = QrCode::Ecc::HIGH; 35 | else 36 | ecc = QrCode::Ecc::LOW; 37 | 38 | const auto qrCode = QrCode::encodeText(qUtf8Printable(imageData), ecc); 39 | QSvgRenderer renderer{QByteArray::fromStdString(qrCode.toSvgString(border))}; 40 | 41 | if(requestedSize.isValid()) 42 | *size = requestedSize; 43 | else { 44 | *size = renderer.defaultSize(); 45 | *size *= QGuiApplication::primaryScreen()->devicePixelRatio(); 46 | } 47 | 48 | QImage image{*size, QImage::Format_Mono}; 49 | image.fill(Qt::transparent); 50 | QPainter painter{&image}; 51 | renderer.render(&painter); 52 | 53 | return image; 54 | } 55 | -------------------------------------------------------------------------------- /webapp/qrimageprovider.h: -------------------------------------------------------------------------------- 1 | #ifndef QRIMAGEPROVIDER_H 2 | #define QRIMAGEPROVIDER_H 3 | 4 | #include 5 | 6 | class QrImageProvider : public QQuickImageProvider 7 | { 8 | public: 9 | QrImageProvider(); 10 | 11 | QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override; 12 | }; 13 | 14 | #endif // QRIMAGEPROVIDER_H 15 | -------------------------------------------------------------------------------- /webapp/qtquickcontrols2.conf: -------------------------------------------------------------------------------- 1 | [Controls] 2 | Style=Material 3 | 4 | [Material] 5 | Theme=Dark 6 | Primary=#8BC34A 7 | PrimaryDark=#689F38 8 | Accent=#7C4DFF 9 | -------------------------------------------------------------------------------- /webapp/qwasmsettings.cpp: -------------------------------------------------------------------------------- 1 | #include "qwasmsettings.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | using namespace emscripten; 8 | 9 | QSettings::Format QWasmSettings::registerFormat() 10 | { 11 | const auto format = QSettings::registerFormat(QStringLiteral("wasmconf"), 12 | &QWasmSettings::readWasmSettings, 13 | &QWasmSettings::writeWasmSettings, 14 | Qt::CaseSensitive); 15 | QSettings::setPath(format, QSettings::UserScope, QDir::tempPath()); 16 | QSettings::setPath(format, QSettings::SystemScope, QDir::tempPath()); 17 | QSettings::setDefaultFormat(format); 18 | 19 | QSettings mPathOrigin; 20 | prepareFile(mPathOrigin.fileName()); 21 | return format; 22 | } 23 | 24 | void QWasmSettings::prepareFile(const QString &path) 25 | { 26 | QFileInfo{path}.dir().mkpath(QStringLiteral(".")); 27 | QFile sFile{path}; 28 | if(!sFile.open(QIODevice::WriteOnly)) { 29 | qWarning() << "QWasmSettings: Failed to prepare path" 30 | << path << "with error:" << qUtf8Printable(sFile.errorString()); 31 | return; 32 | } 33 | 34 | sFile.write(QUuid::createUuid().toByteArray()); 35 | sFile.close(); 36 | } 37 | 38 | bool QWasmSettings::readWasmSettings(QIODevice &device, QSettings::SettingsMap &map) 39 | { 40 | Q_UNUSED(device); 41 | 42 | auto store = val::global("localStorage"); 43 | if(store.isNull()) 44 | return false; 45 | 46 | const auto keyCount = store["length"].as(); 47 | for(auto i = 0; i < keyCount; ++i) { 48 | const auto key = store.call("key", i); 49 | const auto value = store.call("getItem", key).as(); 50 | map.insert(QString::fromStdString(key), 51 | QString::fromStdString(value)); 52 | } 53 | 54 | return true; 55 | } 56 | 57 | bool QWasmSettings::writeWasmSettings(QIODevice &device, const QSettings::SettingsMap &map) 58 | { 59 | auto store = val::global("localStorage"); 60 | if(store.isNull()) 61 | return false; 62 | 63 | store.call("clear"); 64 | for(auto it = map.constBegin(); it != map.constEnd(); ++it) { 65 | store.call("setItem", 66 | it.key().toStdString(), 67 | it.value().toString().toStdString()); 68 | } 69 | 70 | device.write(QUuid::createUuid().toByteArray()); 71 | return true; 72 | } 73 | -------------------------------------------------------------------------------- /webapp/qwasmsettings.h: -------------------------------------------------------------------------------- 1 | #ifndef QWASMSETTINGS_H 2 | #define QWASMSETTINGS_H 3 | 4 | #include 5 | 6 | class QWasmSettings 7 | { 8 | Q_DISABLE_COPY(QWasmSettings) 9 | public: 10 | QWasmSettings() = delete; 11 | 12 | static QSettings::Format registerFormat(); 13 | static void prepareFile(const QString &path); 14 | 15 | private: 16 | static bool readWasmSettings(QIODevice &device, QSettings::SettingsMap &map); 17 | static bool writeWasmSettings(QIODevice &device, const QSettings::SettingsMap &map); 18 | }; 19 | 20 | #endif // QWASMSETTINGS_H 21 | -------------------------------------------------------------------------------- /webapp/serverconnector.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVERCONNECTOR_H 2 | #define SERVERCONNECTOR_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class ServerConnector : public QObject 13 | { 14 | Q_OBJECT 15 | 16 | Q_PROPERTY(bool connected READ isConnected NOTIFY connectedChanged) 17 | Q_PROPERTY(QUuid appId READ appId NOTIFY appIdChanged) 18 | Q_PROPERTY(QString appIdStr READ appIdStr NOTIFY appIdChanged) 19 | 20 | public: 21 | explicit ServerConnector(QUrl url, 22 | QObject *parent = nullptr); 23 | 24 | bool isConnected() const; 25 | QUuid appId() const; 26 | QString appIdStr() const; 27 | 28 | signals: 29 | void credentialsReceived(const QVariantList &receivedCreds, const QString &entryTitle); 30 | void serverError(const QString &message); 31 | 32 | void connectedChanged(bool connected, QPrivateSignal); 33 | void appIdChanged(QPrivateSignal); 34 | 35 | private slots: 36 | void connected(); 37 | void disconnected(); 38 | void error(QAbstractSocket::SocketError error); 39 | void binaryMessageReceived(const QByteArray &message); 40 | 41 | void recreateSocket(); 42 | 43 | private: 44 | const QUrl _serverUrl; 45 | QWebSocket *_socket = nullptr; 46 | QUuid _appId; 47 | 48 | int _retryTimeout = 1000; 49 | 50 | void onServerIdent(const ServerIdentMessage message); 51 | void onError(const ErrorMessage &message); 52 | void onServerTransfer(const ServerTransferMessage &message); 53 | void onFallback(int typeId); 54 | }; 55 | 56 | #endif // SERVERCONNECTOR_H 57 | -------------------------------------------------------------------------------- /webapp/webapp.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT += quick websockets svg quickcontrols2 4 | CONFIG(release, debug|release): CONFIG += qtquickcompiler 5 | 6 | QTPLUGIN.imageformats = qsvg 7 | 8 | # hack to exclude QML plugins: 9 | ADDED_IMPORTS += \ 10 | qtquickcontrols2universalstyleplugin \ 11 | qtquickcontrols2fusionstyleplugin \ 12 | qtquickcontrols2imaginestyleplugin 13 | 14 | TARGET = $${PROJECT_TARGET}-webapp 15 | 16 | QMAKE_TARGET_DESCRIPTION = "$$PROJECT_NAME Webapp" 17 | RC_ICONS += ../../icon/kpt.ico 18 | ICON += ../../icon/kpt.icns 19 | 20 | HEADERS += \ 21 | serverconnector.h \ 22 | iencoder.h \ 23 | qrencoder.h \ 24 | qrimageprovider.h \ 25 | emjsconnector.h \ 26 | passencoder.h 27 | 28 | SOURCES += \ 29 | main.cpp \ 30 | serverconnector.cpp \ 31 | iencoder.cpp \ 32 | qrencoder.cpp \ 33 | qrimageprovider.cpp \ 34 | passencoder.cpp 35 | 36 | RESOURCES += \ 37 | webapp.qrc 38 | 39 | wasm { 40 | HEADERS += \ 41 | qwasmsettings.h 42 | 43 | SOURCES += \ 44 | qwasmsettings.cpp \ 45 | emjsconnector_wasm.cpp 46 | } else { 47 | SOURCES += \ 48 | emjsconnector.cpp 49 | } 50 | 51 | include($$SRC_ROOT_DIR/lib/lib.pri) 52 | include($$SRC_ROOT_DIR/3rdparty/QR-Code-generator/QR-Code-generator.pri) 53 | include($$SRC_ROOT_DIR/deploy/install.pri) 54 | 55 | wasm { 56 | # adjust HTML file 57 | html_fixup_target.target = index.html 58 | html_fixup_target.depends = shellfiles 59 | 60 | REP_STR = 61 | WASM_ICON_SIZES = 16 32 48 64 96 128 256 512 62 | for(pngSize, WASM_ICON_SIZES) { 63 | equals(pngSize, "16") { 64 | REL_STR="shortcut icon" 65 | SIZE_STR= 66 | } else { 67 | REL_STR="icon" 68 | SIZE_STR="sizes=\"$${pngSize}x$${pngSize}\"" 69 | } 70 | REP_STR += "" 71 | wasm_install.files += "../icon/pngs/kpt_$${pngSize}.png" 72 | } 73 | html_fixup_target.commands += sed $$shell_quote(s:$$TARGET:$$PROJECT_NAME$$REP_STR:g) $$shell_path($$OUT_PWD/$${TARGET}.html) > index.html 74 | QMAKE_EXTRA_TARGETS += html_fixup_target 75 | PRE_TARGETDEPS += index.html 76 | 77 | # shellfile target hack 78 | shellfiles_target.target = shellfiles 79 | shellfiles_target.commands += \ 80 | @touch apphtml \ 81 | $$escape_expand(\n\t)@touch appjs \ 82 | $$escape_expand(\n\t)@touch appsvg \ 83 | $$escape_expand(\n\t)@touch shellfiles 84 | QMAKE_EXTRA_TARGETS += shellfiles_target 85 | 86 | wasm_install.files += $$OUT_PWD/index.html \ 87 | $$OUT_PWD/$${TARGET}.wasm \ 88 | $$OUT_PWD/$${TARGET}.js \ 89 | $$OUT_PWD/qtloader.js \ 90 | $$OUT_PWD/qtlogo.svg 91 | wasm_install.CONFIG += no_check_exist 92 | wasm_install.path = $$INSTALL_WWW 93 | target.path = $$INSTALL_WWW 94 | INSTALLS += wasm_install 95 | } else { 96 | target.path = $$INSTALL_BINS 97 | INSTALLS += target 98 | } 99 | 100 | QMAKE_EXTRA_TARGETS += lrelease 101 | -------------------------------------------------------------------------------- /webapp/webapp.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | ErrorDialog.qml 5 | MainView.qml 6 | QrTabView.qml 7 | CredentialsView.qml 8 | AboutDialog.qml 9 | PassTabView.qml 10 | 11 | 12 | qtquickcontrols2.conf 13 | 14 | 15 | icons/baseline-visibility_off-24px.svg 16 | icons/baseline-visibility-24px.svg 17 | icons/baseline-file_copy-24px.svg 18 | icons/kpt.svg 19 | icons/baseline-arrow_back-24px.svg 20 | icons/outline-info-24px.svg 21 | icons/baseline-vpn_key-24px.svg 22 | 23 | 24 | --------------------------------------------------------------------------------