fix: Removing tags now spans its own CSRF tokens in the confirmation popup

- fixes some CSRF issues
- improves rendering performance
pull/1882/head
iglocska 2017-01-31 09:58:21 +01:00
parent 57bfd48b07
commit ad472e8c4b
6 changed files with 154 additions and 135 deletions

View File

@ -46,10 +46,10 @@ class AppController extends Controller {
public $helpers = array('Utility');
private $__jsVersion = '2.4.60';
private $__jsVersion = '2.4.62';
public $pyMispVersion = '2.4.62';
public $phpmin = '5.5.9';
public $phprec = '5.6.0';
public $phprec = '7.0.0';
// Used for _isAutomation(), a check that returns true if the controller & action combo matches an action that is a non-xml and non-json automation method
// This is used to allow authentication via headers for methods not covered by _isRest() - as that only checks for JSON and XML formats

View File

@ -2704,66 +2704,70 @@ class AttributesController extends AppController {
public function removeTag($id = false, $tag_id = false) {
if (!$this->request->is('post')) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that. Only POST requests are accepted.')), 'status' => 200));
}
$rearrangeRules = array(
'request' => false,
'Attribute' => false,
'tag_id' => 'tag',
'attribute_id' => 'attribute',
'id' => 'attribute'
);
$RearrangeTool = new RequestRearrangeTool();
$this->request->data = $RearrangeTool->rearrangeArray($this->request->data, $rearrangeRules);
if ($id === false) $id = $this->request->data['attribute'];
if ($tag_id === false) $tag_id = $this->request->data['tag'];
$this->Attribute->id = $id;
if (!$this->Attribute->exists()) throw new NotFoundException(__('Invalid attribute'));
$this->Attribute->read();
if ($this->Attribute->data['Attribute']['deleted']) throw new NotFoundException(__('Invalid attribute'));
$eventId = $this->Attribute->data['Attribute']['event_id'];
if (empty($tag_id)) return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status' => 200));
if (!is_numeric($tag_id)) {
$tag = $this->Attribute->AttributeTag->Tag->find('first', array('recursive' => -1, 'conditions' => array('LOWER(Tag.name) LIKE' => strtolower(trim($tag_id)))));
if (empty($tag)) return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status' => 200));
$tag_id = $tag['Tag']['id'];
}
if (!is_numeric($id)) $id = $this->request->data['Attribute']['id'];
$this->Attribute->Event->recursive = -1;
$event = $this->Attribute->Event->read(array(), $eventId);
// org should allow to (un)tag too, so that an event that gets pushed can be (un)tagged locally by the owning org
if ((($this->Auth->user('org_id') !== $event['Event']['org_id'] && $this->Auth->user('org_id') !== $event['Event']['orgc_id'] && $event['Event']['distribution'] == 0) || (!$this->userRole['perm_tagger'])) && !$this->_isSiteAdmin()) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')), 'status' => 200));
}
$this->Attribute->recursive = -1;
$attributeTag = $this->Attribute->AttributeTag->find('first', array(
'conditions' => array(
'attribute_id' => $id,
'tag_id' => $tag_id
),
'recursive' => -1,
));
$this->autoRender = false;
if (empty($attributeTag)) return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid attribute - tag combination.')), 'status' => 200));
$tag = $this->Attribute->AttributeTag->Tag->find('first', array(
'conditions' => array('Tag.id' => $tag_id),
'recursive' => -1,
'fields' => array('Tag.name')
));
if ($this->Attribute->AttributeTag->delete($attributeTag['AttributeTag']['id'])) {
$event['Event']['published'] = 0;
$date = new DateTime();
$event['Event']['timestamp'] = $date->getTimestamp();
$this->Attribute->Event->save($event);
$this->Attribute->data['Attribute']['timestamp'] = $date->getTimestamp();
$this->Attribute->save($this->Attribute->data);
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'Attribute', $id, 'Removed tag (' . $tag_id . ') "' . $tag['Tag']['name'] . '" from attribute (' . $id . ')', 'Attribute (' . $id . ') untagged of Tag (' . $tag_id . ')');
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => 'Tag removed.', 'check_publish' => true)), 'status' => 200));
$this->set('id', $id);
$this->set('tag_id', $tag_id);
$this->set('model', 'Attribute');
$this->render('ajax/tagRemoveConfitrmation');
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Tag could not be removed.')), 'status' => 200));
$rearrangeRules = array(
'request' => false,
'Attribute' => false,
'tag_id' => 'tag',
'attribute_id' => 'attribute',
'id' => 'attribute'
);
$RearrangeTool = new RequestRearrangeTool();
$this->request->data = $RearrangeTool->rearrangeArray($this->request->data, $rearrangeRules);
if ($id === false) $id = $this->request->data['attribute'];
if ($tag_id === false) $tag_id = $this->request->data['tag'];
$this->Attribute->id = $id;
if (!$this->Attribute->exists()) throw new NotFoundException(__('Invalid attribute'));
$this->Attribute->read();
if ($this->Attribute->data['Attribute']['deleted']) throw new NotFoundException(__('Invalid attribute'));
$eventId = $this->Attribute->data['Attribute']['event_id'];
if (empty($tag_id)) return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status' => 200));
if (!is_numeric($tag_id)) {
$tag = $this->Attribute->AttributeTag->Tag->find('first', array('recursive' => -1, 'conditions' => array('LOWER(Tag.name) LIKE' => strtolower(trim($tag_id)))));
if (empty($tag)) return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status' => 200));
$tag_id = $tag['Tag']['id'];
}
if (!is_numeric($id)) $id = $this->request->data['Attribute']['id'];
$this->Attribute->Event->recursive = -1;
$event = $this->Attribute->Event->read(array(), $eventId);
// org should allow to (un)tag too, so that an event that gets pushed can be (un)tagged locally by the owning org
if ((($this->Auth->user('org_id') !== $event['Event']['org_id'] && $this->Auth->user('org_id') !== $event['Event']['orgc_id'] && $event['Event']['distribution'] == 0) || (!$this->userRole['perm_tagger'])) && !$this->_isSiteAdmin()) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')), 'status' => 200));
}
$this->Attribute->recursive = -1;
$attributeTag = $this->Attribute->AttributeTag->find('first', array(
'conditions' => array(
'attribute_id' => $id,
'tag_id' => $tag_id
),
'recursive' => -1,
));
$this->autoRender = false;
if (empty($attributeTag)) return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid attribute - tag combination.')), 'status' => 200));
$tag = $this->Attribute->AttributeTag->Tag->find('first', array(
'conditions' => array('Tag.id' => $tag_id),
'recursive' => -1,
'fields' => array('Tag.name')
));
if ($this->Attribute->AttributeTag->delete($attributeTag['AttributeTag']['id'])) {
$event['Event']['published'] = 0;
$date = new DateTime();
$event['Event']['timestamp'] = $date->getTimestamp();
$this->Attribute->Event->save($event);
$this->Attribute->data['Attribute']['timestamp'] = $date->getTimestamp();
$this->Attribute->save($this->Attribute->data);
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'Attribute', $id, 'Removed tag (' . $tag_id . ') "' . $tag['Tag']['name'] . '" from attribute (' . $id . ')', 'Attribute (' . $id . ') untagged of Tag (' . $tag_id . ')');
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => 'Tag removed.', 'check_publish' => true)), 'status' => 200));
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Tag could not be removed.')), 'status' => 200));
}
}
}

View File

@ -2952,56 +2952,60 @@ class EventsController extends AppController {
public function removeTag($id = false, $tag_id = false, $galaxy = false) {
if (!$this->request->is('post')) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that. Only POST requests are accepted.')), 'status'=>200));
}
$rearrangeRules = array(
'request' => false,
'Event' => false,
'tag_id' => 'tag',
'event_id' => 'event',
'id' => 'event'
);
$RearrangeTool = new RequestRearrangeTool();
$this->request->data = $RearrangeTool->rearrangeArray($this->request->data, $rearrangeRules);
if ($id === false) $id = $this->request->data['event'];
if ($tag_id === false) $tag_id = $this->request->data['tag'];
if (empty($tag_id)) return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid ' . ($galaxy ? 'Galaxy' : 'Tag') . '.')),'status'=>200));
if (!is_numeric($tag_id)) {
$tag = $this->Event->EventTag->Tag->find('first', array('recursive' => -1, 'conditions' => array('LOWER(Tag.name) LIKE' => strtolower(trim($tag_id)))));
if (empty($tag)) return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid ' . ($galaxy ? 'Galaxy' : 'Tag') . '.')), 'status'=>200));
$tag_id = $tag['Tag']['id'];
}
if (!is_numeric($id)) $id = $this->request->data['Event']['id'];
$this->Event->recursive = -1;
$event = $this->Event->read(array(), $id);
// org should allow to tag too, so that an event that gets pushed can be tagged locally by the owning org
if ((($this->Auth->user('org_id') !== $event['Event']['org_id'] && $this->Auth->user('org_id') !== $event['Event']['orgc_id']) || (!$this->userRole['perm_tagger'])) && !$this->_isSiteAdmin()) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')),'status'=>200));
}
$eventTag = $this->Event->EventTag->find('first', array(
'conditions' => array(
'event_id' => $id,
'tag_id' => $tag_id
),
'recursive' => -1,
));
$this->autoRender = false;
if (empty($eventTag)) return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid event - ' . ($galaxy ? 'galaxy' : 'tag') . ' combination.')),'status'=>200));
$tag = $this->Event->EventTag->Tag->find('first', array(
'conditions' => array('Tag.id' => $tag_id),
'recursive' => -1,
'fields' => array('Tag.name')
));
if ($this->Event->EventTag->delete($eventTag['EventTag']['id'])) {
$event['Event']['published'] = 0;
$date = new DateTime();
$event['Event']['timestamp'] = $date->getTimestamp();
$this->Event->save($event);
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'Event', $id, 'Removed tag (' . $tag_id . ') "' . $tag['Tag']['name'] . '" from event (' . $id . ')', 'Event (' . $id . ') untagged of Tag (' . $tag_id . ')');
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => ($galaxy ? 'Galaxy' : 'Tag') . ' removed.', 'check_publish' => true)), 'status'=>200));
$this->set('id', $id);
$this->set('tag_id', $tag_id);
$this->set('model', 'Event');
$this->render('/Attributes/ajax/tagRemoveConfitrmation');
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => ($galaxy ? 'Galaxy' : 'Tag') . ' could not be removed.')),'status'=>200));
$rearrangeRules = array(
'request' => false,
'Event' => false,
'tag_id' => 'tag',
'event_id' => 'event',
'id' => 'event'
);
$RearrangeTool = new RequestRearrangeTool();
$this->request->data = $RearrangeTool->rearrangeArray($this->request->data, $rearrangeRules);
if ($id === false) $id = $this->request->data['event'];
if ($tag_id === false) $tag_id = $this->request->data['tag'];
if (empty($tag_id)) return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid ' . ($galaxy ? 'Galaxy' : 'Tag') . '.')),'status'=>200));
if (!is_numeric($tag_id)) {
$tag = $this->Event->EventTag->Tag->find('first', array('recursive' => -1, 'conditions' => array('LOWER(Tag.name) LIKE' => strtolower(trim($tag_id)))));
if (empty($tag)) return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid ' . ($galaxy ? 'Galaxy' : 'Tag') . '.')), 'status'=>200));
$tag_id = $tag['Tag']['id'];
}
if (!is_numeric($id)) $id = $this->request->data['Event']['id'];
$this->Event->recursive = -1;
$event = $this->Event->read(array(), $id);
// org should allow to tag too, so that an event that gets pushed can be tagged locally by the owning org
if ((($this->Auth->user('org_id') !== $event['Event']['org_id'] && $this->Auth->user('org_id') !== $event['Event']['orgc_id']) || (!$this->userRole['perm_tagger'])) && !$this->_isSiteAdmin()) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')),'status'=>200));
}
$eventTag = $this->Event->EventTag->find('first', array(
'conditions' => array(
'event_id' => $id,
'tag_id' => $tag_id
),
'recursive' => -1,
));
$this->autoRender = false;
if (empty($eventTag)) return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid event - ' . ($galaxy ? 'galaxy' : 'tag') . ' combination.')),'status'=>200));
$tag = $this->Event->EventTag->Tag->find('first', array(
'conditions' => array('Tag.id' => $tag_id),
'recursive' => -1,
'fields' => array('Tag.name')
));
if ($this->Event->EventTag->delete($eventTag['EventTag']['id'])) {
$event['Event']['published'] = 0;
$date = new DateTime();
$event['Event']['timestamp'] = $date->getTimestamp();
$this->Event->save($event);
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'Event', $id, 'Removed tag (' . $tag_id . ') "' . $tag['Tag']['name'] . '" from event (' . $id . ')', 'Event (' . $id . ') untagged of Tag (' . $tag_id . ')');
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => ($galaxy ? 'Galaxy' : 'Tag') . ' removed.', 'check_publish' => true)), 'status'=>200));
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => ($galaxy ? 'Galaxy' : 'Tag') . ' could not be removed.')),'status'=>200));
}
}
}

View File

@ -7,10 +7,10 @@
<div style="padding:1px; overflow:hidden; white-space:nowrap; display:flex; float:left; margin-right:2px;">
<a href="<?php echo $baseurl;?>/attributes/search/attributetag:<?php echo h($tag['Tag']['id']); ?>" class="<?php echo $tagClass; ?>" style="display:inline-block; background-color:<?php echo h($tag['Tag']['colour']);?>;color:<?php echo $this->TextColour->getTextColour($tag['Tag']['colour']);?>"><?php echo h($tag['Tag']['name']); ?></a>
<?php if ($full): ?>
<div class="tagSecondHalf useCursorPointer noPrint" onClick="removeAttributeTag('<?php echo h($attributeId); ?>', '<?php echo h($tag['Tag']['id']); ?>');">x</div>
<div class="tagSecondHalf useCursorPointer noPrint" onClick="removeObjectTagPopup('attribute', '<?php echo h($attributeId); ?>', '<?php echo h($tag['Tag']['id']); ?>');">x</div>
<?php endif;?>
</div>
<?php
<?php
endforeach;
?>
<div style="float:left">

View File

@ -7,10 +7,10 @@
<div style="padding:1px; overflow:hidden; white-space:nowrap; display:flex; float:left; margin-right:2px;">
<a href="<?php echo $baseurl;?>/events/index/searchtag:<?php echo h($tag['Tag']['id']); ?>" class="<?php echo $tagClass; ?>" style="display:inline-block; background-color:<?php echo h($tag['Tag']['colour']);?>;color:<?php echo $this->TextColour->getTextColour($tag['Tag']['colour']);?>"><?php echo h($tag['Tag']['name']); ?></a>
<?php if ($full): ?>
<div class="tagSecondHalf useCursorPointer noPrint" onClick="removeEventTag('<?php echo h($event['Event']['id']); ?>', '<?php echo h($tag['Tag']['id']); ?>');">x</div>
<div class="tagSecondHalf useCursorPointer noPrint" onClick="removeObjectTagPopup('event', '<?php echo h($event['Event']['id']); ?>', '<?php echo h($tag['Tag']['id']); ?>');">x</div>
<?php endif;?>
</div>
<?php
<?php
endforeach;
?>
<div style="float:left">
@ -20,4 +20,4 @@
&nbsp;
<?php endif; ?>
</div>
</div>
</div>

View File

@ -675,27 +675,38 @@ function loadAttributeTags(id) {
});
}
function removeAttributeTag(attribute, tag) {
var answer = confirm("Are you sure you want to remove this tag from the attribute?");
if (answer) {
var formData = $('#removeAttributeTag_' + tag).serialize();
$.ajax({
beforeSend: function (XMLHttpRequest) {
$(".loading").show();
},
data: formData,
type:"POST",
cache: false,
url:"/attributes/removeTag/" + attribute + '/' + tag,
success:function (data, textStatus) {
loadAttributeTags(attribute);
handleGenericAjaxResponse(data);
},
complete:function() {
$(".loading").hide();
function removeObjectTagPopup(context, object, tag) {
$.get( "/" + context + "s/removeTag/" + object + '/' + tag, function(data) {
$("#confirmation_box").html(data);
$("#confirmation_box").fadeIn();
$("#gray_out").fadeIn();
});
}
function removeObjectTag(context, object, tag) {
var formData = $('#remove' + context.charAt(0).toUpperCase() + 'Tag_' + tag).serialize();
$.ajax({
beforeSend: function (XMLHttpRequest) {
$(".loading").show();
},
data: formData,
type:"POST",
cache: false,
url:"/" + context + "s/removeTag/" + object + '/' + tag,
success:function (data, textStatus) {
$("#confirmation_box").fadeOut();
$("#gray_out").fadeOut();
if (context == 'Attribute') {
loadAttributeTags(object);
} else {
loadEventTags(object);
}
});
}
handleGenericAjaxResponse(data);
},
complete:function() {
$(".loading").hide();
}
});
return false;
}