Files
amnezia-client/client/ui/controllers/serversBackupController.h
T
NickVs2015 23b7c26609 fix: adapt ServersBackupController and wizard restore to new codebase after rebase
- Fix includes in ServersBackupController (remove core/defs.h, containers_defs.h;
  add core/utils/containerEnum.h, commonStructs.h, errorCodes.h)
- Inject ServersUiController and ServersController into ServersBackupController
  to replace removed ServersModel API (getProcessedServerIndex, getServerCredentials,
  setDefaultServerIndex, getServerConfig, setDefaultContainer)
- Replace ContainerProps::containerFromString/toString with ContainerUtils equivalents
- Fix SCP permission denied: upload to /tmp first, then sudo mv to backup dir
- Fix double restore: use m_autoRestoreAfterUpload=true always (C++ handles both flows);
  remove redundant onBackupUploaded handler from PageSettingsServerData
- Remove duplicate ServersBackupController Connections from PageSettingsServerData
  (now exclusively handled by PageSettingsServerBackup + PageSettingsServerRestoreMode)
- Remove onBackupRestored from PageSettingsServerBackup (handled by PageSettingsServerRestoreMode)
- Fix wizard restore: remove non-existent setShouldCreateServer calls
- Fix wizard restore: use InstallController.getPortForInstall/defaultTransportProto
  instead of ProtocolProps; pass serverId as 4th arg to InstallController.install()
- Fix QML: replace ServersModel.getServerCredentials with
  ServersUiController.getProcessedServerCredentials()
2026-05-30 13:57:21 +03:00

407 lines
14 KiB
C++

#ifndef SERVERSBACKUPCONTROLLER_H
#define SERVERSBACKUPCONTROLLER_H
#include <QObject>
#include <QString>
#include <QDateTime>
#include <QJsonObject>
#include <QJsonArray>
#include <QFileInfo>
class QTemporaryFile;
class ServersModel;
class ServersUiController;
class ServersController;
class SecureQSettings;
#include <QPointer>
#include "core/utils/containerEnum.h"
#include "core/utils/commonStructs.h"
#include "core/utils/errorCodes.h"
#include "core/utils/selfhosted/sshSession.h"
using namespace amnezia;
/**
* @brief Controller for managing Amnezia VPN configuration backups
*
* Uses existing ServerController and libssh::Client from Amnezia
* Bash scripts are embedded directly in C++ code
* Supports direct container backup via docker cp
*
* Fully cross-platform: Windows, macOS, Linux, iOS, Android
*/
class ServersBackupController : public QObject
{
Q_OBJECT
public:
explicit ServersBackupController(SecureQSettings *settings, ServersModel *serversModel,
ServersUiController *serversUiController, ServersController *serversController,
QObject *parent = nullptr);
~ServersBackupController();
/**
* @brief Backup information
*/
struct BackupInfo {
QString filename;
QString fullPath;
QDateTime createdAt;
qint64 size;
bool isValid;
QStringList containers;
};
enum BackupStatus {
Idle,
InProgress,
Success,
Failed
};
Q_ENUM(BackupStatus)
public slots:
/**
* @brief Create backup on server (all containers)
* @param credentials Server credentials
*/
void createBackup(const ServerCredentials &credentials);
/**
* @brief Create backup and automatically download to device (for QML)
* @param downloadToDevice Download to device after creation?
* @param deleteFromServer Delete from server after download?
*/
Q_INVOKABLE void createBackupWithDownload(bool downloadToDevice = true,
bool deleteFromServer = true);
/**
* @brief Create backup of specific container
* @param credentials Server credentials
* @param container Container type for backup
*/
void createContainerBackup(const ServerCredentials &credentials, DockerContainer container);
/**
* @brief Create backup of specific container by name
* @param credentials Server credentials
* @param containerName Container name (e.g. "amnezia-awg")
*/
void createBackupByName(const ServerCredentials &credentials, const QString &containerName);
/**
* @brief Create backup of multiple containers
* @param credentials Server credentials
* @param containers List of containers for backup
*/
void createContainersBackup(const ServerCredentials &credentials, const QList<DockerContainer> &containers);
/**
* @brief Get list of backups from server
* @param credentials Server credentials
*/
void fetchBackupList(const ServerCredentials &credentials);
/**
* @brief Restore from backup
* @param credentials Server credentials
* @param backupFilename Backup file name
* @param containers List of containers (empty = all)
* @param replaceMode If true - clears container first, then restores. If false - adds data on top of existing
*/
void restoreBackup(const ServerCredentials &credentials,
const QString &backupFilename,
const QStringList &containers = QStringList(),
bool replaceMode = false);
/**
* @brief Check backup status on server
* @param credentials Server credentials
*/
void checkBackupStatus(const ServerCredentials &credentials);
/**
* @brief Download backup to local machine
* @param credentials Server credentials
* @param backupFilename Backup file name
* @param localPath Save path
*/
void downloadBackup(const ServerCredentials &credentials,
const QString &backupFilename,
const QString &localPath);
/**
* @brief Upload backup to server
* @param credentials Server credentials
* @param localPath Path to local file
* @param replaceMode Restore mode (true = replace, false = add). Saved for later use in restoreBackup
*/
void uploadBackup(const ServerCredentials &credentials,
const QString &localPath,
bool replaceMode = false);
// Overloaded method for setup wizard with separate credential parameters
Q_INVOKABLE void uploadBackupWithStrings(const QString &hostname,
const QString &username,
const QString &secretData,
const QString &localPath,
bool replaceMode = false);
/**
* @brief Universal method to start restore (from QML)
* Automatically selects correct path depending on parameters
* @param isFromSetupWizard Restore from setup wizard?
* @param backupFilePath Path to local backup file
* @param replaceMode Restore mode (true = replace, false = add)
* @param wizardHostname Hostname for setup wizard (optional)
* @param wizardUsername Username for setup wizard (optional)
* @param wizardSecretData Secret data for setup wizard (optional)
*/
Q_INVOKABLE void startRestore(bool isFromSetupWizard,
const QString &backupFilePath,
bool replaceMode,
const QString &wizardHostname = QString(),
const QString &wizardUsername = QString(),
const QString &wizardSecretData = QString());
/**
* @brief Prepare restore information from backup file
* Parses filename, extracts IP, prepares metadata
* @param backupFilePath Path to backup file
* @return QVariantMap with keys: fileName, serverIp
*/
Q_INVOKABLE QVariantMap getBackupFileInfo(const QString &backupFilePath);
/**
* @brief Scan backup file and determine which containers it contains
* @param localPath Path to local backup file
* @return List of container names found in backup
*/
Q_INVOKABLE QStringList scanBackupForContainers(const QString &localPath);
/**
* @brief Set default server and container after restore (for setup wizard)
* @param isFromSetupWizard Was restore called from setup wizard
* @return true if successful, false if no servers or containers
*/
Q_INVOKABLE bool setDefaultServerAfterRestore(bool isFromSetupWizard);
/**
* @brief Install containers from backup on empty server (for setup wizard)
* Scans backup, adds empty server and sends signal to install containers
* @param backupFilePath Path to local backup file
* @param hostname Server hostname
* @param username Username for SSH
* @param secretData Password/key for SSH
*/
Q_INVOKABLE void prepareRestoreFromBackup(const QString &backupFilePath,
const QString &hostname,
const QString &username,
const QString &secretData);
/**
* @brief Delete backup from server
* @param credentials Server credentials
* @param backupFilename Backup file name
*/
void deleteBackup(const ServerCredentials &credentials,
const QString &backupFilename);
/**
* @brief Set backup directory on server
*/
void setBackupDirectory(const QString &directory);
/**
* @brief Get backup directory
*/
QString backupDirectory() const { return m_backupDir; }
signals:
/**
* @brief Operation status changed
*/
void statusChanged(BackupStatus status);
/**
* @brief Operation progress (0-100)
*/
void progressChanged(int percent, const QString &message);
/**
* @brief Backup list received
*/
void backupListReceived(const QList<BackupInfo> &backups);
/**
* @brief Backup created successfully
*/
void backupCreated(const QString &backupFilename);
/**
* @brief Backup restored successfully
*/
void backupRestored();
/**
* @brief Need to set default server and container (for setup wizard)
* This signal is sent after backupRestored() if restore was from setup wizard
*/
void needSetDefaultServer();
/**
* @brief Default server and container successfully set
* Can navigate to result page
*/
void defaultServerAndContainerSet();
/**
* @brief All containers from backup installed
* Can proceed to data restore
* @param backupFilePath Path to backup file
* @param hostname Hostname
* @param username Username
* @param secretData Secret data
* @param serverIp IP address (for display)
* @param fileName File name (for display)
*/
void readyForRestore(const QString &backupFilePath,
const QString &hostname,
const QString &username,
const QString &secretData,
const QString &serverIp,
const QString &fileName);
/**
* @brief Backup downloaded
*/
void backupDownloaded(const QString &localPath);
/**
* @brief Backup uploaded to server
*/
void backupUploaded(const QString &serverPath);
/**
* @brief Backup status information received
*/
void backupStatusReceived(const QJsonObject &status);
/**
* @brief Error occurred
*/
void errorOccurred(const QString &errorMessage, ErrorCode errorCode);
private:
/**
* @brief Get bash script for creating backup of all containers
* @param ipAddress Server IP address in underscored format (e.g. "192_119_110_11")
*/
QString getBackupScript(const QString &ipAddress) const;
/**
* @brief Get bash script for creating backup of specific container
* @param container Container type
* @param ipAddress Server IP address in underscored format (e.g. "192_119_110_11")
*/
QString getContainerBackupScript(DockerContainer container, const QString &ipAddress) const;
/**
* @brief Get bash script for creating backup of multiple containers
* @param containers List of containers
* @param ipAddress Server IP address in underscored format (e.g. "192_119_110_11")
*/
QString getContainersBackupScript(const QList<DockerContainer> &containers, const QString &ipAddress) const;
/**
* @brief Get bash script for restore
* @param backupFilename Backup file name
* @param containers List of containers
* @param replaceMode If true - clears container first, then restores
*/
QString getRestoreScript(const QString &backupFilename, const QStringList &containers, bool replaceMode = false) const;
/**
* @brief Get bash script for status check
*/
QString getCheckStatusScript() const;
/**
* @brief Get bash script for backup list
*/
QString getListBackupsScript() const;
/**
* @brief Parse backup list from output
*/
QList<BackupInfo> parseBackupList(const QString &output);
/**
* @brief Parse status from output
*/
QJsonObject parseBackupStatus(const QString &output);
/**
* @brief Handle standard output
*/
ErrorCode handleStdOut(const QString &data, QString &output);
/**
* @brief Handle error output
*/
ErrorCode handleStdErr(const QString &data, QString &error);
/**
* @brief Set status
*/
void setStatus(BackupStatus status);
/**
* @brief Set progress
*/
void setProgress(int percent, const QString &message);
/**
* @brief Attempt to set default container (called from timer)
*/
void trySetDefaultContainer();
ErrorCode runHostScript(const ServerCredentials &credentials, const QString &script,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbStdOut = nullptr,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbStdErr = nullptr);
ErrorCode downloadFileFromHost(const ServerCredentials &credentials, const QString &remotePath, const QString &localPath);
ErrorCode uploadFileToHostPublic(const ServerCredentials &credentials, const QString &localPath, const QString &remotePath,
libssh::ScpOverwriteMode overwriteMode = libssh::ScpOverwriteMode::ScpOverwriteExisting);
private:
QPointer<SecureQSettings> m_settings;
ServersModel *m_serversModel;
ServersUiController *m_serversUiController;
ServersController *m_serversController;
SshSession m_sshSession;
BackupStatus m_status;
QString m_backupDir;
QString m_currentOutput;
QString m_currentError;
bool m_restoreReplaceMode; // Save restore mode for use after uploadBackup
QTemporaryFile *m_tempUploadFile; // Temp file for Android URI (to prevent deletion before upload completes)
// For setting default container
int m_containerRetryCount;
static constexpr int m_maxContainerRetries = 3;
// For automatic restore after upload
ServerCredentials m_pendingRestoreCredentials;
bool m_autoRestoreAfterUpload;
// For automatic backup download/delete
bool m_autoDownloadAfterCreate;
bool m_autoDeleteAfterDownload;
QString m_lastCreatedBackupFilename;
};
#endif // SERVERSBACKUPCONTROLLER_H