new: [internal] Simplication of the push functionality

pull/3551/head
iglocska 2018-08-03 13:22:17 +02:00
parent b65dce32f7
commit fe3fc13fbd
3 changed files with 79 additions and 122 deletions

View File

@ -1608,4 +1608,20 @@ class AppModel extends Model
$request = $this->addHeaders($request);
return $request;
}
public function addHeaders($request)
{
$version = $this->checkMISPVersion();
$version = implode('.', $version);
try {
$commit = trim(shell_exec('git log --pretty="%H" -n1 HEAD'));
} catch (Exception $e) {
$commit = false;
}
$request['header']['MISP-version'] = $version;
if ($commit) {
$request['header']['commit'] = $commit;
}
return $request;
}
}

View File

@ -858,42 +858,8 @@ class Event extends AppModel
return $error;
}
public function uploadEventToServer($event, $server, $HttpSocket = null)
private function __executeRestfulEventToServer($event, $server, $resourceId, &$newLocation, &$newTextBody, $HttpSocket)
{
$this->Server = ClassRegistry::init('Server');
$push = $this->Server->checkVersionCompatibility($server['Server']['id'], false, $HttpSocket);
if (!isset($push['canPush'])) {
$test = $this->Server->checkLegacyServerSyncPrivilege($server['Server']['id'], $HttpSocket);
} else {
if (!$push['canPush']) {
return 'The remote user is not a sync user - the upload of the event has been blocked.';
}
}
$deletedAttributes = false;
if (($push['version'][0] > 2) ||
($push['version'][0] == 2 && $push['version'][1] > 4) ||
($push['version'][0] == 2 && $push['version'][1] == 4 && $push['version'][2] > 42)) {
$deletedAttributes = true;
}
if (isset($event['Attribute']) && !$deletedAttributes) {
foreach ($event['Attribute'] as $k => $v) {
if ($v['deleted']) {
unset($event['Attribute'][$k]);
}
}
$event['Attribute'] = array_values($event['Attribute']);
}
if (!isset($push['canPush']) || !$push['canPush']) {
return 'Trying to push to an outdated instance.';
}
if (isset($server['Server']['unpublish_event'])) {
$unpublish_event = $server['Server']['unpublish_event'];
if ($unpublish_event) {
$event['Event']['published'] = 0;
}
}
$updated = null;
$newLocation = $newTextBody = '';
$result = $this->restfulEventToServer($event, $server, null, $newLocation, $newTextBody, $HttpSocket);
if (is_numeric($result)) {
$error = $this->__resolveErrorCode($result, $event, $server);
@ -901,60 +867,47 @@ class Event extends AppModel
return $error . ' Error code: ' . $result;
}
}
if (strlen($newLocation) || $result) { // HTTP/1.1 200 OK or 302 Found and Location: http://<newLocation>
if (strlen($newLocation)) { // HTTP/1.1 302 Found and Location: http://<newLocation>
$result = $this->restfulEventToServer($event, $server, $newLocation, $newLocation, $newTextBody, $HttpSocket);
if (is_numeric($result)) {
$error = $this->__resolveErrorCode($result, $event, $server);
if ($error) {
return $error . ' Error code: ' . $result;
}
}
}
$uploadFailed = false;
try {
$json = json_decode($newTextBody, true);
} catch (Exception $e) {
$uploadFailed = true;
}
if (!is_array($json) || $uploadFailed) {
return $this->__logUploadResult($server, $event, $newTextBody);
}
// get the remote event_id
foreach ($json as $jsonEvent) {
if (is_array($jsonEvent)) {
foreach ($jsonEvent as $key => $value) {
if ($key == 'id') {
break;
}
}
} else {
return $this->__logUploadResult($server, $event, $newTextBody);
return true;
}
public function uploadEventToServer($event, $server, $HttpSocket = null)
{
$this->Server = ClassRegistry::init('Server');
$push = $this->Server->checkVersionCompatibility($server['Server']['id'], false, $HttpSocket);
if (empty($push['canPush'])) {
return 'The remote user is not a sync user - the upload of the event has been blocked.';
}
if (!empty($server['Server']['unpublish_event'])) {
$event['Event']['published'] = 0;
}
$updated = null;
$newLocation = $newTextBody = '';
$result = $this->__executeRestfulEventToServer($event, $server, null, $newLocation, $newTextBody, $HttpSocket);
if ($result !== true) {
return $result;
}
if (strlen($newLocation)) { // HTTP/1.1 302 Found and Location: http://<newLocation>
$result = $this->restfulEventToServer($event, $server, $newLocation, $newLocation, $newTextBody, $HttpSocket);
if (is_numeric($result)) {
$error = $this->__resolveErrorCode($result, $event, $server);
if ($error) {
return $error . ' Error code: ' . $result;
}
}
}
$uploadFailed = false;
try {
$json = json_decode($newTextBody, true);
} catch (Exception $e) {
$uploadFailed = true;
}
if (!is_array($json) || $uploadFailed) {
return $this->__logUploadResult($server, $event, $newTextBody);
}
return 'Success';
}
public function addHeaders($request)
{
$version = $this->checkMISPVersion();
$version = implode('.', $version);
try {
$commit = trim(shell_exec('git log --pretty="%H" -n1 HEAD'));
} catch (Exception $e) {
$commit = false;
}
$request['header']['MISP-version'] = $version;
if ($commit) {
$request['header']['commit'] = $commit;
}
return $request;
}
// Uploads the event and the associated Attributes to another Server
public function restfulEventToServer($event, $server, $urlPath, &$newLocation, &$newTextBody, $HttpSocket = null)
{
private function __prepareForPushToServer($event, $server) {
if ($event['Event']['distribution'] == 4) {
if (!empty($event['SharingGroup']['SharingGroupServer'])) {
$found = false;
@ -979,17 +932,20 @@ class Event extends AppModel
} else {
return 403;
}
$url = $server['Server']['url'];
$HttpSocket = $this->setupHttpSocket($server, $HttpSocket);
$request = $this->setupSyncRequest($server);
$uri = $url . '/events';
if (isset($urlPath)) {
return $event;
}
private function __getLastUrlPathComponent($urlPath)
{
if (!empty($urlPath)) {
$pieces = explode('/', $urlPath);
$uri .= '/' . end($pieces);
return '/' . end($pieces);
}
$data = json_encode($event);
// LATER validate HTTPS SSL certificate
$response = $HttpSocket->post($uri, $data, $request);
return '';
}
private function __handleRestfulEventToServerResponse($response, &$newLocation, &$newTextBody)
{
switch ($response->code) {
case '200': // 200 (OK) + entity-action-result
if ($response->isOk()) {
@ -1002,11 +958,7 @@ class Event extends AppModel
} catch (Exception $e) {
return true;
}
if (strpos($jsonArray['name'], "Event already exists")) { // strpos, so i can piggyback some value if needed.
return true;
} else {
return $jsonArray['name'];
}
return $jsonArray['name'];
}
case '302': // Found
$newLocation = $response->headers['Location'];
@ -1023,6 +975,20 @@ class Event extends AppModel
}
}
// Uploads the event and the associated Attributes to another Server
public function restfulEventToServer($event, $server, $urlPath, &$newLocation, &$newTextBody, $HttpSocket = null)
{
$event = $this->__prepareForPushToServer($event, $server);
if (is_numeric($event)) return $event;
$url = $server['Server']['url'];
$HttpSocket = $this->setupHttpSocket($server, $HttpSocket);
$request = $this->setupSyncRequest($server);
$uri = $url . '/events' . $this->__getLastUrlPathComponent($urlPath);
$data = json_encode($event);
$response = $HttpSocket->post($uri, $data, $request);
return $this->__handleRestfulEventToServerResponse($response, $newLocation, $newTextBody);
}
private function __updateEventForSync($event, $server)
{
// rearrange things to be compatible with the Xml::fromArray()

View File

@ -3318,31 +3318,6 @@ class Server extends AppModel
return array('success' => $success, 'response' => $response, 'canPush' => $canPush, 'version' => $remoteVersion);
}
/* This is a fallback for legacy remote instances that don't report back the current user's sync permission.
*
* The idea is simple: If we have no way of determining the perm_sync flag from the remote instance, request
* /servers/testConnection from the remote. This API is used to check the remote connectivity and expects an ID to be passed
* In this case however we are not passing an ID so ideally it will return 404, meaning that the instance is invalid.
* We are abusing the fact that only sync users can use this functionality, if we don't have sync permission we'll get a 403
* instead of the 404. It's hacky but it works fine and serves the purpose.
*/
public function checkLegacyServerSyncPrivilege($id, $HttpSocket = false)
{
$server = $this->find('first', array('conditions' => array('Server.id' => $id)));
$uri = $server['Server']['url'] . '/servers/testConnection';
$HttpSocket = $this->setupHttpSocket($server, $HttpSocket);
$request = $this->setupSyncRequest($server);
try {
$response = $HttpSocket->get($uri, '', $request);
} catch (Exception $e) {
return false;
}
if ($response->code == '404') {
return true;
}
return false;
}
public function isJson($string)
{
return (json_last_error() == JSON_ERROR_NONE);