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;
|
||||
}
|
||||
|
||||
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");
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue