Files
amnezia-client/client/ui/pages_logic/StartPageLogic.cpp
T

329 lines
10 KiB
C++
Raw Normal View History

2021-09-04 12:53:58 +03:00
#include "StartPageLogic.h"
2022-08-29 01:32:42 +03:00
#include "ViewConfigLogic.h"
2021-09-04 12:53:58 +03:00
#include "core/errorstrings.h"
#include "configurators/ssh_configurator.h"
2022-08-25 17:35:28 +03:00
#include "configurators/vpn_configurator.h"
2021-09-06 12:29:56 +03:00
#include "../uilogic.h"
#include "utilities.h"
2021-09-04 12:53:58 +03:00
2021-12-20 02:29:23 +03:00
#include <QFileDialog>
#include <QStandardPaths>
#ifdef Q_OS_ANDROID
2022-12-23 17:32:20 +03:00
#include <QJniObject>
2022-12-27 15:37:58 +03:00
#include "../../platforms/android/androidutils.h"
2021-12-20 02:29:23 +03:00
#endif
2022-11-01 23:12:42 +03:00
namespace {
enum class ConfigTypes {
Amnezia,
OpenVpn,
WireGuard
};
ConfigTypes checkConfigFormat(const QString &config)
2022-11-01 23:12:42 +03:00
{
const QString openVpnConfigPatternCli = "client";
const QString openVpnConfigPatternProto1 = "proto tcp";
const QString openVpnConfigPatternProto2 = "proto udp";
const QString openVpnConfigPatternDriver1 = "dev tun";
const QString openVpnConfigPatternDriver2 = "dev tap";
2022-11-03 23:39:58 +03:00
const QString wireguardConfigPatternSectionInterface = "[Interface]";
const QString wireguardConfigPatternSectionPeer = "[Peer]";
2022-11-01 23:12:42 +03:00
if (config.contains(openVpnConfigPatternCli) &&
(config.contains(openVpnConfigPatternProto1) || config.contains(openVpnConfigPatternProto2)) &&
(config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) {
return ConfigTypes::OpenVpn;
2022-11-03 23:39:58 +03:00
} else if (config.contains(wireguardConfigPatternSectionInterface) &&
config.contains(wireguardConfigPatternSectionPeer))
return ConfigTypes::WireGuard;
return ConfigTypes::Amnezia;
2022-11-01 23:12:42 +03:00
}
}
2021-09-07 21:01:56 +03:00
StartPageLogic::StartPageLogic(UiLogic *logic, QObject *parent):
PageLogicBase(logic, parent),
2021-09-08 14:23:02 +03:00
m_pushButtonConnectEnabled{true},
m_pushButtonConnectText{tr("Connect")},
m_pushButtonConnectKeyChecked{false},
m_labelWaitInfoVisible{true},
2021-09-04 12:53:58 +03:00
m_pushButtonBackFromStartVisible{true},
2021-12-25 23:01:53 +03:00
m_ipAddressPortRegex{Utils::ipAddressPortRegExp()}
2021-09-04 12:53:58 +03:00
{
2022-09-23 21:50:25 +03:00
#ifdef Q_OS_ANDROID
// Set security screen for Android app
2022-12-23 17:32:20 +03:00
AndroidUtils::runOnAndroidThreadSync([]() {
QJniObject activity = AndroidUtils::getActivity();
QJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;");
2022-09-23 21:50:25 +03:00
if (window.isValid()){
const int FLAG_SECURE = 8192;
window.callMethod<void>("addFlags", "(I)V", FLAG_SECURE);
}
});
#endif
2021-09-04 12:53:58 +03:00
}
void StartPageLogic::onUpdatePage()
2021-09-04 12:53:58 +03:00
{
2021-09-08 13:52:36 +03:00
set_lineEditStartExistingCodeText("");
2021-09-08 14:23:02 +03:00
set_textEditSshKeyText("");
set_lineEditIpText("");
set_lineEditPasswordText("");
set_textEditSshKeyText("");
set_lineEditLoginText("");
2021-09-04 12:53:58 +03:00
2021-09-08 14:23:02 +03:00
set_labelWaitInfoVisible(false);
set_labelWaitInfoText("");
set_pushButtonConnectKeyChecked(false);
2021-11-06 13:47:52 +03:00
set_pushButtonBackFromStartVisible(uiLogic()->pagesStackDepth() > 0);
2021-09-04 12:53:58 +03:00
}
2021-09-08 14:23:02 +03:00
void StartPageLogic::onPushButtonConnect()
2021-09-04 12:53:58 +03:00
{
2021-09-08 14:23:02 +03:00
if (pushButtonConnectKeyChecked()){
if (lineEditIpText().isEmpty() ||
lineEditLoginText().isEmpty() ||
textEditSshKeyText().isEmpty() ) {
set_labelWaitInfoText(tr("Please fill in all fields"));
2021-09-04 12:53:58 +03:00
return;
}
}
else {
2021-09-08 14:23:02 +03:00
if (lineEditIpText().isEmpty() ||
lineEditLoginText().isEmpty() ||
lineEditPasswordText().isEmpty() ) {
set_labelWaitInfoText(tr("Please fill in all fields"));
2021-09-04 12:53:58 +03:00
return;
}
}
ServerCredentials serverCredentials;
2021-09-08 14:23:02 +03:00
serverCredentials.hostName = lineEditIpText();
2021-09-04 12:53:58 +03:00
if (serverCredentials.hostName.contains(":")) {
serverCredentials.port = serverCredentials.hostName.split(":").at(1).toInt();
serverCredentials.hostName = serverCredentials.hostName.split(":").at(0);
}
2021-09-08 14:23:02 +03:00
serverCredentials.userName = lineEditLoginText();
if (pushButtonConnectKeyChecked()){
QString key = textEditSshKeyText();
2021-09-04 12:53:58 +03:00
if (key.startsWith("ssh-rsa")) {
2021-09-07 21:01:56 +03:00
emit uiLogic()->showPublicKeyWarning();
2021-09-04 12:53:58 +03:00
return;
}
if (key.contains("OPENSSH") && key.contains("BEGIN") && key.contains("PRIVATE KEY")) {
2022-08-25 17:35:28 +03:00
key = m_configurator->sshConfigurator->convertOpenSShKey(key);
2021-09-04 12:53:58 +03:00
}
serverCredentials.password = key;
}
else {
2021-09-08 14:23:02 +03:00
serverCredentials.password = lineEditPasswordText();
2021-09-04 12:53:58 +03:00
}
2021-09-08 14:23:02 +03:00
set_pushButtonConnectEnabled(false);
set_pushButtonConnectText(tr("Connecting..."));
2021-09-04 12:53:58 +03:00
ErrorCode e = ErrorCode::NoError;
#ifdef Q_DEBUG
2022-08-25 17:35:28 +03:00
//QString output = m_serverController->checkSshConnection(serverCredentials, &e);
2021-09-04 12:53:58 +03:00
#else
QString output;
#endif
bool ok = true;
if (e) {
2021-09-08 14:23:02 +03:00
set_labelWaitInfoVisible(true);
set_labelWaitInfoText(errorString(e));
2021-09-04 12:53:58 +03:00
ok = false;
}
else {
if (output.contains("Please login as the user")) {
output.replace("\n", "");
2021-09-08 14:23:02 +03:00
set_labelWaitInfoVisible(true);
set_labelWaitInfoText(output);
2021-09-04 12:53:58 +03:00
ok = false;
}
}
2021-09-08 14:23:02 +03:00
set_pushButtonConnectEnabled(true);
set_pushButtonConnectText(tr("Connect"));
2021-09-04 12:53:58 +03:00
2021-09-07 21:01:56 +03:00
uiLogic()->installCredentials = serverCredentials;
2021-11-19 23:04:35 +03:00
if (ok) emit uiLogic()->goToPage(Page::NewServer);
2021-09-04 12:53:58 +03:00
}
2021-09-08 14:23:02 +03:00
void StartPageLogic::onPushButtonImport()
2021-09-04 12:53:58 +03:00
{
2021-12-20 02:29:23 +03:00
importConnectionFromCode(lineEditStartExistingCodeText());
}
2021-09-04 12:53:58 +03:00
2021-12-20 02:29:23 +03:00
void StartPageLogic::onPushButtonImportOpenFile()
{
QString fileName = QFileDialog::getOpenFileName(Q_NULLPTR, tr("Open config file"),
2022-11-03 23:39:58 +03:00
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.vpn *.ovpn *.conf");
2021-12-20 02:29:23 +03:00
if (fileName.isEmpty()) return;
2021-09-04 12:53:58 +03:00
2021-12-20 02:29:23 +03:00
QFile file(fileName);
file.open(QIODevice::ReadOnly);
QByteArray data = file.readAll();
2021-09-04 12:53:58 +03:00
2022-11-01 23:12:42 +03:00
auto configFormat = checkConfigFormat(QString(data));
if (configFormat == ConfigTypes::OpenVpn) {
2022-11-01 23:12:42 +03:00
importConnectionFromOpenVpnConfig(QString(data));
} else if (configFormat == ConfigTypes::WireGuard) {
2022-11-03 23:39:58 +03:00
importConnectionFromWireguardConfig(QString(data));
2022-11-01 23:12:42 +03:00
} else {
importConnectionFromCode(QString(data));
}
2021-12-20 02:29:23 +03:00
}
2021-09-04 12:53:58 +03:00
2021-12-20 02:29:23 +03:00
bool StartPageLogic::importConnection(const QJsonObject &profile)
{
ServerCredentials credentials;
credentials.hostName = profile.value(config_key::hostName).toString();
credentials.port = profile.value(config_key::port).toInt();
credentials.userName = profile.value(config_key::userName).toString();
credentials.password = profile.value(config_key::password).toString();
2021-09-04 12:53:58 +03:00
2021-12-20 02:29:23 +03:00
if (credentials.isValid() || profile.contains(config_key::containers)) {
2022-08-29 01:32:42 +03:00
// check config
uiLogic()->pageLogic<ViewConfigLogic>()->set_configJson(profile);
emit uiLogic()->goToPage(Page::ViewConfig);
2021-09-04 12:53:58 +03:00
}
else {
qDebug() << "Failed to import profile";
2021-12-20 02:29:23 +03:00
qDebug().noquote() << QJsonDocument(profile).toJson();
return false;
2021-09-04 12:53:58 +03:00
}
2021-12-20 02:29:23 +03:00
return true;
}
bool StartPageLogic::importConnectionFromCode(QString code)
{
code.replace("vpn://", "");
QByteArray ba = QByteArray::fromBase64(code.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
QByteArray ba_uncompressed = qUncompress(ba);
if (!ba_uncompressed.isEmpty()) {
ba = ba_uncompressed;
}
QJsonObject o;
o = QJsonDocument::fromJson(ba).object();
if (!o.isEmpty()) {
return importConnection(o);
}
return false;
}
bool StartPageLogic::importConnectionFromQr(const QByteArray &data)
{
QJsonObject dataObj = QJsonDocument::fromJson(data).object();
if (!dataObj.isEmpty()) {
return importConnection(dataObj);
}
QByteArray ba_uncompressed = qUncompress(data);
if (!ba_uncompressed.isEmpty()) {
return importConnection(QJsonDocument::fromJson(ba_uncompressed).object());
}
return false;
2021-09-04 12:53:58 +03:00
}
2022-11-01 23:12:42 +03:00
bool StartPageLogic::importConnectionFromOpenVpnConfig(const QString &config)
{
QJsonObject openVpnConfig;
openVpnConfig[config_key::config] = config;
QJsonObject lastConfig;
lastConfig[config_key::last_config] = QString(QJsonDocument(openVpnConfig).toJson());
lastConfig[config_key::isThirdPartyConfig] = true;
2022-11-01 23:12:42 +03:00
QJsonObject containers;
containers.insert(config_key::container, QJsonValue("amnezia-openvpn"));
2022-11-01 23:24:58 +03:00
containers.insert(config_key::openvpn, QJsonValue(lastConfig));
2022-11-01 23:12:42 +03:00
QJsonArray arr;
arr.push_back(containers);
QString hostName;
const static QRegularExpression hostNameRegExp("remote (.*) [0-9]*");
QRegularExpressionMatch hostNameMatch = hostNameRegExp.match(config);
if (hostNameMatch.hasMatch()) {
hostName = hostNameMatch.captured(1);
}
2022-11-01 23:12:42 +03:00
QJsonObject o;
o[config_key::containers] = arr;
o[config_key::defaultContainer] = "amnezia-openvpn";
2023-01-08 21:24:06 +00:00
o[config_key::description] = m_settings->nextAvailableServerName();
2022-11-01 23:12:42 +03:00
const static QRegularExpression dnsRegExp("dhcp-option DNS (\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)");
2022-11-01 23:12:42 +03:00
QRegularExpressionMatchIterator dnsMatch = dnsRegExp.globalMatch(config);
if (dnsMatch.hasNext()) {
o[config_key::dns1] = dnsMatch.next().captured(1);
2022-11-01 23:12:42 +03:00
}
if (dnsMatch.hasNext()) {
o[config_key::dns2] = dnsMatch.next().captured(1);
2022-11-01 23:12:42 +03:00
}
o[config_key::hostName] = hostName;
2022-11-01 23:12:42 +03:00
return importConnection(o);
}
2022-11-03 23:39:58 +03:00
bool StartPageLogic::importConnectionFromWireguardConfig(const QString &config)
{
QJsonObject lastConfig;
lastConfig[config_key::config] = config;
const static QRegularExpression hostNameAndPortRegExp("Endpoint = (.*):([0-9]*)");
2022-11-03 23:39:58 +03:00
QRegularExpressionMatch hostNameAndPortMatch = hostNameAndPortRegExp.match(config);
QString hostName;
QString port;
if (hostNameAndPortMatch.hasMatch()) {
hostName = hostNameAndPortMatch.captured(1);
port = hostNameAndPortMatch.captured(2);
}
QJsonObject wireguardConfig;
wireguardConfig[config_key::last_config] = QString(QJsonDocument(lastConfig).toJson());
wireguardConfig[config_key::isThirdPartyConfig] = true;
2022-11-03 23:39:58 +03:00
wireguardConfig[config_key::port] = port;
wireguardConfig[config_key::transport_proto] = "udp";
QJsonObject containers;
containers.insert(config_key::container, QJsonValue("amnezia-wireguard"));
containers.insert(config_key::wireguard, QJsonValue(wireguardConfig));
QJsonArray arr;
arr.push_back(containers);
QJsonObject o;
o[config_key::containers] = arr;
o[config_key::defaultContainer] = "amnezia-wireguard";
2023-01-08 21:24:06 +00:00
o[config_key::description] = m_settings->nextAvailableServerName();
const static QRegularExpression dnsRegExp("DNS = (\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b).*(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)");
QRegularExpressionMatch dnsMatch = dnsRegExp.match(config);
if (dnsMatch.hasMatch()) {
o[config_key::dns1] = dnsMatch.captured(1);
o[config_key::dns2] = dnsMatch.captured(2);
}
2022-11-03 23:39:58 +03:00
o[config_key::hostName] = hostName;
2022-11-03 23:39:58 +03:00
return importConnection(o);
}