MISP/app/Controller/TemplatesController.php

432 lines
17 KiB
PHP

<?php
App::uses('AppController', 'Controller');
App::uses('Folder', 'Utility');
App::uses('File', 'Utility');
/**
* Templates Controller
*
* @property Template $Templates
*/
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' => true);
}
if (!$this->_isSiteAdmin()) {
$this->paginate = Set::merge($this->paginate,array(
'conditions' =>
array("OR" => array(
array('org' => $this->Auth->user('Organisation')['name']),
array('share' => true),
))));
}
$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('name' => $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('name' => $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 &$e) {
$e = 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));
$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));
$template_id = $elements[0]['TemplateElement']['template_id'];
foreach ($elements as &$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));
foreach ($orderedElements as $k => $orderedElement) {
if ($orderedElement == $e['TemplateElement']['id']) {
$e['TemplateElement']['position'] = $k+1;
}
}
}
$this->Template->TemplateElement->saveMany($elements);
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => 'Elements repositioned.')),'status'=>200));
}
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->Session->setFlash('Template deleted.');
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash('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'),
));
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' => true);
}
$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', 'distribution'),
));
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'] != $this->Auth->user('Organisation')['name']) 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')) {
$errors = array();
$this->set('template', $this->request->data);
$result = $this->Event->Attribute->checkTemplateAttributes($template, $this->request->data, $event_id, $event['Event']['distribution']);
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->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', '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(
'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']) && preg_match('/^[a-zA-Z0-9]{12}$/', $attribute['data'])) {
$file = new File(APP . 'tmp/files/' . $attribute['data']);
$content = $file->read();
$attribute['data'] = base64_encode($content);
$file->delete();
}
$this->Attribute->create();
if (!$this->Attribute->save(array('Attribute' => $attribute))) $fails++;
}
$count = $k + 1;
$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->Session->setFlash(__('Event populated, ' . $count . ' attributes successfully created.'));
else $this->Session->setFlash(__('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);
} else if ($this->request->is('post')) {
$fileArray = array();
$filenames = array();
$tmp_names = array();
$element_ids = array();
$result = array();
$added = 0;
$failed = 0;
// filename checks
foreach ($this->request->data['Template']['file'] as $k => $file) {
if ($file['size'] > 0 && $file['error'] == 0) {
if (preg_match('@^[\w\-. ]+$@', $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));
}
}
private function __combineArrays($array, $array2) {
foreach ($array2 as $element) {
if (!in_array($element, $array)) {
$array[] = $element;
}
}
return $array;
}
// 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 (preg_match('/^[a-zA-Z0-9]{12}$/', $filename)) {
$file = new File(APP . 'tmp/files/' . $filename);
if ($file->exists()) {
$file->delete();
}
}
}
}