From 5ec979d6eba286069c1569d56e80691ebd983809 Mon Sep 17 00:00:00 2001 From: Riccardo Di Dato Date: Fri, 26 Feb 2016 12:07:22 +0100 Subject: [PATCH] Implementato backup client CBS --- .build.config | 5 +- private/common/config.local.php | 9 +- private/common/config.php | 11 +- private/common/config.prod.php | 7 +- private/common/config.test.php | 8 +- private/crontab/core.daily.php | 21 + private/lib/AnalyticsHelper.php | 2 +- private/lib/PipelineHelper.php | 132 ++++++ private/lib/backup/FDN2CBS_DataStorage.php | 112 +++++ private/lib/backup/FDN2CBS_Logger.php | 55 +++ private/lib/backup/cbsClient/CBSClient.php | 29 ++ .../cbsClient/CBSClient_DataStorageBase.php | 66 +++ .../CBS_RAPIClientImplementation.php | 45 ++ .../backup/cbsClient/cbs.client.include.php | 28 ++ .../request/RAPI_BackupListRequestDetails.php | 51 +++ .../RAPI_CreateBackupRequestDetails.php | 51 +++ .../request/RAPI_GetBackupRequestDetails.php | 52 +++ .../RAPI_BackupListResponseDetails.php | 24 ++ .../RAPI_CreateBackupResponseDetails.php | 23 ++ .../RAPI_GetBackupResponseDetails.php | 23 ++ .../lib/backup/cbsClient/rapi/RAPI_Config.php | 45 ++ .../backup/cbsClient/rapi/RAPI_CryptUtils.php | 48 +++ .../lib/backup/cbsClient/rapi/RAPI_Logger.php | 44 ++ .../rapi/exceptions/RAPI_Exception.php | 16 + .../exceptions/RAPI_ValidationException.php | 40 ++ private/lib/backup/cbsClient/rapi/include.php | 30 ++ .../cbsClient/rapi/messages/RAPI_Message.php | 256 ++++++++++++ .../rapi/messages/RAPI_MessageDetails.php | 135 ++++++ .../cbsClient/rapi/messages/RAPI_Request.php | 143 +++++++ .../rapi/messages/RAPI_RequestDetails.php | 135 ++++++ .../messages/RAPI_RequestDetailsFactory.php | 52 +++ .../cbsClient/rapi/messages/RAPI_Response.php | 172 ++++++++ .../rapi/messages/RAPI_ResponseDetails.php | 11 + .../request/RAPI_UnreadableRequest.php | 18 + .../request/RAPI_UnreadableRequestDetails.php | 51 +++ .../response/RAPI_EmptyResponseDetails.php | 24 ++ .../RAPI_SimpleMessageResponseDetails.php | 33 ++ .../rapi/rapi_client/RAPI_Client.php | 383 ++++++++++++++++++ .../rapi/rapi_client/RAPI_ClientException.php | 34 ++ .../rapi/rapi_client/RAPI_ClientHelper.php | 120 ++++++ .../rapi/rapi_client/RAPI_DataStorage.php | 70 ++++ .../rapi/rapi_client/client_include.php | 20 + .../request_helper/RAPI_ResponseFetcher.php | 13 + .../RAPI_SingleValueResponseFetcher.php | 26 ++ .../RAPI_StandardResponseFetcher.php | 33 ++ private/lib/backup/lib.inclusion.php | 18 + private/lib/dao/GenericDao.php | 10 + private/lib/dao/lib.inclusion.php | 4 +- private/lib/dao/models/CBSQueueModel.php | 23 ++ private/lib/gui/HTMLHelper.php | 2 +- private/lib/lib.inclusions.php | 2 + private/lib/logger/lib.inclusion.php | 6 + private/lib/system/FSObject.php | 4 + private/lib/system/SFSManager.php | 15 + private/lib/system/SystemController.php | 4 + .../lib/system/fsobjects/LocallyMountedFS.php | 52 +++ private/lib/system/lib.inclusion.php | 8 +- private/lib/task/SendBackupTask.php | 36 ++ private/lib/task/lib.inclusion.php | 2 + public/admin/editConfig.php | 2 +- public/admin/login.php | 5 +- public/admin/statSito.php | 222 ++++------ public/articolo.php | 32 ++ public/style/admin.css | 13 +- 64 files changed, 2996 insertions(+), 170 deletions(-) create mode 100644 private/lib/PipelineHelper.php create mode 100644 private/lib/backup/FDN2CBS_DataStorage.php create mode 100644 private/lib/backup/FDN2CBS_Logger.php create mode 100644 private/lib/backup/cbsClient/CBSClient.php create mode 100644 private/lib/backup/cbsClient/CBSClient_DataStorageBase.php create mode 100644 private/lib/backup/cbsClient/CBS_RAPIClientImplementation.php create mode 100644 private/lib/backup/cbsClient/cbs.client.include.php create mode 100644 private/lib/backup/cbsClient/messages/request/RAPI_BackupListRequestDetails.php create mode 100644 private/lib/backup/cbsClient/messages/request/RAPI_CreateBackupRequestDetails.php create mode 100644 private/lib/backup/cbsClient/messages/request/RAPI_GetBackupRequestDetails.php create mode 100644 private/lib/backup/cbsClient/messages/response/RAPI_BackupListResponseDetails.php create mode 100644 private/lib/backup/cbsClient/messages/response/RAPI_CreateBackupResponseDetails.php create mode 100644 private/lib/backup/cbsClient/messages/response/RAPI_GetBackupResponseDetails.php create mode 100644 private/lib/backup/cbsClient/rapi/RAPI_Config.php create mode 100644 private/lib/backup/cbsClient/rapi/RAPI_CryptUtils.php create mode 100644 private/lib/backup/cbsClient/rapi/RAPI_Logger.php create mode 100644 private/lib/backup/cbsClient/rapi/exceptions/RAPI_Exception.php create mode 100644 private/lib/backup/cbsClient/rapi/exceptions/RAPI_ValidationException.php create mode 100644 private/lib/backup/cbsClient/rapi/include.php create mode 100644 private/lib/backup/cbsClient/rapi/messages/RAPI_Message.php create mode 100644 private/lib/backup/cbsClient/rapi/messages/RAPI_MessageDetails.php create mode 100644 private/lib/backup/cbsClient/rapi/messages/RAPI_Request.php create mode 100644 private/lib/backup/cbsClient/rapi/messages/RAPI_RequestDetails.php create mode 100644 private/lib/backup/cbsClient/rapi/messages/RAPI_RequestDetailsFactory.php create mode 100644 private/lib/backup/cbsClient/rapi/messages/RAPI_Response.php create mode 100644 private/lib/backup/cbsClient/rapi/messages/RAPI_ResponseDetails.php create mode 100644 private/lib/backup/cbsClient/rapi/messages/request/RAPI_UnreadableRequest.php create mode 100644 private/lib/backup/cbsClient/rapi/messages/request/RAPI_UnreadableRequestDetails.php create mode 100644 private/lib/backup/cbsClient/rapi/messages/response/RAPI_EmptyResponseDetails.php create mode 100644 private/lib/backup/cbsClient/rapi/messages/response/RAPI_SimpleMessageResponseDetails.php create mode 100644 private/lib/backup/cbsClient/rapi/rapi_client/RAPI_Client.php create mode 100644 private/lib/backup/cbsClient/rapi/rapi_client/RAPI_ClientException.php create mode 100644 private/lib/backup/cbsClient/rapi/rapi_client/RAPI_ClientHelper.php create mode 100644 private/lib/backup/cbsClient/rapi/rapi_client/RAPI_DataStorage.php create mode 100644 private/lib/backup/cbsClient/rapi/rapi_client/client_include.php create mode 100644 private/lib/backup/cbsClient/rapi/rapi_client/request_helper/RAPI_ResponseFetcher.php create mode 100644 private/lib/backup/cbsClient/rapi/rapi_client/request_helper/RAPI_SingleValueResponseFetcher.php create mode 100644 private/lib/backup/cbsClient/rapi/rapi_client/request_helper/RAPI_StandardResponseFetcher.php create mode 100644 private/lib/backup/lib.inclusion.php create mode 100644 private/lib/dao/models/CBSQueueModel.php create mode 100644 private/lib/task/SendBackupTask.php create mode 100644 public/articolo.php diff --git a/.build.config b/.build.config index 4a583b2..69b72f2 100644 --- a/.build.config +++ b/.build.config @@ -16,6 +16,7 @@ APACHE2_DOCUMENTROOT="/var/www" SYSTEM_LOG_PATH="/var/log/asdynamics" SYSTEM_PRIVATE="/home/asdynamics/private" SYSTEM_STORAGE="/home/asdynamics/storage" +SYSTEM_TMP="/tmp/asdynamics" ################################### @@ -33,8 +34,8 @@ APPLICATION_XSENDFILE_PATH="/tmp/xsend/$APPLICATION_BUILDNAME" ##### OTHER APPLICATION PATHS ###### #################################### APPLICATION_MEDIA_PATH="$APPLICATION_STORAGE/media" -APPLICATION_BACKUPS_PATH="$APPLICATION_STORAGE/backups" -APPLICATION_TMP_PATH="$APPLICATION_STORAGE/tmp" +APPLICATION_BACKUPS_PATH="$APPLICATION_STORAGE/backup" +APPLICATION_TMP_PATH="$SYSTEM_TMP/$APPLICATION_BUILDNAME" APPLICATION_CONFIG_PATH="$APPLICATION_PRIVATE/common" APPLICATION_BINARY_PATH="$APPLICATION_PRIVATE/bin" APPLICATION_CRON_PATH="$APPLICATION_PRIVATE/crontab" diff --git a/private/common/config.local.php b/private/common/config.local.php index d7e76af..3ab3a73 100644 --- a/private/common/config.local.php +++ b/private/common/config.local.php @@ -15,12 +15,13 @@ $database->dbName = "fdn2"; $database->connectionString = "mongodb://10.0.0.2:27017"; $currentSystem = new stdClass(); -$currentSystem->storageBaseDir = "/home/asdynamics/storage"; // Il path con storage ecc in cui mettere immagini, file temporanei ecc +$currentSystem->storageBaseDir = "/home/asdynamics/storage"; // Il path con storage ecc in cui mettere i contenuti dell'applicazione (immagini, dump db ecc) $currentSystem->privateBaseDir = "/home/asdynamics/private"; // Il path in cui inserire la cartella con lib, task, binari ecc +$currentSystem->tmpBaseDir = "/tmp/asdynamics"; $currentSystem->logBaseDir = "/var/log/asdynamics"; // Il path dei log.... $currentSystem->xSendFileDir = "/tmp/xsend"; -$currentSystem->safeStorage = "/home/cbs/storage"; +// $currentSystem->safeStorage = "/home/cbs/storage"; $currentSystem->apache = new StdClass(); $currentSystem->apache->user = "var-www"; @@ -29,7 +30,9 @@ $currentSystem->apache->workdir = "/var/www"; // Il path in cui inserire la car $currentSystem->remoteLocationPath = "/fdn2/"; - +$backupSystem = new stdClass(); +$backupSystem->account = "40a911e14db8ad6faf0a0e7385e7c267"; +$backupSystem->passphrase = "a54af48c2ec44bba903666b6d12290750178154a6965c9165d3b387e7fd0f14c5f2d62cb93f468be640d469c80f1260feed3ad98f5f52d52c045b0487e59981bf365f4037f6c7cb93572cdd5d20daeb8185afcc65dba1bd2067829f827d9b795451f6e5e8fafe5e1fbe29675feb93e7d208a6b53a14df5aeec62d97fbf34d56a"; // $config->locations = new stdClass(); diff --git a/private/common/config.php b/private/common/config.php index 815d55b..44b7537 100644 --- a/private/common/config.php +++ b/private/common/config.php @@ -40,6 +40,7 @@ $config->paths->storage = $currentSystem->storageBaseDir . "/" . $project->buil $config->paths->private = $currentSystem->privateBaseDir . "/" . $project->buildName; $config->paths->public = $currentSystem->apache->workdir . "/" . $project->buildName; $config->paths->log = $currentSystem->logBaseDir . "/" . $project->buildName; +$config->paths->tmp = $currentSystem->tmpBaseDir . "/" . $project->buildName; $config->paths->backup = $config->paths->storage . "/backup"; @@ -47,12 +48,13 @@ $config->paths->binaries = $config->paths->private . "/bin"; $config->paths->common = $config->paths->private . "/common"; $config->paths->libraries = $config->paths->private . "/lib"; $config->paths->task = $config->paths->private . "/task"; +$config->paths->cbsQueue = $config->paths->tmp . "/cbsQueue"; +$config->paths->backupTmp = $config->paths->tmp . "/bak"; $config->paths->pubImages = $config->paths->public . "/style/images"; $config->paths->media = $config->paths->storage . "/media"; // $config->paths->defMedia = $config->paths->pubImages . "/defaults"; -$config->paths->tmp = $config->paths->storage . "/tmp"; $config->paths->xsendfile = $currentSystem->xSendFileDir . "/" . $project->buildName; @@ -65,6 +67,7 @@ $config->files->task_log = $config->paths->log . "/task.log"; $config->files->general_log = $config->paths->log . "/general.log"; $config->files->gui_log = $config->paths->log . "/gui.log"; $config->files->mail_log = $config->paths->log . "/mail.log"; +$config->files->api_log = $config->paths->log . "/api.log"; // Pages $config->pages = new StdClass(); @@ -79,9 +82,13 @@ $config->emails->info = "info@ifattidinapoli.it"; $config->emails->system = "system@ifattidinapoli.it"; $config->emails->postmaster = "postmaster@ifattidinapoli.it"; - // $config->pages->index = $currentSystem->remoteLocation . "/index.php"; // $config->pages->login = $currentSystem->remoteLocation . "/login.php"; // $config->pages->logout = $currentSystem->remoteLocation . "/logout.php"; + +$config->api = new stdClass(); +$config->api->account = $backupSystem->account; +$config->api->passphrase = $backupSystem->passphrase; + ?> diff --git a/private/common/config.prod.php b/private/common/config.prod.php index e5ab7f7..078878f 100644 --- a/private/common/config.prod.php +++ b/private/common/config.prod.php @@ -19,10 +19,11 @@ $database->connectionString = null; $currentSystem = new stdClass(); $currentSystem->storageBaseDir = "/home/asdynamics/storage"; // Il path con storage ecc in cui mettere immagini, file temporanei ecc $currentSystem->privateBaseDir = "/home/asdynamics/private"; // Il path in cui inserire la cartella con lib, task, binari ecc +$currentSystem->tmpBaseDir = "/tmp/asdynamics"; $currentSystem->logBaseDir = "/var/log/asdynamics"; // Il path dei log.... $currentSystem->xSendFileDir = "/tmp/xsend"; -$currentSystem->safeStorage = "/home/cbs/storage"; +// $currentSystem->safeStorage = "/home/cbs/storage"; $currentSystem->apache = new StdClass(); $currentSystem->apache->user = "var-www"; @@ -31,7 +32,9 @@ $currentSystem->apache->workdir = "/var/www"; // Il path in cui inserire la car $currentSystem->remoteLocationPath = "/"; - +$backupSystem = new stdClass(); +$backupSystem->account = "1582528f056a7ea7f391149fddc75553"; +$backupSystem->passphrase = "232728b3e504a400a62a9f94893a9a962ecc6543ed7d3c293340414b259aac727f14d60a4f2cd52e228c9694a55774ff5652520b38d120a299394715247645b8293a880901162f268c8c8777a3ee9c6e410455cb4c8137f58f9d7162d45582ab363679ed456e56bf3b36d0384368b62eced40abd0fe117f04c9322f07ee33a7c"; // $config->locations = new stdClass(); diff --git a/private/common/config.test.php b/private/common/config.test.php index 7eebd20..dbd3c84 100644 --- a/private/common/config.test.php +++ b/private/common/config.test.php @@ -18,10 +18,11 @@ $database->connectionString = null; $currentSystem = new stdClass(); $currentSystem->storageBaseDir = "/home"; // Il path con storage ecc in cui mettere immagini, file temporanei ecc $currentSystem->privateBaseDir = "/home/asdynamics"; // Il path in cui inserire la cartella con lib, task, binari ecc +$currentSystem->tmpBaseDir = "/tmp/asdynamics"; $currentSystem->logBaseDir = "/var/log"; // Il path dei log.... $currentSystem->xSendFileDir = "/tmp/xsend"; -$currentSystem->safeStorage = "/home/cbs/storage"; +// $currentSystem->safeStorage = "/home/cbs/storage"; $currentSystem->apache = new StdClass(); $currentSystem->apache->user = "var-www"; @@ -31,6 +32,11 @@ $currentSystem->apache->workdir = "/var/www"; // Il path in cui inserire la car $currentSystem->remoteLocationPath = "/"; +$backupSystem = new stdClass(); +$backupSystem->account = "40a911e14db8ad6faf0a0e7385e7c267"; +$backupSystem->passphrase = "a54af48c2ec44bba903666b6d12290750178154a6965c9165d3b387e7fd0f14c5f2d62cb93f468be640d469c80f1260feed3ad98f5f52d52c045b0487e59981bf365f4037f6c7cb93572cdd5d20daeb8185afcc65dba1bd2067829f827d9b795451f6e5e8fafe5e1fbe29675feb93e7d208a6b53a14df5aeec62d97fbf34d56a"; + + // $config->locations = new stdClass(); diff --git a/private/crontab/core.daily.php b/private/crontab/core.daily.php index dee4448..f8ec127 100644 --- a/private/crontab/core.daily.php +++ b/private/crontab/core.daily.php @@ -2,6 +2,27 @@ 0){ + foreach ($tasks as $taskName){ + try { + if ($taskName::isActive()){ + LoggingFacilityManager::getLogger("task")->log(LoggingFacility::$LEVEL_INFO,"Executing task '".$taskName::getLabel()."' "); + $taskName::execute(); + LoggingFacilityManager::getLogger("task")->log(LoggingFacility::$LEVEL_INFO,"Task '".$taskName::getLabel()."' completed successfully"); + } + }catch (CoreException $ex){ + $msg = "Error while executing task '".$taskName::getLabel()."' with message '".$ex->getMessage()."'"; + LoggingFacilityManager::getLogger("task")->log(LoggingFacility::$LEVEL_ERROR,$msg); + } + catch (Exception $ex){ + $msg = "Unexpected error while executing task '".$taskName::getLabel()."' with message '".$ex->getMessage()."'"; + LoggingFacilityManager::getLogger("task")->log(LoggingFacility::$LEVEL_ERROR,$msg); + } + } +} + // try { diff --git a/private/lib/AnalyticsHelper.php b/private/lib/AnalyticsHelper.php index b8a1ab3..e74c92f 100644 --- a/private/lib/AnalyticsHelper.php +++ b/private/lib/AnalyticsHelper.php @@ -6,7 +6,7 @@ Creation Date: 27/gen/2016 class AnalyticsHelper { private static $COOKIE_NAME = "FDN_STAT_NUM"; - // Switch this value to +1 year in production environment + //TODO: Switch this value to +1 year in production environment private static $COOKIE_TIME = "+5 minutes"; public static function savePageImpression($ip, $content, $source){ diff --git a/private/lib/PipelineHelper.php b/private/lib/PipelineHelper.php new file mode 100644 index 0000000..5fa3b44 --- /dev/null +++ b/private/lib/PipelineHelper.php @@ -0,0 +1,132 @@ +array( + 'statType'=>StatisticModel::STAT_TYPE_PAGE, + 'date'=>array( + '$gte'=>new MongoDate($startDate) + ) + ) + ), + array( + '$group'=>array( + "_id"=>array( + 'date'=>array( + "day"=>array('$dayOfMonth'=>'$date'), + "month"=>array('$month'=>'$date'), + "year"=>array('$year'=>'$date') + ), + 'user'=>'$user.id', + ), + "visualizzazioni"=>array( + '$sum'=>1 + ), + "isNew"=>array( + '$sum'=>array( + '$cond'=>array( + array('$eq'=>array('$user.isNew',true)), + 1, + 0 + ) + ) + ) + ) + ), + array( + '$group'=>array( + "_id"=>array( + 'date'=>'$_id.date' + ), + "visualizzazioni"=>array( + '$sum'=>'$visualizzazioni' + ), + "unici"=>array( + '$sum'=>'$isNew' + ), + "visitatori"=>array( + '$sum'=>1 + ) + ) + ), + array( + '$sort'=>array( + "_id.date.year"=>1, + "_id.date.month"=>1, + "_id.date.day"=>1 + ) + ) + ); + return $rval; + } + + public static function getMonthlyVisualizationPipeline($startDate){ + $rval = array( + array( + '$match'=>array( + 'statType'=>StatisticModel::STAT_TYPE_PAGE, + 'date'=>array( + '$gte'=>new MongoDate($startDate) + ) + ) + ), + array( + '$group'=>array( + "_id"=>array( + 'date'=>array( + "month"=>array('$month'=>'$date'), + "year"=>array('$year'=>'$date') + ), + 'user'=>'$user.id', + ), + "visualizzazioni"=>array( + '$sum'=>1 + ), + "isNew"=>array( + '$sum'=>array( + '$cond'=>array( + array('$eq'=>array('$user.isNew',true)), + 1, + 0 + ) + ) + ) + ) + ), + array( + '$group'=>array( + "_id"=>array( + 'date'=>'$_id.date' + ), + "visualizzazioni"=>array( + '$sum'=>'$visualizzazioni' + ), + "unici"=>array( + '$sum'=>'$isNew' + ), + "visitatori"=>array( + '$sum'=>1 + ) + ) + ), + array( + '$sort'=>array( + "_id.date.year"=>1, + "_id.date.month"=>1 + ) + ) + ); + return $rval; + } + + +} + +?> \ No newline at end of file diff --git a/private/lib/backup/FDN2CBS_DataStorage.php b/private/lib/backup/FDN2CBS_DataStorage.php new file mode 100644 index 0000000..ea60cd0 --- /dev/null +++ b/private/lib/backup/FDN2CBS_DataStorage.php @@ -0,0 +1,112 @@ +getFirst("ConfigModel",array("name"=>"cbsQueue")); + if (!is_null($conf)){ + $rval = $conf->lastOperationId+1; + } + return $rval; + +// $cur = GlobalVariables::get("dao")->getFirst("CBSQueueModel",array(),array("sort"=>"operationId")); +// if (is_null($cur)){ +// return 1; +// } +// else { +// return $cur->operationId+1; +// } + } + /** + * (non-PHPdoc) + * @see CBSClient_DataStorageBase::setMaxOperationId() + */ + public function setMaxOperationId($id){ + $conf = GlobalVariables::get("dao")->getFirst("ConfigModel",array("name"=>"cbsQueue")); + if (is_null($conf)){ + $obj = new stdClass(); + $obj->name="cbsQueue"; + $conf = new ConfigModel($obj); + } + $conf->lastOperationId = $id; + GlobalVariables::get("dao")->save($conf); + } + + /** + * @see CBSClient_DataStorageBase::queueUncompletedRequest() + */ + public function queueUncompletedRequest($id, RAPI_RequestDetails $req){ + $queueFolder = GlobalVariables::get("config")->paths->cbsQueue; + $obj = new stdClass(); + $obj->operationId = $id; + $obj->retry = 0; + $queueObj = new CBSQueueModel($obj); + GlobalVariables::get("dao")->save($queueObj); + + if (!SFSManager::fileExists($queueFolder)){ + SFSManager::createDirectory($queueFolder); + } + $path = $queueFolder."/".$queueObj->id; + + SFSManager::writeFile(serialize($req), $path); + } + + /** + * @see CBSClient_DataStorageBase::getUncompletedRequests() + */ + public function getUncompletedRequests($limit = null){ + $rval = array(); + + $basePath = GlobalVariables::get("config")->paths->cbsQueue; + + $opt = array("sort"=>array("retry"=>1)); + if (!is_null($limit)){ + $opt["limit"] = $limit; + } + + $requests = GlobalVariables::get("dao")->query("CBSQueueModel", array(), $opt); + if (sizeof($requests)>0){ + foreach ($requests as $request){ + $path = $basePath."/".$queueObj->id; + $cont = implode("",SFSManager::readFile($path)); + $rval[] = unserialize($cont); + } + } + return $rval; + } + + /** + * @see CBSClient_DataStorageBase::onRequestCompletedFromQueue() + */ + public function onRequestCompletedFromQueue($id){ + $queueObj = GlobalVariables::get("dao")->getFirst("CBSQueueModel", array("operationId"=>$id)); + + $path = GlobalVariables::get("config")->paths->cbsQueue."/".$queueObj->id; + SFSManager::deleteFile($path); + GlobalVariables::get("dao")->delete($queueObj); + } + + /** + * @see CBSClient_DataStorageBase::onRequestFailedFromQueue() + */ + public function onRequestFailedFromQueue($id){ + $queueObj = GlobalVariables::get("dao")->getFirst("CBSQueueModel", array("operationId"=>$id)); + $queueObj->retry = $queueObj->retry+1; + GlobalVariables::get("dao")->save($queueObj); + } + +// private function getOperationIdFile(){ +// $config = GlobalVariables::get("config"); +// return $config->paths->common."/RAPI_maxOperationId"; +// } +} + +?> \ No newline at end of file diff --git a/private/lib/backup/FDN2CBS_Logger.php b/private/lib/backup/FDN2CBS_Logger.php new file mode 100644 index 0000000..07b5868 --- /dev/null +++ b/private/lib/backup/FDN2CBS_Logger.php @@ -0,0 +1,55 @@ +log($this->convertToCbsLogLevel($level),$message); + } + + /** + * (non-PHPdoc) + * @see RAPI_Logger::generateSecurityWarning() + */ + public function generateSecurityWarning($severity, $message, RAPI_Request $request){ + LoggingFacilityManager::getLogger("api")->log(LoggingFacility::$LEVEL_WARNING,"CBS SECURITY WARNING - ".$message); + } + + /** + * (non-PHPdoc) + * @see RAPI_Logger::generateSecurityOperationWarning() + */ + public function generateSecurityOperationWarning($severity, $message, RAPI_Request $request, RAPI_Operation $op){ + + } + + + private function convertToCbsLogLevel($level){ + switch ($level){ + case RAPI_Logger::LOG_LEVEL_DEBUG: + $rval = LoggingFacility::$LEVEL_DEBUG; + break; + case RAPI_Logger::LOG_LEVEL_INFO: + $rval = LoggingFacility::$LEVEL_INFO; + break; + case RAPI_Logger::LOG_LEVEL_WARNING: + $rval = LoggingFacility::$LEVEL_WARNING; + break; + case RAPI_Logger::LOG_LEVEL_ERROR: + $rval = LoggingFacility::$LEVEL_ERROR; + break; + } + return $rval; + } + + +} + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/CBSClient.php b/private/lib/backup/cbsClient/CBSClient.php new file mode 100644 index 0000000..8720e0f --- /dev/null +++ b/private/lib/backup/cbsClient/CBSClient.php @@ -0,0 +1,29 @@ +defineRequest("getBackups", "RAPI_BackupListRequestDetails", new RAPI_SingleValueResponseFetcher("list")); + $this->defineRequest("sendBackup", "RAPI_CreateBackupRequestDetails", new RAPI_SingleValueResponseFetcher("id")); +// $this->defineRequest("getBackup", "RAPI_GetBackupRequestDetails", new RAPI_StandardResponseFetcher(function($d){$d->content = utf8_decode($d->content); return $d; })); + $this->defineRequest("getBackup", "RAPI_GetBackupRequestDetails", new RAPI_StandardResponseFetcher()); + } + +} + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/CBSClient_DataStorageBase.php b/private/lib/backup/cbsClient/CBSClient_DataStorageBase.php new file mode 100644 index 0000000..3c6f3b6 --- /dev/null +++ b/private/lib/backup/cbsClient/CBSClient_DataStorageBase.php @@ -0,0 +1,66 @@ +api->passphrase; + } + /** + * (non-PHPdoc) + * @see RAPI_DataStorage::getRapiAccount() + */ + public function getRapiAccount(){ + return GlobalVariables::get("config")->api->account; + } + /** + * (non-PHPdoc) + * @see RAPI_DataStorage::getRapiUser() + */ + public function getRapiUser(){ + return "1"; + } + /** + * (non-PHPdoc) + * @see RAPI_DataStorage::getNextOperationId() + */ + abstract public function getNextOperationId(); + + /** + * (non-PHPdoc) + * @see RAPI_DataStorage::setMaxOperationId() + */ + abstract public function setMaxOperationId($id); + + /** + * (non-PHPdoc) + * @see RAPI_DataStorage::queueUncompletedRequest() + */ + abstract public function queueUncompletedRequest($id, RAPI_RequestDetails $req); + + /** + * (non-PHPdoc) + * @see RAPI_DataStorage::getUncompletedRequests() + */ + abstract public function getUncompletedRequests($limit = null); + + /** + * (non-PHPdoc) + * @see RAPI_DataStorage::onRequestCompletedFromQueue() + */ + abstract public function onRequestCompletedFromQueue($id); + + /** + * (non-PHPdoc) + * @see RAPI_DataStorage::onRequestFailedFromQueue() + */ + abstract public function onRequestFailedFromQueue($id); +} + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/CBS_RAPIClientImplementation.php b/private/lib/backup/cbsClient/CBS_RAPIClientImplementation.php new file mode 100644 index 0000000..c181a79 --- /dev/null +++ b/private/lib/backup/cbsClient/CBS_RAPIClientImplementation.php @@ -0,0 +1,45 @@ +attachmentPath = $attachmentPath; + } + + protected function openConnection(){ + $service_port = getservbyname('rapi', 'tcp'); + $address = RAPI_Config::RAPI_SERVER_ADDRESS; + $this->fh = stream_socket_client("tcp://$address:$service_port", $errno, $errstr, 30); + + } + + protected function closeConnection(){ + fclose($this->fh); + } + + protected function sendMessage($msg){ + fwrite($this->fh, $msg); + } + + protected function getMessage($bufferSize = null){ + if (is_null($bufferSize)){ + return fgets($this->fh); + } + else { + return fgets($this->fh,$bufferSize); + } + } + + protected function getReceivedAttachmentPath(){ + return $this->attachmentPath; + } +} + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/cbs.client.include.php b/private/lib/backup/cbsClient/cbs.client.include.php new file mode 100644 index 0000000..4397de5 --- /dev/null +++ b/private/lib/backup/cbsClient/cbs.client.include.php @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/messages/request/RAPI_BackupListRequestDetails.php b/private/lib/backup/cbsClient/messages/request/RAPI_BackupListRequestDetails.php new file mode 100644 index 0000000..ac99010 --- /dev/null +++ b/private/lib/backup/cbsClient/messages/request/RAPI_BackupListRequestDetails.php @@ -0,0 +1,51 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/messages/request/RAPI_GetBackupRequestDetails.php b/private/lib/backup/cbsClient/messages/request/RAPI_GetBackupRequestDetails.php new file mode 100644 index 0000000..5603425 --- /dev/null +++ b/private/lib/backup/cbsClient/messages/request/RAPI_GetBackupRequestDetails.php @@ -0,0 +1,52 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/messages/response/RAPI_BackupListResponseDetails.php b/private/lib/backup/cbsClient/messages/response/RAPI_BackupListResponseDetails.php new file mode 100644 index 0000000..86c3a6d --- /dev/null +++ b/private/lib/backup/cbsClient/messages/response/RAPI_BackupListResponseDetails.php @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/messages/response/RAPI_CreateBackupResponseDetails.php b/private/lib/backup/cbsClient/messages/response/RAPI_CreateBackupResponseDetails.php new file mode 100644 index 0000000..44ed78e --- /dev/null +++ b/private/lib/backup/cbsClient/messages/response/RAPI_CreateBackupResponseDetails.php @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/messages/response/RAPI_GetBackupResponseDetails.php b/private/lib/backup/cbsClient/messages/response/RAPI_GetBackupResponseDetails.php new file mode 100644 index 0000000..2514329 --- /dev/null +++ b/private/lib/backup/cbsClient/messages/response/RAPI_GetBackupResponseDetails.php @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/RAPI_Config.php b/private/lib/backup/cbsClient/rapi/RAPI_Config.php new file mode 100644 index 0000000..58cc434 --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/RAPI_Config.php @@ -0,0 +1,45 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/RAPI_CryptUtils.php b/private/lib/backup/cbsClient/rapi/RAPI_CryptUtils.php new file mode 100644 index 0000000..8542ff5 --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/RAPI_CryptUtils.php @@ -0,0 +1,48 @@ +getUser(); + } + else if ($msg instanceof RAPI_Response){ + $user = $msg->getRelatedRequest()->getUser(); + } + else { + throw new RAPI_Exception("Invalid usage of CryptUtils::getDigestForMessage(); Unimplemented message type ('".get_class($msg)."')"); + } + $timestamp = $msg->getTime(); + $details = $msg->getDetails(true); + + return self::getDigest($user, $timestamp, $details, $passphrase); + } + +} + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/RAPI_Logger.php b/private/lib/backup/cbsClient/rapi/RAPI_Logger.php new file mode 100644 index 0000000..6c39db3 --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/RAPI_Logger.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/exceptions/RAPI_Exception.php b/private/lib/backup/cbsClient/rapi/exceptions/RAPI_Exception.php new file mode 100644 index 0000000..6cf1d2b --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/exceptions/RAPI_Exception.php @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/exceptions/RAPI_ValidationException.php b/private/lib/backup/cbsClient/rapi/exceptions/RAPI_ValidationException.php new file mode 100644 index 0000000..1e62c0f --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/exceptions/RAPI_ValidationException.php @@ -0,0 +1,40 @@ +status = $status; + parent::__construct("RAPI_ValidationException 'Status $status'"); + } + + /** + * Restituisce lo status code che ha causato l'eccezione + * @return int + */ + public function getStatus (){ + return $this->status; + } + +} + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/include.php b/private/lib/backup/cbsClient/rapi/include.php new file mode 100644 index 0000000..51265df --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/include.php @@ -0,0 +1,30 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/messages/RAPI_Message.php b/private/lib/backup/cbsClient/rapi/messages/RAPI_Message.php new file mode 100644 index 0000000..9e49f12 --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/messages/RAPI_Message.php @@ -0,0 +1,256 @@ +protocolVersion; + } + + /** + * Timestamp in microsecondi + * @var int + */ + private $time; + public function getTime(){ + return $this->time; + } + + /** + * Digest per valutare l'autenticità + * @var string + */ + private $digest; + public function getDigest(){ + return $this->digest; + } + /** + * Imposta il digest per il messaggio + * @param string $digest il digest da impostare + */ + public function setDigest($digest){ + $this->digest = $digest; + } + + /** + * Una classe contenente i dettagli per generare l'operazione + * @var RAPI_MessageDetails + */ + private $details; + /** + * @param string $encoded + * @return string|RAPI_MessageDetails + */ + public function getDetails($encoded = false){ + if ($encoded){ + return json_encode($this->details); + } + else { + return $this->details; + } + } + + /** + * Metodo di utility che richiama il metodo omonimo del message details. + * @return stdClass + */ + public function getAttachmentData($name){ + return $this->getDetails()->getAttachmentData($name); + } + + /** + * Metodo di utility che richiama il metodo omonimo del message details per l'istanza utilizzata all'interno + * @return stdClass + */ + public function getAttachmentList(){ + return $this->getDetails()->getAttachmentList(); + } + + /** + * Metodo di utility che richiama il metodo omonimo del message details per l'istanza utilizzata all'interno + */ + public function setAttachmentLocalFileReference($name, $path){ + $this->getDetails()->setAttachmentLocalFileReference($name,$path); + } + + /** + * Metodo di utility che richiama il metodo omonimo del message details per l'istanza utilizzata all'interno + */ + public function getAttachmentLocalFileReference($name){ + return $this->details->getAttachmentLocalFileReference($name); + } + + + /* + * Costruttore + */ + /** + * @param string $protocolVersion La versione del protocollo RAPI + * @param RAPI_MessageDetails $details Il contenuto del messaggio + * @param int $time Timestamp in microsecondi + * @param string $digest Digest per valutare l'autenticità del messaggio + */ + public function __construct($protocolVersion, RAPI_MessageDetails $details, $time = null, $digest = null){ + $this->protocolVersion = $protocolVersion; + $this->time = is_null($time)?array_sum( explode( ' ' , microtime() ) ):$time; + $this->details = $details; + $this->digest = $digest; + } + + /* + * Metodi per la SERIALIZZAZIONE + */ + /** + * Genera un oggetto standard da utilizzare per + * la serializzazione. + * Questa versione genera solo gli attributi + * relativi a RAPI_Message + * @return stdClass + */ + protected function generateEncryptionBaseObject(){ + $rval = new stdClass(); + $rval->version = $this->protocolVersion; + $rval->time = $this->time; + $rval->digest = $this->digest; + $rval->details = $this->details->generateEncryptionObject(); + return $rval; + } + + /** + * Restituisce la serializzazione dell'oggetto + * @return string + */ + public function getEncryption(){ + if (is_null($this->encryptedCache)){ + $this->testEncryption(); + } + return $this->encryptedCache; + } + + public function testEncryption(){ + $this->encryptedCache = null; + $enc = json_encode($this->generateEncryptionObject()); + if ($enc === false){ + throw new RAPI_Exception("JSON Encoding failed. Message '".json_last_error_msg()."'"); + } + $this->encryptedCache = $enc; + } + + /* + * Metodi di DE-SERIALIZZAZIONE + */ + /** + * Deserializza la stringa e ritorna un oggetto RAPI_Message + * valido. + * @param string $string + * @param array $additionalData Parametro opzionale per aggiungere attributi (già decodificati) all'oggetto dopo la decodifica + * @throws RAPI_Exception Se non riesce a parsare la stringa + * @return RAPI_Message + */ + public static function fromEncrypted($string, array $additionalData = array()){ + $appoggio = json_decode(trim($string)); + if (!is_null($appoggio)){ + if (sizeof($additionalData)>0){ + foreach ($additionalData as $key => $val){ + $appoggio->$key = $val; + } + } + } + else { + $errMsg = "Invalid request format "; + switch (json_last_error()) { + case JSON_ERROR_NONE: + $errMsg.= ' (No JSON errors)'; + break; + case JSON_ERROR_DEPTH: + $errMsg.= ' (JSON - Maximum stack depth exceeded)'; + break; + case JSON_ERROR_STATE_MISMATCH: + $errMsg.= ' (JSON - Underflow or the modes mismatch)'; + break; + case JSON_ERROR_CTRL_CHAR: + $errMsg.= ' (JSON - Unexpected control character found)'; + break; + case JSON_ERROR_SYNTAX: + $errMsg.= ' (JSON - Syntax error, malformed JSON)'; + break; + case JSON_ERROR_UTF8: + $errMsg.= ' (JSON - Malformed UTF-8 characters, possibly incorrectly encoded)'; + break; + default: + $errMsg.= ' (JSON - Unknown error)'; + break; + } + throw new RAPI_Exception($errMsg); + } + return static::createFromObject($appoggio); + } + + /** + * Ritorna true se l'oggetto ha gli + * attributi per costruire un RAPI_Message. + * @param stdClass $obj + * @return bool + */ + protected static function isValidObjectForCreationBase($obj){ + return property_exists($obj, "version") && + property_exists($obj, "time") && + property_exists($obj, "digest") && + property_exists($obj, "details"); + } + + /* + * Abstract + */ + /** + * Genera un oggetto che contiene tutti + * i valori da encodare (con JSON). + * Utilizza generateEncryptionBaseObject e gli aggiunge + * tutti gli attributi da includere nel messaggio + * @return stdClass + */ + protected abstract function generateEncryptionObject(); + + /** + * Ritorna true se l'oggetto ha gli + * attributi per costruire un RAPI_Message. + * Utilizzare isValidObjectForCreationBase e dopo + * valutare gli attributi della sottoclasse + * @param stdClass $obj + * @return bool + */ + protected static abstract function isValidObjectForCreation($obj); + + /** + * Costruisce un message a partire da una stdClass. + * @param stdClass $obj + * @return RAPI_Message + * @throws RAPI_Exception + */ + public static abstract function createFromObject($obj); +} + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/messages/RAPI_MessageDetails.php b/private/lib/backup/cbsClient/rapi/messages/RAPI_MessageDetails.php new file mode 100644 index 0000000..073e05e --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/messages/RAPI_MessageDetails.php @@ -0,0 +1,135 @@ +data; + } + + /** + * @return stdClass + */ + public function getAttachmentData($name){ + if (!array_key_exists($name, $this->attachments)){ + throw new RAPI_Exception("Invalid attachment name ($name) passed to '".get_called_class()."::getAttachmentData()'"); + } + return $this->attachments[$name]; + } + + /** + * Imposta il file di appoggio LOCALE per un attachment + * @param string $name nome dell'attachment + * @param string $path il path del file + * @throws RAPI_Exception + */ + public function setAttachmentLocalFileReference($name, $path){ + if (!array_key_exists($name, $this->attachments)){ + throw new RAPI_Exception("Invalid attachment name ($name) passed to '".get_called_class()."::setAttachmentLocalFileReference()'"); + } + $this->attachments[$name]->localReference = $path; + } + + public function getAttachmentLocalFileReference($name){ + if (!array_key_exists($name, $this->attachments)){ + throw new RAPI_Exception("Invalid attachment name ($name) passed to '".get_called_class()."::getAttachmentLocalFileReference()'"); + } + return $this->attachments[$name]->localReference; + } + + /** + * Il parametro $data deve avere come attributi almeno quelli restituiti da getArgumentList() + * @param stdClass $data + * @throws RAPI_Exception + */ + public function __construct(stdClass $data, array $attachments = array()){ + foreach (static::getArgumentList() as $arg){ + if (!property_exists($data, $arg)){ + throw new RAPI_Exception("Invalid data object passed to '".get_called_class()."'. Missing property '$arg'"); + } + } + $requiredAttachments = static::getAttachmentList(); + $requiredFields = array("md5","size","name"); + if (sizeof($attachments)>0){ + foreach ($attachments as $attachment){ + foreach ($requiredFields as $field){ + if (!property_exists($attachment, $field)){ + throw new RAPI_Exception("Invalid attachment data object passed to '".get_called_class()."'. Missing property '$field' for attachment '$attachName'"); + } + } + $this->attachments[$attachment->name] = $attachment; + if ( ($key = array_search($attachment->name, $requiredAttachments)) !== false ){ + unset($requiredAttachments[$key]); + } + } + } + if (sizeof($requiredAttachments)>0){ + throw new RAPI_Exception("Invalid attachment array passed to '".get_called_class()."'. Missing attachments '".implode(", ", $requiredAttachments)."'"); + } + + $this->data = $data; + } + + /** + * Restituisce la codifica JSON del messaggio + * @return string + */ + public function __toString(){ + return json_encode($this->generateEncryptionObject()); + } + + /** + * Restituisce una stdClass utilizzabile per rigenerare l'oggetto + * @return stdClass + */ + public function generateEncryptionObject(){ + $tmp = new stdClass(); + $tmp->data = new stdClass(); + foreach (static::getArgumentList() as $argName){ + $tmp->data->$argName = $this->data->$argName; + } + $tmp->attachments = array(); + foreach (static::getAttachmentList() as $attachName){ + $ele = new stdClass(); + $ele->name = $attachName; + $ele->md5 = $this->attachments[$attachName]->md5; + $ele->size = $this->attachments[$attachName]->size; + $tmp->attachments[] = $ele; + } + return $tmp; + } + + /* + * Abstract Methods + */ + /** + * Returns the list of arguments + * @return string[] + */ + public static abstract function getArgumentList(); + /** + * Returns the list of attachments + * @var stdClass[] + */ + public static abstract function getAttachmentList(); + +} + + + + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/messages/RAPI_Request.php b/private/lib/backup/cbsClient/rapi/messages/RAPI_Request.php new file mode 100644 index 0000000..0482f5a --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/messages/RAPI_Request.php @@ -0,0 +1,143 @@ +account; + } + + /** + * Utente dell'account + * @var string + */ + private $user; + public function getUser(){ + return $this->user; + } + + /** + * Identificativo della richiesta (NULL in lettura) + * @var string + */ + private $operationId; + public function getOperationId(){ + return $this->operationId; + } + + /* + * Metodi propri della classe + */ + /** + * @param string $account Il token dell'account che fa la richiesta + * @param string $user L'identificativo dell'utente (collegato all'account) che fa la richiesta + * @param string $operationId Identificativo univoco del messaggio. UTILIZZARE SOLO IN SCRITTURA, IN LETTURA UTILIZZARE null + * @param string $protocolVersion La versione del protocollo RAPI + * @param RAPI_RequestDetails $details Il contenuto della richiesta + * @param int $time Timestamp in microsecondi + * @param string $digest Digest per valutare l'autenticità del messaggio + */ + public function __construct($account, $user, $operationId, $protocolVersion, RAPI_RequestDetails $details, $time = null, $digest = null){ + parent::__construct($protocolVersion, $details, $time, $digest); + $this->account = $account; + $this->user = $user; + $this->operationId = $operationId; + } + + /** + * Metodo di utility che richiama il metodo omonimo del request details. + * Se una delle request è un checksumFake confronta solo i due checksum. + * @param RAPI_Request $req + * @return boolean + */ + public function isEqual(RAPI_Request $req){ + return strcmp($this->getProtocolVersion(),$req->getProtocolVersion())==0 && + strcmp($this->account,$req->account)==0 && + strcmp($this->user,$req->user)==0 && + strcmp($this->operationId,$req->operationId)==0 && + $this->getDetails()->isEqual($req->getDetails()); + } + + /** + * Metodo di utility che richiama il metodo omonimo del request details. + * @return bool + */ + public function isChecksumFake(){ + return $this->getDetails()->isChecksumFake(); + } + + /** + * Genera la versione checksumFake della rapi request. + * @return RAPI_Request + */ + public function generateChecksumFake(){ + $rval = new RAPI_Request($this->account, $this->user, $this->getOperationId(), $this->getProtocolVersion(), $this->getDetails()->generateChecksumFake(), $this->getTime(), $this->getDigest()); + return $rval; + } + + /* + * Abstract Implementations + */ + /** + * @see RAPI_Message::generateEncryptionObject() + */ + protected function generateEncryptionObject(){ + $rval = $this->generateEncryptionBaseObject(); + $rval->account = $this->account; + $rval->user = $this->user; + $rval->operationId = $this->operationId; + + return $rval; + } + + /** + * @see RAPI_Message::isValidObjectForCreation() + */ + protected static function isValidObjectForCreation($obj){ + return self::isValidObjectForCreationBase($obj) && + property_exists($obj, "account") && + property_exists($obj, "user") && + property_exists($obj, "operationId"); + } + + /** + * @see RAPI_Message::createFromObject() + */ + public static function createFromObject($obj){ + if (self::isValidObjectForCreation($obj)){ + $details = RAPI_RequestDetailsFactory::generateFromEncryptionObject($obj->details); + return new RAPI_Request($obj->account, $obj->user, $obj->operationId, $obj->version, $details, $obj->time, $obj->digest); + } + else { + throw new RAPI_Exception("Invalid request format"); + } + } + + +} + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/messages/RAPI_RequestDetails.php b/private/lib/backup/cbsClient/rapi/messages/RAPI_RequestDetails.php new file mode 100644 index 0000000..42ddddb --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/messages/RAPI_RequestDetails.php @@ -0,0 +1,135 @@ +md5; + if (is_null($rval)){ + $rval = md5(strval($this)); + } + return $rval; + } + + /** + * Forza il valore della variabile interna contenente il checkusm. + * ATTENZIONE! I non checksumFake non dovrebbero avere questo attributo valorizzato + * @param string $md5 + */ + public function forceChecksum($md5){ + $this->md5 = $md5; + } + + /** + * Genera la versione checksumFake di un rapi request details. + * @return RAPI_RequestDetails + */ + public function generateChecksumFake(){ + $tmp = new stdClass(); + if (sizeof(static::getArgumentList())>0){ + foreach (static::getArgumentList() as $arg){ + $tmp->$arg = ""; + } + } + $obj = new static($tmp); + $obj->md5 = $this->getChecksum(); + + return $obj; + } + + /** + * Restituisce true se si tratta di un checksum fake. + * @return boolean + */ + public function isChecksumFake(){ + return !is_null($this->md5); + } + + /* + * Metodi propri della classe + */ + /** + * Valuta l'uguaglianza delle request details + * NOTA: Funziona anche se un requestDetails è un checksumFake, ma in tal caso confronta solo i due checksum. + * @param RAPI_Request $req + * @return boolean + */ + public function isEqual(RAPI_RequestDetails $req){ + $rval = ( strcmp($this->getChecksum(), $req->getChecksum())==0 ) ; + if (!$this->isChecksumFake() && !$req->isChecksumFake()){ + $rval = strcmp($this, $req); + } + return $rval; + } + + + + /** + * @see RAPI_MessageDetails::generateEncryptionObject() + */ + public function generateEncryptionObject(){ + $tmp = parent::generateEncryptionObject(); + $tmp->operation = static::getOperationName(); + if ($this->isChecksumFake()){ + $tmp->md5 = $this->getChecksum(); + } + return $tmp; + } + + /* + * Factory + */ + /** + * Registra il details alla factory + */ + public static function registerToFactory(){ + RAPI_RequestDetailsFactory::addToRegister(static::getOperationName(), get_called_class()); + } + + /* + * Metodi astratti + */ + /** + * Returns true if the operation requires an + * operationId (like for writes and deletion) + * @return bool + */ + public static abstract function usesOperationId(); + + /** + * Returns the name of the operation used by the request factory (NOT THE RAPI_Operation !!!!!) + * @return string + */ + public static abstract function getOperationName(); + + /** + * Returns the class name of the response details to use + * @return string + */ + public static abstract function getResponseDetailsClass(); + +} + + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/messages/RAPI_RequestDetailsFactory.php b/private/lib/backup/cbsClient/rapi/messages/RAPI_RequestDetailsFactory.php new file mode 100644 index 0000000..7de6d15 --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/messages/RAPI_RequestDetailsFactory.php @@ -0,0 +1,52 @@ +operation); + $rval = new $classname($tmp->data,$tmp->attachments); + if (property_exists($tmp, 'md5')){ + $rval->forceChecksum($tmp->md5); + } + return $rval; + } + } + + +} + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/messages/RAPI_Response.php b/private/lib/backup/cbsClient/rapi/messages/RAPI_Response.php new file mode 100644 index 0000000..56877e7 --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/messages/RAPI_Response.php @@ -0,0 +1,172 @@ + array("message"=>"MALFORMED"), + self::STATUS_UNAUTHORIZED => array("message"=>"UNAUTHORIZED"), + self::STATUS_INVALID => array("message"=>"INVALID"), + self::STATUS_EXPIRED => array("message"=>"EXPIRED"), + self::STATUS_INTERNAL_SERVER_ERROR => array("message"=>"INTERNAL_SERVER_ERROR") + ); + + public static function getStatusDataMessage($status){ + $rval = "UNKNOWN"; + if (array_key_exists($status, self::$STATUS_DATA)){ + return self::$STATUS_DATA[$status]["message"]; + } + } + /* + * Attribute, setters e getters + */ + /** + * La richiesta relativa a questa risposta + * @var RAPI_Request + */ + private $related_request; + /** + * Restituisce la richiesta associata alla risposta + * @return RAPI_Request + */ + public function getRelatedRequest(){ + return $this->related_request; + } + + /** + * Lo stato della richiesta. + * In caso di richiesta non valida digest e details saranno vuoti + * @var int + */ + private $status; + /** + * Restituisce lo stato della richiesta + * @return int + */ + public function getStatus(){ + return $this->status; + } + + /* + * Costruttore + */ + /** + * @param RAPI_Request $relatedRequest La richiesta relativa a questa risposta + * @param string $protocolVersion La versione del protocollo RAPI + * @param RAPI_ResponseDetails $details Il contenuto del messaggio + * @param int $time Timestamp in microsecondi + * @param string $digest Digest per valutare l'autenticità del messaggio + */ + public function __construct(RAPI_Request $relatedRequest, $status, $protocolVersion, RAPI_ResponseDetails $details = NULL, $time = null, $digest = null){ + $this->related_request = $relatedRequest; + $this->status = $status; + if ($this->status > 0){ +// $details = new stdClass(); +// $details->message = self::$STATUS_DATA[$this->status]["message"]; + $details = new RAPI_SimpleMessageResponseDetails(self::$STATUS_DATA[$this->status]["message"]); +// $details = "{'message':'".self::$STATUS_DATA[$this->status]["message"]."'}"; + } + else if (is_null($details)){ + throw new RAPI_Exception("Building a RAPI_Response without passing a valid details object"); + } + parent::__construct($protocolVersion, $details, $time, $digest); + } + + /* + * Metodi propri della classe + */ + /** + * Ritorna true se la request corrisponde + * alla request che ha generato questa response + * @param RAPI_Request $req + * @return boolean + */ + public function fromSameRequest(RAPI_Request $req){ + return $this->related_request->isEqual($req); + } + + /** + * La funzione esegue l'operazione solo se la response ha come related una + * request in versione checksum, se le request corrispondono aggiorna + * la versione locale con quella completa, altrimenti lancia eccezione. + * @param RAPI_Request $req + * @return boolean + * @throws RAPI_Exception + */ + public function updateRelatedRequestChecksum(RAPI_Request $req){ + if ($this->fromSameRequest($req)){ + $this->related_request = $req; + } + else { + throw new RAPI_Exception("Calling function RAPI_Response::updateRelatedRequestChecksum() on not corresponding requests"); + } + } + + + /* + * Abstract + */ + /** + * @see RAPI_Message::generateEncryptionObject() + */ + protected function generateEncryptionObject(){ + $rval = $this->generateEncryptionBaseObject(); + $rval->status = $this->status; + return $rval; + } + /** + * NOTA: All'oggetto va aggiunta la relatedRequest ! + * @see RAPI_Message::isValidObjectForCreation() + */ + protected static function isValidObjectForCreation($obj){ + return self::isValidObjectForCreationBase($obj) && + property_exists($obj, "status") && + property_exists($obj, "relatedRequest") && + ($obj->relatedRequest instanceof RAPI_Request); + } + + /** + * @see RAPI_Message::createFromObject() + */ + public static function createFromObject($obj){ + if (self::isValidObjectForCreation($obj)){ + $details = null; + if ($obj->status == RAPI_Response::STATUS_OK){ + $requestClass = get_class($obj->relatedRequest->getDetails()); + $responseClass = $requestClass::getResponseDetailsClass(); + + $details = new $responseClass($obj->details->data,$obj->details->attachments); + } + + return new RAPI_Response($obj->relatedRequest, $obj->status, $obj->version, $details, $obj->time, $obj->digest); + } + else { + throw new RAPI_Exception("Invalid request format"); + } + } +} +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/messages/RAPI_ResponseDetails.php b/private/lib/backup/cbsClient/rapi/messages/RAPI_ResponseDetails.php new file mode 100644 index 0000000..b5acdcd --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/messages/RAPI_ResponseDetails.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/messages/request/RAPI_UnreadableRequest.php b/private/lib/backup/cbsClient/rapi/messages/request/RAPI_UnreadableRequest.php new file mode 100644 index 0000000..3f663fe --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/messages/request/RAPI_UnreadableRequest.php @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/messages/request/RAPI_UnreadableRequestDetails.php b/private/lib/backup/cbsClient/rapi/messages/request/RAPI_UnreadableRequestDetails.php new file mode 100644 index 0000000..057c46e --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/messages/request/RAPI_UnreadableRequestDetails.php @@ -0,0 +1,51 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/messages/response/RAPI_EmptyResponseDetails.php b/private/lib/backup/cbsClient/rapi/messages/response/RAPI_EmptyResponseDetails.php new file mode 100644 index 0000000..742dc99 --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/messages/response/RAPI_EmptyResponseDetails.php @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/messages/response/RAPI_SimpleMessageResponseDetails.php b/private/lib/backup/cbsClient/rapi/messages/response/RAPI_SimpleMessageResponseDetails.php new file mode 100644 index 0000000..f7c60e5 --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/messages/response/RAPI_SimpleMessageResponseDetails.php @@ -0,0 +1,33 @@ +message = $message; + parent::__construct($obj); + } + + /** + * @see RAPI_ResponseDetails::getArgumentList() + */ + public static function getArgumentList(){ + return array("message"); + } + + /** + * @see RAPI_MessageDetails::getAttachmentList() + */ + public static function getAttachmentList(){ + return array(); + } +} + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/rapi_client/RAPI_Client.php b/private/lib/backup/cbsClient/rapi/rapi_client/RAPI_Client.php new file mode 100644 index 0000000..f58c9cb --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/rapi_client/RAPI_Client.php @@ -0,0 +1,383 @@ +logger = $logger; + $this->dataStorage = $dataStorage; + + } + + /** + * Wrapper per la funzione del logger, metodo di utilità. + * @param int $level Livello di log + * @param string $message Messaggio da scrivere nel log + */ + private function log($level, $message){ + $this->logger->log($level, $message); + } + + /** + * Genera un warning di sicurezza. + * @param int $level Importanza del warning + * @param string $message Messaggio da scrivere nel log + * @param RAPI_Response $data RAPI_Response che ha generato il warning + */ + private function generateSecurityWarning($severity, $message, RAPI_Response $request){ + $this->logger->generateSecurityWarning($severity, $message, $request); + } + + /** + * Effettua la chiamata al server per la richiesta inserita. + * Se la richiesta fallisce lancia eccezione e mette la richiesta in coda (SOLO SE USA OPERATION_ID). + * @param RAPI_RequestDetails $det + * @throws RAPI_ClientException (ANY) + * @return RAPI_ResponseDetails + */ + public function request(RAPI_RequestDetails $details){ + try { + $req = $this->getRequestFromRequestDetails($details); + $response = $this->executeRequest($req); + + $responseDetails = $response->getDetails(); + } + catch (Exception $ex){ + if ($details->usesOperationId()){ + $this->dataStorage->queueUncompletedRequest($req->getOperationId(),$details); + } + throw $ex; + } + + return $responseDetails; + } + + /** + * Esegue una richiesta (in caso di fallimento lancia eccezione) + * @param RAPI_Request $req + * @throws RAPI_ClientException + * @return RAPI_Response + */ + private function executeRequest(RAPI_Request $req){ + $this->openConnection(); + $this->sendMessage($req->getEncryption()); + $this->sendMessage("\n"); + + $attachmentList = $req->getAttachmentList(); + if (sizeof($attachmentList)>0){ + foreach ($attachmentList as $attachment){ + $msg = $this->getMessage(2048); + if (strcmp($msg, "<< ----- ACK / $attachment ----- >>\n")!=0){ + $this->logger->log(RAPI_Logger::LOG_LEVEL_ERROR, "Invalid protocol use, client not sending ACK message for attachment '$attachment'. The request will be rejected"); + throw new RAPI_ClientException(RAPI_ClientException::INVALID_UNPARSABLE); + } + + $buffer = ""; + $filePath = $req->getAttachmentLocalFileReference($attachment); + + $fh = fopen($filePath, "rb"); + do { + $buffer = fread($fh, 32768); + $this->sendMessage($buffer); + } + while(!feof($fh)); +// while ( ($buffer = fread($fh, 2048)) !== false ) { +// $this->sendMessage($buffer); +// } + fclose($fh); + $this->sendMessage("\n"); + } + } + + $textResponse = $this->getMessage(); + $response = RAPI_Response::fromEncrypted($textResponse,array("relatedRequest"=>$req)); + $this->validateResponse($response); + + $attachmentList = $response->getAttachmentList(); + if ($response->getStatus() == RAPI_Response::STATUS_OK && sizeof($attachmentList)>0){ + foreach ($attachmentList as $attachment){ + $data = $response->getAttachmentData($attachment); + $buffer = ""; + + $this->sendMessage("<< ----- ACK / $attachment ----- >>"); + $this->sendMessage("\n"); + + $filePath = $this->getReceivedAttachmentPath()."/".uniqid($attachment."_"); + + $fh = fopen($filePath, "wb"); + $next = $this->getMessage(32768); + while ($next!==false) { + $current = $next; + $length = strlen($current); + + $next = $this->getMessage(32768); + if ($next===false){ + $length = $length-1; + } + fwrite($fh,$current,$length); + } + + +// while ( ($buffer = $this->getMessage(2048)) !== false ){ +// fwrite($fh,$buffer); +// } + fclose($fh); + if (filesize($filePath)!=$data->size){ + $this->logger->log(RAPI_Logger::LOG_LEVEL_ERROR, "The received file has invalid size for attachment '$attachment'. The request will be rejected"); + throw new RAPI_ClientException(RAPI_ClientException::INVALID_UNPARSABLE); + } + if ( strcmp(md5_file($filePath),$data->md5)!=0 ){ + $this->logger->log(RAPI_Logger::LOG_LEVEL_ERROR, "The received file has invalid MD5 for attachment '$attachment'. The request will be rejected"); + throw new RAPI_ClientException(RAPI_ClientException::INVALID_UNPARSABLE); + } + $response->setAttachmentLocalFileReference($attachment,$filePath); + } + } + $this->closeConnection(); + + return $response; + } + +// /** +// * Esegue una richiesta e restituisce la risposta +// * @param RAPI_Request $req +// * @param string $forceOperationId se null usa il prossimo libero, altrimenti usa quello ricevuto +// * @throws RAPI_ClientException +// * @return RAPI_Response +// */ +// private function getResponse(RAPI_Request $req){ +// $ans = $this->sendMessage($req->getEncryption()); +// try { +// $response = RAPI_Response::fromEncrypted($ans,array("relatedRequest"=>$req)); +// } +// catch (RAPI_Exception $rex){ +// $this->log(RAPI_Logger::LOG_LEVEL_ERROR,"Impossible to parse response. Reason: '".$rex->getMessage()."'"); +// throw new RAPI_ClientException(RAPI_ClientException::INVALID_UNPARSABLE); +// } +// $this->validateResponse($response); +// return $response; +// } + + /** + * Riprova ad eseguire le operazioni in pending. + * Limit limita il numero di operazioni da riprovare ad eseguire. + * @param int $limit per limitare la quantità di operazioni + * @throws RAPI_ClientException + */ + public function executePendingRequests($limit = null){ + $reqsDetails = $this->dataStorage->getUncompletedRequests($limit); + + if (sizeof($reqsDetails)>0){ + $excs = array(); + foreach ($reqsDetails as $id=>$details){ + try { + $req = $this->getRequestFromRequestDetails($details,$id); + $resp = $this->executeRequest($req); + $this->dataStorage->onRequestCompletedFromQueue($id); + } + catch (Exception $ex){ + $excs[] = "(".$ex->getMessage().")"; + $this->dataStorage->onRequestFailedFromQueue($id); + } + } + if (sizeof($excs)>0){ + $this->log(RAPI_Logger::LOG_LEVEL_ERROR,"Errors while executing queue in ".sizeof($excs)." requests. Messages: ".implode(", ", $excs)); + throw new RAPI_ClientException(RAPI_ClientException::INVALID_UNPARSABLE); + } + } + } + + +// /** +// * Restituisce la stringa col messaggio +// * @param string $msg +// * @returns string +// */ +// private function sendMessage($msg){ +// $service_port = getservbyname('rapi', 'tcp'); +// $address = RAPI_Config::RAPI_SERVER_ADDRESS; + +// $this->log(RAPI_Logger::LOG_LEVEL_INFO,"Connecting to '$address:$service_port'"); + +// $this->log(RAPI_Logger::LOG_LEVEL_DEBUG,"Creating TCP socket"); +// $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + + +// if ($socket === false) { +// $this->log(RAPI_Logger::LOG_LEVEL_ERROR,"Impossible to create TCP socket. Reason: '".socket_strerror(socket_last_error())."'"); +// throw new RAPI_ClientException(RAPI_ClientException::CONNECTION_ERROR); +// } +// else { +// $this->log(RAPI_Logger::LOG_LEVEL_DEBUG,"TCP Socket created successfully"); +// } + +// $this->log(RAPI_Logger::LOG_LEVEL_DEBUG,"Connecting to '$address:$service_port'"); +// $result = socket_connect($socket, $address, $service_port); +// if ($result === false) { +// $this->log(RAPI_Logger::LOG_LEVEL_ERROR,"Impossible to connect to '$address:$service_port'. Reason: '".socket_strerror(socket_last_error($socket))."'"); +// throw new RAPI_ClientException(RAPI_ClientException::CONNECTION_ERROR); +// } +// else { +// $this->log(RAPI_Logger::LOG_LEVEL_DEBUG,"TCP Socket connection complete"); +// } + + +// $this->log(RAPI_Logger::LOG_LEVEL_INFO,"Sending request to '$address:$service_port'"); +// socket_write($socket, $msg, strlen($msg)); +// $this->log(RAPI_Logger::LOG_LEVEL_DEBUG,"Reading response from '$address:$service_port'"); + +// $out = ''; +// $acc = ''; + +// while ($out = socket_read($socket, 2048)) { +// $acc .= $out; +// } +// $this->log(RAPI_Logger::LOG_LEVEL_DEBUG,"Response from '$address:$service_port' complete"); + +// $this->log(RAPI_Logger::LOG_LEVEL_INFO,"Closing connection to '$address:$service_port'"); +// socket_close($socket); +// return $acc; +// } + +// /** +// * Genera una RAPI_Request a partire da una RAPI_RequestDetails. +// * @param RAPI_RequestDetails $details +// * @param string $forceOperationId se null usa il prossimo libero, altrimenti usa quello ricevuto +// * @return RAPI_Request +// */ +// private function wrapRequest(RAPI_RequestDetails $details, $forceOperationId = null){ +// $account = $this->dataStorage->getRapiAccount(); +// $user = $this->dataStorage->getRapiUser(); +// $operationId = $details::usesOperationId()?(is_null($forceOperationId)?$this->dataStorage->getNextOperationId():$forceOperationId):null; +// $protocolVersion = RAPI_Config::RAPI_VERSION; +// $req = new RAPI_Request($account, $user, $operationId, $protocolVersion, $details); +// $req->setDigest(RAPI_CryptUtils::getDigestForMessage($req, $this->dataStorage->getRapiPassphrase())); +// return $req; +// } + + /** + * Genera una RAPI_Request a partire da una RAPI_RequestDetails. + * @param RAPI_RequestDetails $details + * @param string $forceOperationId se null usa il prossimo libero, altrimenti usa quello ricevuto + * @return RAPI_Request + */ + private function getRequestFromRequestDetails(RAPI_RequestDetails $details, $forceOperationId = null){ + $account = $this->dataStorage->getRapiAccount(); + $user = $this->dataStorage->getRapiUser(); + $operationId = null; + if ($details::usesOperationId()){ + if (is_null($forceOperationId)){ + $operationId = $this->dataStorage->getNextOperationId(); + $this->dataStorage->setMaxOperationId($operationId); + } + else { + $operationId = $forceOperationId; + } + } + $protocolVersion = RAPI_Config::RAPI_VERSION; + $req = new RAPI_Request($account, $user, $operationId, $protocolVersion, $details); + $req->setDigest(RAPI_CryptUtils::getDigestForMessage($req, $this->dataStorage->getRapiPassphrase())); + return $req; + } + + + /** + * Valuta che la versione del protocollo utilizzata nella risposta sia la stessa del client. + * Lancia eccezione in caso di richiesta non valida + * @param RAPI_Response $req La risposta + * @throws RAPI_ClientException (INVALID_PROTOCOL) + */ + private function validateProtocolVersion(RAPI_Response $resp){ + if (RAPI_Config::RAPI_VERSION != $resp->getProtocolVersion()){ + $this->log(RAPI_Logger::LOG_LEVEL_WARNING, "Invalid protocol version detected (".$resp->getProtocolVersion()."). The response will be rejected"); + throw new RAPI_ClientException(RAPI_ClientException::INVALID_PROTOCOL); + } + } + + /** + * Valuta che la risposta sia in status OK. + * Lancia eccezione in caso di status non valido + * @param RAPI_Response $req La risposta + * @throws RAPI_ClientException (INVALID_STATUS) + */ + private function validateStatus(RAPI_Response $resp){ + if (RAPI_Response::STATUS_OK != $resp->getStatus()){ + $this->log(RAPI_Logger::LOG_LEVEL_INFO, "Invalid status detected (".RAPI_Response::getStatusDataMessage($resp->getStatus())."). The response will be rejected"); + throw new RAPI_ClientException(RAPI_ClientException::INVALID_STATUS); + } + } + + /** + * Valuta che il digest della risposta sia valido. + * Lancia eccezione in caso di digest non valido + * @param RAPI_Response $req La risposta + * @throws RAPI_ClientException (INVALID_DIGEST) + */ + private function validateDigest(RAPI_Response $resp){ + if ( strcmp("", $resp->getDigest())==0 ){ + $this->log(RAPI_Logger::LOG_LEVEL_INFO, "Invalid digest detected. The incident will be reported"); + $this->generateSecurityWarning(RAPI_Logger::WARNING_SEVERITY_HIGH, "Rejecting a connection because has no digest", $resp); + throw new RAPI_ClientException(RAPI_ClientException::INVALID_DIGEST); + } + else if ($resp->getDigest() != RAPI_CryptUtils::getDigestForMessage($resp, $this->dataStorage->getRapiPassphrase())){ + $this->log(RAPI_Logger::LOG_LEVEL_INFO, "Invalid digest detected. The incident will be reported"); + $this->generateSecurityWarning(RAPI_Logger::WARNING_SEVERITY_CRITICAL, "Rejecting a connection because has an invalid digest", $resp); + throw new RAPI_ClientException(RAPI_ClientException::INVALID_DIGEST); + } + } + + /** + * Effettua i vari controlli sulla risposta. + * Lancia eccezione in caso di risposta non valida + * @param RAPI_Response $req La risposta + * @throws RAPI_ClientException (INVALID_DIGEST INVALID_STATUS INVALID_PROTOCOL) + */ + private function validateResponse(RAPI_Response $resp){ + $this->validateProtocolVersion($resp); + $this->validateStatus($resp); + $this->validateDigest($resp); + + } + + /** + * Opens a connection (socket, file stream ecc) + */ + protected abstract function openConnection(); + + /** + * Closes a connection (socket, file stream ecc) + */ + protected abstract function closeConnection(); + + /** + * Sends a message + */ + protected abstract function sendMessage($msg); + + /** + * Reads a message. BufferSize rappresenta la dimensione del buffer da utilizzare, + * la funzione ritorna false se non c'è niente da leggere + */ + protected abstract function getMessage($bufferSize = null); + + /** + * Write attachment step + */ + protected abstract function getReceivedAttachmentPath(); +} + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/rapi_client/RAPI_ClientException.php b/private/lib/backup/cbsClient/rapi/rapi_client/RAPI_ClientException.php new file mode 100644 index 0000000..d92f395 --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/rapi_client/RAPI_ClientException.php @@ -0,0 +1,34 @@ + "CONNECTION_ERROR", + self::INVALID_PROTOCOL => "INVALID_PROTOCOL", + self::INVALID_STATUS => "INVALID_STATUS", + self::INVALID_DIGEST => "INVALID_DIGEST", + self::INVALID_UNPARSABLE => "INVALID_UNPARSABLE" + ); + + public function __construct($status){ + $this->status = $status; + parent::__construct("RAPI_ClientException 'Status $status' - ".self::$ERROR_NAMES[$this->status]); + } + + public function getStatus (){ + return $this->status; + } +} + +?> diff --git a/private/lib/backup/cbsClient/rapi/rapi_client/RAPI_ClientHelper.php b/private/lib/backup/cbsClient/rapi/rapi_client/RAPI_ClientHelper.php new file mode 100644 index 0000000..2280204 --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/rapi_client/RAPI_ClientHelper.php @@ -0,0 +1,120 @@ +client = $client; + } + + /** + * Chiama il metodo richiesto e ne fetcha il risultato. + * + * @param string $name Nome del metodo + * @param mixed $values Argomenti da passare al metodo + * @throws RAPI_ClientException Rilancia le eccezioni del client + * @throws RAPI_Exception Se il metodo non esiste o gli argomenti non sono validi o se il fetcher lancia eccezione + * @return mixed In base al fetcher + */ + public function __call($name, array $values){ + if (!array_key_exists($name, $this->requests)){ + throw new RAPI_Exception("Call to undefined function RAPI_ClientHelper::$methodName"); + } + $resp = $this->client->request($this->generateDetails($name, $values)); + return $this->fetchResponse($name, $resp); + } + + /** + * Aggiunge un metodo all'helper. + * + * @param string $name Il nome con cui si desidera chiamare il metodo + * @param string $className Nome della RAPI_RequestDetails associata alla request + * @param RAPI_ResponseFetcher $respFetcher Il metodo per fetchare la risposta + */ + public function defineRequest($name, $className, RAPI_ResponseFetcher $respFetcher){ + if (class_exists($className) && (is_subclass_of($className, "RAPI_RequestDetails") ) ){ + $this->requests[$name]['class'] = $className; + $this->requests[$name]['fetcher'] = $respFetcher; + } + else { + if (!class_exists($className)){ + throw new RAPI_Exception("Invalid method definition. Undefined class '$className'"); + } + else { + throw new RAPI_Exception("Invalid method definition. Class '$className' is not a RAPI_RequestDetails"); + } + } + } + + + /** + * Genera una RAPI_RequestDetails a partire dal nome del metodo chiamato e dagli + * argomenti da passargli. + * Lancia eccezione se il numero di argomenti passati non corrisponde a quelli + * del metodo chiamato o se il metodo non esiste. + * + * @param string $methodName Nome del metodo chiamato + * @param array $args Gli argomenti da passare alla RAPI_RequestDetails + * @throws RAPI_Exception Se il metodo non esiste o se $args non è valido + * @return RAPI_RequestDetails I details da utilizzare per il metodo chiamato + */ + private function generateDetails($methodName, array $args){ + $className = $this->requests[$methodName]['class']; + + $argList = $className::getArgumentList(); + $attList = $className::getAttachmentList(); + if (sizeof($args) != (sizeof($argList) + sizeof($attList)) ){ + $paramString = implode(", ",array_map(function($d){return "\$".$d."";}, array_merge($argList,$attList))); + throw new RAPI_Exception("Invalid arguments passed to function RAPI_ClientHelper::$methodName($paramString). (Received ".sizeof($args)." arguments)"); + } + + $constructObj = new stdClass(); + $i = 0; + foreach ($argList as $argName){ + $constructObj->$argName = $args[$i++]; + } + $constructAtt = array(); + foreach ($attList as $argName){ + $localFile = $args[$i++]; + + $attData = new stdClass(); + $attData->name = $argName; + $attData->size = filesize($localFile); + $attData->md5 = md5_file($localFile); + $attData->localReference = $localFile; + + $constructAtt[] = $attData; + } + return new $className($constructObj,$constructAtt); + } + + /** + * Chiama il fetcher del metodo passandogli la RAPI_ResponseDetails. + * Fetcha il risultato e lo restituisce. + * + * @param string $methodName Nome del metodo chiamato + * @param RAPI_ReponseDetails $response Risposta da fetchare + * @throws RAPI_Exception Se il metodo non esiste o se il fetcher lancia eccezione + * @return mixed In base a ciò che ritorna il fetch + */ + private function fetchResponse($methodName, RAPI_ResponseDetails $response){ +// if (!array_key_exists($methodName, $this->requests)){ +// throw new RAPI_Exception("Invalid call to RAPI_ClientHelper::fetchResponse for method '$methodName'. (The method is undefined)"); +// } + return $this->requests[$methodName]['fetcher']($response); + } +} + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/rapi_client/RAPI_DataStorage.php b/private/lib/backup/cbsClient/rapi/rapi_client/RAPI_DataStorage.php new file mode 100644 index 0000000..6e1512d --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/rapi_client/RAPI_DataStorage.php @@ -0,0 +1,70 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/rapi_client/client_include.php b/private/lib/backup/cbsClient/rapi/rapi_client/client_include.php new file mode 100644 index 0000000..606e143 --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/rapi_client/client_include.php @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/rapi_client/request_helper/RAPI_ResponseFetcher.php b/private/lib/backup/cbsClient/rapi/rapi_client/request_helper/RAPI_ResponseFetcher.php new file mode 100644 index 0000000..b5a11da --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/rapi_client/request_helper/RAPI_ResponseFetcher.php @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/rapi_client/request_helper/RAPI_SingleValueResponseFetcher.php b/private/lib/backup/cbsClient/rapi/rapi_client/request_helper/RAPI_SingleValueResponseFetcher.php new file mode 100644 index 0000000..1a985be --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/rapi_client/request_helper/RAPI_SingleValueResponseFetcher.php @@ -0,0 +1,26 @@ +paramName = $paramName; + $this->callback = $callback; + } + + public function __invoke(RAPI_ResponseDetails $resp){ + $rval = $resp->getData()->{$this->paramName}; + if (!is_null($this->callback)){ + $cb = $this->callback; + $rval = $cb($rval); + } + return $rval; + } +} + +?> \ No newline at end of file diff --git a/private/lib/backup/cbsClient/rapi/rapi_client/request_helper/RAPI_StandardResponseFetcher.php b/private/lib/backup/cbsClient/rapi/rapi_client/request_helper/RAPI_StandardResponseFetcher.php new file mode 100644 index 0000000..de410f4 --- /dev/null +++ b/private/lib/backup/cbsClient/rapi/rapi_client/request_helper/RAPI_StandardResponseFetcher.php @@ -0,0 +1,33 @@ +callback = $callback; + } + + public function __invoke(RAPI_ResponseDetails $resp){ + $rval = new stdClass(); + $rval->data = $resp->getData(); + $rval->attachments = array(); + $attList = $resp->getAttachmentList(); + if (sizeof($attList)>0){ + foreach ($attList as $att){ + $rval->attachments[$att] = $resp->getAttachmentLocalFileReference($att); + } + } + + if (!is_null($this->callback)){ + $cb = $this->callback; + $rval = $cb($rval); + } + return $rval; + } +} + +?> \ No newline at end of file diff --git a/private/lib/backup/lib.inclusion.php b/private/lib/backup/lib.inclusion.php new file mode 100644 index 0000000..b4a25f4 --- /dev/null +++ b/private/lib/backup/lib.inclusion.php @@ -0,0 +1,18 @@ +paths->backupTmp); +GlobalVariables::set("backupClient",$cbsClient); + +?> \ No newline at end of file diff --git a/private/lib/dao/GenericDao.php b/private/lib/dao/GenericDao.php index cca357e..33d8f17 100644 --- a/private/lib/dao/GenericDao.php +++ b/private/lib/dao/GenericDao.php @@ -8,6 +8,7 @@ class GenericDao{ private $mongoObj; private $database; + private $dbName; /** * La connection string viene passata interamente a MongoClient, richiede formato 'mongo://server:port'. * host1 e database sono obbligatori @@ -25,8 +26,17 @@ class GenericDao{ $this->mongoObj = new MongoClient($connectionString); } + $this->dbName = $dbName; $this->database = $this->mongoObj->$dbName; } + + /** + * Restituisce il nome del database attualmente in uso + * @return string + */ + public function getDbName(){ + return $this->dbName; + } /** * Ritorna un array di model diff --git a/private/lib/dao/lib.inclusion.php b/private/lib/dao/lib.inclusion.php index 2a6df63..8b7cd2c 100644 --- a/private/lib/dao/lib.inclusion.php +++ b/private/lib/dao/lib.inclusion.php @@ -33,9 +33,11 @@ require_once(dirname(__FILE__)."/models/AccessModel.php"); require_once(dirname(__FILE__)."/models/LogModel.php"); require_once(dirname(__FILE__)."/models/StatisticModel.php"); - require_once(dirname(__FILE__)."/models/BannerModel.php"); +require_once(dirname(__FILE__)."/models/CBSQueueModel.php"); + + $dao = new GenericDao($database->dbName,$database->connectionString); GlobalVariables::set("dao", $dao); ?> diff --git a/private/lib/dao/models/CBSQueueModel.php b/private/lib/dao/models/CBSQueueModel.php new file mode 100644 index 0000000..b69237b --- /dev/null +++ b/private/lib/dao/models/CBSQueueModel.php @@ -0,0 +1,23 @@ +hasProperty("retry")){ + $this->retry = 0; + } + } + + public static function getCollectionName(){ + return "CBS_queue"; + } + + +} + +?> \ No newline at end of file diff --git a/private/lib/gui/HTMLHelper.php b/private/lib/gui/HTMLHelper.php index 8223f41..e965a8b 100644 --- a/private/lib/gui/HTMLHelper.php +++ b/private/lib/gui/HTMLHelper.php @@ -7,7 +7,7 @@ Creation Date: 14/gen/2016 class HTMLHelper { public static function generateAdminHead() { - echo '
'; + echo '
'; } public static function generateModelsTable(array $columnInfo, array $models, array $datatableOpts = array()) { diff --git a/private/lib/lib.inclusions.php b/private/lib/lib.inclusions.php index ee8255c..be6624a 100644 --- a/private/lib/lib.inclusions.php +++ b/private/lib/lib.inclusions.php @@ -35,11 +35,13 @@ require_once(dirname(__FILE__)."/dao/lib.inclusion.php"); require_once(dirname(__FILE__)."/task/lib.inclusion.php"); +require_once(dirname(__FILE__)."/backup/lib.inclusion.php"); // Special utility modules require_once(dirname(__FILE__)."/FDN_MailHelper.php"); require_once(dirname(__FILE__)."/AnalyticsHelper.php"); +require_once(dirname(__FILE__)."/PipelineHelper.php"); ?> \ No newline at end of file diff --git a/private/lib/logger/lib.inclusion.php b/private/lib/logger/lib.inclusion.php index 6243425..c7b78c8 100644 --- a/private/lib/logger/lib.inclusion.php +++ b/private/lib/logger/lib.inclusion.php @@ -64,4 +64,10 @@ LoggingFacilityManager::addLogger( ); LoggingFacilityManager::getLogger("mail")->setLoggingLevel(LoggingFacility::$LEVEL_DEBUG); +LoggingFacilityManager::addLogger( + "api", + new FileLogger("API",$systemCatalogManager,$config->files->api_log,true) +); +LoggingFacilityManager::getLogger("api")->setLoggingLevel(LoggingFacility::$LEVEL_DEBUG); + ?> \ No newline at end of file diff --git a/private/lib/system/FSObject.php b/private/lib/system/FSObject.php index 7818c96..34172fd 100644 --- a/private/lib/system/FSObject.php +++ b/private/lib/system/FSObject.php @@ -158,4 +158,8 @@ abstract class FSObject { */ public abstract function lsDir($path); + public abstract function createArchive($path,$origin); + + public abstract function deleteDirectory($source,$destination,$sudo); + }?> \ No newline at end of file diff --git a/private/lib/system/SFSManager.php b/private/lib/system/SFSManager.php index 3b705fb..4c8247c 100644 --- a/private/lib/system/SFSManager.php +++ b/private/lib/system/SFSManager.php @@ -123,5 +123,20 @@ class SFSManager { } } + // Accepts file array or single directory + public static function createArchive($source,$dest){ + $fso=self::getFSObjByPath($dest); + if($fso!=null){ + return $fso->createArchive($dest,$source); + } + } + + public static function deleteDirectory($path,$sudo=false){ + $fso=self::getFSObjByPath($path); + if($fso!=null){ + return $fso->deleteDirectory($path,$sudo); + } + } + } ?> \ No newline at end of file diff --git a/private/lib/system/SystemController.php b/private/lib/system/SystemController.php index cd794f6..6be5521 100644 --- a/private/lib/system/SystemController.php +++ b/private/lib/system/SystemController.php @@ -74,6 +74,10 @@ class SystemController { return self::shellExec("rm",'"'.$path.'"',$useSudo); } + public static function rmDir($path,$useSudo=false){ + return self::shellExec("rm",'-r "'.$path.'"',$useSudo); + } + public static function wget($targetPage,$destFile,$useSudo=false){ return self::shellExec("wget",'-O "'.$destFile.'" '.$targetPage,$useSudo); } diff --git a/private/lib/system/fsobjects/LocallyMountedFS.php b/private/lib/system/fsobjects/LocallyMountedFS.php index afb5464..0134744 100644 --- a/private/lib/system/fsobjects/LocallyMountedFS.php +++ b/private/lib/system/fsobjects/LocallyMountedFS.php @@ -168,4 +168,56 @@ class LocallyMountedFS extends FSObject { } return $rval; } + + /** + * (non-PHPdoc) + * @see FSObject::createArchive() + */ + public function createArchive($path,$origin){ + if ($this->accessMode==self::$ACCESSMODE_RO || $this->writeLaw==parent::$WRITELAW_NOT_WRITEABLE){ + throw new SFSException('fsobj.not_writeable',$this->name); + } + else if ($this->writeLaw==parent::$WRITELAW_NORMALLY_W) { + $matches= array(); + if (preg_match("/^(.*)\.gz$/",$path,$matches)){ + $path = $matches[1]; + } + $a = new PharData($path); + if (is_array($origin) && sizeof($origin)>0){ + foreach ($origin as $file){ + $a->addFile($file); + } + } + else { + $a->buildFromDirectory($origin); + } + $a->compress(Phar::GZ); // Crea il file .tar.gz + unset($a); + $this->deleteFile($path); // Cancella il tar (non il tar.gz) + } + else if ($this->writeLaw==parent::$WRITELAW_NORMALLY_RO) { + SystemController::mountRw($this->mountPoint); + $matches= array(); + if (preg_match("/^(.*)\.gz$/",$path,$matches)){ + $path = $matches[1]; + } + $a = new PharData($path); + if (is_array($origin) && sizeof($origin)>0){ + foreach ($origin as $file){ + $a->addFile($file); + } + } + else { + $a->buildFromDirectory($origin); + } + $a->compress(Phar::GZ); // Crea il file .tar.gz + unset($a); + $this->deleteFile($path); // Cancella il tar (non il tar.gz) + SystemController::mountRw($this->mountPoint); + } + } + + public function deleteDirectory($source,$destination,$useSudo=false){ + $this->useSysFunction("rmDir",$source,$destination,$useSudo); + } } \ No newline at end of file diff --git a/private/lib/system/lib.inclusion.php b/private/lib/system/lib.inclusion.php index e506b85..3ce76fc 100644 --- a/private/lib/system/lib.inclusion.php +++ b/private/lib/system/lib.inclusion.php @@ -61,5 +61,11 @@ SFSManager::addFilesystem(new LocallyMountedFS( $config->paths->xsendfile, "XSendFile Filesystem") ); - +SFSManager::addFilesystem(new LocallyMountedFS( + FSObject::$DEVICE_TYPE_HARD_DRIVE, + FSObject::$WRITELAW_NORMALLY_W, + LocallyMountedFS::$ACCESSMODE_RW, + $config->paths->cbsQueue, + "CBS Queue Filesystem") +); ?> \ No newline at end of file diff --git a/private/lib/task/SendBackupTask.php b/private/lib/task/SendBackupTask.php new file mode 100644 index 0000000..0cf8da6 --- /dev/null +++ b/private/lib/task/SendBackupTask.php @@ -0,0 +1,36 @@ +getDbName(); + $backDir = $config->paths->backup."/mongoDump"; + SystemController::shellExec("mongodump","-d $dbName -o $backDir"); + + $archive = $config->paths->tmp."/backup.tar.gz"; +// if (SFSManager::fileExists($archive)){ +// SFSManager::deleteFile($archive); +// } + +// SFSManager::createArchive($config->paths->storage, $archive); + GlobalVariables::get("backupClient")->sendBackup("backup_".date("d-m-Y").".tar.gz",$archive); + + // OLD +// GlobalVariables::get("backupClient")->sendBackup(utf8_encode(file_get_contents($archive)),"backup_".date("d-m-Y").".tar.gz"); + } +} + + +?> \ No newline at end of file diff --git a/private/lib/task/lib.inclusion.php b/private/lib/task/lib.inclusion.php index bac519c..60925c7 100644 --- a/private/lib/task/lib.inclusion.php +++ b/private/lib/task/lib.inclusion.php @@ -8,4 +8,6 @@ require_once(dirname(__FILE__)."/Task.php"); require_once(dirname(__FILE__)."/MailSendTask.php"); require_once(dirname(__FILE__)."/NewsletterCheckTask.php"); + +require_once(dirname(__FILE__)."/SendBackupTask.php"); ?> \ No newline at end of file diff --git a/public/admin/editConfig.php b/public/admin/editConfig.php index 895eabc..a94090b 100644 --- a/public/admin/editConfig.php +++ b/public/admin/editConfig.php @@ -20,7 +20,7 @@ MenuGenerator::generateMenu(); HTMLHelper::generateAdminHead(); -$taskList = array("MailSendTask","NewsletterCheckTask"); +$taskList = array("MailSendTask","NewsletterCheckTask","SendBackupTask"); $saved = false; $action = PostHandler::get("action"); diff --git a/public/admin/login.php b/public/admin/login.php index 89e6df9..56fec29 100644 --- a/public/admin/login.php +++ b/public/admin/login.php @@ -35,10 +35,9 @@ echo ''; ?>
- +
-

Login

@@ -51,7 +50,7 @@ echo '';
-
+ diff --git a/public/admin/statSito.php b/public/admin/statSito.php index 6df4c2d..a451442 100644 --- a/public/admin/statSito.php +++ b/public/admin/statSito.php @@ -20,69 +20,25 @@ MenuGenerator::generateMenu(); HTMLHelper::generateAdminHead(); -$pipeline = array( - array( - '$match'=>array( - 'statType'=>StatisticModel::STAT_TYPE_PAGE - ) - ), - array( - '$group'=>array( - "_id"=>array( - 'date'=>array( - "day"=>array('$dayOfMonth'=>'$date'), - "month"=>array('$month'=>'$date'), - "year"=>array('$year'=>'$date') - ), - 'user'=>'$user.id', - ), - "visualizzazioni"=>array( - '$sum'=>1 - ), - "isNew"=>array( - '$sum'=>array( - '$cond'=>array( - array('$eq'=>array('$user.isNew',true)), - 1, - 0 - ) - ) - ) - ) - ), - array( - '$group'=>array( - "_id"=>array( - 'date'=>'$_id.date' - ), - "visualizzazioni"=>array( - '$sum'=>'$visualizzazioni' - ), - "unici"=>array( - '$sum'=>'$isNew' - ), - "visitatori"=>array( - '$sum'=>1 - ) - ) - ) -); +// Pipeline Visualizzazioni, Visitatori, Unici Ultimo mese -$result = GlobalVariables::get("dao")->aggregate("StatisticModel",$pipeline); +$result = GlobalVariables::get("dao")->aggregate("StatisticModel",PipelineHelper::getDailyVisualizationPipeline(strtotime("-1 month"))); +for ($i=0; $i
- -
+
+
+
\ No newline at end of file + \ No newline at end of file diff --git a/public/articolo.php b/public/articolo.php new file mode 100644 index 0000000..1b90226 --- /dev/null +++ b/public/articolo.php @@ -0,0 +1,32 @@ +getFirst("NotiziaModel",array("id"=>$_GET["id"])); + } + if (is_null($articolo)){ + GUIHandler::redirect("index.php"); + } + AnalyticsHelper::logNotiziaImpression($articolo->id); + AnalyticsHelper::logPageImpression(); + + GUIHandler::generateHtmlHeaders(); + echo $articolo->titolo; + +}catch(GUIException $ex){ + $error = $ex->getMessage(); +}catch (Exception $exec){ + $msg = LogModel::fromException($exec); + GlobalVariables::get("dao")->save($msg); + + GUIHandler::redirect("index.php"); +} + +?> \ No newline at end of file diff --git a/public/style/admin.css b/public/style/admin.css index b86c97e..5acbd10 100644 --- a/public/style/admin.css +++ b/public/style/admin.css @@ -12,7 +12,7 @@ #admin_menu ul ul li a{padding-left:25px; } #admin_menu ul ul{height:0px;} -.admin_head{margin-left:300px;} +.admin_head{margin-left:300px; text-align:center;} .admin_head + div{margin-left:300px; padding: 20px; position:relative;min-height:50px;} @@ -24,6 +24,17 @@ table.dataTable tr.even td{background-color:rgba(126, 151, 214, 0.4); } .dataTables_wrapper .toolbar > *{vertical-align:middle;} +/* + _ _ ____ +| | ___ __ _(_)_ __ | _ \ __ _ __ _ ___ +| | / _ \ / _` | | '_ \ | |_) / _` |/ _` |/ _ \ +| |__| (_) | (_| | | | | | | __/ (_| | (_| | __/ +|_____\___/ \__, |_|_| |_| |_| \__,_|\__, |\___| + |___/ |___/ +*/ +#login_page .pageHead{text-align:center;} +#login_page .formRow input{padding:9px 6px;} + /* _____ | ___|__ _ __ _ __ ___