diff --git a/src/opnsense/mvc/app/library/OPNsense/Backup/BackupFactory.php b/src/opnsense/mvc/app/library/OPNsense/Backup/BackupFactory.php new file mode 100644 index 000000000..8d3ffddcc --- /dev/null +++ b/src/opnsense/mvc/app/library/OPNsense/Backup/BackupFactory.php @@ -0,0 +1,81 @@ +implementsInterface('OPNsense\\Backup\\IBackupProvider') + && !$reflClass->isInterface()) { + $providers[$classname] = array( + "class" => "{$vendor}\\{$module}\\{$classname}", + "handle" => $reflClass->newInstance() + ); + } + } catch (\ReflectionException $e) { + null; // skip when unable to parse + } + } + return $providers; + } + + /** + * return a specific provider by class name (without namespace) + * @param string $className without namespace + * @return mixed|null + */ + public function getProvider($className) + { + $providers = $this->listProviders(); + if (!empty($providers[$className])) { + return $providers[$className]; + } else { + return null; + } + } +} \ No newline at end of file diff --git a/src/opnsense/mvc/app/library/OPNsense/Backup/Base.php b/src/opnsense/mvc/app/library/OPNsense/Backup/Base.php new file mode 100644 index 000000000..046cb69fd --- /dev/null +++ b/src/opnsense/mvc/app/library/OPNsense/Backup/Base.php @@ -0,0 +1,92 @@ + "GDriveEnabled", + "type" => "checkbox", + "label" => gettext("Enable") + ); + $fields[] = array( + "name" => "GDriveEmail", + "type" => "text", + "label" => gettext("Email Address") + ); + $fields[] = array( + "name" => "GDriveP12file", + "type" => "file", + "label" => gettext("P12 key (not loaded)") + ); + $fields[] = array( + "name" => "GDriveFolderID", + "type" => "text", + "label" => gettext("Folder ID") + ); + $fields[] = array( + "name" => "GDrivePrefixHostname", + "type" => "text", + "label" => gettext("Prefix hostname to backupfile") + ); + $fields[] = array( + "name" => "GDriveBackupCount", + "type" => "text", + "label" => gettext("Backup Count") + ); + $fields[] = array( + "name" => "GDrivePassword", + "type" => "password", + "label" => gettext("Password") + ); + $fields[] = array( + "name" => "GDrivePasswordConfirm", + "type" => "password", + "label" => gettext("Confirm") + ); + + return $fields; + } + + /** + * backup provider name + * @return string user friendly name + */ + public function getName() + { + return gettext("Google Drive"); + } + + /** + * validate and set configuration + * @param array $conf configuration array + * @return array of validation errors + */ + public function setConfiguration($conf) + { + // TODO: Implement setConfiguration() method. + } + + /** + * @return array filelist + */ + public function backup() + { + $cnf = Config::getInstance(); + if ($cnf->isValid()) { + $config = $cnf->object(); + if (isset($config->system->remotebackup) && isset($config->system->remotebackup->GDriveEnabled) + && !empty($config->system->remotebackup->GDriveEnabled)) { + if (!empty($config->system->remotebackup->GDrivePrefixHostname)) { + $fileprefix = (string)$config->system->hostname . "." . (string)$config->system->domain . "-"; + } else { + $fileprefix = "config-"; + } + try { + $client = new Google\API\Drive(); + $client->login($config->system->remotebackup->GDriveEmail->__toString(), + $config->system->remotebackup->GDriveP12key->__toString()); + } catch (Exception $e) { + log_error("error connecting to Google Drive"); + return array(); + } + + // backup source data to local strings (plain/encrypted) + $confdata = file_get_contents('/conf/config.xml'); + $confdata_enc = chunk_split( + $this->encrypt($confdata, $config->system->remotebackup->GDrivePassword->__toString()) + ); + + // read filelist ({prefix}*.xml) + try { + $files = $client->listFiles($config->system->remotebackup->GDriveFolderID->__toString()); + } catch (Exception $e) { + log_error("error while fetching filelist from Google Drive"); + return array(); + } + + $configfiles = array(); + foreach ($files as $file) { + if (fnmatch("{$fileprefix}*.xml", $file['title'])) { + $configfiles[$file['title']] = $file; + } + } + krsort($configfiles); + + + // backup new file if changed (or if first in backup) + $target_filename = $fileprefix . time() . ".xml"; + if (count($configfiles) > 1) { + // compare last backup with current, only save new + try { + $bck_data_enc = $client->download($configfiles[array_keys($configfiles)[0]]); + $bck_data = $this->decrypt($bck_data_enc, + $config->system->remotebackup->GDrivePassword->__toString()); + if ($bck_data == $confdata) { + $target_filename = null; + } + } catch (Exception $e) { + log_error("unable to download " . $configfiles[array_keys($configfiles)[0]]->description . " from Google Drive (" . $e . ")"); + } + } + if (!is_null($target_filename)) { + log_error("backup configuration as " . $target_filename); + try { + $configfiles[$target_filename] = $client->upload($config->system->remotebackup->GDriveFolderID->__toString(), $target_filename, $confdata_enc); + } catch (Exception $e) { + log_error("unable to upload " . $target_filename . " to Google Drive (" . $e . ")"); + return array(); + } + + krsort($configfiles); + } + + // cleanup old files + if (isset($config->system->remotebackup->GDriveBackupCount) && is_numeric($config->system->remotebackup->GDriveBackupCount->__toString())) { + $fcount = 0; + foreach ($configfiles as $filename => $file) { + if ($fcount >= $config->system->remotebackup->GDriveBackupCount->__toString()) { + log_error("remove " . $filename . " from Google Drive"); + try { + $client->delete($file); + } catch (Google_Service_Exception $e) { + log_error("unable to remove " . $filename . " from Google Drive"); + } + } + $fcount++; + } + } + + // return filelist + return $configfiles; + } + } + + // not configured / issue, return empty list + return array(); + } + + /** + * Is this provider enabled + * @return boolean enabled status + */ + public function isEnabled() + { + $cnf = Config::getInstance(); + if ($cnf->isValid()) { + $config =$cnf->object(); + return isset($config->system->remotebackup) && isset($config->system->remotebackup->GDriveEnabled) + && !empty($config->system->remotebackup->GDriveEnabled); + } + return false; + } +} \ No newline at end of file diff --git a/src/opnsense/mvc/app/library/OPNsense/Backup/IBackupProvider.php b/src/opnsense/mvc/app/library/OPNsense/Backup/IBackupProvider.php new file mode 100644 index 000000000..68bf7a214 --- /dev/null +++ b/src/opnsense/mvc/app/library/OPNsense/Backup/IBackupProvider.php @@ -0,0 +1,69 @@ +