> _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