From: Marcin Haba Date: Thu, 18 Aug 2022 07:28:35 +0000 (+0200) Subject: baculum: Add Microsoft 365 email list endpoints X-Git-Tag: Release-13.0.2~67 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d2cfd9201a0f0de85e8d9b42fa469b7575b9b8de;p=thirdparty%2Fbacula.git baculum: Add Microsoft 365 email list endpoints --- diff --git a/gui/baculum/protected/API/Modules/Bconsole.php b/gui/baculum/protected/API/Modules/Bconsole.php index 872a04544..e65892265 100644 --- a/gui/baculum/protected/API/Modules/Bconsole.php +++ b/gui/baculum/protected/API/Modules/Bconsole.php @@ -97,7 +97,8 @@ class Bconsole extends APIModule { '.status', '.ls', 'setbandwidth', - '.query' + '.query', + '.jlist' ); private $config; diff --git a/gui/baculum/protected/API/Modules/ConsoleOutputJSONPage.php b/gui/baculum/protected/API/Modules/ConsoleOutputJSONPage.php new file mode 100644 index 000000000..313557eb2 --- /dev/null +++ b/gui/baculum/protected/API/Modules/ConsoleOutputJSONPage.php @@ -0,0 +1,51 @@ + + * @category API + * @package Baculum API + */ +abstract class ConsoleOutputJSONPage extends ConsoleOutputPage { + + /** + * Parse '.jlist' type command output. + * + * @param array $output dot query command output + * @return object parsed output or empty object if there occurs a problem with parsing output + */ + protected function parseOutput(array $output) { + $out = new \StdClass; + for ($i = 0; $i < count($output); $i++) { + if (preg_match('/^[{\[]/', $output[$i]) === 1) { + $out = json_decode($output[$i]); + break; + } + } + return $out; + } +} +?> diff --git a/gui/baculum/protected/API/Pages/API/PluginM365EmailList.php b/gui/baculum/protected/API/Pages/API/PluginM365EmailList.php new file mode 100644 index 000000000..b229cb13f --- /dev/null +++ b/gui/baculum/protected/API/Pages/API/PluginM365EmailList.php @@ -0,0 +1,212 @@ + + * @category API + * @package Baculum API + */ +class PluginM365EmailList extends ConsoleOutputJSONPage { + + public function get() { + $misc = $this->getModule('misc'); + $client = null; + $clientid = $this->Request->contains('id') ? (int)$this->Request['id'] : 0; + $result = $this->getModule('bconsole')->bconsoleCommand( + $this->director, + ['.client'], + null, + true + ); + if ($result->exitcode === 0) { + $client_val = $this->getModule('client')->getClientById($clientid); + if (is_object($client_val) && in_array($client_val->name, $result->output)) { + $client = $client_val->name; + } else { + $this->output = ClientError::MSG_ERROR_CLIENT_DOES_NOT_EXISTS; + $this->error = ClientError::ERROR_CLIENT_DOES_NOT_EXISTS; + return; + } + } else { + $this->output = PluginError::MSG_ERROR_WRONG_EXITCODE; + $this->error = PluginError::ERROR_WRONG_EXITCODE; + return; + } + + $tenantid = $this->Request->contains('tenantid') ? $this->Request['tenantid'] : null; + $fd_plugin_cfg = $this->getModule('fd_plugin_cfg')->getConfig('m365', $client, $tenantid); + if (!empty($tenantid) && (!$misc->isValidUUID($tenantid) || count($fd_plugin_cfg) == 0)) { + $this->output = PluginM365Error::MSG_ERROR_TENANT_DOES_NOT_EXISTS; + $this->error = PluginM365Error::ERROR_TENANT_DOES_NOT_EXISTS; + return; + } + $tenant = $fd_plugin_cfg['tenant_name']; + + $params = [ + 'client' => $client, + 'tenant' => $tenant + ]; + if ($this->Request->contains('mailbox') && $misc->isValidEmail($this->Request['mailbox'])) { + $params['mailbox'] = $this->Request['mailbox']; + } + if ($this->Request->contains('mailbox_pattern') && $misc->isValidEmail($this->Request['mailbox_pattern'])) { + $params['mailbox_pattern'] = $this->Request['mailbox_pattern']; + } + if ($this->Request->contains('limit') && $misc->isValidInteger($this->Request['limit'])) { + $params['limit'] = (int)$this->Request['limit']; + } + if ($this->Request->contains('mintime') && $misc->isValidBDate($this->Request['mintime'])) { + $params['mintime'] = $this->Request['mintime']; + } + if ($this->Request->contains('maxtime') && $misc->isValidBDate($this->Request['maxtime'])) { + $params['maxtime'] = $this->Request['maxtime']; + } + if ($this->Request->contains('folder') && $misc->isValidFilename($this->Request['folder'])) { + $params['folder'] = $this->Request['folder']; + } + if ($this->Request->contains('tags') && $misc->isValidName($this->Request['tags'])) { + $params['tags'] = $this->Request['tags']; + } + if ($this->Request->contains('from') && $misc->isValidEmail($this->Request['from'])) { + $params['from'] = $this->Request['from']; + } + if ($this->Request->contains('to') && $misc->isValidEmail($this->Request['to'])) { + $params['to'] = $this->Request['to']; + } + if ($this->Request->contains('cc') && $misc->isValidEmail($this->Request['cc'])) { + $params['cc'] = $this->Request['cc']; + } + if ($this->Request->contains('minsize') && $misc->isValidInteger($this->Request['minsize'])) { + $params['minsize'] = $this->Request['minsize']; + } + if ($this->Request->contains('maxsize') && $misc->isValidInteger($this->Request['maxsize'])) { + $params['maxsize'] = $this->Request['maxsize']; + } + if ($this->Request->contains('conversationid') && $misc->isValidNameExt($this->Request['conversationid'])) { + $params['conversationid'] = $this->Request['conversationid']; + } + $out = $this->getJSONOutput($params); + + $output = []; + $error = PluginM365Error::ERROR_NO_ERRORS; + if ($out->exitcode === 0) { + $output = $out->output; + } else { + $error = PluginM365Error::ERROR_WRONG_EXITCODE; + $output = PluginM365Error::MSG_ERROR_WRONG_EXITCODE . implode(PHP_EOL, $out->output); + } + $this->output = $output; + $this->error = $error; + } + + /** + * Get M365 email list in JSON string format. + * + * @param array $params command parameters + * @return StdClass object with output and exitcode + */ + protected function getRawOutput($params = []) { + $cmd = [ + '.jlist', + 'metadata', + 'type="email"', + 'tenant="' . $params['tenant'] . '"' + ]; + + if (key_exists('mailbox', $params)) { + $cmd[] ='owner="' . $params['mailbox'] . '"'; + } + if (key_exists('mailbox_pattern', $params)) { + $cmd[] ='owner="' . $params['mailbox_pattern'] . '%"'; + } + if (key_exists('limit', $params)) { + $cmd[] ='limit="' . $params['limit'] . '"'; + } + if (key_exists('mintime', $params)) { + $cmd[] ='mintime="' . $params['mintime'] . ' 0:00:00"'; + } + if (key_exists('maxtime', $params)) { + $cmd[] ='maxtime="' . $params['maxtime'] . ' 23:59:59"'; + } + if (key_exists('folder', $params)) { + $cmd[] ='foldername="' . $params['folder'] . '"'; + } + if (key_exists('tags', $params)) { + $cmd[] ='tags="' . $params['tags'] . '"'; + } + if (key_exists('from', $params)) { + $cmd[] ='from="' . $params['from'] . '"'; + } + if (key_exists('to', $params)) { + $cmd[] ='to="' . $params['to'] . '"'; + } + if (key_exists('cc', $params)) { + $cmd[] ='cc="' . $params['cc'] . '"'; + } + if (key_exists('minsize', $params)) { + $cmd[] ='minsize="' . $params['minsize'] . '"'; + } + if (key_exists('maxsize', $params)) { + $cmd[] ='maxsize="' . $params['maxsize'] . '"'; + } + if (key_exists('conversationid', $params)) { + $cmd[] ='conversationid="' . $params['conversationid'] . '"'; + } + $ret = $this->getModule('bconsole')->bconsoleCommand( + $this->director, + $cmd + ); + + if ($ret->exitcode !== 0) { + $this->getModule('logging')->log( + Logging::CATEGORY_EXECUTE, + 'Wrong output from m365 RAW email list: ' . implode(PHP_EOL, $ret->output) + ); + } + return $ret; + } + + /** + * Get M365 email list in validated and formatted JSON format. + * + * @param array $params command parameters + * @return StdClass object with output and exitcode + */ + protected function getJSONOutput($params = []) { + $ret = $this->getRawOutput($params); + if ($ret->exitcode === 0) { + $ret->output = $this->parseOutput($ret->output); + if ($ret->output->error === 0) { + $ret->output = $ret->output->data; + } else { + $ret->output = $ret->output->errmsg; + } + } + return $ret; + } +} diff --git a/gui/baculum/protected/API/Pages/API/endpoints.xml b/gui/baculum/protected/API/Pages/API/endpoints.xml index f8316f8e6..bf6416936 100644 --- a/gui/baculum/protected/API/Pages/API/endpoints.xml +++ b/gui/baculum/protected/API/Pages/API/endpoints.xml @@ -125,6 +125,7 @@ + diff --git a/gui/baculum/protected/API/openapi_baculum.json b/gui/baculum/protected/API/openapi_baculum.json index 51a64702f..4f39bbda2 100644 --- a/gui/baculum/protected/API/openapi_baculum.json +++ b/gui/baculum/protected/API/openapi_baculum.json @@ -140,6 +140,15 @@ }, "Event": { "$ref": "#/definitions/Event" + }, + "PluginM365Emails": { + "type": "array", + "items": { + "$ref": "#/definitions/PluginM365Email" + } + }, + "PluginM365Email": { + "$ref": "#/definitions/PluginM365Email" } }, "parameters": { @@ -298,9 +307,9 @@ }, "TenantId": { "name": "tenantid", - "in": "query", + "in": "path", "description": "Tenant identifier", - "required": false, + "required": true, "schema": { "type": "string" } @@ -6626,13 +6635,167 @@ "$ref": "#/components/parameters/ClientId" }, { - "$ref": "#/components/parameters/TenantId" + "name": "tenantid", + "in": "path", + "description": "Tenant identifier", + "required": false, + "schema": { + "type": "string" + } }, { "$ref": "#/components/parameters/Output" } ] } + }, + "/api/v2/plugins/m365/{clientid}/{tenantid}/emails": { + "get": { + "tags": ["plugins"], + "summary": "Microsoft 365 plugin email list", + "description": "Get Microsoft 365 email list.", + "responses": { + "200": { + "description": "List of Microsoft 365 emails", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "output": { + "$ref": "#/components/schemas/PluginM365Emails" + }, + "error": { + "type": "integer", + "description": "Error code", + "enum": [0, 1, 4, 5, 6, 7, 11, 1000] + } + } + } + } + } + } + }, + "parameters": [ + { + "$ref": "#/components/parameters/ClientId" + }, + { + "$ref": "#/components/parameters/TenantId" + }, + { + "$ref": "#/components/parameters/Limit" + }, + { + "name": "mailbox", + "in": "query", + "required": false, + "description": "Mailbox address", + "schema": { + "type": "string" + } + }, + { + "name": "mailbox_pattern", + "in": "query", + "required": false, + "description": "Mailbox pattern address (it can be partial email address)", + "schema": { + "type": "string" + } + }, + { + "name": "mintime", + "in": "query", + "required": false, + "description": "Date start (YYYY-MM-DD)", + "schema": { + "type": "string" + } + }, + { + "name": "maxtime", + "in": "query", + "required": false, + "description": "Date end (YYYY-MM-DD)", + "schema": { + "type": "string" + } + }, + { + "name": "folder", + "in": "query", + "required": false, + "description": "Email folder name", + "schema": { + "type": "string" + } + }, + { + "name": "tags", + "in": "query", + "required": false, + "description": "Email tags", + "schema": { + "type": "string" + } + }, + { + "name": "from", + "in": "query", + "required": false, + "description": "Email sender (from)", + "schema": { + "type": "string" + } + }, + { + "name": "to", + "in": "query", + "required": false, + "description": "Email recipient (to)", + "schema": { + "type": "string" + } + }, + { + "name": "cc", + "in": "query", + "required": false, + "description": "Email copy address (cc)", + "schema": { + "type": "string" + } + }, + { + "name": "minsize", + "in": "query", + "required": false, + "description": "Email minimum size in bytes", + "schema": { + "type": "integer" + } + }, + { + "name": "maxsize", + "in": "query", + "required": false, + "description": "Email maximum size in bytes", + "schema": { + "type": "integer" + } + }, + { + "name": "conversationid", + "in": "query", + "required": false, + "description": "Email conversation identifier", + "schema": { + "type": "string" + } + } + ] + } } }, "definitions": { @@ -7529,6 +7692,95 @@ "type": "string" } } + }, + "PluginM365Email": { + "type": "object", + "properties": { + "jobid": { + "description": "Job identifier", + "type": "integer" + }, + "fileindex": { + "description": "File index", + "type": "integer" + }, + "emailtenant": { + "description": "Tenant name", + "type": "string" + }, + "emailowner": { + "description": "Email owner", + "type": "string" + }, + "emailbodypreview": { + "description": "Email body preview", + "type": "string" + }, + "emailcc": { + "description": "Email copy address (cc)", + "type": "string" + }, + "emailconversationid": { + "description": "Email conversation identifier", + "type": "string" + }, + "emailfoldername": { + "description": "Email folder name", + "type": "string" + }, + "emailfrom": { + "description": "Email sender (from)", + "type": "string" + }, + "emailid": { + "description": "Email identifier", + "type": "string" + }, + "emailimportance": { + "description": "Email importance", + "type": "string" + }, + "emailinternetmessageid": { + "description": "Email Internet message identifier", + "type": "string" + }, + "emailisread": { + "description": "Email is read flag", + "type": "integer" + }, + "emailisdraft": { + "description": "Email is draft flag", + "type": "integer" + }, + "emailtime": { + "description": "Email time (YYYY-MM-DD HH:II:SS)", + "type": "string" + }, + "emailsubject": { + "description": "Email subject", + "type": "string" + }, + "emailtags": { + "description": "Email tags", + "type": "string" + }, + "emailto": { + "description": "Email recipient (to)", + "type": "string" + }, + "emailsize": { + "description": "Email size in bytes", + "type": "string" + }, + "emailhasattachment": { + "description": "Email attachment flag", + "type": "integer" + }, + "plugin": { + "description": "Plugin name", + "type": "string" + } + } } } } diff --git a/gui/baculum/protected/Common/Modules/Miscellaneous.php b/gui/baculum/protected/Common/Modules/Miscellaneous.php index 86f33bedf..6a415f765 100644 --- a/gui/baculum/protected/Common/Modules/Miscellaneous.php +++ b/gui/baculum/protected/Common/Modules/Miscellaneous.php @@ -223,7 +223,7 @@ class Miscellaneous extends TModule { } public function isValidNameExt($name_ext) { - return (preg_match('/^[\w:\.\-\s\*]{1,127}$/', $name_ext) === 1); + return (preg_match('/^[\w:\.\-\s\*=]{1,127}$/', $name_ext) === 1); } public function isValidState($state) { @@ -298,6 +298,10 @@ class Miscellaneous extends TModule { return (preg_match('/^[\w]{8}(-[\w]{4}){3}-[\w]{12}$/', $uuid) === 1); } + public function isValidEmail($email) { + return filter_var($email, FILTER_VALIDATE_EMAIL); + } + public function escapeCharsToConsole($path) { return preg_replace('/([$])/', '\\\${1}', $path); }