Backup/restore config
This commit is contained in:
parent
71b57bfed1
commit
1e85b25438
12 changed files with 155 additions and 105 deletions
|
@ -148,21 +148,7 @@ int main(int argc, char *argv[])
|
||||||
Settings settingsTemp;
|
Settings settingsTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSettings oldSettings(ORGANIZATION_NAME, APPLICATION_NAME);
|
|
||||||
QSettings newSettings(QSettings::Format::CustomFormat1, QSettings::UserScope,
|
|
||||||
ORGANIZATION_NAME, APPLICATION_NAME);
|
|
||||||
|
|
||||||
// QString newSettingsFileName = newSettings.fileName();
|
|
||||||
// QFile::remove(newSettingsFileName);
|
|
||||||
|
|
||||||
if (!oldSettings.allKeys().isEmpty() && newSettings.allKeys().isEmpty()) {
|
|
||||||
QString oldSettingsFileName = oldSettings.fileName();
|
|
||||||
QString newSettingsFileName = newSettings.fileName();
|
|
||||||
qDebug() << "oldSettingsFileName:" << oldSettingsFileName << QFile::exists(oldSettingsFileName) << oldSettings.isWritable();
|
|
||||||
qDebug() << "newSettingsFileName:" << newSettingsFileName << QFile::exists(newSettingsFileName) << newSettings.isWritable();
|
|
||||||
|
|
||||||
SecureFormat::chiperSettings(oldSettings, newSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
// MobileUtils::writeToKeychain("testKey", "12345");
|
// MobileUtils::writeToKeychain("testKey", "12345");
|
||||||
// qDebug() << "MobileUtils::readFromKeychain(\"testKey\"):" << MobileUtils::readFromKeychain("testKey");
|
// qDebug() << "MobileUtils::readFromKeychain(\"testKey\"):" << MobileUtils::readFromKeychain("testKey");
|
||||||
|
|
|
@ -2,34 +2,52 @@
|
||||||
#include "secureformat.h"
|
#include "secureformat.h"
|
||||||
|
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
SecureQSettings::SecureQSettings(const QString &organization, const QString &application, QObject *parent)
|
SecureQSettings::SecureQSettings(const QString &organization, const QString &application, QObject *parent)
|
||||||
: QObject{parent},
|
: QObject{parent},
|
||||||
m_setting(organization, application, parent)
|
m_setting(organization, application, parent),
|
||||||
|
encryptedKeys({"Servers/serversList"})
|
||||||
{
|
{
|
||||||
encrypted = m_setting.value("encrypted").toBool();
|
encrypted = m_setting.value("Conf/encrypted").toBool();
|
||||||
|
|
||||||
// convert settings to encrypted
|
// convert settings to encrypted
|
||||||
if (! encrypted) {
|
if (! encrypted) {
|
||||||
// TODO: convert
|
for (const QString &key : m_setting.allKeys()) {
|
||||||
// m_setting.sync();
|
if (encryptedKeys.contains(key)) {
|
||||||
|
const QVariant &val = value(key);
|
||||||
|
setValue(key, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_setting.setValue("Conf/encrypted", true);
|
||||||
|
m_setting.sync();
|
||||||
|
encrypted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue) const
|
QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue) const
|
||||||
{
|
{
|
||||||
if (encrypted) {
|
if (m_cache.contains(key)) {
|
||||||
QByteArray encryptedValue = m_setting.value(key, defaultValue).toByteArray();
|
return m_cache.value(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant retVal;
|
||||||
|
if (encrypted && encryptedKeys.contains(key)) {
|
||||||
|
if (!m_setting.contains(key)) return defaultValue;
|
||||||
|
|
||||||
|
QByteArray encryptedValue = m_setting.value(key).toByteArray();
|
||||||
QByteArray decryptedValue = decryptText(encryptedValue);
|
QByteArray decryptedValue = decryptText(encryptedValue);
|
||||||
|
|
||||||
QDataStream ds(&decryptedValue, QIODevice::ReadOnly);
|
QDataStream ds(&decryptedValue, QIODevice::ReadOnly);
|
||||||
QVariant v;
|
ds >> retVal;
|
||||||
ds >> v;
|
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return m_setting.value(key, defaultValue);
|
retVal = m_setting.value(key, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_cache.insert(key, retVal);
|
||||||
|
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SecureQSettings::setValue(const QString &key, const QVariant &value)
|
void SecureQSettings::setValue(const QString &key, const QVariant &value)
|
||||||
|
@ -42,6 +60,55 @@ void SecureQSettings::setValue(const QString &key, const QVariant &value)
|
||||||
|
|
||||||
QByteArray encryptedValue = encryptText(decryptedValue);
|
QByteArray encryptedValue = encryptText(decryptedValue);
|
||||||
m_setting.setValue(key, encryptedValue);
|
m_setting.setValue(key, encryptedValue);
|
||||||
|
m_cache.insert(key, value);
|
||||||
|
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SecureQSettings::remove(const QString &key)
|
||||||
|
{
|
||||||
|
m_setting.remove(key);
|
||||||
|
m_cache.remove(key);
|
||||||
|
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SecureQSettings::sync()
|
||||||
|
{
|
||||||
|
m_setting.sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray SecureQSettings::backupAppConfig() const
|
||||||
|
{
|
||||||
|
QMap<QString, QVariant> cfg;
|
||||||
|
for (const QString &key : m_setting.allKeys()) {
|
||||||
|
cfg.insert(key, value(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray ba;
|
||||||
|
{
|
||||||
|
QDataStream ds(&ba, QIODevice::WriteOnly);
|
||||||
|
ds << cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ba.toBase64();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SecureQSettings::restoreAppConfig(const QByteArray &base64Cfg)
|
||||||
|
{
|
||||||
|
QByteArray ba = QByteArray::fromBase64(base64Cfg);
|
||||||
|
QMap<QString, QVariant> cfg;
|
||||||
|
|
||||||
|
{
|
||||||
|
QDataStream ds(&ba, QIODevice::ReadOnly);
|
||||||
|
ds >> cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const QString &key : cfg.keys()) {
|
||||||
|
setValue(key, cfg.value(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,19 @@ public:
|
||||||
|
|
||||||
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
|
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
|
||||||
void setValue(const QString &key, const QVariant &value);
|
void setValue(const QString &key, const QVariant &value);
|
||||||
void sync() { m_setting.sync(); }
|
void remove(const QString &key);
|
||||||
void remove(const QString &key) { m_setting.remove(key); }
|
void sync();
|
||||||
|
|
||||||
|
QByteArray backupAppConfig() const;
|
||||||
|
void restoreAppConfig(const QByteArray &base64Cfg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSettings m_setting;
|
QSettings m_setting;
|
||||||
bool encrypted {false};
|
bool encrypted {false};
|
||||||
|
|
||||||
|
mutable QMap<QString, QVariant> m_cache;
|
||||||
|
|
||||||
|
QStringList encryptedKeys; // encode only key listed here
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SECUREQSETTINGS_H
|
#endif // SECUREQSETTINGS_H
|
||||||
|
|
|
@ -148,71 +148,7 @@ QByteArray decryptText(const QByteArray& qEncryptArray) {
|
||||||
return QByteArray::fromRawData((const char *)decryptPlainText, qEncryptArray.size());
|
return QByteArray::fromRawData((const char *)decryptPlainText, qEncryptArray.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
SecureFormat::SecureFormat()
|
|
||||||
{
|
|
||||||
m_format = QSettings::registerFormat("sconf",
|
|
||||||
readSecureFile,
|
|
||||||
writeSecureFile);
|
|
||||||
qDebug() << "SecureFormat" << m_format;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SecureFormat::readSecureFile(QIODevice& device, QSettings::SettingsMap& map) {
|
|
||||||
if (!device.isOpen()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTextStream inStream(&device);
|
|
||||||
while (!inStream.atEnd()) {
|
|
||||||
QString line = inStream.readLine();
|
|
||||||
|
|
||||||
QStringList keyValue = line.split("<=>");
|
|
||||||
QString key = keyValue.first();
|
|
||||||
QString value = decryptText(keyValue.last().toUtf8());
|
|
||||||
map.insert(key, value);
|
|
||||||
|
|
||||||
qDebug() << "SecureFormat::readSecureFile: " << key << "<=>" << value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SecureFormat::writeSecureFile(QIODevice& device, const QSettings::SettingsMap& map) {
|
|
||||||
// if (!device.isOpen()) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// QTextStream outStream(&device);
|
|
||||||
// auto keys = map.keys();
|
|
||||||
// for (auto key : keys) {
|
|
||||||
// QString value = map.value(key).toString();
|
|
||||||
// QByteArray qEncryptArray = encryptText(value);
|
|
||||||
// outStream << key << "<=>" << qEncryptArray << "\n";
|
|
||||||
|
|
||||||
// qDebug() << "SecureFormat::writeSecureFile: " << key << "<=>" << qEncryptArray;
|
|
||||||
// }
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SecureFormat::chiperSettings(const QSettings &oldSetting, QSettings &newSetting) {
|
|
||||||
// QVariantMap keysValuesPairs;
|
|
||||||
// QStringList keys = oldSetting.allKeys();
|
|
||||||
// QStringListIterator it(keys);
|
|
||||||
// while ( it.hasNext() ) {
|
|
||||||
// QString currentKey = it.next();
|
|
||||||
// keysValuesPairs.insert(currentKey, oldSetting.value(currentKey));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for (const QString& key : keys) {
|
|
||||||
// QString value = keysValuesPairs.value(key).toString();
|
|
||||||
// QByteArray qEncryptArray = encryptText(value);
|
|
||||||
|
|
||||||
// newSetting.setValue(key, qEncryptArray);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// newSetting.sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
const QSettings::Format& SecureFormat::format() const{
|
|
||||||
return m_format;
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,15 +12,9 @@ class SecureFormat
|
||||||
public:
|
public:
|
||||||
SecureFormat();
|
SecureFormat();
|
||||||
|
|
||||||
static bool readSecureFile(QIODevice &device, QSettings::SettingsMap &map);
|
|
||||||
static bool writeSecureFile(QIODevice &device, const QSettings::SettingsMap &map);
|
|
||||||
|
|
||||||
static void chiperSettings(const QSettings &oldSetting, QSettings &newSetting);
|
|
||||||
|
|
||||||
const QSettings::Format& format() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QSettings::Format m_format;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SECUREFORMAT_H
|
#endif // SECUREFORMAT_H
|
||||||
|
|
|
@ -112,8 +112,10 @@ public:
|
||||||
// static constexpr char openNicNs5[] = "94.103.153.176";
|
// static constexpr char openNicNs5[] = "94.103.153.176";
|
||||||
// static constexpr char openNicNs13[] = "144.76.103.143";
|
// static constexpr char openNicNs13[] = "144.76.103.143";
|
||||||
|
|
||||||
|
QByteArray backupAppConfig() const { return m_settings.backupAppConfig(); }
|
||||||
|
void restoreAppConfig(const QByteArray &cfg) { m_settings.restoreAppConfig(cfg); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//static SecureFormat m_secureFormat;
|
|
||||||
SecureQSettings m_settings;
|
SecureQSettings m_settings;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -74,3 +74,26 @@ void AppSettingsLogic::onPushButtonClearLogsClicked()
|
||||||
Debug::clearLogs();
|
Debug::clearLogs();
|
||||||
Debug::clearServiceLogs();
|
Debug::clearServiceLogs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppSettingsLogic::onPushButtonBackupAppConfigClicked()
|
||||||
|
{
|
||||||
|
uiLogic()->saveTextFile("Backup application config", "AmneziaVPN.backup", ".backup", m_settings.backupAppConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppSettingsLogic::onPushButtonRestoreAppConfigClicked()
|
||||||
|
{
|
||||||
|
QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open backup"),
|
||||||
|
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.backup");
|
||||||
|
|
||||||
|
if (fileName.isEmpty()) return;
|
||||||
|
|
||||||
|
QFile file(fileName);
|
||||||
|
file.open(QIODevice::ReadOnly);
|
||||||
|
QByteArray data = file.readAll();
|
||||||
|
|
||||||
|
m_settings.restoreAppConfig(data);
|
||||||
|
|
||||||
|
emit uiLogic()->goToPage(Page::Vpn);
|
||||||
|
emit uiLogic()->setStartPage(Page::Vpn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,10 @@ public:
|
||||||
Q_INVOKABLE void onPushButtonExportLogsClicked();
|
Q_INVOKABLE void onPushButtonExportLogsClicked();
|
||||||
Q_INVOKABLE void onPushButtonClearLogsClicked();
|
Q_INVOKABLE void onPushButtonClearLogsClicked();
|
||||||
|
|
||||||
|
Q_INVOKABLE void onPushButtonBackupAppConfigClicked();
|
||||||
|
Q_INVOKABLE void onPushButtonRestoreAppConfigClicked();
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AppSettingsLogic(UiLogic *uiLogic, QObject *parent = nullptr);
|
explicit AppSettingsLogic(UiLogic *uiLogic, QObject *parent = nullptr);
|
||||||
~AppSettingsLogic() = default;
|
~AppSettingsLogic() = default;
|
||||||
|
|
|
@ -24,7 +24,6 @@ StartPageLogic::StartPageLogic(UiLogic *logic, QObject *parent):
|
||||||
m_labelWaitInfoVisible{true},
|
m_labelWaitInfoVisible{true},
|
||||||
m_labelWaitInfoText{},
|
m_labelWaitInfoText{},
|
||||||
m_pushButtonBackFromStartVisible{true},
|
m_pushButtonBackFromStartVisible{true},
|
||||||
m_pushButtonConnectVisible{true},
|
|
||||||
m_ipAddressPortRegex{Utils::ipAddressPortRegExp()}
|
m_ipAddressPortRegex{Utils::ipAddressPortRegExp()}
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -41,7 +40,6 @@ void StartPageLogic::onUpdatePage()
|
||||||
|
|
||||||
set_labelWaitInfoVisible(false);
|
set_labelWaitInfoVisible(false);
|
||||||
set_labelWaitInfoText("");
|
set_labelWaitInfoText("");
|
||||||
set_pushButtonConnectVisible(true);
|
|
||||||
|
|
||||||
set_pushButtonConnectKeyChecked(false);
|
set_pushButtonConnectKeyChecked(false);
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ class StartPageLogic : public PageLogicBase
|
||||||
AUTO_PROPERTY(bool, labelWaitInfoVisible)
|
AUTO_PROPERTY(bool, labelWaitInfoVisible)
|
||||||
AUTO_PROPERTY(QString, labelWaitInfoText)
|
AUTO_PROPERTY(QString, labelWaitInfoText)
|
||||||
AUTO_PROPERTY(bool, pushButtonBackFromStartVisible)
|
AUTO_PROPERTY(bool, pushButtonBackFromStartVisible)
|
||||||
AUTO_PROPERTY(bool, pushButtonConnectVisible)
|
|
||||||
|
|
||||||
READONLY_PROPERTY(QRegExp, ipAddressPortRegex)
|
READONLY_PROPERTY(QRegExp, ipAddressPortRegex)
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -107,7 +107,7 @@ PageBase {
|
||||||
|
|
||||||
BlueButtonType {
|
BlueButtonType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 15
|
Layout.topMargin: 10
|
||||||
Layout.preferredHeight: 41
|
Layout.preferredHeight: 41
|
||||||
text: qsTr("Export logs")
|
text: qsTr("Export logs")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
@ -117,7 +117,7 @@ PageBase {
|
||||||
|
|
||||||
BlueButtonType {
|
BlueButtonType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 15
|
Layout.topMargin: 10
|
||||||
Layout.preferredHeight: 41
|
Layout.preferredHeight: 41
|
||||||
|
|
||||||
property string start_text: qsTr("Clear logs")
|
property string start_text: qsTr("Clear logs")
|
||||||
|
@ -135,6 +135,31 @@ PageBase {
|
||||||
AppSettingsLogic.onPushButtonClearLogsClicked()
|
AppSettingsLogic.onPushButtonClearLogsClicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LabelType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 30
|
||||||
|
text: qsTr("Backup and restore configuration")
|
||||||
|
}
|
||||||
|
|
||||||
|
BlueButtonType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 10
|
||||||
|
Layout.preferredHeight: 41
|
||||||
|
text: qsTr("Backup app config")
|
||||||
|
onClicked: {
|
||||||
|
AppSettingsLogic.onPushButtonBackupAppConfigClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BlueButtonType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 10
|
||||||
|
Layout.preferredHeight: 41
|
||||||
|
text: qsTr("Restore app config")
|
||||||
|
onClicked: {
|
||||||
|
AppSettingsLogic.onPushButtonRestoreAppConfigClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,6 @@ PageBase {
|
||||||
anchors.topMargin: 40
|
anchors.topMargin: 40
|
||||||
|
|
||||||
text: qsTr("Open file")
|
text: qsTr("Open file")
|
||||||
visible: StartPageLogic.pushButtonConnectVisible
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
StartPageLogic.onPushButtonImportOpenFile()
|
StartPageLogic.onPushButtonImportOpenFile()
|
||||||
}
|
}
|
||||||
|
@ -133,7 +132,6 @@ PageBase {
|
||||||
anchors.topMargin: 10
|
anchors.topMargin: 10
|
||||||
|
|
||||||
text: qsTr("Scan QR code")
|
text: qsTr("Scan QR code")
|
||||||
visible: StartPageLogic.pushButtonConnectVisible
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (Qt.platform.os == "ios") {
|
if (Qt.platform.os == "ios") {
|
||||||
UiLogic.goToPage(PageEnum.QrDecoderIos)
|
UiLogic.goToPage(PageEnum.QrDecoderIos)
|
||||||
|
@ -144,7 +142,19 @@ PageBase {
|
||||||
enabled: StartPageLogic.pushButtonConnectEnabled
|
enabled: StartPageLogic.pushButtonConnectEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlueButtonType {
|
||||||
|
id: btn_restore_cfg
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: qr_code_import.bottom
|
||||||
|
anchors.topMargin: 30
|
||||||
|
visible: UiLogic.pagesStackDepth == 1
|
||||||
|
enabled: StartPageLogic.pushButtonConnectEnabled
|
||||||
|
|
||||||
|
text: qsTr("Restore app config")
|
||||||
|
onClicked: {
|
||||||
|
AppSettingsLogic.onPushButtonRestoreAppConfigClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -270,7 +280,6 @@ PageBase {
|
||||||
anchors.topMargin: 10
|
anchors.topMargin: 10
|
||||||
|
|
||||||
text: StartPageLogic.pushButtonConnectText
|
text: StartPageLogic.pushButtonConnectText
|
||||||
visible: StartPageLogic.pushButtonConnectVisible
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
StartPageLogic.onPushButtonConnect()
|
StartPageLogic.onPushButtonConnect()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue