mirror of https://github.com/MISP/MISP
482 lines
21 KiB
PHP
482 lines
21 KiB
PHP
<?php
|
|
|
|
App::uses('AppController', 'Controller');
|
|
App::uses('Folder', 'Utility');
|
|
App::uses('File', 'Utility');
|
|
|
|
class TemplatesController extends AppController
|
|
{
|
|
public $components = array('Security' ,'RequestHandler');
|
|
|
|
public $paginate = array(
|
|
'limit' => 50,
|
|
'order' => array(
|
|
'Template.id' => 'desc'
|
|
)
|
|
);
|
|
|
|
public function beforeFilter()
|
|
{ // TODO REMOVE
|
|
parent::beforeFilter();
|
|
$this->Security->unlockedActions = array('uploadFile', 'deleteTemporaryFile');
|
|
}
|
|
|
|
public function index()
|
|
{
|
|
$conditions = array();
|
|
if (!$this->_isSiteAdmin()) {
|
|
$conditions['OR'] = array('org' => $this->Auth->user('Organisation')['name'], 'share' => 1);
|
|
}
|
|
if (!$this->_isSiteAdmin()) {
|
|
$this->paginate = Set::merge($this->paginate, array(
|
|
'conditions' =>
|
|
array("OR" => array(
|
|
array('org' => $this->Auth->user('Organisation')['name']),
|
|
array('share' => 1),
|
|
))));
|
|
}
|
|
$this->set('list', $this->paginate());
|
|
}
|
|
|
|
public function edit($id)
|
|
{
|
|
$template = $this->Template->checkAuthorisation($id, $this->Auth->user(), true);
|
|
if (!$this->_isSiteAdmin() && !$template) {
|
|
throw new MethodNotAllowedException('No template with the provided ID exists, or you are not authorised to edit it.');
|
|
}
|
|
$this->set('mayModify', true);
|
|
|
|
if ($this->request->is('post') || $this->request->is('put')) {
|
|
$this->request->data['Template']['id'] = $id;
|
|
unset($this->request->data['Template']['tagsPusher']);
|
|
$tags = $this->request->data['Template']['tags'];
|
|
unset($this->request->data['Template']['tags']);
|
|
$this->request->data['Template']['org'] = $this->Auth->user('Organisation')['name'];
|
|
$this->Template->create();
|
|
if ($this->Template->save($this->request->data)) {
|
|
$id = $this->Template->id;
|
|
$tagArray = json_decode($tags);
|
|
$this->loadModel('TemplateTag');
|
|
$oldTags = $this->TemplateTag->find('all', array(
|
|
'conditions' => array('template_id' => $id),
|
|
'recursive' => -1,
|
|
'contain' => 'Tag'
|
|
));
|
|
|
|
$newTags = $this->TemplateTag->Tag->find('all', array(
|
|
'recursive' => -1,
|
|
'conditions' => array('id' => $tagArray)
|
|
));
|
|
|
|
foreach ($oldTags as $k => $oT) {
|
|
if (!in_array($oT['Tag'], $newTags)) {
|
|
$this->TemplateTag->delete($oT['TemplateTag']['id']);
|
|
}
|
|
}
|
|
|
|
foreach ($newTags as $k => $nT) {
|
|
if (!in_array($nT['Tag'], $oldTags)) {
|
|
$this->TemplateTag->create();
|
|
$this->TemplateTag->save(array('TemplateTag' => array('template_id' => $id, 'tag_id' => $nT['Tag']['id'])));
|
|
}
|
|
}
|
|
$this->redirect(array('action' => 'view', $this->Template->id));
|
|
} else {
|
|
throw new Exception('The template could not be edited.');
|
|
}
|
|
}
|
|
$this->request->data = $template;
|
|
|
|
// get all existing tags for the tag add dropdown menu
|
|
$this->loadModel('Tags');
|
|
$tags = $this->Tags->find('all');
|
|
$tagArray = array();
|
|
foreach ($tags as $tag) {
|
|
$tagArray[$tag['Tags']['id']] = $tag['Tags']['name'];
|
|
}
|
|
|
|
//get all tags currently assigned to the event
|
|
$currentTags = $this->Template->TemplateTag->find('all', array(
|
|
'recursive' => -1,
|
|
'contain' => 'Tag',
|
|
'conditions' => array('template_id' => $id),
|
|
));
|
|
$this->set('currentTags', $currentTags);
|
|
$this->set('id', $id);
|
|
$this->set('template', $template);
|
|
$this->set('tags', $tagArray);
|
|
$this->set('tagInfo', $tags);
|
|
}
|
|
|
|
public function view($id)
|
|
{
|
|
if (!$this->_isSiteAdmin() && !$this->Template->checkAuthorisation($id, $this->Auth->user(), false)) {
|
|
throw new MethodNotAllowedException('No template with the provided ID exists, or you are not authorised to see it.');
|
|
}
|
|
if ($this->Template->checkAuthorisation($id, $this->Auth->user(), true)) {
|
|
$this->set('mayModify', true);
|
|
} else {
|
|
$this->set('mayModify', false);
|
|
}
|
|
$template = $this->Template->find('first', array(
|
|
'conditions' => array(
|
|
'id' => $id,
|
|
),
|
|
'contain' => array(
|
|
'TemplateElement',
|
|
'TemplateTag' => array(
|
|
'Tag',
|
|
),
|
|
),
|
|
));
|
|
if (empty($template)) {
|
|
throw new NotFoundException('No template with the provided ID exists, or you are not authorised to see it.');
|
|
}
|
|
$tagArray = array();
|
|
foreach ($template['TemplateTag'] as $tt) {
|
|
$tagArray[] = $tt;
|
|
}
|
|
$this->set('id', $id);
|
|
$this->set('template', $template);
|
|
}
|
|
|
|
public function add()
|
|
{
|
|
if (!$this->userRole['perm_template']) {
|
|
throw new MethodNotAllowedException('You are not authorised to do that.');
|
|
}
|
|
if ($this->request->is('post')) {
|
|
unset($this->request->data['Template']['tagsPusher']);
|
|
$tags = $this->request->data['Template']['tags'];
|
|
unset($this->request->data['Template']['tags']);
|
|
$this->request->data['Template']['org'] = $this->Auth->user('Organisation')['name'];
|
|
$this->Template->create();
|
|
if ($this->Template->save($this->request->data)) {
|
|
$id = $this->Template->id;
|
|
$tagArray = json_decode($tags);
|
|
$this->loadModel('TemplateTag');
|
|
$this->loadModel('Tag');
|
|
foreach ($tagArray as $t) {
|
|
$tag = $this->Tag->find('first', array(
|
|
'conditions' => array('id' => $t),
|
|
'fields' => array('id', 'name'),
|
|
'recursive' => -1,
|
|
));
|
|
$this->TemplateTag->create();
|
|
$this->TemplateTag->save(array('TemplateTag' => array('template_id' => $id, 'tag_id' => $tag['Tag']['id'])));
|
|
}
|
|
$this->redirect(array('action' => 'view', $this->Template->id));
|
|
} else {
|
|
throw new Exception('The template could not be created.');
|
|
}
|
|
}
|
|
$this->loadModel('Tags');
|
|
$tags = $this->Tags->find('all');
|
|
$tagArray = array();
|
|
foreach ($tags as $tag) {
|
|
$tagArray[$tag['Tags']['id']] = $tag['Tags']['name'];
|
|
}
|
|
$this->set('tags', $tagArray);
|
|
$this->set('tagInfo', $tags);
|
|
}
|
|
|
|
public function saveElementSorting()
|
|
{
|
|
// check if user can edit the template
|
|
$this->autoRender = false;
|
|
$this->request->onlyAllow('ajax');
|
|
$orderedElements = $this->request->data;
|
|
foreach ($orderedElements as $key => $e) {
|
|
$orderedElements[$key] = ltrim($e, 'id_');
|
|
}
|
|
$extractedIds = array();
|
|
foreach ($orderedElements as $element) {
|
|
$extractedIds[] = $element;
|
|
}
|
|
$template_id = $this->Template->TemplateElement->find('first', array(
|
|
'conditions' => array('id' => $extractedIds),
|
|
'recursive' => -1,
|
|
'fields' => array('id', 'template_id'),
|
|
));
|
|
|
|
if (!$this->_isSiteAdmin() && !$this->Template->checkAuthorisation($template_id['TemplateElement']['template_id'], $this->Auth->user(), true)) {
|
|
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You are not authorised to do that.')), 'status' => 200, 'type' => 'json'));
|
|
}
|
|
|
|
$elements = $this->Template->TemplateElement->find('all', array(
|
|
'conditions' => array('template_id' => $template_id['TemplateElement']['template_id']),
|
|
'recursive' => -1,
|
|
));
|
|
if (empty($elements)) {
|
|
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Something went wrong, the supplied template elements don\'t exist, or you are not eligible to edit them.')),'status'=>200));
|
|
}
|
|
if (count($elements) != count($orderedElements)) {
|
|
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Incomplete template element list passed as argument. Expecting ' . count($elements) . ' elements, only received positions for ' . count($orderedElements) . '.')), 'status'=>200, 'type' => 'json'));
|
|
}
|
|
$template_id = $elements[0]['TemplateElement']['template_id'];
|
|
|
|
foreach ($elements as $key => $e) {
|
|
if ($template_id !== $e['TemplateElement']['template_id']) {
|
|
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Cannot sort template elements belonging to separate templates. You should never see this message during legitimate use.')), 'status'=>200, 'type' => 'json'));
|
|
}
|
|
foreach ($orderedElements as $k => $orderedElement) {
|
|
if ($orderedElement == $e['TemplateElement']['id']) {
|
|
$elements[$key]['TemplateElement']['position'] = $k+1;
|
|
}
|
|
}
|
|
}
|
|
$this->Template->TemplateElement->saveMany($elements);
|
|
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => 'Elements repositioned.')), 'status'=>200, 'type' => 'json'));
|
|
}
|
|
|
|
public function delete($id)
|
|
{
|
|
$template = $this->Template->checkAuthorisation($id, $this->Auth->user(), true);
|
|
if (!$this->request->is('post')) {
|
|
throw new MethodNotAllowedException('This action can only be invoked via a post request.');
|
|
}
|
|
if (!$this->_isSiteAdmin() && !$template) {
|
|
throw new MethodNotAllowedException('No template with the provided ID exists, or you are not authorised to edit it.');
|
|
}
|
|
if ($this->Template->delete($id, true)) {
|
|
$this->Flash->success('Template deleted.');
|
|
$this->redirect(array('action' => 'index'));
|
|
} else {
|
|
$this->Flash->error('The template could not be deleted.');
|
|
$this->redirect(array('action' => 'index'));
|
|
}
|
|
}
|
|
|
|
|
|
public function templateChoices($id)
|
|
{
|
|
$this->loadModel('Event');
|
|
$event = $this->Event->find('first', array(
|
|
'conditions' => array('id' => $id),
|
|
'recursive' => -1,
|
|
'fields' => array('orgc_id', 'id'),
|
|
));
|
|
if (empty($event) || (!$this->_isSiteAdmin() && $event['Event']['orgc_id'] != $this->Auth->user('org_id'))) {
|
|
throw new NotFoundException('Event not found or you are not authorised to edit it.');
|
|
}
|
|
|
|
$conditions = array();
|
|
if (!$this->_isSiteAdmin) {
|
|
$conditions['OR'] = array('Template.org' => $this->Auth->user('Organisation')['name'], 'Template.share' => 1);
|
|
}
|
|
$templates = $this->Template->find('all', array(
|
|
'recursive' => -1,
|
|
'conditions' => $conditions
|
|
));
|
|
$this->set('templates', $templates);
|
|
$this->set('id', $id);
|
|
$this->render('ajax/template_choices');
|
|
}
|
|
|
|
public function populateEventFromTemplate($template_id, $event_id)
|
|
{
|
|
$template = $this->Template->find('first', array(
|
|
'conditions' => array('Template.id' => $template_id),
|
|
'contain' => array(
|
|
'TemplateElement' => array(
|
|
'TemplateElementAttribute',
|
|
'TemplateElementText',
|
|
'TemplateElementFile'
|
|
),
|
|
'TemplateTag' => array(
|
|
'Tag'
|
|
)
|
|
),
|
|
));
|
|
$this->loadModel('Event');
|
|
$event = $this->Event->find('first', array(
|
|
'conditions' => array('id' => $event_id),
|
|
'recursive' => -1,
|
|
'fields' => array('id', 'orgc_id', 'distribution'),
|
|
));
|
|
$this->set('event', $event);
|
|
if (empty($event)) {
|
|
throw new MethodNotAllowedException('Event not found or you are not authorised to edit it.');
|
|
}
|
|
if (empty($template)) {
|
|
throw new MethodNotAllowedException('Template not found or you are not authorised to edit it.');
|
|
}
|
|
if (!$this->_isSiteAdmin()) {
|
|
if ($event['Event']['orgc_id'] != $this->Auth->user('org_id')) {
|
|
throw new MethodNotAllowedException('Event not found or you are not authorised to edit it.');
|
|
}
|
|
if ($template['Template']['org'] != $this->Auth->user('Organisation')['name'] && !$template['Template']['share']) {
|
|
throw new MethodNotAllowedException('Template not found or you are not authorised to use it.');
|
|
}
|
|
}
|
|
|
|
$this->set('template_id', $template_id);
|
|
$this->set('event_id', $event_id);
|
|
if ($this->request->is('post')) {
|
|
$this->set('template', $this->request->data);
|
|
$result = $this->Event->Attribute->checkTemplateAttributes($template, $this->request->data, $event_id);
|
|
if (isset($this->request->data['Template']['modify']) || !empty($result['errors'])) {
|
|
$fileArray = $this->request->data['Template']['fileArray'];
|
|
$this->set('fileArray', $fileArray);
|
|
$this->set('errors', $result['errors']);
|
|
$this->set('templateData', $template);
|
|
$this->set('validTypeGroups', $this->Event->Attribute->validTypeGroups);
|
|
} else {
|
|
$this->set('errors', $result['errors']);
|
|
$this->set('attributes', $result['attributes']);
|
|
$fileArray = $this->request->data['Template']['fileArray'];
|
|
$this->set('fileArray', $fileArray);
|
|
$this->set('distributionLevels', $this->Event->Attribute->distributionLevels);
|
|
$this->render('populate_event_from_template_attributes');
|
|
}
|
|
} else {
|
|
$this->set('templateData', $template);
|
|
$this->set('validTypeGroups', $this->Event->Attribute->validTypeGroups);
|
|
}
|
|
}
|
|
|
|
|
|
// called when the user is finished populating a template and is has finished reviewing the resulting attributes at the last stage of the process
|
|
public function submitEventPopulation($template_id, $event_id)
|
|
{
|
|
if ($this->request->is('post')) {
|
|
$this->loadModel('Event');
|
|
$event = $this->Event->find('first', array(
|
|
'conditions' => array('id' => $event_id),
|
|
'recursive' => -1,
|
|
'fields' => array('id', 'orgc_id', 'distribution', 'published'),
|
|
'contain' => 'EventTag',
|
|
));
|
|
if (empty($event)) {
|
|
throw new MethodNotAllowedException('Event not found or you are not authorised to edit it.');
|
|
}
|
|
if (!$this->_isSiteAdmin()) {
|
|
if ($event['Event']['orgc_id'] != $this->Auth->user('org_id')) {
|
|
throw new MethodNotAllowedException('Event not found or you are not authorised to edit it.');
|
|
}
|
|
}
|
|
|
|
$template = $this->Template->find('first', array(
|
|
'conditions' => array('Template.id' => $template_id),
|
|
'recursive' => -1,
|
|
'contain' => 'TemplateTag',
|
|
'fields' => 'id',
|
|
));
|
|
foreach ($template['TemplateTag'] as $tag) {
|
|
$exists = false;
|
|
foreach ($event['EventTag'] as $eventTag) {
|
|
if ($eventTag['tag_id'] == $tag['tag_id']) {
|
|
$exists = true;
|
|
}
|
|
}
|
|
if (!$exists) {
|
|
$this->Event->EventTag->create();
|
|
$this->Event->EventTag->save(array('event_id' => $event_id, 'tag_id' => $tag['tag_id']));
|
|
}
|
|
}
|
|
|
|
if (isset($this->request->data['Template']['attributes'])) {
|
|
$attributes = json_decode($this->request->data['Template']['attributes'], true);
|
|
$this->loadModel('Attribute');
|
|
$fails = 0;
|
|
foreach ($attributes as $k => $attribute) {
|
|
if (isset($attribute['data']) && $this->Template->checkFilename($attribute['data'])) {
|
|
$file = new File(APP . 'tmp/files/' . $attribute['data']);
|
|
$content = $file->read();
|
|
$attributes[$k]['data'] = base64_encode($content);
|
|
if ($this->Event->Attribute->typeIsMalware($attributes[$k]['type'])) {
|
|
$hashes = $this->Event->Attribute->handleMaliciousBase64($event_id, explode('|', $attributes[$k]['value'])[0], $attributes[$k]['data'], array('md5'));
|
|
$attributes[$k]['data'] = $hashes['data'];
|
|
}
|
|
$file->delete();
|
|
}
|
|
$this->Attribute->create();
|
|
if (!$this->Attribute->save(array('Attribute' => $attributes[$k]))) {
|
|
$fails++;
|
|
}
|
|
}
|
|
$count = isset($k) ? $k + 1 : 0;
|
|
$event = $this->Event->find('first', array(
|
|
'conditions' => array('Event.id' => $event_id),
|
|
'recursive' => -1
|
|
));
|
|
$event['Event']['published'] = 0;
|
|
$date = new DateTime();
|
|
$event['Event']['timestamp'] = $date->getTimestamp();
|
|
$this->Event->save($event);
|
|
if ($fails == 0) {
|
|
$this->Flash->success(__('Event populated, ' . $count . ' attributes successfully created.'));
|
|
} else {
|
|
$this->Flash->success(__('Event populated, but ' . $fails . ' attributes could not be saved.'));
|
|
}
|
|
$this->redirect(array('controller' => 'events', 'action' => 'view', $event_id));
|
|
} else {
|
|
throw new MethodNotAllowedException('No attributes submitted for creation.');
|
|
}
|
|
} else {
|
|
throw new MethodNotAllowedException();
|
|
}
|
|
}
|
|
|
|
public function uploadFile($elementId, $batch)
|
|
{
|
|
$this->layout = 'iframe';
|
|
$this->set('batch', $batch);
|
|
$this->set('element_id', $elementId);
|
|
if ($this->request->is('get')) {
|
|
$this->set('element_id', $elementId);
|
|
} elseif ($this->request->is('post')) {
|
|
$fileArray = array();
|
|
$filenames = array();
|
|
$added = 0;
|
|
$failed = 0;
|
|
// filename checks
|
|
foreach ($this->request->data['Template']['file'] as $k => $file) {
|
|
if ($file['size'] > 0 && $file['error'] == 0) {
|
|
if ($this->Template->checkFilename($file['name'])) {
|
|
$fn = $this->Template->generateRandomFileName();
|
|
move_uploaded_file($file['tmp_name'], APP . 'tmp/files/' . $fn);
|
|
$filenames[] = $file['name'];
|
|
$fileArray[] = array('filename' => $file['name'], 'tmp_name' => $fn, 'element_id' => $elementId);
|
|
$added++;
|
|
} else {
|
|
$failed++;
|
|
}
|
|
} else {
|
|
$failed ++;
|
|
}
|
|
}
|
|
$result = $added . ' files uploaded.';
|
|
if ($failed) {
|
|
$result .= ' ' . $failed . ' files either failed to upload, or were empty.';
|
|
$this->set('upload_error', true);
|
|
} else {
|
|
$this->set('upload_error', false);
|
|
}
|
|
$this->set('result', $result);
|
|
$this->set('filenames', $filenames);
|
|
$this->set('fileArray', json_encode($fileArray));
|
|
}
|
|
}
|
|
|
|
// deletes a temporary file created by the user while populating a template
|
|
// users can add files to attachment fields and when they change their mind about it, they can remove a file (deleting the temporary file)
|
|
// before it gets saved as an attribute and moved to the persistent attachment store
|
|
public function deleteTemporaryFile($filename)
|
|
{
|
|
if (!$this->request->is('post')) {
|
|
throw new MethodNotAllowedException('This action is restricted to accepting POST requests only.');
|
|
}
|
|
if (!$this->request->is('ajax')) {
|
|
throw new MethodNotAllowedException('This action is only accessible through AJAX.');
|
|
}
|
|
$this->autoRender = false;
|
|
if ($this->Template->checkFilename($filename)) {
|
|
$file = new File(APP . 'tmp/files/' . $filename);
|
|
if ($file->exists()) {
|
|
$file->delete();
|
|
}
|
|
}
|
|
}
|
|
}
|