mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-24 02:00:24 +07:00
update: files encrypt on export and files data decrypt on import
This commit is contained in:
@@ -117,6 +117,8 @@ bool SubscriptionUiController::exportNativeConfig(const QString &serverId, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bool saved = SystemController::saveFile(fileName, nativeConfig);
|
const bool saved = SystemController::saveFile(fileName, nativeConfig);
|
||||||
|
if (m_settingsController->isFileEncryptionEnabled())
|
||||||
|
SystemController::encryptFile(fileName, m_settingsController->getPassword(), m_settingsController->getHint());
|
||||||
getAccountInfo(serverId, true);
|
getAccountInfo(serverId, true);
|
||||||
return saved;
|
return saved;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ void ExportUiController::exportConfig(const QString &fileName)
|
|||||||
if (!SystemController::saveFile(fileName, m_config)) {
|
if (!SystemController::saveFile(fileName, m_config)) {
|
||||||
qInfo() << "ExportUiController::exportConfig: save or share was cancelled or failed";
|
qInfo() << "ExportUiController::exportConfig: save or share was cancelled or failed";
|
||||||
}
|
}
|
||||||
|
if (m_settingsController->isFileEncryptionEnabled())
|
||||||
|
SystemController::encryptFile(fileName, m_settingsController->getPassword(), m_settingsController->getHint());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExportUiController::updateClientManagementModel(const QString &serverId, int containerIndex)
|
void ExportUiController::updateClientManagementModel(const QString &serverId, int containerIndex)
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ static QString opensslErrString()
|
|||||||
return QString::fromUtf8(buf);
|
return QString::fromUtf8(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool deriveKey(const QByteArray &password, const QByteArray &salt, QByteArray &outKey, QString *err)
|
static bool deriveKey(const QByteArray &password, const QByteArray &salt, QByteArray &outKey)
|
||||||
{
|
{
|
||||||
outKey.resize(KEY_LEN);
|
outKey.resize(KEY_LEN);
|
||||||
const unsigned char *pw = reinterpret_cast<const unsigned char *>(password.constData());
|
const unsigned char *pw = reinterpret_cast<const unsigned char *>(password.constData());
|
||||||
@@ -136,27 +136,23 @@ static bool deriveKey(const QByteArray &password, const QByteArray &salt, QByteA
|
|||||||
int ok = PKCS5_PBKDF2_HMAC(reinterpret_cast<const char *>(pw), password.size(), s, salt.size(), PBKDF2_ITER,
|
int ok = PKCS5_PBKDF2_HMAC(reinterpret_cast<const char *>(pw), password.size(), s, salt.size(), PBKDF2_ITER,
|
||||||
EVP_sha256(), KEY_LEN, reinterpret_cast<unsigned char *>(outKey.data()));
|
EVP_sha256(), KEY_LEN, reinterpret_cast<unsigned char *>(outKey.data()));
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
if (err)
|
qDebug() << opensslErrString();
|
||||||
*err = opensslErrString();
|
|
||||||
}
|
}
|
||||||
return ok == 1;
|
return ok == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool aesCrypt(const QByteArray &in, const QByteArray &key, const QByteArray &iv, QByteArray &out, bool encrypt,
|
static bool aesCrypt(const QByteArray &in, const QByteArray &key, const QByteArray &iv, QByteArray &out, bool encrypt)
|
||||||
QString *err)
|
|
||||||
{
|
{
|
||||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
if (err)
|
qDebug() << "EVP_CIPHER_CTX_new failed";
|
||||||
*err = "EVP_CIPHER_CTX_new failed";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const EVP_CIPHER *cipher = EVP_aes_256_cbc();
|
const EVP_CIPHER *cipher = EVP_aes_256_cbc();
|
||||||
if (1
|
if (1
|
||||||
!= EVP_CipherInit_ex(ctx, cipher, nullptr, reinterpret_cast<const unsigned char *>(key.constData()),
|
!= EVP_CipherInit_ex(ctx, cipher, nullptr, reinterpret_cast<const unsigned char *>(key.constData()),
|
||||||
reinterpret_cast<const unsigned char *>(iv.constData()), encrypt ? 1 : 0)) {
|
reinterpret_cast<const unsigned char *>(iv.constData()), encrypt ? 1 : 0)) {
|
||||||
if (err)
|
qDebug() << opensslErrString();
|
||||||
*err = opensslErrString();
|
|
||||||
EVP_CIPHER_CTX_free(ctx);
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -167,15 +163,13 @@ static bool aesCrypt(const QByteArray &in, const QByteArray &key, const QByteArr
|
|||||||
if (1
|
if (1
|
||||||
!= EVP_CipherUpdate(ctx, reinterpret_cast<unsigned char *>(out.data()), &outlen1,
|
!= EVP_CipherUpdate(ctx, reinterpret_cast<unsigned char *>(out.data()), &outlen1,
|
||||||
reinterpret_cast<const unsigned char *>(in.constData()), in.size())) {
|
reinterpret_cast<const unsigned char *>(in.constData()), in.size())) {
|
||||||
if (err)
|
qDebug() << opensslErrString();
|
||||||
*err = opensslErrString();
|
|
||||||
EVP_CIPHER_CTX_free(ctx);
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int outlen2 = 0;
|
int outlen2 = 0;
|
||||||
if (1 != EVP_CipherFinal_ex(ctx, reinterpret_cast<unsigned char *>(out.data()) + outlen1, &outlen2)) {
|
if (1 != EVP_CipherFinal_ex(ctx, reinterpret_cast<unsigned char *>(out.data()) + outlen1, &outlen2)) {
|
||||||
if (err)
|
qDebug() << opensslErrString();
|
||||||
*err = opensslErrString();
|
|
||||||
EVP_CIPHER_CTX_free(ctx);
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -184,20 +178,18 @@ static bool aesCrypt(const QByteArray &in, const QByteArray &key, const QByteArr
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SystemController::encryptFile(const QString &filePath, const QString &password, const QString &hint, QString *error)
|
bool SystemController::encryptFile(const QString &filePath, const QString &password, const QString &hint)
|
||||||
{
|
{
|
||||||
QFile f(filePath);
|
QFile f(filePath);
|
||||||
if (!f.open(QIODevice::ReadOnly)) {
|
if (!f.open(QIODevice::ReadOnly)) {
|
||||||
if (error)
|
qDebug() << QStringLiteral("Cannot open file for read: %1").arg(f.errorString());
|
||||||
*error = QStringLiteral("Cannot open file for read: %1").arg(f.errorString());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QByteArray content = f.readAll();
|
QByteArray content = f.readAll();
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
if (content.startsWith(magicString)) {
|
if (content.startsWith(magicString)) {
|
||||||
if (error)
|
qDebug() << QStringLiteral("File already encrypted (magic found)");
|
||||||
*error = QStringLiteral("File already encrypted (magic found)");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,15 +203,14 @@ bool SystemController::encryptFile(const QString &filePath, const QString &passw
|
|||||||
|
|
||||||
if (1 != RAND_bytes(reinterpret_cast<unsigned char *>(salt.data()), SALT_LEN)
|
if (1 != RAND_bytes(reinterpret_cast<unsigned char *>(salt.data()), SALT_LEN)
|
||||||
|| 1 != RAND_bytes(reinterpret_cast<unsigned char *>(iv.data()), IV_LEN)) {
|
|| 1 != RAND_bytes(reinterpret_cast<unsigned char *>(iv.data()), IV_LEN)) {
|
||||||
if (error)
|
qDebug() << opensslErrString();
|
||||||
*error = opensslErrString();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deriveKey(password.toUtf8(), salt, key, error))
|
if (!deriveKey(password.toUtf8(), salt, key))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!aesCrypt(content, key, iv, cipher, true, error))
|
if (!aesCrypt(content, key, iv, cipher, true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
out.reserve(magicString.size() + SALT_LEN + IV_LEN + cipher.size());
|
out.reserve(magicString.size() + SALT_LEN + IV_LEN + cipher.size());
|
||||||
@@ -231,78 +222,43 @@ bool SystemController::encryptFile(const QString &filePath, const QString &passw
|
|||||||
out += cipher;
|
out += cipher;
|
||||||
|
|
||||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||||
if (error)
|
qDebug() << QStringLiteral("Cannot open file for write: %1").arg(f.errorString());
|
||||||
*error = QStringLiteral("Cannot open file for write: %1").arg(f.errorString());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
qint64 written = f.write(out);
|
qint64 written = f.write(out);
|
||||||
f.close();
|
f.close();
|
||||||
if (written != out.size()) {
|
if (written != out.size()) {
|
||||||
if (error)
|
qDebug() << QStringLiteral("Write failed or incomplete");
|
||||||
*error = QStringLiteral("Write failed or incomplete");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SystemController::decryptFile(const QString &filePath, const QString &password, QString *error)
|
QByteArray SystemController::getDecryptedData(const QString &filePath, const QString &password)
|
||||||
{
|
{
|
||||||
QFile f(filePath);
|
QByteArray encData;
|
||||||
if (!f.open(QIODevice::ReadOnly)) {
|
readFile(filePath, encData);
|
||||||
if (error)
|
|
||||||
*error = QStringLiteral("Cannot open file for read: %1").arg(f.errorString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QByteArray content = f.readAll();
|
|
||||||
f.close();
|
|
||||||
|
|
||||||
if (!content.startsWith(magicString)) {
|
|
||||||
if (error)
|
|
||||||
*error = QStringLiteral("File is not recognized as encrypted (magic missing)");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pos = magicString.size();
|
int pos = magicString.size();
|
||||||
|
|
||||||
quint32 hintLen = 0;
|
quint32 hintLen = 0;
|
||||||
memcpy(&hintLen, content.constData() + pos, sizeof(quint32));
|
memcpy(&hintLen, encData.constData() + pos, sizeof(quint32));
|
||||||
|
|
||||||
pos += sizeof(quint32);
|
pos += sizeof(quint32);
|
||||||
pos += hintLen;
|
pos += hintLen;
|
||||||
|
|
||||||
if (content.size() < pos + SALT_LEN + IV_LEN) {
|
QByteArray salt = encData.mid(pos, 16);
|
||||||
if (error)
|
pos += 16;
|
||||||
*error = QStringLiteral("Encrypted file too small / corrupted");
|
QByteArray iv = encData.mid(pos, 16);
|
||||||
return false;
|
pos += 16;
|
||||||
}
|
QByteArray cipher = encData.mid(pos);
|
||||||
|
|
||||||
QByteArray salt = content.mid(pos, SALT_LEN);
|
|
||||||
pos += SALT_LEN;
|
|
||||||
QByteArray iv = content.mid(pos, IV_LEN);
|
|
||||||
pos += IV_LEN;
|
|
||||||
QByteArray cipher = content.mid(pos);
|
|
||||||
QByteArray key;
|
QByteArray key;
|
||||||
QByteArray plain;
|
deriveKey(password.toUtf8(), salt, key);
|
||||||
|
|
||||||
if (!deriveKey(password.toUtf8(), salt, key, error))
|
QByteArray data;
|
||||||
return false;
|
!aesCrypt(cipher, key, iv, data, false);
|
||||||
|
|
||||||
if (!aesCrypt(cipher, key, iv, plain, false, error))
|
return data;
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
|
||||||
if (error)
|
|
||||||
*error = QStringLiteral("Cannot open file for write: %1").arg(f.errorString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
qint64 written = f.write(plain);
|
|
||||||
f.close();
|
|
||||||
if (written != plain.size()) {
|
|
||||||
if (error)
|
|
||||||
*error = QStringLiteral("Write failed or incomplete");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SystemController::isFileEncrypted(const QString &filePath)
|
bool SystemController::isFileEncrypted(const QString &filePath)
|
||||||
@@ -312,11 +268,49 @@ bool SystemController::isFileEncrypted(const QString &filePath)
|
|||||||
qDebug() << "Cannot open file for read: %1", f.errorString();
|
qDebug() << "Cannot open file for read: %1", f.errorString();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
QByteArray data = f.readAll();
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
if (!data.startsWith(magicString)) {
|
||||||
|
qDebug() << "File is not recognized as encrypted (magic missing)";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SystemController::isPasswordValid(const QString &filePath, const QString &password)
|
||||||
|
{
|
||||||
|
QFile f(filePath);
|
||||||
|
if (!f.open(QIODevice::ReadOnly)) {
|
||||||
|
qDebug() << f.errorString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray content = f.readAll();
|
QByteArray content = f.readAll();
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
if (!content.startsWith(magicString)) {
|
int pos = magicString.size();
|
||||||
qDebug() << "File is not recognized as encrypted (magic missing)";
|
quint32 hintLen = 0;
|
||||||
|
memcpy(&hintLen, content.constData() + pos, sizeof(quint32));
|
||||||
|
pos += sizeof(quint32);
|
||||||
|
pos += hintLen;
|
||||||
|
|
||||||
|
QByteArray salt = content.mid(pos, 16);
|
||||||
|
pos += 16;
|
||||||
|
QByteArray iv = content.mid(pos, 16);
|
||||||
|
pos += 16;
|
||||||
|
QByteArray cipher = content.mid(pos);
|
||||||
|
|
||||||
|
QByteArray key;
|
||||||
|
if (!deriveKey(password.toUtf8(), salt, key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QByteArray plain;
|
||||||
|
bool ok = aesCrypt(cipher, key, iv, plain, false);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
qDebug() << "Wrong password";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,19 +319,8 @@ bool SystemController::isFileEncrypted(const QString &filePath)
|
|||||||
|
|
||||||
QString SystemController::readHint(const QString &filePath)
|
QString SystemController::readHint(const QString &filePath)
|
||||||
{
|
{
|
||||||
QFile f(filePath);
|
QByteArray data;
|
||||||
if (!f.open(QIODevice::ReadOnly)) {
|
readFile(filePath, data);
|
||||||
qDebug() << f.errorString();
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray data = f.readAll();
|
|
||||||
f.close();
|
|
||||||
|
|
||||||
if (!data.startsWith(magicString)) {
|
|
||||||
qDebug() << "File is not encrypted";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
int pos = magicString.size();
|
int pos = magicString.size();
|
||||||
|
|
||||||
|
|||||||
@@ -15,15 +15,16 @@ public:
|
|||||||
static bool readFile(const QString &fileName, QByteArray &data);
|
static bool readFile(const QString &fileName, QByteArray &data);
|
||||||
static bool readFile(const QString &fileName, QString &data);
|
static bool readFile(const QString &fileName, QString &data);
|
||||||
|
|
||||||
static bool encryptFile(const QString &filePath, const QString &password, const QString &hint, QString *error = nullptr);
|
static bool encryptFile(const QString &filePath, const QString &password, const QString &hint);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QString getFileName(const QString &acceptLabel, const QString &nameFilter, const QString &selectedFile = "",
|
QString getFileName(const QString &acceptLabel, const QString &nameFilter, const QString &selectedFile = "",
|
||||||
const bool isSaveMode = false, const QString &defaultSuffix = "");
|
const bool isSaveMode = false, const QString &defaultSuffix = "");
|
||||||
|
|
||||||
bool decryptFile(const QString &filePath, const QString &password, QString *error = nullptr);
|
QByteArray getDecryptedData(const QString &filePath, const QString &password);
|
||||||
|
|
||||||
bool isFileEncrypted(const QString &filePath);
|
bool isFileEncrypted(const QString &filePath);
|
||||||
|
bool isPasswordValid(const QString &filePath, const QString &password);
|
||||||
QString readHint(const QString &filePath);
|
QString readHint(const QString &filePath);
|
||||||
|
|
||||||
void setQmlRoot(QObject *qmlRoot);
|
void setQmlRoot(QObject *qmlRoot);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import PageEnum 1.0
|
||||||
import Style 1.0
|
import Style 1.0
|
||||||
|
|
||||||
import "../Controls2"
|
import "../Controls2"
|
||||||
@@ -17,6 +18,9 @@ DrawerType2 {
|
|||||||
property string fileName
|
property string fileName
|
||||||
property var securedFunc
|
property var securedFunc
|
||||||
|
|
||||||
|
signal restoreSecuredBackup
|
||||||
|
signal importSecuredFile
|
||||||
|
|
||||||
expandedStateContent: ColumnLayout {
|
expandedStateContent: ColumnLayout {
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
@@ -25,6 +29,27 @@ DrawerType2 {
|
|||||||
anchors.leftMargin: 16
|
anchors.leftMargin: 16
|
||||||
anchors.rightMargin: 16
|
anchors.rightMargin: 16
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
|
||||||
|
function onRestoreSecuredBackup() {
|
||||||
|
root.securedFunc = function() {
|
||||||
|
SettingsController.restoreAppConfigFromData(SystemController.getDecryptedData(fileName, passwordField.textField.text))
|
||||||
|
}
|
||||||
|
passwordDrawer.openTriggered()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onImportSecuredFile() {
|
||||||
|
// TODO: file name not showing on import
|
||||||
|
root.securedFunc = function() {
|
||||||
|
if (ImportController.extractConfigFromData(SystemController.getDecryptedData(fileName, passwordField.textField.text))) {
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
passwordDrawer.openTriggered()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Header2TextType {
|
Header2TextType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.bottomMargin: 8
|
Layout.bottomMargin: 8
|
||||||
@@ -49,7 +74,7 @@ DrawerType2 {
|
|||||||
|
|
||||||
headerText: qsTr("Password")
|
headerText: qsTr("Password")
|
||||||
textField.echoMode: hideContent ? TextInput.Password : TextInput.Normal
|
textField.echoMode: hideContent ? TextInput.Password : TextInput.Normal
|
||||||
textField.text: ""
|
textField.text: textField.text
|
||||||
|
|
||||||
rightButtonClickedOnEnter: true
|
rightButtonClickedOnEnter: true
|
||||||
|
|
||||||
@@ -84,7 +109,7 @@ DrawerType2 {
|
|||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
if (fromOutside) {
|
if (fromOutside) {
|
||||||
if (!SystemController.decryptFile(fileName, passwordField.textField.text)) {
|
if (!SystemController.isPasswordValid(fileName, passwordField.textField.text)) {
|
||||||
passwordField.errorText = qsTr("Incorrect password")
|
passwordField.errorText = qsTr("Incorrect password")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ PageType {
|
|||||||
qsTr("Backup files (*.backup)"))
|
qsTr("Backup files (*.backup)"))
|
||||||
if (filePath !== "") {
|
if (filePath !== "") {
|
||||||
passwordDrawer.fileName = filePath
|
passwordDrawer.fileName = filePath
|
||||||
SystemController.isFileEncrypted(filePath) ? passwordDrawer.openTriggered() : passwordDrawer.securedFunc()
|
SystemController.isFileEncrypted(filePath) ? passwordDrawer.openTriggered() : restoreBackup(filePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,7 +155,7 @@ PageType {
|
|||||||
expandedHeight: root.height * 0.45
|
expandedHeight: root.height * 0.45
|
||||||
|
|
||||||
securedFunc: function() {
|
securedFunc: function() {
|
||||||
restoreBackup(fileName)
|
passwordDrawer.restoreSecuredBackup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import "./"
|
|||||||
import "../Controls2"
|
import "../Controls2"
|
||||||
import "../Controls2/TextTypes"
|
import "../Controls2/TextTypes"
|
||||||
import "../Config"
|
import "../Config"
|
||||||
|
import "../Components"
|
||||||
|
|
||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
@@ -264,6 +265,15 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PasswordDrawer {
|
||||||
|
id: passwordDrawer
|
||||||
|
|
||||||
|
parent: root
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
expandedHeight: root.height * 0.45
|
||||||
|
}
|
||||||
|
|
||||||
property list<QtObject> variants: [
|
property list<QtObject> variants: [
|
||||||
amneziaVpn,
|
amneziaVpn,
|
||||||
selfHostVpn,
|
selfHostVpn,
|
||||||
@@ -318,7 +328,12 @@ PageType {
|
|||||||
qsTr("Backup files (*.backup)"))
|
qsTr("Backup files (*.backup)"))
|
||||||
if (filePath !== "") {
|
if (filePath !== "") {
|
||||||
PageController.showBusyIndicator(true)
|
PageController.showBusyIndicator(true)
|
||||||
SettingsController.restoreAppConfig(filePath)
|
if (SystemController.isFileEncrypted(filePath)) {
|
||||||
|
passwordDrawer.fileName = filePath
|
||||||
|
passwordDrawer.restoreSecuredBackup()
|
||||||
|
} else {
|
||||||
|
SettingsController.restoreAppConfig(filePath)
|
||||||
|
}
|
||||||
PageController.showBusyIndicator(false)
|
PageController.showBusyIndicator(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,8 +351,13 @@ PageType {
|
|||||||
var nameFilter = "Config files (*.vpn *.ovpn *.conf *.json)"
|
var nameFilter = "Config files (*.vpn *.ovpn *.conf *.json)"
|
||||||
var fileName = SystemController.getFileName(qsTr("Open config file"), nameFilter)
|
var fileName = SystemController.getFileName(qsTr("Open config file"), nameFilter)
|
||||||
if (fileName !== "") {
|
if (fileName !== "") {
|
||||||
if (ImportController.extractConfigFromFile(fileName)) {
|
if (SystemController.isFileEncrypted(fileName)) {
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
|
passwordDrawer.fileName = fileName
|
||||||
|
passwordDrawer.importSecuredFile()
|
||||||
|
} else {
|
||||||
|
if (ImportController.extractConfigFromFile(fileName)) {
|
||||||
|
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user