Backup/restore config

This commit is contained in:
pokamest 2022-08-05 18:59:47 +03:00
parent 71b57bfed1
commit 1e85b25438
12 changed files with 155 additions and 105 deletions

View file

@ -148,21 +148,7 @@ int main(int argc, char *argv[])
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");
// qDebug() << "MobileUtils::readFromKeychain(\"testKey\"):" << MobileUtils::readFromKeychain("testKey");

View file

@ -2,34 +2,52 @@
#include "secureformat.h"
#include <QDataStream>
#include <QDebug>
SecureQSettings::SecureQSettings(const QString &organization, const QString &application, 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
if (! encrypted) {
// TODO: convert
// m_setting.sync();
for (const QString &key : m_setting.allKeys()) {
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
{
if (encrypted) {
QByteArray encryptedValue = m_setting.value(key, defaultValue).toByteArray();
if (m_cache.contains(key)) {
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);
QDataStream ds(&decryptedValue, QIODevice::ReadOnly);
QVariant v;
ds >> v;
return v;
ds >> retVal;
}
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)
@ -42,6 +60,55 @@ void SecureQSettings::setValue(const QString &key, const QVariant &value)
QByteArray encryptedValue = encryptText(decryptedValue);
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();
}

View file

@ -11,12 +11,19 @@ public:
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
void setValue(const QString &key, const QVariant &value);
void sync() { m_setting.sync(); }
void remove(const QString &key) { m_setting.remove(key); }
void remove(const QString &key);
void sync();
QByteArray backupAppConfig() const;
void restoreAppConfig(const QByteArray &base64Cfg);
private:
QSettings m_setting;
bool encrypted {false};
mutable QMap<QString, QVariant> m_cache;
QStringList encryptedKeys; // encode only key listed here
};
#endif // SECUREQSETTINGS_H

View file

@ -148,71 +148,7 @@ QByteArray decryptText(const QByteArray& qEncryptArray) {
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;
}

View file

@ -12,15 +12,9 @@ class SecureFormat
public:
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

View file

@ -112,8 +112,10 @@ public:
// static constexpr char openNicNs5[] = "94.103.153.176";
// 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:
//static SecureFormat m_secureFormat;
SecureQSettings m_settings;
};

View file

@ -74,3 +74,26 @@ void AppSettingsLogic::onPushButtonClearLogsClicked()
Debug::clearLogs();
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);
}

View file

@ -25,6 +25,10 @@ public:
Q_INVOKABLE void onPushButtonExportLogsClicked();
Q_INVOKABLE void onPushButtonClearLogsClicked();
Q_INVOKABLE void onPushButtonBackupAppConfigClicked();
Q_INVOKABLE void onPushButtonRestoreAppConfigClicked();
public:
explicit AppSettingsLogic(UiLogic *uiLogic, QObject *parent = nullptr);
~AppSettingsLogic() = default;

View file

@ -24,7 +24,6 @@ StartPageLogic::StartPageLogic(UiLogic *logic, QObject *parent):
m_labelWaitInfoVisible{true},
m_labelWaitInfoText{},
m_pushButtonBackFromStartVisible{true},
m_pushButtonConnectVisible{true},
m_ipAddressPortRegex{Utils::ipAddressPortRegExp()}
{
@ -41,7 +40,6 @@ void StartPageLogic::onUpdatePage()
set_labelWaitInfoVisible(false);
set_labelWaitInfoText("");
set_pushButtonConnectVisible(true);
set_pushButtonConnectKeyChecked(false);

View file

@ -20,7 +20,6 @@ class StartPageLogic : public PageLogicBase
AUTO_PROPERTY(bool, labelWaitInfoVisible)
AUTO_PROPERTY(QString, labelWaitInfoText)
AUTO_PROPERTY(bool, pushButtonBackFromStartVisible)
AUTO_PROPERTY(bool, pushButtonConnectVisible)
READONLY_PROPERTY(QRegExp, ipAddressPortRegex)
public:

View file

@ -107,7 +107,7 @@ PageBase {
BlueButtonType {
Layout.fillWidth: true
Layout.topMargin: 15
Layout.topMargin: 10
Layout.preferredHeight: 41
text: qsTr("Export logs")
onClicked: {
@ -117,7 +117,7 @@ PageBase {
BlueButtonType {
Layout.fillWidth: true
Layout.topMargin: 15
Layout.topMargin: 10
Layout.preferredHeight: 41
property string start_text: qsTr("Clear logs")
@ -135,6 +135,31 @@ PageBase {
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()
}
}
}
}

View file

@ -119,7 +119,6 @@ PageBase {
anchors.topMargin: 40
text: qsTr("Open file")
visible: StartPageLogic.pushButtonConnectVisible
onClicked: {
StartPageLogic.onPushButtonImportOpenFile()
}
@ -133,7 +132,6 @@ PageBase {
anchors.topMargin: 10
text: qsTr("Scan QR code")
visible: StartPageLogic.pushButtonConnectVisible
onClicked: {
if (Qt.platform.os == "ios") {
UiLogic.goToPage(PageEnum.QrDecoderIos)
@ -144,7 +142,19 @@ PageBase {
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
text: StartPageLogic.pushButtonConnectText
visible: StartPageLogic.pushButtonConnectVisible
onClicked: {
StartPageLogic.onPushButtonConnect()
}