mirror of https://github.com/MISP/MISP
Several features finished
- first version of templating system complete - first version of freetext importer complete - first version of mass attribute replace tool complete - some UI changespull/274/head^2
parent
893ef5a129
commit
ab5b9a9dae
|
@ -1697,9 +1697,13 @@ class AttributesController extends AppController {
|
|||
}
|
||||
|
||||
public function generateCorrelation() {
|
||||
$start = microtime(true);
|
||||
if (!self::_isSiteAdmin()) throw new NotFoundException();
|
||||
$k = $this->Attribute->generateCorrelation();
|
||||
$this->Session->setFlash(__('All done. ' . $k . ' attributes processed.'));
|
||||
$time_elapsed_us = microtime(true) - $start;
|
||||
debug($time_elapsed_us);
|
||||
throw new Exception();
|
||||
$this->redirect(array('controller' => 'pages', 'action' => 'display', 'administration'));
|
||||
}
|
||||
|
||||
|
@ -1794,4 +1798,118 @@ class AttributesController extends AppController {
|
|||
$fieldURL = ucfirst($field);
|
||||
$this->render('ajax/attributeEdit' . $fieldURL . 'Form');
|
||||
}
|
||||
|
||||
|
||||
public function attributeReplace($id) {
|
||||
if (!$this->userRole['perm_add']) {
|
||||
throw new MethodNotAllowedException('Event not found or you don\'t have permissions to create attributes');
|
||||
}
|
||||
$event = $this->Attribute->Event->find('first', array(
|
||||
'conditions' => array('Event.id' => $id),
|
||||
'fields' => array('id', 'orgc', 'distribution'),
|
||||
'recursive' => -1
|
||||
));
|
||||
if (empty($event) || (!$this->_isSiteAdmin() && ($event['Event']['orgc'] != $this->Auth->user('org') || !$this->userRole['perm_add']))) throw new MethodNotAllowedException('Event not found or you don\'t have permissions to create attributes');
|
||||
$this->set('event_id', $id);
|
||||
if ($this->request->is('get')) {
|
||||
$this->layout = 'ajax';
|
||||
$this->request->data['Attribute']['event_id'] = $id;
|
||||
|
||||
// combobox for types
|
||||
$types = array_keys($this->Attribute->typeDefinitions);
|
||||
$types = $this->_arrayToValuesIndexArray($types);
|
||||
$this->set('types', $types);
|
||||
// combobos for categories
|
||||
$categories = $this->Attribute->validate['category']['rule'][1];
|
||||
array_pop($categories);
|
||||
$categories = $this->_arrayToValuesIndexArray($categories);
|
||||
$this->set('categories', compact('categories'));
|
||||
$this->set('attrDescriptions', $this->Attribute->fieldDescriptions);
|
||||
$this->set('typeDefinitions', $this->Attribute->typeDefinitions);
|
||||
$this->set('categoryDefinitions', $this->Attribute->categoryDefinitions);
|
||||
}
|
||||
if ($this->request->is('post')) {
|
||||
if (!$this->request->is('ajax')) throw new MethodNotAllowedException('This action can only be accessed via AJAX.');
|
||||
|
||||
$newValues = explode(PHP_EOL, $this->request->data['Attribute']['value']);
|
||||
$category = $this->request->data['Attribute']['category'];
|
||||
$type = $this->request->data['Attribute']['type'];
|
||||
$to_ids = $this->request->data['Attribute']['to_ids'];
|
||||
|
||||
if (!$this->_isSiteAdmin() && $this->Auth->user('org') != $event['Event']['orgc'] && !$this->userRole['perm_add']) throw new MethodNotAllowedException('You are not authorised to do that.');
|
||||
|
||||
$oldAttributes = $this->Attribute->find('all', array(
|
||||
'conditions' => array(
|
||||
'event_id' => $id,
|
||||
'category' => $category,
|
||||
'type' => $type,
|
||||
),
|
||||
'fields' => array('id', 'event_id', 'category', 'type', 'value'),
|
||||
'recursive' => -1,
|
||||
));
|
||||
$results = array('untouched' => count($oldAttributes), 'created' => 0, 'deleted' => 0, 'createdFail' => 0, 'deletedFail' => 0);
|
||||
|
||||
foreach ($newValues as &$value) {
|
||||
$value = trim($value);
|
||||
$found = false;
|
||||
foreach ($oldAttributes as &$old) {
|
||||
if ($value == $old['Attribute']['value']) {
|
||||
$found = true;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
$attribute = array(
|
||||
'value' => $value,
|
||||
'event_id' => $id,
|
||||
'category' => $category,
|
||||
'type' => $type,
|
||||
'distribution' => $event['Event']['distribution'],
|
||||
'to_ids' => $to_ids,
|
||||
);
|
||||
$this->Attribute->create();
|
||||
if ($this->Attribute->save(array('Attribute' => $attribute))) {
|
||||
$results['created']++;
|
||||
} else {
|
||||
$results['createdFail']++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($oldAttributes as &$old) {
|
||||
if (!in_array($old['Attribute']['value'], $newValues)) {
|
||||
if ($this->Attribute->delete($old['Attribute']['id'])) {
|
||||
$results['deleted']++;
|
||||
$results['untouched']--;
|
||||
} else {
|
||||
$results['deletedFail']++;
|
||||
}
|
||||
}
|
||||
}
|
||||
$message = '';
|
||||
$success = true;
|
||||
if (($results['created'] > 0 || $results['deleted'] > 0) && $results['createdFail'] == 0 && $results['deletedFail'] == 0) {
|
||||
$message .= 'Update completed without any issues.';
|
||||
} else {
|
||||
$message .= 'Update completed with some errors.';
|
||||
$success = false;
|
||||
}
|
||||
|
||||
if ($results['created']) $message .= $results['created'] . ' attribute' . $this->__checkCountForOne($results['created']) . ' created. ';
|
||||
if ($results['createdFail']) $message .= $results['createdFail'] . ' attribute' . $this->__checkCountForOne($results['createdFail']) . ' could not be created. ';
|
||||
if ($results['deleted']) $message .= $results['deleted'] . ' attribute' . $this->__checkCountForOne($results['deleted']) . ' deleted.';
|
||||
if ($results['deletedFail']) $message .= $results['deletedFail'] . ' attribute' . $this->__checkCountForOne($results['deletedFail']) . ' could not be deleted. ';
|
||||
$message .= $results['untouched'] . ' attributes left untouched. ';
|
||||
|
||||
$this->autoRender = false;
|
||||
$this->layout = 'ajax';
|
||||
if ($success) return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $message)),'status'=>200));
|
||||
else return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'errors' => $message)),'status'=>200));
|
||||
}
|
||||
}
|
||||
|
||||
private function __checkCountForOne($number) {
|
||||
if ($number != 1) return 's';
|
||||
return '';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2332,7 +2332,6 @@ class EventsController extends AppController {
|
|||
$this->set('defaultCategories', $defaultCategories);
|
||||
$this->set('typeCategoryMapping', $typeCategoryMapping);
|
||||
$this->set('resultArray', $resultArray);
|
||||
//$this->autoRender = false;
|
||||
$this->render('free_text_results');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -970,6 +970,7 @@ class Attribute extends AppModel {
|
|||
'Attribute.type !=' => 'comment',
|
||||
)),
|
||||
'recursive' => 0,
|
||||
//'contain' => 'Event',
|
||||
//'fields' => '', // we want to have the Attribute AND Event, so do not filter here
|
||||
);
|
||||
// search for the related attributes for that "value(1|2)"
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
<div class="attribute_replace">
|
||||
<?php
|
||||
echo $this->Form->create('Attribute', array('id'));
|
||||
?>
|
||||
<fieldset>
|
||||
<legend><?php echo __('Attribute Replace Tool'); ?></legend>
|
||||
<div class="add_attribute_fields">
|
||||
<p>Choose a category and a type, then paste a list of IOCs that match the selection into the field below. This will delete all of the attributes not found in the new inserted list, whilst creating the attributes that are in the new list but don't exist as attributes. Found matches will be left untouched.</p>
|
||||
<?php
|
||||
echo $this->Form->hidden('event_id');
|
||||
echo $this->Form->input('category', array(
|
||||
'empty' => '(choose one)'
|
||||
));
|
||||
echo $this->Form->input('type', array(
|
||||
'empty' => '(first choose category)'
|
||||
));
|
||||
echo $this->Form->input('to_ids', array(
|
||||
'type' => 'checkbox',
|
||||
'label' => 'Mark all new attributes as to IDS',
|
||||
));
|
||||
echo $this->Form->input('value', array(
|
||||
'type' => 'textarea',
|
||||
'error' => array('escape' => false),
|
||||
'div' => 'input clear',
|
||||
'class' => 'input-xxlarge',
|
||||
'label' => 'Values'
|
||||
));
|
||||
$this->Js->get('#AttributeCategory')->event('change', 'formCategoryChanged("#AttributeCategory")');
|
||||
?>
|
||||
<div class="input clear"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<p style="color:red;font-weight:bold;display:none;" id="warning-message">Warning: You are about to share data that is of a classified nature (Attribution / targeting data). Make sure that you are authorised to share this.</p>
|
||||
<div class="overlay_spacing">
|
||||
<table>
|
||||
<tr>
|
||||
<td style="vertical-align:top">
|
||||
<span id="submitButton" class="btn btn-primary" onClick="submitPopoverForm('<?php echo $event_id;?>', 'replaceAttributes')">Submit</span>
|
||||
</td>
|
||||
<td style="width:540px;">
|
||||
<p style="color:red;font-weight:bold;display:none;text-align:center" id="warning-message">Warning: You are about to share data that is of a classified nature (Attribution / targeting data). Make sure that you are authorised to share this.</p>
|
||||
</td>
|
||||
<td style="vertical-align:top;">
|
||||
<span class="btn btn-inverse" id="cancel_attribute_add">Cancel</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->Form->end();
|
||||
?>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
//
|
||||
//Generate Category / Type filtering array
|
||||
//
|
||||
var category_type_mapping = new Array();
|
||||
<?php
|
||||
foreach ($categoryDefinitions as $category => $def) {
|
||||
echo "category_type_mapping['" . addslashes($category) . "'] = {";
|
||||
$first = true;
|
||||
foreach ($def['types'] as $type) {
|
||||
if ($first) $first = false;
|
||||
else echo ', ';
|
||||
echo "'" . addslashes($type) . "' : '" . addslashes($type) . "'";
|
||||
}
|
||||
echo "}; \n";
|
||||
}
|
||||
?>
|
||||
|
||||
function formCategoryChanged(id) {
|
||||
// fill in the types
|
||||
var options = $('#AttributeType').prop('options');
|
||||
$('option', $('#AttributeType')).remove();
|
||||
$.each(category_type_mapping[$('#AttributeCategory').val()], function(val, text) {
|
||||
options[options.length] = new Option(text, val);
|
||||
});
|
||||
// enable the form element
|
||||
$('#AttributeType').prop('disabled', false);
|
||||
}
|
||||
//
|
||||
//Generate tooltip information
|
||||
//
|
||||
var formInfoValues = new Array();
|
||||
var fieldsArray = new Array('AttributeCategory', 'AttributeType');
|
||||
<?php
|
||||
foreach ($typeDefinitions as $type => $def) {
|
||||
$info = isset($def['formdesc']) ? $def['formdesc'] : $def['desc'];
|
||||
echo "formInfoValues['" . addslashes($type) . "'] = \"" . addslashes($info) . "\";\n"; // as we output JS code we need to add slashes
|
||||
}
|
||||
foreach ($categoryDefinitions as $category => $def) {
|
||||
$info = isset($def['formdesc']) ? $def['formdesc'] : $def['desc'];
|
||||
echo "formInfoValues['" . addslashes($category) . "'] = \"" . addslashes($info) . "\";\n"; // as we output JS code we need to add slashes
|
||||
}
|
||||
?>
|
||||
|
||||
$(document).ready(function() {
|
||||
$("#AttributeType, #AttributeCategory").on('mouseover', function(e) {
|
||||
var $e = $(e.target);
|
||||
if ($e.is('option')) {
|
||||
$('#'+e.currentTarget.id).popover('destroy');
|
||||
$('#'+e.currentTarget.id).popover({
|
||||
trigger: 'focus',
|
||||
placement: 'right',
|
||||
container: 'body',
|
||||
content: formInfoValues[$e.val()],
|
||||
}).popover('show');
|
||||
}
|
||||
});
|
||||
|
||||
$("input, label").on('mouseleave', function(e) {
|
||||
$('#'+e.currentTarget.id).popover('destroy');
|
||||
});
|
||||
|
||||
$("input, label").on('mouseover', function(e) {
|
||||
var $e = $(e.target);
|
||||
$('#'+e.currentTarget.id).popover('destroy');
|
||||
$('#'+e.currentTarget.id).popover({
|
||||
trigger: 'focus',
|
||||
placement: 'right',
|
||||
container: 'body',
|
||||
}).popover('show');
|
||||
});
|
||||
|
||||
// workaround for browsers like IE and Chrome that do now have an onmouseover on the 'options' of a select.
|
||||
// disadvangate is that user needs to click on the item to see the tooltip.
|
||||
// no solutions exist, except to generate the select completely using html.
|
||||
$("#AttributeType, #AttributeCategory").on('change', function(e) {
|
||||
if (this.id === "AttributeCategory") {
|
||||
var select = document.getElementById("AttributeCategory");
|
||||
if (select.value === 'Attribution' || select.value === 'Targeting data') {
|
||||
$("#warning-message").show();
|
||||
} else {
|
||||
$("#warning-message").hide();
|
||||
}
|
||||
}
|
||||
var $e = $(e.target);
|
||||
$('#'+e.currentTarget.id).popover('destroy');
|
||||
$('#'+e.currentTarget.id).popover({
|
||||
trigger: 'focus',
|
||||
placement: 'right',
|
||||
container: 'body',
|
||||
content: formInfoValues[$e.val()],
|
||||
}).popover('show');
|
||||
});
|
||||
|
||||
$('#cancel_attribute_add').click(function() {
|
||||
cancelPopoverForm();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php echo $this->Js->writeBuffer(); // Write cached scripts
|
|
@ -65,6 +65,7 @@
|
|||
<div class="tabMenu tabMenuToolsBlock noPrint">
|
||||
<span id="create-button" title="Populate using a template" class="icon-list-alt useCursorPointer" onClick="getPopup(<?php echo $event['Event']['id']; ?>, 'templates', 'templateChoices');"></span>
|
||||
<span id="freetext-button" title="Populate using the freetext import tool" class="icon-exclamation-sign useCursorPointer" onClick="getPopup(<?php echo $event['Event']['id']; ?>, 'events', 'freeTextImport');"></span>
|
||||
<span id="attribute-replace-button" title="Replace all attributes of a category/type combination within the event" class="icon-random useCursorPointer" onClick="getPopup(<?php echo $event['Event']['id']; ?>, 'attributes', 'attributeReplace');"></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<table class="table table-striped table-condensed">
|
||||
|
|
|
@ -128,9 +128,13 @@ if ($object['objectType'] == 1) {
|
|||
</div>
|
||||
</td>
|
||||
<td class="<?php echo $extra; ?> shortish">
|
||||
<?php
|
||||
$turnRed = '';
|
||||
if ($object['objectType'] == 0 && $object['distribution'] == 0) $turnRed = 'style="color:red"';
|
||||
?>
|
||||
<div id = "<?php echo $currentType . '_' . $object['id'] . '_distribution_placeholder'; ?>" class = "inline-field-placeholder"></div>
|
||||
<div id = "<?php echo $currentType . '_' . $object['id'] . '_distribution_solid'; ?>" class="inline-field-solid" onClick="activateField('<?php echo $currentType; ?>', '<?php echo $object['id']; ?>', 'distribution', <?php echo $event['Event']['id'];?>);">
|
||||
<?php if ($object['objectType'] != 1 && $object['objectType'] != 2) echo h($distributionLevels[$object['distribution']]); ?>
|
||||
<div id = "<?php echo $currentType . '_' . $object['id'] . '_distribution_solid'; ?>" <?php echo $turnRed; ?> class="inline-field-solid" onClick="activateField('<?php echo $currentType; ?>', '<?php echo $object['id']; ?>', 'distribution', <?php echo $event['Event']['id'];?>);">
|
||||
<?php if ($object['objectType'] == 0) echo h($distributionLevels[$object['distribution']]); ?>
|
||||
</div>
|
||||
</td>
|
||||
<td class="short action-links <?php echo $extra;?>">
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
if ($menuItem === 'addAttribute' ||
|
||||
$menuItem === 'addAttachment' ||
|
||||
$menuItem === 'addIOC' ||
|
||||
$menuItem === 'addThreatConnect'
|
||||
$menuItem === 'addThreatConnect' ||
|
||||
$menuItem === 'populateFromtemplate'
|
||||
) {
|
||||
// we can safely assume that mayModify is true if comming from these actions, as they require it in the controller and the user has already passed that check
|
||||
$mayModify = true;
|
||||
|
@ -23,6 +24,9 @@
|
|||
<li <?php if ($menuItem === 'addAttachment') echo 'class="active"';;?>><a href="/attributes/add_attachment/<?php echo $event['Event']['id'];?>">Add Attachment</a></li>
|
||||
<li <?php if ($menuItem === 'addIOC') echo 'class="active"';?>><a href="/events/addIOC/<?php echo $event['Event']['id'];?>">Populate from OpenIOC</a></li>
|
||||
<li <?php if ($menuItem === 'addThreatConnect') echo 'class="active"';?>><a href="/attributes/add_threatconnect/<?php echo $event['Event']['id']; ?>">Populate from ThreatConnect</a></li>
|
||||
<?php if ($menuItem === 'populateFromtemplate'): ?>
|
||||
<li class="active"><a href="/templates/populateEventFromTemplate/<?php echo $template_id . '/' . $event['Event']['id']; ?>">Populate From Template</a></li>
|
||||
<?php endif; ?>
|
||||
<?php elseif (!isset($mayModify) || !$mayModify): ?>
|
||||
<li class="divider"></li>
|
||||
<li <?php if ($menuItem === 'proposeAttribute') echo 'class="active"';?>><a href="/shadow_attributes/add/<?php echo $event['Event']['id'];?>">Propose Attribute</a></li>
|
||||
|
|
|
@ -27,7 +27,7 @@ echo $this->Form->create('Attribute', array('id'));
|
|||
<button id="submitButton" class="btn btn-primary">Submit</button>
|
||||
</td>
|
||||
<td style="width:540px;">
|
||||
<p style="color:red;font-weight:bold;display:none;text-align:center" id="warning-message">Warning: You are about to share data that is of a classified nature (Attribution / targeting data). Make sure that you are authorised to share this.</p>
|
||||
<p style="color:red;font-weight:bold;display:none;text-align:center" id="warning-message"></p>
|
||||
</td>
|
||||
<td style="vertical-align:top;">
|
||||
<span class="btn btn-inverse" id="cancel_attribute_add">Cancel</span>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
echo $this->Form->input('Attribute.' . $k . '.value', array(
|
||||
'label' => false,
|
||||
'type' => 'hidden',
|
||||
'value' => $item['value'],
|
||||
'value' => h($item['value']),
|
||||
));
|
||||
?>
|
||||
<td><?php echo h($item['value']); ?></td>
|
||||
|
|
|
@ -102,11 +102,19 @@ $mayPublish = ($isAclPublish && $event['Event']['orgc'] == $me['org']);
|
|||
<?php echo nl2br(h($event['Event']['info'])); ?>
|
||||
|
||||
</dd>
|
||||
<?php if ($isAclPublish && $event['Event']['published'] == 0) :?>
|
||||
<dt class="visibleDL">Published</dt>
|
||||
<dd class="visibleDL">
|
||||
<?php echo ($event['Event']['published'] == 1 ? 'Yes' : 'No'); ?>
|
||||
|
||||
</dd>
|
||||
<?php else: ?>
|
||||
<dt>Published</dt>
|
||||
<dd style="color: red;">
|
||||
<dd style="color: <?php echo ($event['Event']['published'] == 1 ? 'green' : 'red'); ?>">
|
||||
<b><?php echo ($event['Event']['published'] == 1 ? 'Yes' : 'No'); ?></b>
|
||||
|
||||
</dd>
|
||||
<?php endif; ?>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -22,6 +22,9 @@ echo $this->Form->button('Add', array('class' => 'btn btn-primary'));
|
|||
echo $this->Form->end();
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('side_menu', array('menuList' => 'event', 'menuItem' => 'populateFromtemplate', 'event' => array('Event' => array('id' => $event_id)), 'template_id' => $template_id));
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
<?php if (isset($fileArray)): ?>
|
||||
|
|
|
@ -1207,6 +1207,16 @@ a.proposal_link_red:hover {
|
|||
padding: 10px;
|
||||
}
|
||||
|
||||
.visibleDL {
|
||||
background-color: red !important;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: red;
|
||||
}
|
||||
|
||||
@-webkit-keyframes rotation {
|
||||
from {-webkit-transform: rotate(0deg);}
|
||||
to {-webkit-transform: rotate(359deg);}
|
||||
|
|
|
@ -422,6 +422,9 @@ function submitPopoverForm(context_id, referer, update_context_id) {
|
|||
context_id = update_context_id;
|
||||
contextNamingConvention = 'TemplateElementFile';
|
||||
break;
|
||||
case 'replaceAttributes':
|
||||
url = "/attributes/attributeReplace/" + context_id;
|
||||
break;
|
||||
}
|
||||
|
||||
if (url !== null) {
|
||||
|
|
Loading…
Reference in New Issue