diff --git a/.gitignore b/.gitignore
index d6ce1a071..10d43b40d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,5 @@
/app/tmp/cache/views/myapp*
/app/files/*
/app/webroot/img/logo.png
+/app/Config/bootstrap.php
+/app/Config/database.php
diff --git a/app/Config/Schema/db_group.php b/app/Config/Schema/db_group.php
new file mode 100755
index 000000000..7457d55eb
--- /dev/null
+++ b/app/Config/Schema/db_group.php
@@ -0,0 +1,45 @@
+create();
+// $groups->save(array('Group' => array('name' => 'malware analyst', 'perm_add' => true, 'perm_modify' => true, 'perm_publish' => false, 'perm_full' => false)));
+// $groups->create();
+// $groups->save(array('Group' => array('name' => 'admin', 'perm_add' => true, 'perm_modify' => true, 'perm_publish' => true, 'perm_full' => true)));
+// $groups->create();
+// $groups->save(array('Group' => array('name' => 'IDS analyst', 'perm_add' => true, 'perm_modify' => true, 'perm_publish' => true, 'perm_full' => false)));
+// $groups->create();
+// $groups->save(array('Group' => array('name' => 'guest', 'perm_add' => false, 'perm_modify' => false, 'perm_publish' => false, 'perm_full' => false)));
+ // populate Users.group_id
+// $users = ClassRegistry::init('User');
+// $user = $users->read(null, '1');
+// $users->saveField('group_id', '2'); // $user['User']['group_id'] = '2';
+ break;
+ }
+ }
+ }
+
+ public $groups = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'name' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 100, 'collate' => 'latin1_swedish_ci', 'charset' => 'latin1'),
+ 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'perm_add' => array('type' => 'boolean', 'null' => true, 'default' => NULL),
+ 'perm_modify' => array('type' => 'boolean', 'null' => true, 'default' => NULL),
+ 'perm_publish' => array('type' => 'boolean', 'null' => true, 'default' => NULL),
+ 'perm_full' => array('type' => 'boolean', 'null' => true, 'default' => NULL),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
+ 'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'InnoDB')
+ );
+}
diff --git a/app/Config/Schema/db_group.sql b/app/Config/Schema/db_group.sql
new file mode 100755
index 000000000..87c3107c8
--- /dev/null
+++ b/app/Config/Schema/db_group.sql
@@ -0,0 +1,31 @@
+-- ACL, group table
+-- works in conjunction with: CakePHP AclComponent
+
+CREATE TABLE groups (
+ id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(100) NOT NULL,
+ perm_add boolean,
+ perm_modify boolean,
+ perm_publish boolean,
+ perm_full boolean,
+ created DATETIME,
+ modified DATETIME
+);
+
+-- ALTER TABLE users ADD COLUMN group_id INT(11);
+
+-- data of Groups
+-- INSERT INTO groups (name,perm_add,perm_modify,perm_publish,perm_full) VALUES ('malware analyst',true,true,false,false);
+-- INSERT INTO groups (name,perm_add,perm_modify,perm_publish,perm_full) VALUES ('admin',true,true,true,true);
+-- INSERT INTO groups (name,perm_add,perm_modify,perm_publish,perm_full) VALUES ('IDS analyst',true,true,true,false);
+-- INSERT INTO groups (name,perm_add,perm_modify,perm_publish,perm_full) VALUES ('guest',false,false,false,false);
+
+-- CakePHP AclComponent acor & aros tables
+
+-- aros table (should be auto generated on group create)
+-- INSERT INTO aros (model,foreign_key,lft,rght) VALUES ('Group',1,1,2);
+-- INSERT INTO aros (model,foreign_key,lft,rght) VALUES ('Group',2,3,4);
+-- INSERT INTO aros (model,foreign_key,lft,rght) VALUES ('Group',3,5,6);
+-- INSERT INTO aros (model,foreign_key,lft,rght) VALUES ('Group',4,7,8);
+
+-- aros_acos
diff --git a/app/Config/Schema/db_log.php b/app/Config/Schema/db_log.php
new file mode 100755
index 000000000..a35e515a2
--- /dev/null
+++ b/app/Config/Schema/db_log.php
@@ -0,0 +1,28 @@
+ array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'title' => array('type' => 'string', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'model' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 20, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'model_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
+ 'action' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 20, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'user_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
+ 'change' => array('type' => 'string', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'email' => array('type' => 'string', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'org' => array('type' => 'string', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'description' => array('type' => 'string', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_bin', 'engine' => 'MyISAM')
+ );
+}
diff --git a/app/Config/Schema/db_log.sql b/app/Config/Schema/db_log.sql
new file mode 100755
index 000000000..226717d72
--- /dev/null
+++ b/app/Config/Schema/db_log.sql
@@ -0,0 +1,21 @@
+-- Audit, log table
+-- works in conjunction with:
+-- https://github.com/alkemann/CakePHP-Assets/wiki
+-- also described at:
+-- http://bakery.cakephp.org/articles/alkemann/2008/10/21/logablebehavior
+
+DROP TABLE logs;
+CREATE TABLE logs (
+ id int(11) NOT NULL AUTO_INCREMENT,
+ title varchar(255),
+ created DATETIME,
+ description varchar(255),
+ model varchar(20),
+ model_id int(11),
+ action varchar(20),
+ user_id int(11),
+ `change` varchar(255),
+ email varchar(255),
+ org varchar(255) COLLATE utf8_bin,
+ PRIMARY KEY (id)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=2 ;
\ No newline at end of file
diff --git a/app/Config/Schema/schema_0.2.2.1.php b/app/Config/Schema/schema_0.2.2.1.php
new file mode 100755
index 000000000..bc532f04e
--- /dev/null
+++ b/app/Config/Schema/schema_0.2.2.1.php
@@ -0,0 +1,81 @@
+ array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'event_id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'index'),
+ 'type' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 100, 'collate' => 'utf8_unicode_ci', 'charset' => 'utf8'),
+ 'category' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'value1' => array('type' => 'text', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'to_ids' => array('type' => 'boolean', 'null' => false, 'default' => '1'),
+ 'uuid' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 40, 'key' => 'index', 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'revision' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => 10),
+ 'private' => array('type' => 'boolean', 'null' => false, 'default' => NULL),
+ 'value2' => array('type' => 'text', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'event_id' => array('column' => 'event_id', 'unique' => 0), 'uuid' => array('column' => 'uuid', 'unique' => 0)),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_bin', 'engine' => 'MyISAM')
+ );
+ public $bruteforces = array(
+ 'ip' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'username' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'expire' => array('type' => 'datetime', 'null' => false, 'default' => NULL),
+ 'indexes' => array(),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_bin', 'engine' => 'MyISAM')
+ );
+ public $events = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'org' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'date' => array('type' => 'date', 'null' => false, 'default' => NULL),
+ 'info' => array('type' => 'text', 'null' => false, 'default' => NULL, 'key' => 'index', 'collate' => 'utf8_unicode_ci', 'charset' => 'utf8'),
+ 'user_id' => array('type' => 'integer', 'null' => false, 'default' => NULL),
+ 'alerted' => array('type' => 'boolean', 'null' => false, 'default' => '0'),
+ 'uuid' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 40, 'key' => 'index', 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'private' => array('type' => 'boolean', 'null' => false, 'default' => NULL),
+ 'published' => array('type' => 'boolean', 'null' => false, 'default' => '0'),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'uuid' => array('column' => 'uuid', 'unique' => 0), 'info' => array('column' => 'info', 'unique' => 0)),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_bin', 'engine' => 'MyISAM')
+ );
+ public $servers = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'url' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'authkey' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 40, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'org' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'push' => array('type' => 'boolean', 'null' => false, 'default' => NULL),
+ 'pull' => array('type' => 'boolean', 'null' => false, 'default' => NULL),
+ 'lastfetchedid' => array('type' => 'integer', 'null' => false, 'default' => NULL),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_bin', 'engine' => 'MyISAM')
+ );
+ public $users = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'password' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 40, 'key' => 'index', 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'org' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'email' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'autoalert' => array('type' => 'boolean', 'null' => false, 'default' => NULL),
+ 'authkey' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 40, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'invited_by' => array('type' => 'integer', 'null' => false, 'default' => NULL),
+ 'gpgkey' => array('type' => 'text', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'nids_sid' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'length' => 15),
+ 'termsaccepted' => array('type' => 'boolean', 'null' => false, 'default' => NULL),
+ 'newsread' => array('type' => 'date', 'null' => false, 'default' => NULL),
+ 'group_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'username' => array('column' => 'password', 'unique' => 0)),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_bin', 'engine' => 'MyISAM')
+ );
+}
diff --git a/app/Config/Schema/schema_0.2.2.php b/app/Config/Schema/schema_0.2.2.php
index f08502ab9..0674df73e 100644
--- a/app/Config/Schema/schema_0.2.2.php
+++ b/app/Config/Schema/schema_0.2.2.php
@@ -1,6 +1,8 @@
- array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'event_id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'index'),
+ 'type' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 100, 'collate' => 'utf8_unicode_ci', 'charset' => 'utf8'),
+ 'category' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'value1' => array('type' => 'text', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'to_ids' => array('type' => 'boolean', 'null' => false, 'default' => '1'),
+ 'uuid' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 40, 'key' => 'index', 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'revision' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => 10),
+ 'private' => array('type' => 'boolean', 'null' => false, 'default' => NULL),
+ 'value2' => array('type' => 'text', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'event_id' => array('column' => 'event_id', 'unique' => 0), 'uuid' => array('column' => 'uuid', 'unique' => 0)),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_bin', 'engine' => 'MyISAM')
+ );
+ public $bruteforces = array(
+ 'ip' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'username' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'expire' => array('type' => 'datetime', 'null' => false, 'default' => NULL),
+ 'indexes' => array(),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_bin', 'engine' => 'MyISAM')
+ );
+ public $events = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'org' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'date' => array('type' => 'date', 'null' => false, 'default' => NULL),
+ 'info' => array('type' => 'text', 'null' => false, 'default' => NULL, 'key' => 'index', 'collate' => 'utf8_unicode_ci', 'charset' => 'utf8'),
+ 'user_id' => array('type' => 'integer', 'null' => false, 'default' => NULL),
+ 'alerted' => array('type' => 'boolean', 'null' => false, 'default' => '0'),
+ 'uuid' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 40, 'key' => 'index', 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'private' => array('type' => 'boolean', 'null' => false, 'default' => NULL),
+ 'published' => array('type' => 'boolean', 'null' => false, 'default' => '0'),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'uuid' => array('column' => 'uuid', 'unique' => 0), 'info' => array('column' => 'info', 'unique' => 0)),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_bin', 'engine' => 'MyISAM')
+ );
+ public $groups = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'name' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 100, 'collate' => 'latin1_swedish_ci', 'charset' => 'latin1'),
+ 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'perm_add' => array('type' => 'boolean', 'null' => true, 'default' => NULL),
+ 'perm_modify' => array('type' => 'boolean', 'null' => true, 'default' => NULL),
+ 'perm_publish' => array('type' => 'boolean', 'null' => true, 'default' => NULL),
+ 'perm_full' => array('type' => 'boolean', 'null' => true, 'default' => NULL),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
+ 'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'InnoDB')
+ );
+ public $logs = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'title' => array('type' => 'string', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'model' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 20, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'model_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
+ 'action' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 20, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'user_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
+ 'change' => array('type' => 'string', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'email' => array('type' => 'string', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'org' => array('type' => 'string', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'description' => array('type' => 'string', 'null' => true, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_bin', 'engine' => 'MyISAM')
+ );
+ public $servers = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'url' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'authkey' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 40, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'org' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'push' => array('type' => 'boolean', 'null' => false, 'default' => NULL),
+ 'pull' => array('type' => 'boolean', 'null' => false, 'default' => NULL),
+ 'lastfetchedid' => array('type' => 'integer', 'null' => false, 'default' => NULL),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_bin', 'engine' => 'MyISAM')
+ );
+ public $users = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'password' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 40, 'key' => 'index', 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'org' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'email' => array('type' => 'string', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'autoalert' => array('type' => 'boolean', 'null' => false, 'default' => NULL),
+ 'authkey' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 40, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'invited_by' => array('type' => 'integer', 'null' => false, 'default' => NULL),
+ 'gpgkey' => array('type' => 'text', 'null' => false, 'default' => NULL, 'collate' => 'utf8_bin', 'charset' => 'utf8'),
+ 'nids_sid' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'length' => 15),
+ 'termsaccepted' => array('type' => 'boolean', 'null' => false, 'default' => NULL),
+ 'newsread' => array('type' => 'date', 'null' => false, 'default' => NULL),
+ 'group_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1), 'username' => array('column' => 'password', 'unique' => 0)),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_bin', 'engine' => 'MyISAM')
+ );
+}
diff --git a/app/Config/bootstrap.default.php b/app/Config/bootstrap.default.php
index 525dd8e86..e31a08d49 100644
--- a/app/Config/bootstrap.default.php
+++ b/app/Config/bootstrap.default.php
@@ -111,6 +111,10 @@ Configure::write('CyDefSIG.logo', 'orgs/MIL.be.png'); // used in Events::ind
Configure::write('CyDefSIG.showorg', 'true'); // show the name/flag of the organisation that uploaded the data
Configure::write('CyDefSIG.showowner', 'false'); // show the email of the owner that uploaded the data
Configure::write('CyDefSIG.sync', 'false'); // enable features related to syncing with other CyDefSIG instances
+Configure::write('CyDefSIG.private', 'true'); // respect private to org or server.
+if ('true' == Configure::read('CyDefSIG.private')) {
+ Configure::write('CyDefSIG.sync', 'true');
+}
Configure::write('CyDefSIG.email', 'no-reply@sig.mil.be'); // email from for all the mails
Configure::write('GnuPG.onlyencrypted', 'true'); // only allow encrypted email, do not allow plaintext mails
@@ -183,6 +187,12 @@ Configure::write('CyDefSIG.correlation', 'sql'); // correlation between a
*
*/
+CakePlugin::load('AclExtras');
+
+CakePlugin::load('SysLog');
+CakePlugin::load('Assets'); // having Logable
+CakePlugin::load('SysLogLogable');
+CakePlugin::load('MagicTools'); // having OrphansProtectable
/**
* You can attach event listeners to the request lifecyle as Dispatcher Filter . By Default CakePHP bundles two filters:
diff --git a/app/Config/routes.php b/app/Config/routes.php
old mode 100644
new mode 100755
index 82aa26118..42d48c587
--- a/app/Config/routes.php
+++ b/app/Config/routes.php
@@ -27,8 +27,10 @@
*/
Router::connect('/', array('controller' => 'events', 'action' => 'index'));
- // admin pagination
+ // admin Paginator
Router::connect('/users/admin_index/*', array('controller' => 'users', 'action' => 'index', 'admin' => true));
+ Router::connect('/groups/admin_index/*', array('controller' => 'groups', 'action' => 'index', 'admin' => true));
+ Router::connect('/logs/admin_index/*', array('controller' => 'logs', 'action' => 'index', 'admin' => true));
// Activate REST
Router::mapResources(array('events'));
diff --git a/app/Console/Command/Populate023Shell.php b/app/Console/Command/Populate023Shell.php
new file mode 100755
index 000000000..200b355e0
--- /dev/null
+++ b/app/Console/Command/Populate023Shell.php
@@ -0,0 +1,12 @@
+Groups->execute();
+ $this->GroupId->execute('2');
+ $this->GroupToAroAco->execute();
+ }
+}
\ No newline at end of file
diff --git a/app/Console/Command/Task/GroupIdTask.php b/app/Console/Command/Task/GroupIdTask.php
new file mode 100755
index 000000000..14868e312
--- /dev/null
+++ b/app/Console/Command/Task/GroupIdTask.php
@@ -0,0 +1,14 @@
+Users = new UsersController();
+ $this->Users->constructClasses();
+ $this->Users->setgroupid($fk);
+ }
+}
\ No newline at end of file
diff --git a/app/Console/Command/Task/GroupToAroAcoTask.php b/app/Console/Command/Task/GroupToAroAcoTask.php
new file mode 100755
index 000000000..da7f05849
--- /dev/null
+++ b/app/Console/Command/Task/GroupToAroAcoTask.php
@@ -0,0 +1,18 @@
+Groups = new GroupsController();
+ $this->Groups->constructClasses();
+
+ $groups = $this->Group->find('all');
+ foreach ($groups as $group) {
+ $this->Groups->saveAcl(array('model' => 'Group', 'foreign_key' => $group['Group']['id']), $group['Group']['perm_add'], $group['Group']['perm_modify'], $group['Group']['perm_publish']);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/Console/Command/Task/GroupsTask.php b/app/Console/Command/Task/GroupsTask.php
new file mode 100755
index 000000000..ac243f089
--- /dev/null
+++ b/app/Console/Command/Task/GroupsTask.php
@@ -0,0 +1,24 @@
+Groups = new GroupsController();
+ $this->Groups->constructClasses();
+
+ $groups = ClassRegistry::init('Group');
+ $groups->create();
+ $groups->save(array('Group' => array('name' => 'malware analyst', 'perm_add' => true, 'perm_modify' => true, 'perm_publish' => false, 'perm_full' => false)));
+ $groups->create();
+ $groups->save(array('Group' => array('name' => 'admin', 'perm_add' => true, 'perm_modify' => true, 'perm_publish' => true, 'perm_full' => true)));
+ $groups->create();
+ $groups->save(array('Group' => array('name' => 'IDS analyst', 'perm_add' => true, 'perm_modify' => true, 'perm_publish' => true, 'perm_full' => false)));
+ $groups->create();
+ $groups->save(array('Group' => array('name' => 'guest', 'perm_add' => false, 'perm_modify' => false, 'perm_publish' => false, 'perm_full' => false)));
+
+ }
+}
\ No newline at end of file
diff --git a/app/Console/cake b/app/Console/cake
old mode 100644
new mode 100755
diff --git a/app/Console/shell/degrate-0.2.3-0.2.2.sh b/app/Console/shell/degrate-0.2.3-0.2.2.sh
new file mode 100755
index 000000000..a0b4f0268
--- /dev/null
+++ b/app/Console/shell/degrate-0.2.3-0.2.2.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# degrate 0.2.3 to 0.2.2
+
+# step into project and ..
+PRJCT=/var/www/cydefsig/app
+cd ${PRJCT}
+
+# update Schema, remove Users.group_id
+./Console/cake schema update -s 0.2.2
+
+exit 0;
\ No newline at end of file
diff --git a/app/Console/shell/migrate-0.2.2-0.2.3.sh b/app/Console/shell/migrate-0.2.2-0.2.3.sh
new file mode 100755
index 000000000..9501f10fe
--- /dev/null
+++ b/app/Console/shell/migrate-0.2.2-0.2.3.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# migrate 0.2.2 to 0.2.3
+
+# DataBase migrate, Audit and Access Control granulation
+
+# step into project and ..
+PRJCT=/var/www/cydefsig/app
+cd ${PRJCT}
+
+# create ACL tables
+./Console/cake schema create DbAcl
+# populate ACL acos
+./Console/cake acl create aco root controllers
+./Console/cake AclExtras.AclExtras aco_sync
+
+# update Schema, add Users.group_id
+./Console/cake schema update -s 0.2.2.1
+
+# create Log table
+./Console/cake schema create DbLog
+
+# create Groups, populate ACL aros and Users.group_id
+./Console/cake schema create DbGroup
+
+# populate 0.2.3
+./Console/cake populate0_2_3
+
+exit 0;
\ No newline at end of file
diff --git a/app/Console/shell/rights.sh b/app/Console/shell/rights.sh
new file mode 100755
index 000000000..101411039
--- /dev/null
+++ b/app/Console/shell/rights.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+USER=noud
+
+chown -R ${USER}:www-data /var/www/cydefsig
+chmod -R 750 /var/www/cydefsig
+chmod -R g+s /var/www/cydefsig
+cd /var/www/cydefsig/app/
+chmod -R g+w tmp
+chmod -R g+w files
+
+exit 0
diff --git a/app/Controller/AppController.php b/app/Controller/AppController.php
index ad9f250d6..7f6aa45c7 100755
--- a/app/Controller/AppController.php
+++ b/app/Controller/AppController.php
@@ -24,7 +24,6 @@
App::uses('Controller', 'Controller');
App::uses('Sanitize', 'Utility');
-
/**
* Application Controller
*
@@ -37,6 +36,7 @@ App::uses('Sanitize', 'Utility');
class AppController extends Controller {
public $components = array(
+ 'Acl', // TODO XXX remove
'Session',
'Auth' => array(
'className' => 'SecureAuth',
@@ -48,8 +48,9 @@ class AppController extends Controller {
'authError' => 'Did you really think you are allowed to see that?',
'loginRedirect' => array('controller' => 'users', 'action' => 'routeafterlogin'),
'logoutRedirect' => array('controller' => 'users', 'action' => 'login'),
- 'authorize' => array('Controller') // Added this line
- )
+ 'authorize' => array('Controller', // Added this line
+ 'Actions' => array('actionPath' => 'controllers')) // TODO ACL, 4: tell actionPath
+ )
);
public function isAuthorized($user) {
@@ -94,6 +95,11 @@ class AppController extends Controller {
// These variables are required for every view
$this->set('me', $this->Auth->user());
$this->set('isAdmin', $this->_isAdmin());
+
+ // TODO ACL: 5: from Controller to Views
+ $this->set('isAclAdd', $this->checkAcl('add'));
+ $this->set('isAclModify', $this->checkAcl('edit'));
+ $this->set('isAclPublish', $this->checkAcl('publish'));
}
public function blackhole($type) {
@@ -316,7 +322,7 @@ class AppController extends Controller {
$this->loadModel('Correlation');
$this->loadModel('Attribute');
- $fields = array('Attribute.id', 'Attribute.event_id', 'Event.date');
+ $fields = array('Attribute.id', 'Attribute.event_id', 'Attribute.private', 'Event.date', 'Event.org');
// get all attributes..
$attributes = $this->Attribute->find('all',array('recursive' => 0));
// for all attributes..
@@ -337,4 +343,52 @@ class AppController extends Controller {
//}
}
}
+
+/**
+ * TODO ACL, 6b: check on Group and per Model (not used)
+ */
+ public function checkAccess() {
+ $aco = ucfirst($this->params['controller']);
+ $user = ClassRegistry::init('User')->findById($this->Auth->user('id'));
+ return $this->Acl->check($user, 'controllers/' . $aco, '*');
+ }
+
+/**
+ * TODO ACL, 6: check on Group and any Model
+ */
+ public function checkAcl($action) {
+ $aco = 'Events'; // TODO ACL was 'Attributes'
+ $user = ClassRegistry::init('User')->findById($this->Auth->user('id'));
+ // TODO ACL, CHECK, below if indicates some wrong: Fatal error: Call to a member function check() on a non-object in /var/www/cydefsig/app/Controller/AppController.php on line 289
+ if ($this->Acl) {
+ return $this->Acl->check($user, 'controllers/' . $aco . '/' . $action, '*');
+ } else {
+ return true;
+ }
+ }
+
+ public function generatePrivate() {
+ if (!self::_isAdmin()) throw new NotFoundException();
+
+ $this->loadModel('Correlation');
+ $this->loadModel('Attribute');
+ $attributes = $this->Attribute->find('all',array('recursive' => 0));
+ foreach ($attributes as $attribute) {
+ if ($attribute['Attribute']['private']) {
+ $attribute['Attribute']['private'] = false;
+ $attribute['Attribute']['pull'] = true;
+ }
+ $this->Attribute->save($attribute);
+ }
+
+ $this->loadModel('Event');
+ $events = $this->Event->find('all',array('recursive' => 0));
+ foreach ($events as $event) {
+ if ($event['Event']['private']) {
+ $event['Event']['private'] = false;
+ $event['Event']['pull'] = true;
+ }
+ $this->Event->save($event);
+ }
+ }
}
diff --git a/app/Controller/AttributesController.php b/app/Controller/AttributesController.php
old mode 100644
new mode 100755
index 06887015b..36200cc2d
--- a/app/Controller/AttributesController.php
+++ b/app/Controller/AttributesController.php
@@ -10,7 +10,7 @@ App::uses('File', 'Utility');
*/
class AttributesController extends AppController {
- public $components = array('Security', 'RequestHandler');
+ public $components = array('Acl', 'Security', 'RequestHandler'); // XXX ACL component
public $paginate = array(
'limit' => 60,
@@ -41,6 +41,31 @@ class AttributesController extends AppController {
$this->params->addParams(array('pass' => array($id))); // FIXME find better way to change id variable if uuid is found. params->url and params->here is not modified accordingly now
}
}
+
+ // do not show private to other groups
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ // if not admin or own org, check private as well..
+ if (!$this->_IsAdmin()) {
+ $this->paginate = Set::merge($this->paginate,array(
+ 'conditions' =>
+ array("OR" => array(
+ array('Event.org =' => $this->Auth->user('org')),
+ array("AND" => array('Event.org !=' => $this->Auth->user('org')), array('Event.private !=' => 1), array('Attribute.private !=' => 1)))),
+ )
+ );
+ }
+ }
+
+ // do not show cluster outside server
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ if ($this->_isRest()) {
+ $this->paginate = Set::merge($this->paginate,array(
+ 'conditions' =>
+ array("AND" => array('Event.cluster !=' => true),array('Attribute.cluster !=' => true)),
+ //array("AND" => array(array('Event.private !=' => 2))),
+ ));
+ }
+ }
}
public function isAuthorized($user) {
@@ -49,7 +74,7 @@ class AttributesController extends AppController {
return true;
}
// Only on own attributes for these actions
- if (in_array($this->action, array('edit', 'delete'))) {
+ if (in_array($this->action, array('delete'))) { // TODO ACL, removed 'edit' override
$attributeid = $this->request->params['pass'][0];
return $this->Attribute->isOwnedByOrg($attributeid, $this->Auth->user('org'));
}
@@ -114,6 +139,9 @@ class AttributesController extends AppController {
$this->Attribute->create();
$this->request->data['Attribute']['value'] = $attribute; // set the value as the content of the single line
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ $this->request->data = $this->Attribute->massageData(&$this->request->data);
+ }
if ($this->Attribute->save($this->request->data)) {
$successes .= " " . ($key + 1);
} else {
@@ -140,6 +168,10 @@ class AttributesController extends AppController {
// create the attribute
$this->Attribute->create();
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ $this->request->data = $this->Attribute->massageData(&$this->request->data);
+ }
+
if ($this->Attribute->save($this->request->data)) {
// inform the user and redirect
$this->Session->setFlash(__('The attribute has been saved'));
@@ -162,6 +194,12 @@ class AttributesController extends AppController {
$categories = $this->_arrayToValuesIndexArray($categories);
$this->set('categories',compact('categories'));
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ $sharings = array('Org', 'Server', 'Pull only', 'All');
+ $sharings = $this->_arrayToValuesIndexArray($sharings);
+ $this->set('sharings',compact('sharings'));
+ }
+
$this->set('attrDescriptions', $this->Attribute->fieldDescriptions);
$this->set('typeDefinitions', $this->Attribute->typeDefinitions);
$this->set('categoryDefinitions', $this->Attribute->categoryDefinitions);
@@ -183,6 +221,7 @@ class AttributesController extends AppController {
} elseif ('malware-sample' == $this->Attribute->data['Attribute']['type']) {
$filenameHash = explode('|', $this->Attribute->data['Attribute']['value']);
$filename = $filenameHash[0];
+ $filename = substr($filenameHash[0], strrpos($filenameHash[0], '\\'));
$fileExt = "zip";
} else {
throw new NotFoundException(__('Attribute not an attachment or malware-sample'));
@@ -191,10 +230,10 @@ class AttributesController extends AppController {
$this->viewClass = 'Media';
$params = array(
'id' => $file->path,
- 'name' => $filename,
+ 'name' => $filename,
'extension' => $fileExt,
'download' => true,
- 'path' => DS
+ 'path' => DS
);
$this->set($params);
}
@@ -241,6 +280,9 @@ class AttributesController extends AppController {
}
$this->request->data['Attribute']['uuid'] = String::uuid();
$this->request->data['Attribute']['batch_import'] = 0;
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ $this->request->data = $this->Attribute->massageData(&$this->request->data);
+ }
if ($this->Attribute->save($this->request->data)) {
// attribute saved correctly in the db
@@ -329,6 +371,12 @@ class AttributesController extends AppController {
$this->set('zippedDefinitions', $this->Attribute->zippedDefinitions);
$this->set('uploadDefinitions', $this->Attribute->uploadDefinitions);
+
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ $sharings = array('Org', 'Server', 'Pull only', 'All');
+ $sharings = $this->_arrayToValuesIndexArray($sharings);
+ $this->set('sharings',compact('sharings'));
+ }
}
/**
@@ -358,8 +406,12 @@ class AttributesController extends AppController {
}
if ($this->request->is('post') || $this->request->is('put')) {
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ $this->request->data = $this->Attribute->massageData(&$this->request->data);
+ }
+
// say what fields are to be updated
- $fieldList = array('category', 'type', 'value1', 'value2', 'to_ids', 'private');
+ $fieldList = array('category', 'type', 'value1', 'value2', 'to_ids', 'private', 'cluster', 'pull');
if ($this->Attribute->save($this->request->data)) {
$this->Session->setFlash(__('The attribute has been saved'));
@@ -385,6 +437,12 @@ class AttributesController extends AppController {
$categories = $this->_arrayToValuesIndexArray($categories);
$this->set('categories',compact('categories'));
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ $sharings = array('Org', 'Server', 'Pull only', 'All');
+ $sharings = $this->_arrayToValuesIndexArray($sharings);
+ $this->set('sharings',compact('sharings'));
+ }
+
$this->set('attrDescriptions', $this->Attribute->fieldDescriptions);
$this->set('typeDefinitions', $this->Attribute->typeDefinitions);
$this->set('categoryDefinitions', $this->Attribute->categoryDefinitions);
@@ -492,6 +550,20 @@ class AttributesController extends AppController {
$this->paginate = array(
'conditions' => $conditions
);
+
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ if (!$this->_IsAdmin()) {
+ // merge in private conditions
+ $this->paginate = Set::merge($this->paginate,array(
+ 'conditions' =>
+ array("OR" => array(
+ array('Event.org =' => $this->Auth->user('org')),
+ array("AND" => array('Event.org !=' => $this->Auth->user('org')), array('Event.private !=' => 1), array('Attribute.private !=' => 1)))),
+ )
+ );
+ }
+ }
+
$this->set('attributes', $this->paginate());
// and store into session
diff --git a/app/Controller/EventsController.php b/app/Controller/EventsController.php
old mode 100644
new mode 100755
index 078092eda..f0a9d8412
--- a/app/Controller/EventsController.php
+++ b/app/Controller/EventsController.php
@@ -15,6 +15,7 @@ class EventsController extends AppController {
* @var array
*/
public $components = array(
+ 'Acl', // XXX ACL component
'Security',
'Email',
'RequestHandler',
@@ -43,6 +44,13 @@ class EventsController extends AppController {
$this->Auth->allow('dot');
+ // TODO Audit, activate logable in a Controller
+ if (count($this->uses) && $this->{$this->modelClass}->Behaviors->attached('SysLogLogable')) {
+ $this->{$this->modelClass}->setUserData($this->activeUser);
+ }
+
+ // TODO ACL, if on ent/attr level, $this->set('isAcl', $this->checkAccess());
+
// convert uuid to id if present in the url, and overwrite id field
if (isset($this->params->query['uuid'])) {
$params = array(
@@ -56,6 +64,30 @@ class EventsController extends AppController {
$this->params->addParams(array('pass' => array($id))); // FIXME find better way to change id variable if uuid is found. params->url and params->here is not modified accordingly now
}
}
+
+ // do not show private to other groups
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ // if not admin or own org, check private as well..
+ if (!$this->_IsAdmin()) {
+ $this->paginate = Set::merge($this->paginate,array(
+ 'conditions' =>
+ array("OR" => array(
+ array('Event.org =' => $this->Auth->user('org')),
+ array("AND" => array('Event.org !=' => $this->Auth->user('org')), array('Event.private !=' => 1)))),
+ ));
+ }
+ }
+
+ // do not show cluster outside server
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ if ($this->_isRest()) {
+ $this->paginate = Set::merge($this->paginate,array(
+ 'conditions' =>
+ array(array('Event.cluster !=' => true)),
+ //array("AND" => array(array('Event.private !=' => 2))),
+ ));
+ }
+ }
}
public function isAuthorized($user) {
@@ -64,7 +96,7 @@ class EventsController extends AppController {
return true;
}
// Only on own events for these actions
- if (in_array($this->action, array('edit', 'delete', 'alert', 'publish'))) {
+ if (in_array($this->action, array('alert'))) { // TODO ACL, CHECK, remove overruling 'edit', 'delete' and 'publish'
$eventid = $this->request->params['pass'][0];
return $this->Event->isOwnedByOrg($eventid, $this->Auth->user('org'));
}
@@ -102,21 +134,44 @@ class EventsController extends AppController {
}
$this->Event->read(null, $id);
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ if (!$this->_IsAdmin()) {
+ // check for non-private and re-read
+ if ($this->Event->data['Event']['org'] != $this->Auth->user('org')) {
+ $this->Event->hasMany['Attribute']['conditions'] = array('Attribute.private !=' => 1);
+ $this->Event->read(null, $id);
+ }
+
+ // check private
+ if (($this->Event->data['Event']['private']) && ($this->Event->data['Event']['org'] != $this->Auth->user('org'))) {
+ $this->Session->setFlash('Invalid event.');
+ $this->redirect(array('controller' => 'users', 'action' => 'terms'));
+ }
+ }
+ }
+
$relatedAttributes = array();
$this->loadModel('Attribute');
if ('db' == Configure::read('CyDefSIG.correlation')) {
$this->loadModel('Correlation');
$fields = array('Correlation.event_id', 'Correlation.attribute_id', 'Correlation.date');
- $fields2 = array('Correlation.1_attribute_id','Correlation.event_id', 'Correlation.attribute_id', 'Correlation.date');
+ $fields2 = array('Correlation.1_attribute_id','Correlation.event_id', 'Correlation.attribute_id', 'Correlation.date', 'Correlation.private', 'Correlation.org');
$relatedAttributes2 = array();
- $relatedAttributes2 = $this->Correlation->find('all',array(
- 'fields' => $fields2,
- 'conditions' => array(
- 'OR' => array(
- 'Correlation.1_event_id' => $id
- )
- ),
- 'recursive' => 0));
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ $conditionsCorrelation =
+ array('AND' => array('Correlation.1_event_id' => $id,),
+ array("OR" => array(
+ array('Correlation.org =' => $this->Event->data['Event']['org']),
+ array("AND" => array('Correlation.org !=' => $this->Event->data['Event']['org']), array('Correlation.private !=' => 1)))));
+ } else {
+ $conditionsCorrelation =
+ array('AND' => array('Correlation.1_event_id' => $id,));
+ }
+ $relatedAttributes2 = $this->Correlation->find('all',array(
+ 'fields' => $fields2,
+ 'conditions' => $conditionsCorrelation,
+ 'recursive' => 0));
+
if (empty($relatedAttributes2)) {
$relatedEvents = null;
} else {
@@ -223,19 +278,44 @@ class EventsController extends AppController {
*/
public function add() {
if ($this->request->is('post')) {
- if ($this->_add($this->request->data, $this->Auth, $this->_isRest(),'')) {
- if ($this->_isRest()) {
- // REST users want to see the newly created event
- $this->view($this->Event->getId());
- $this->render('view');
+
+ // TODO or massageData here
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ $this->request->data = $this->Event->massageData(&$this->request->data);
+ }
+
+ if (!empty($this->data)) {
+ if (isset($this->data['Event']['submittedfile'])) {
+ App::uses('File', 'Utility');
+ $file = new File($this->data['Event']['submittedfile']['name']);
+ $ext = $file->ext();
} else {
- // redirect to the view of the newly created event
- $this->Session->setFlash(__('The event has been saved'));
- $this->redirect(array('action' => 'view', $this->Event->getId()));
+ $ext = '';
+ }
+ if (isset($this->data['Event']['submittedfile']) && $ext != 'zip' && $this->data['Event']['submittedfile']['size'] > 0 &&
+ is_uploaded_file($this->data['Event']['submittedfile']['tmp_name'])) {
+ //return false;
+ $this->Session->setFlash('You may only upload GFI Sandbox zip files.');
+ } else {
+ // TODO or massageData here
+ if ($this->_add($this->request->data, $this->Auth, $this->_isRest(),'')) {
+ if ($this->_isRest()) {
+ // REST users want to see the newly created event
+ $this->view($this->Event->getId());
+ $this->render('view');
+ } else {
+ // TODO now save uploaded attributes using $this->Event->getId() ..
+ $this->addGfiZip($this->Event->getId());
+
+ // redirect to the view of the newly created event
+ $this->Session->setFlash(__('The event has been saved'));
+ $this->redirect(array('action' => 'view', $this->Event->getId()));
+ }
+ } else {
+ $this->Session->setFlash(__('The event could not be saved. Please, try again.'), 'default', array(), 'error');
+ // TODO return error if REST
+ }
}
- } else {
- $this->Session->setFlash(__('The event could not be saved. Please, try again.'), 'default', array(), 'error');
- // TODO return error if REST
}
}
// combobox for risks
@@ -243,6 +323,12 @@ class EventsController extends AppController {
$risks = $this->_arrayToValuesIndexArray($risks);
$this->set('risks',compact('risks'));
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ $sharings = array('Org', 'Server', 'Pull only', 'All');
+ $sharings = $this->_arrayToValuesIndexArray($sharings);
+ $this->set('sharings',compact('sharings'));
+ }
+
$this->set('eventDescriptions', $this->Event->fieldDescriptions);
}
@@ -296,9 +382,14 @@ class EventsController extends AppController {
}
$fieldList = array(
- 'Event' => array('org', 'date', 'risk', 'info', 'user_id', 'published', 'uuid', 'private'),
- 'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'revision', 'private')
+ 'Event' => array('org', 'date', 'risk', 'info', 'user_id', 'published', 'uuid', 'private', 'cluster', 'pull'),
+ 'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'revision', 'private', 'cluster', 'pull')
);
+
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ $data = $this->Event->massageData(&$data);
+ }
+
// this saveAssociated() function will save not only the event, but also the attributes
// from the attributes attachments are also saved to the disk thanks to the afterSave() fonction of Attribute
if ($this->Event->saveAssociated($data, array('validate' => true, 'fieldList' => $fieldList))) {
@@ -364,7 +455,7 @@ class EventsController extends AppController {
}
// say what fields are to be updated
- $fieldList = array('date', 'risk', 'info', 'published', 'private');
+ $fieldList = array('date', 'risk', 'info', 'published', 'private', 'cluster', 'pull');
// always force the org, but do not force it for admins
if ($this->_isAdmin()) {
// set the same org as existed before
@@ -374,6 +465,10 @@ class EventsController extends AppController {
// we probably also want to remove the published flag
$this->request->data['Event']['published'] = 0;
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ $this->request->data = $this->Event->massageData(&$this->request->data);
+ }
+
if ($this->Event->save($this->request->data, true, $fieldList)) {
$this->Session->setFlash(__('The event has been saved'));
$this->redirect(array('action' => 'view', $id));
@@ -389,7 +484,14 @@ class EventsController extends AppController {
$risks = $this->_arrayToValuesIndexArray($risks);
$this->set('risks',compact('risks'));
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ $sharings = array('Org', 'Server', 'Pull only', 'All');
+ $sharings = $this->_arrayToValuesIndexArray($sharings);
+ $this->set('sharings', compact('sharings'));
+ }
+
$this->set('eventDescriptions', $this->Event->fieldDescriptions);
+ $this->set('privateDefinitions', $this->Event->privateDefinitions);
}
/**
@@ -564,13 +666,13 @@ class EventsController extends AppController {
// The mail body, h() is NOT needed as we are sending plain-text mails.
$body = "";
$appendlen = 20;
- $body .= 'URL : ' . Configure::read('CyDefSIG.baseurl') . '/events/view/' . $event['Event']['id'] . "\n";
- $body .= 'Event : ' . $event['Event']['id'] . "\n";
- $body .= 'Date : ' . $event['Event']['date'] . "\n";
+ $body .= 'URL : ' . Configure::read('CyDefSIG.baseurl') . '/events/view/' . $event['Event']['id'] . "\n";
+ $body .= 'Event : ' . $event['Event']['id'] . "\n";
+ $body .= 'Date : ' . $event['Event']['date'] . "\n";
if ('true' == Configure::read('CyDefSIG.showorg')) {
$body .= 'Reported by : ' . $event['Event']['org'] . "\n";
}
- $body .= 'Risk : ' . $event['Event']['risk'] . "\n";
+ $body .= 'Risk : ' . $event['Event']['risk'] . "\n";
$relatedEvents = $this->Event->getRelatedEvents($id);
if (!empty($relatedEvents)) {
foreach ($relatedEvents as &$relatedEvent) {
@@ -586,7 +688,7 @@ class EventsController extends AppController {
if (isset($event['Attribute'])) {
foreach ($event['Attribute'] as &$attribute) {
- $line = '- ' . $attribute['type'] . str_repeat(' ', $appendlen - 2 - strlen( $attribute['type'])) . ': ' . $attribute['value'] . "\n";
+ $line = '- ' . $attribute['type'] . str_repeat(' ', $appendlen - 2 - strlen($attribute['type'])) . ': ' . $attribute['value'] . "\n";
if ('other' == $attribute['type']) // append the 'other' attribute types to the bottom.
$bodyTempOther .= $line;
else $body .= $line;
@@ -613,7 +715,7 @@ class EventsController extends AppController {
'conditions' => array('User.autoalert' => 1,
'User.gpgkey =' => ""),
'recursive' => 0,
- ) );
+ ));
$alertEmails = Array();
foreach ($alertUsers as &$user) {
$alertEmails[] = $user['User']['email'];
@@ -624,7 +726,7 @@ class EventsController extends AppController {
$this->Email->bcc = $alertEmails;
$this->Email->subject = "[" . Configure::read('CyDefSIG.name') . "] Event " . $id . " - " . $event['Event']['risk'] . " - TLP Amber";
$this->Email->template = 'body';
- $this->Email->sendAs = 'text'; // both text or html
+ $this->Email->sendAs = 'text'; // both text or html
$this->set('body', $bodySigned);
// send it
$this->Email->send();
@@ -649,7 +751,7 @@ class EventsController extends AppController {
$this->Email->to = $user['User']['email'];
$this->Email->subject = "[" . Configure::read('CyDefSIG.name') . "] Event " . $id . " - " . $event['Event']['risk'] . " - TLP Amber";
$this->Email->template = 'body';
- $this->Email->sendAs = 'text'; // both text or html
+ $this->Email->sendAs = 'text'; // both text or html
// import the key of the user into the keyring
// this is not really necessary, but it enables us to find
@@ -1101,4 +1203,205 @@ class EventsController extends AppController {
// debug($gv);
// $gv->image();
//}
+
+ public function getName($id = null) {
+ $events = $this->Event->find('first', array(
+ 'conditions' => array('Event.id' => $id)
+ ));
+ $name = $events['Event']['info'];
+ return $name;
+ }
+
+ public function addGfiZip($id) {
+ if (!empty($this->data) && $this->data['Event']['submittedfile']['size'] > 0 &&
+ is_uploaded_file($this->data['Event']['submittedfile']['tmp_name'])) {
+ $zipData = fread(fopen($this->data['Event']['submittedfile']['tmp_name'], "r"),
+ $this->data['Event']['submittedfile']['size']);
+
+ // write
+ $rootDir = APP . "files" . DS . $id . DS;
+ App::uses('Folder', 'Utility');
+ $dir = new Folder($rootDir, true);
+ $destpath = $rootDir;
+ $file = new File ($destpath);
+ $zipfile = new File ($destpath . DS . $this->data['Event']['submittedfile']['name']);
+ $result = $zipfile->write($zipData);
+ if (!$result) $this->Session->setFlash(__('Problem with writing the zip file. Please report to administrator.'));
+
+ // extract zip..
+ $execRetval = '';
+ exec("unzip " . $zipfile->path . ' -d "' . addslashes($rootDir) . '"', $execOutput, $execRetval);
+ $execOutput = array();
+ if ($execRetval != 0) { // not EXIT_SUCCESS
+ // do some?
+ }
+
+ // now open the xml..
+ $xml = $rootDir . DS . 'Analysis' . DS . 'analysis.xml';
+ $fileData = fread(fopen($xml, "r"), $this->data['Event']['submittedfile']['size']);
+
+ // read XML
+ $this->readGfiXML($fileData, $id);
+ }
+ }
+
+ public function readGfiXML($data, $id) {
+ $this->loadModel('Attribute');
+
+ // import XML class
+ App::uses('Xml', 'Utility');
+ // now parse it
+ $parsedXml =& Xml::build($data, array('return' => 'simplexml'));
+
+ // xpath..
+
+ //Payload delivery -- malware-sample
+ $results = $parsedXml->xpath('/analysis');
+ foreach ($results as $result) {
+ foreach ($result[0]->attributes() as $key => $val) {
+ if ((string)$key == 'filename') $realFileName = (string)$val;
+ }
+ }
+ $realMalware = $realFileName;
+ $rootDir = APP . "files" . DS . $id . DS;
+ $malware = $rootDir . DS . 'sample';
+ $this->Event->Attribute->uploadAttachment($malware, $realFileName, true, $id);
+
+ //Network activity -- .pcap
+ $realFileName = 'analysis.pcap';
+ $rootDir = APP . "files" . DS . $id . DS;
+ $malware = $rootDir . DS . 'Analysis' . DS . 'analysis.pcap';
+ $this->Event->Attribute->uploadAttachment($malware, $realFileName, false, $id, 'Network activity');
+
+ //Artifacts dropped -- filename|md5
+ $files = array();
+ // TODO what about stored_modified_file ??
+ $results = $parsedXml->xpath('/analysis/processes/process/stored_files/stored_created_file');
+ foreach ($results as $result) {
+ $arrayItemKey = '';
+ $arrayItemValue = '';
+ foreach ($result[0]->attributes() as $key => $val) {
+ if ($key == 'filename') $arrayItemKey = (string)$val;
+ if ($key == 'md5') $arrayItemValue = (string)$val;
+ }
+
+ $files[$arrayItemKey] = $arrayItemValue;
+ }
+ //$files = array_unique($files);
+
+ // write content..
+ foreach ($files as $key => $val) {
+ $keyName = $key;
+ // replace Windows Environment Variables
+ $keyName = str_replace('C:\Users\John', '%UserProfile%', $keyName);
+ $keyName = str_replace('C:\Documents and Settings\James Cocks', '%UserProfile%', $keyName);
+ $keyName = str_replace('C:\DOCUME~1\JAMESC~1', '%UserProfile%', $keyName);
+ $keyName = str_replace('C:\Documents and Settings\All Users', '%AllUsersProfile%', $keyName);
+
+ if (!strpos($key, $realMalware)) {
+ $itsType = 'malware-sample';
+ } else {
+ $itsType = 'filename|md5';
+ }
+
+ // the actual files..
+ // seek $val in dirs and add..
+ $ext = substr($key, strrpos($key, '.'));
+ $actualFileName = $val . $ext;
+ $actualFileNameBase = str_replace('\\', '/', $key);
+ $actualFileNameArray[] = basename($actualFileNameBase);
+ $realFileName = end(explode('\\', $key));
+ // have the filename, now look at parents parent for the process number
+ $express = "/analysis/processes/process/stored_files/stored_created_file[@md5='" . $val . "']/../..";
+ $results = $parsedXml->xpath($express);
+ foreach ($results as $result) {
+ foreach ($result[0]->attributes() as $key => $val) {
+ if ((string)$key == 'index') $index = (string)$val;
+ }
+ }
+ $actualFile = $rootDir . DS . 'Analysis' . DS . 'proc_' . $index . DS . 'modified_files' . DS . $actualFileName;
+ $extraPath = 'Analysis' . DS . 'proc_' . $index . DS . 'modified_files' . DS;
+ $file = new File($actualFile);
+ if ($file->exists()) { // TODO put in array for test later
+ $this->Event->Attribute->uploadAttachment($actualFile, $realFileName, true, $id, null, $extraPath, $keyName); // TODO was false
+ }
+ }
+
+ //Network activity -- ip-dst
+ $ips = array();
+ $results = $parsedXml->xpath('/analysis/processes/process/networkpacket_section/connect_to_computer');
+ foreach ($results as $result) {
+ foreach ($result[0]->attributes() as $key => $val) {
+ if ($key == 'remote_ip') $ips[] = (string)$val;
+ }
+ }
+ // write content..
+ foreach ($ips as $ip) {
+ // add attribute..
+ $this->Attribute->read(null, 1);
+ $this->Attribute->save(array(
+ 'event_id' => $id,
+ 'category' => 'Network activity',
+ 'type' => 'ip-dst',
+ 'value' => $ip,
+ 'to_ids' => false));
+ }
+
+ // Persistence mechanism -- regkey|value
+ $regs = array();
+ $results = $parsedXml->xpath('/analysis/processes/process/registry_section/set_value');
+ foreach ($results as $result) {
+ $arrayItemKey = '';
+ $arrayItemValue = '';
+ foreach ($result[0]->attributes() as $key => $val) {
+ if ($key == 'key_name') $arrayItemKey = (string)$val;
+ if ($key == 'data') $arrayItemValue = (string)$val;
+ }
+ $arrayItemKey = preg_replace('@\\\REGISTRY\\\USER\\\S(-[0-9]{1}){2}-[0-9]{2}(-[0-9]{10}){2}-[0-9]{9}-[0-9]{4}@','HKEY_CURRENT_USER',$arrayItemKey);
+ $regs[$arrayItemKey] = str_replace('(UNICODE_0x00000000)', '', $arrayItemValue);
+ }
+ //$regs = array_unique($regs);
+
+ // write content..
+ foreach ($regs as $key => $val) {
+ // add attribute..
+ $this->Attribute->read(null, 1);
+ if ($val == '[binary_data]') {
+ $itsCategory = 'Persistence mechanism';
+ $itsType = 'regkey';
+ $itsValue = $key;
+ } else {
+ if ($this->strposarray($val,$actualFileNameArray)) {
+ $itsCategory = 'Persistence mechanism';
+ $itsType = 'regkey|value';
+ $itsValue = $key . '|' . $val;
+ } else {
+ // replace Windows Environment Variables
+ $val = str_replace('C:\Users\John', '%UserProfile%', $val);
+ $val = str_replace('C:\Documents and Settings\James Cocks', '%UserProfile%', $val);
+ $val = str_replace('C:\DOCUME~1\JAMESC~1', '%UserProfile%', $val);
+ $val = str_replace('C:\Documents and Settings\All Users', '%AllUsersProfile%', $val);
+
+ $itsCategory = 'Artifacts dropped'; // Persistence mechanism
+ $itsType = 'regkey|value';
+ $itsValue = $key . '|' . $val;
+ }
+ }
+ $this->Attribute->save(array(
+ 'event_id' => $id,
+ 'category' => $itsCategory, // 'Persistence mechanism'
+ 'type' => $itsType,
+ 'value' => $itsValue,
+ 'to_ids' => false));
+ }
+ }
+ public function strposarray($string, $array) {
+ $toReturn = false;
+ foreach ($array as $item) {
+ if (strpos($string,$item)) {
+ $toReturn = true;
+ }
+ }
+ return $toReturn;
+ }
}
diff --git a/app/Controller/GroupsController.php b/app/Controller/GroupsController.php
new file mode 100755
index 000000000..d6ef4ba34
--- /dev/null
+++ b/app/Controller/GroupsController.php
@@ -0,0 +1,178 @@
+ array(
+ 'authorize' => array(
+ 'Actions' => array('actionPath' => 'controllers/Groups')
+ )
+ ),
+ 'Session'
+ );
+
+ //public $components = array('Security');
+ public $paginate = array(
+ 'limit' => 60,
+ 'order' => array(
+ 'Group.name' => 'ASC'
+ )
+ );
+
+ function beforeFilter() {
+ parent::beforeFilter();
+ }
+
+/**
+ * view method
+ *
+ * @param string $id
+ * @return void
+ */
+ public function view($id = null) {
+ $this->Group->id = $id;
+ if (!$this->Group->exists()) {
+ throw new NotFoundException(__('Invalid group'));
+ }
+ $this->set('group', $this->Group->read(null, $id));
+ }
+
+/**
+ * admin_index method
+ *
+ * @return void
+ */
+ public function admin_index() {
+ $this->Group->recursive = 0;
+ $this->set('groups', $this->paginate());
+ }
+
+/**
+ * admin_view method
+ *
+ * @param string $id
+ * @return void
+ */
+ public function admin_view($id = null) {
+ $this->Group->id = $id;
+ if (!$this->Group->exists()) {
+ throw new NotFoundException(__('Invalid group'));
+ }
+ $this->set('group', $this->Group->read(null, $id));
+ }
+
+/**
+ * admin_add method
+ *
+ * @return void
+ */
+ public function admin_add() {
+ if ($this->request->is('post')) {
+ $this->Group->create();
+ if ($this->Group->save($this->request->data)) {
+ $this->saveAcl($this->Group, $this->data['Group']['perm_add'], $this->data['Group']['perm_modify'], $this->data['Group']['perm_publish']); // save to ACL as well
+ $this->Session->setFlash(__('The group has been saved'));
+ $this->redirect(array('action' => 'index'));
+ } else {
+ $this->Session->setFlash(__('The group could not be saved. Please, try again.'));
+ }
+ } else {
+ // generate auth key for a new user
+ //$newkey = $this->Group->generateAuthKey(); // TODO generateAuthKey?
+ //$this->set('authkey', $newkey);
+ }
+ }
+
+/**
+ * admin_edit method
+ *
+ * @param string $id
+ * @return void
+ */
+ public function admin_edit($id = null) {
+ $this->Group->id = $id;
+ if (!$this->Group->exists()) {
+ throw new NotFoundException(__('Invalid group'));
+ }
+ if ($this->request->is('post') || $this->request->is('put')) {
+ $fields = array();
+ foreach (array_keys($this->request->data['Group']) as $field) {
+ if($field != 'password') array_push($fields, $field);
+ }
+ if ("" != $this->request->data['Group']['password'])
+ $fields[] = 'password';
+ if ($this->Group->save($this->request->data, true, $fields)) {
+ $this->saveAcl($this->Group, $this->data['Group']['perm_add'], $this->data['Group']['perm_modify'], $this->data['Group']['perm_publish']); // save to ACL as well
+ $this->Session->setFlash(__('The group has been saved'));
+ $this->_refreshAuth(); // in case we modify ourselves
+ $this->redirect(array('action' => 'index'));
+ } else {
+ $this->Session->setFlash(__('The group could not be saved. Please, try again.'));
+ }
+ } else {
+ $this->Group->recursive=0;
+ $this->Group->read(null, $id);
+ //$this->Group->set('password', ''); // TODO set password?
+ $this->request->data = $this->Group->data;
+
+ }
+ }
+
+/**
+ * admin_delete method
+ *
+ * @param string $id
+ * @return void
+ */
+ public function admin_delete($id = null) {
+ if (!$this->request->is('post')) {
+ throw new MethodNotAllowedException();
+ }
+ $this->Group->id = $id;
+ if (!$this->Group->exists()) {
+ throw new NotFoundException(__('Invalid group'));
+ }
+ if ($this->Group->delete(null, false)) {
+ $this->Session->setFlash(__('Group deleted'));
+ $this->redirect(array('action' => 'index'));
+ }
+ $this->Session->setFlash(__('Group was not deleted'));
+ $this->redirect(array('action' => 'index'));
+ }
+
+/**
+ * saveAcl method
+ *
+ * @param string $id
+ * @return void
+ */
+ public function saveAcl($group, $permAdd = false, $permModify = false, $permPublish = false) {
+ // this all could need some 'if-changed then do'
+
+ if ($permAdd) {
+ $this->Acl->allow($group, 'controllers/Events/add');
+ $this->Acl->allow($group, 'controllers/Attributes/add');
+ } else {
+ $this->Acl->deny($group, 'controllers/Events/add');
+ $this->Acl->deny($group, 'controllers/Attributes/add');
+ }
+ if ($permModify) {
+ $this->Acl->allow($group, 'controllers/Events/edit');
+ $this->Acl->allow($group, 'controllers/Attributes/edit');
+ } else {
+ $this->Acl->deny($group, 'controllers/Events/edit');
+ $this->Acl->deny($group, 'controllers/Attributes/edit');
+ }
+ if ($permPublish) {
+ $this->Acl->allow($group, 'controllers/Events/publish');
+ } else {
+ $this->Acl->deny($group, 'controllers/Events/publish');
+ }
+ }
+}
diff --git a/app/Controller/LogsController.php b/app/Controller/LogsController.php
new file mode 100755
index 000000000..aab967044
--- /dev/null
+++ b/app/Controller/LogsController.php
@@ -0,0 +1,112 @@
+ 60,
+ 'order' => array(
+ 'Log.id' => 'DESC'
+ )
+ );
+ public $helpers = array('Js' => array('Jquery'));
+
+ function beforeFilter() {
+ parent::beforeFilter();
+
+ // permit reuse of CSRF tokens on the search page.
+ if ('search' == $this->request->params['action']) {
+ $this->Security->csrfUseOnce = false;
+ }
+ }
+
+ public function isAuthorized($user) {
+ // Admins can access everything
+ if (parent::isAuthorized($user)) {
+ return true;
+ }
+ // the other pages are allowed by logged in users
+ return true;
+ }
+
+/**
+ * admin_index method
+ *
+ * @return void
+ */
+ public function admin_index() {
+ $this->Log->recursive = 0;
+ $this->set('logs', $this->paginate());
+ }
+
+/**
+ * admin_view method
+ *
+ * @param string $id
+ * @return void
+ */
+ public function admin_view($id = null) {
+ $this->Log->id = $id;
+ if (!$this->Log->exists()) {
+ throw new NotFoundException(__('Invalid log'));
+ }
+ $this->set('log', $this->Log->read(null, $id));
+ }
+
+ public function search() {
+ $this->admin_search();
+ }
+
+ public function admin_search() {
+
+ $this->set('actionDefinitions', $this->Log->actionDefinitions);
+
+ if ($this->request->is('post')) {
+ $email = $this->request->data['Log']['email'];
+ $org = $this->request->data['Log']['org'];
+ $action = $this->request->data['Log']['action'];
+ $title = $this->request->data['Log']['title'];
+ $change = $this->request->data['Log']['change'];
+
+ // search the db
+ $conditions = array();
+ if($email) {
+ $conditions['Log.email LIKE'] = '%'.$email.'%';
+ }
+ if($org) {
+ $conditions['Log.org LIKE'] = '%'.$org.'%';
+ }
+ if($action != 'ALL') {
+ $conditions['Log.action ='] = $action;
+ }
+ if($title) {
+ $conditions['Log.title LIKE'] = '%'.$title.'%';
+ }
+ if($change) {
+ $conditions['Log.change LIKE'] = '%'.$change.'%';
+ }
+ $this->Log->recursive = 0;
+ $this->paginate = array(
+ 'conditions' => $conditions
+ );
+ $this->set('logs', $this->paginate());
+
+ // set the same view as the index page
+ $this->render('index');
+ } else {
+ // no search keyword is given, show the search form
+
+ // combobox for actions
+ $actions = array('ALL');
+ $actions = array_merge($actions, $this->Log->validate['action']['rule'][1]);
+ $actions = $this->_arrayToValuesIndexArray($actions);
+ $this->set('actions',compact('actions'));
+ }
+ }
+}
diff --git a/app/Controller/ServersController.php b/app/Controller/ServersController.php
old mode 100755
new mode 100644
index 46fcf3f88..78b557f0a
--- a/app/Controller/ServersController.php
+++ b/app/Controller/ServersController.php
@@ -9,7 +9,7 @@ App::uses('Xml', 'Utility');
*/
class ServersController extends AppController {
- public $components = array('Security' ,'RequestHandler');
+ public $components = array('Acl' ,'Security' ,'RequestHandler'); // XXX ACL component
public $paginate = array(
'limit' => 60,
@@ -283,9 +283,15 @@ class ServersController extends AppController {
// increment lastid based on the highest ID seen
$this->Server->saveField('lastpushedid', $lastpushedid);
}
-
$this->set('successes', $successes);
$this->set('fails', $fails);
}
+ public function getName($id = null) {
+ $servers = $this->Server->find('first', array(
+ 'conditions' => array('Server.id' => $id)
+ ));
+ $name = $servers['Server']['url'];
+ return $name;
+ }
}
diff --git a/app/Controller/UsersController.php b/app/Controller/UsersController.php
old mode 100644
new mode 100755
index 4c82ce691..1ba51153e
--- a/app/Controller/UsersController.php
+++ b/app/Controller/UsersController.php
@@ -9,7 +9,7 @@ class UsersController extends AppController {
public $newkey;
- public $components = array('Security');
+ public $components = array('Acl','Security'); // TODO ACL, components
public $paginate = array(
'limit' => 60,
@@ -94,6 +94,9 @@ class UsersController extends AppController {
$this->request->data = $this->User->data;
}
$this->request->data['User']['org'] = $this->Auth->user('org');
+ // XXX ACL groups
+ $groups = $this->User->Group->find('list');
+ $this->set(compact('groups'));
}
/**
@@ -171,6 +174,9 @@ class UsersController extends AppController {
$this->newkey = $this->User->generateAuthKey();
$this->set('authkey', $this->newkey);
}
+ // XXX ACL groups
+ $groups = $this->User->Group->find('list');
+ $this->set(compact('groups'));
}
/**
@@ -190,9 +196,48 @@ class UsersController extends AppController {
foreach (array_keys($this->request->data['User']) as $field) {
if($field != 'password') array_push($fields, $field);
}
+ // TODO Audit, extraLog, fields get orig
+ $fieldsOldValues = array();
+ foreach ($fields as $field) {
+ if($field != 'confirm_password') array_push($fieldsOldValues, $this->User->field($field));
+ else array_push($fieldsOldValues, $this->User->field('password'));
+ }
+ // TODO Audit, extraLog, fields get orig END
if ("" != $this->request->data['User']['password'])
$fields[] = 'password';
if ($this->User->save($this->request->data, true, $fields)) {
+ // TODO Audit, extraLog, fields compare
+ // newValues to array
+ $fieldsNewValues = array();
+ foreach ($fields as $field) {
+ if ($field != 'confirm_password') {
+ $newValue = $this->data['User'][$field];
+ if (gettype($newValue) == 'array') {
+ $newValueStr = '';
+ $cP = 0;
+ foreach ($newValue as $newValuePart) {
+ if ($cP < 2) $newValueStr .= '-' . $newValuePart;
+ else $newValueStr = $newValuePart . $newValueStr;
+ $cP++;
+ }
+ array_push($fieldsNewValues, $newValueStr);
+ }
+ else array_push($fieldsNewValues, $newValue);
+ }
+ else array_push($fieldsNewValues, $this->data['User']['password']);
+ }
+ // compare
+ $fieldsResultStr = '';
+ $c = 0;
+ foreach ($fields as $field) {
+ if (isset($fieldsOldValues[$c]) && $fieldsOldValues[$c] != $fieldsNewValues[$c]) {
+ if($field != 'confirm_password') $fieldsResultStr = $fieldsResultStr . ', ' . $field . ' (' . $fieldsOldValues[$c] . ') => (' . $fieldsNewValues[$c] . ')';
+ }
+ $c++;
+ }
+ $fieldsResultStr = substr($fieldsResultStr, 2);
+ $this->extraLog("edit", "user", $fieldsResultStr); // TODO Audit, check: modify User
+ // TODO Audit, extraLog, fields compare END
$this->Session->setFlash(__('The user has been saved'));
$this->_refreshAuth(); // in case we modify ourselves
$this->redirect(array('action' => 'index'));
@@ -206,6 +251,13 @@ class UsersController extends AppController {
$this->request->data = $this->User->data;
}
+ // TODO ACL CLEANUP combobox for orgs
+ $orgIds = array('ADMIN', 'NCIRC', 'Other MOD');
+ $orgIds = $this->_arrayToValuesIndexArray($orgIds);
+ $this->set('orgIds', compact('orgIds'));
+ // XXX ACL, Groups in Users
+ $groups = $this->User->Group->find('list');
+ $this->set(compact('groups'));
}
/**
@@ -234,6 +286,7 @@ class UsersController extends AppController {
public function login() {
if ($this->Auth->login()) {
+ $this->extraLog("login"); // TODO Audit, extraLog, check: customLog i.s.o. extraLog, no auth user?: $this->User->customLog('login', $this->Auth->user('id'), array('title' => '','user_id' => $this->Auth->user('id'),'email' => $this->Auth->user('email'),'org' => 'IN2'));
$this->redirect($this->Auth->redirect());
} else {
// don't display authError before first login attempt
@@ -253,7 +306,7 @@ class UsersController extends AppController {
}
// News page
- $newNewsdate = new DateTime("2012-03-27");
+ $newNewsdate = new DateTime("2012-03-27"); // TODO general, fixed odd date??
$newsdate = new DateTime($this->Auth->user('newsread'));
if ($newNewsdate > $newsdate) {
$this->redirect(array('action' => 'news'));
@@ -264,6 +317,7 @@ class UsersController extends AppController {
}
public function logout() {
+ $this->extraLog("logout"); // TODO Audit, extraLog, check: customLog i.s.o. extraLog, $this->User->customLog('logout', $this->Auth->user('id'), array());
$this->Session->setFlash('Good-Bye');
$this->redirect($this->Auth->logout());
}
@@ -360,4 +414,65 @@ class UsersController extends AppController {
$this->_refreshAuth(); // refresh auth info
}
+ public function extraLog($action = null, $description = null, $fieldsResult = null) { // TODO move audit to AuditsController?
+ // new data
+ $userId = $this->Auth->user('id');
+ $model = 'User';
+ $modelId = $this->Auth->user('id');
+ if ($action == 'login') {
+ $description = "User (" . $this->Auth->user('id') . "): " . $this->data['User']['email'];
+ } elseif ($action == 'logout') {
+ $description = "User (" . $this->Auth->user('id') . "): " . $this->Auth->user('email');
+ } else { // edit
+ $description = "User (" . $this->User->id . "): " . $this->data['User']['email'];
+ }
+
+ // query
+ $this->Log = ClassRegistry::init('Log');
+ $this->Log->create();
+ $this->Log->save(array(
+ 'org' => $this->Auth->user('org'),
+ 'email' => $this->Auth->user('email'),
+ 'action' => $action,
+ 'title' => $description,
+ 'change' => $fieldsResult));
+
+ // write to syslogd as well
+ App::import('Lib', 'SysLog.SysLog');
+ $syslog = new SysLog();
+ if ($fieldsResult) $syslog->write('notice', $description . ' -- ' . $action . ' -- ' . $fieldsResult);
+ else $syslog->write('notice', $description . ' -- ' . $action);
+ }
+
+/**
+ * Used for fields_before and fields for audit
+ *
+ * @param $array
+ */
+ public function arrayCopy(array $array) {
+ $result = array();
+ foreach ($array as $key => $val) {
+ if (is_array( $val)) {
+ $result[$key] = arrayCopy($val);
+ } elseif (is_object($val)) {
+ $result[$key] = clone $val;
+ } else {
+ $result[$key] = $val;
+ }
+ }
+ return $result;
+ }
+
+ public function setgroupid($fk = '2') {
+ $params = array(
+ 'conditions' => array('User.group_id' => ''),
+ 'recursive' => 0,
+ 'fields' => array('User.id'),
+ );
+ $users = $this->User->find('all', $params);
+ foreach ($users as $user) {
+ $this->User->id = $user['User']['id'];
+ $this->User->saveField('group_id', $fk);
+ }
+ }
}
diff --git a/app/MYSQL.correlation.sql b/app/MYSQL.correlation.sql
index cb5e42243..355bf8cbf 100755
--- a/app/MYSQL.correlation.sql
+++ b/app/MYSQL.correlation.sql
@@ -5,6 +5,11 @@ CREATE TABLE `correlations` (
`1_attribute_id` int(11) NOT NULL,
`event_id` int(11) NOT NULL,
`attribute_id` int(11) NOT NULL,
- `date` date NOT NULL,
+ `org` varchar(255) COLLATE utf8_bin NOT NULL,
+ `private` tinyint(1) NOT NULL,
+ `date` date NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=118 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+-- ALTER TABLE `correlations` ADD private tinyint(1) NOT NULL;
+-- ALTER TABLE `correlations` ADD org varchar(255) COLLATE utf8_bin NOT NULL;
\ No newline at end of file
diff --git a/app/MYSQL.private.sql b/app/MYSQL.private.sql
new file mode 100644
index 000000000..2a2ccb228
--- /dev/null
+++ b/app/MYSQL.private.sql
@@ -0,0 +1,8 @@
+ALTER TABLE `events` ADD `cluster` tinyint(1) NOT NULL;
+ALTER TABLE `attributes` ADD `cluster` tinyint(1) NOT NULL;
+
+ALTER TABLE `events` ADD `pull` tinyint(1) NOT NULL;
+ALTER TABLE `attributes` ADD `pull` tinyint(1) NOT NULL;
+
+ALTER TABLE `correlations` ADD private tinyint(1) NOT NULL;
+ALTER TABLE `correlations` ADD org varchar(255) COLLATE utf8_bin NOT NULL;
\ No newline at end of file
diff --git a/app/Model/AppModel.php b/app/Model/AppModel.php
index 94e5e5f39..d126ce95b 100644
--- a/app/Model/AppModel.php
+++ b/app/Model/AppModel.php
@@ -21,6 +21,7 @@
*/
App::uses('Model', 'Model');
+App::uses('LogableBehavior', 'Assets.models/behaviors');
/**
* Application model for Cake.
diff --git a/app/Model/Attribute.php b/app/Model/Attribute.php
index a3ce44cb0..b045aa315 100644
--- a/app/Model/Attribute.php
+++ b/app/Model/Attribute.php
@@ -1,4 +1,5 @@
array( // TODO Audit, logable
+ 'userModel' => 'User',
+ 'userKey' => 'user_id',
+ 'change' => 'full'
+ ));
+
/**
* Display field
*
@@ -17,24 +28,30 @@ class Attribute extends AppModel {
*/
public $displayField = 'value';
+/**
+ * Virtual field
+ *
+ * @var array
+ */
public $virtualFields = array(
'value' => 'IF (Attribute.value2="", Attribute.value1, CONCAT(Attribute.value1, "|", Attribute.value2))',
'category_order' => 'IF (Attribute.category="Internal reference", "a",
-IF (Attribute.category="Antivirus detection", "b",
-IF (Attribute.category="Payload delivery", "c",
-IF (Attribute.category="Payload installation", "d",
-IF (Attribute.category="Artifacts dropped", "e",
-IF (Attribute.category="Persistence mechanism", "f",
-IF (Attribute.category="Network activity", "g",
-IF (Attribute.category="Payload type", "h",
-IF (Attribute.category="Attribution", "i",
-IF (Attribute.category="External analysis", "j", "k"))))))))))'); // TODO hardcoded
+ IF (Attribute.category="Antivirus detection", "b",
+ IF (Attribute.category="Payload delivery", "c",
+ IF (Attribute.category="Payload installation", "d",
+ IF (Attribute.category="Artifacts dropped", "e",
+ IF (Attribute.category="Persistence mechanism", "f",
+ IF (Attribute.category="Network activity", "g",
+ IF (Attribute.category="Payload type", "h",
+ IF (Attribute.category="Attribution", "i",
+ IF (Attribute.category="External analysis", "j", "k"))))))))))'
+ ); // TODO hardcoded
/**
- * Description field
+ * Field Descriptions
* explanations of certain fields to be used in various views
*
- * @var array
+ * @public array
*/
public $fieldDescriptions = array(
'signature' => array('desc' => 'Is this attribute eligible to automatically create an IDS signature (network IDS or host IDS) out of it ?'),
@@ -143,7 +160,7 @@ IF (Attribute.category="External analysis", "j", "k"))))))))))'); // TODO hardc
)
);
- public $order = array("Attribute.event_id" => "DESC", "Attribute.type" => "ASC");
+ public $order = array("Attribute.event_id" => "DESC", "Attribute.type" => "ASC");
/**
* Validation rules
@@ -257,6 +274,52 @@ IF (Attribute.category="External analysis", "j", "k"))))))))))'); // TODO hardc
),
);
+ public function __construct($id = false, $table = null, $ds = null) {
+ parent::__construct($id, $table, $ds);
+
+ if ('true' == Configure::read('CyDefSIG.private')) {
+
+ $this->virtualFields = Set::merge($this->virtualFields,array(
+ 'sharing' => 'IF (Attribute.private=true, "Org", IF (Attribute.cluster=true, "Server", IF (Attribute.pull=true, "Pull only", "All")))',
+ ));
+
+ $this->fieldDescriptions = Set::merge($this->fieldDescriptions,array(
+ 'sharing' => array('desc' => 'This field tells how and if the attribute should be shared with other CyDefSIG users'),
+ ));
+
+ $this->validate = Set::merge($this->validate,array(
+ 'cluster' => array(
+ 'boolean' => array(
+ 'rule' => array('boolean'),
+ //'message' => 'Your custom message here',
+ //'allowEmpty' => false,
+ 'required' => false,
+ //'last' => false, // Stop validation after this rule
+ //'on' => 'create', // Limit validation to 'create' or 'update' operations
+ ),
+ ),
+ 'pull' => array(
+ 'boolean' => array(
+ 'rule' => array('boolean'),
+ //'message' => 'Your custom message here',
+ //'allowEmpty' => false,
+ 'required' => false,
+ //'last' => false, // Stop validation after this rule
+ //'on' => 'create', // Limit validation to 'create' or 'update' operations
+ ),
+ ),
+ 'sharing' => array(
+ 'rule' => array('inList', array('Org', 'Server', 'Pull only')),
+ //'message' => 'Your custom message here',
+ 'allowEmpty' => false,
+ 'required' => false,
+ //'last' => false, // Stop validation after this rule
+ //'on' => 'create', // Limit validation to 'create' or 'update' operations
+ ),
+ ));
+ }
+ }
+
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
@@ -345,6 +408,32 @@ IF (Attribute.category="External analysis", "j", "k"))))))))))'); // TODO hardc
}
}
+ public function massageData(&$data) {
+ switch ($data['Attribute']['sharing']) {
+ case 'Org':
+ $data['Attribute']['private'] = true;
+ $data['Attribute']['cluster'] = false;
+ $data['Attribute']['pull'] = false;
+ break;
+ case 'Server':
+ $data['Attribute']['private'] = false;
+ $data['Attribute']['cluster'] = true;
+ $data['Attribute']['pull'] = false;
+ break;
+ case 'Pull only':
+ $data['Attribute']['private'] = false;
+ $data['Attribute']['cluster'] = false;
+ $data['Attribute']['pull'] = true;
+ break;
+ case 'All':
+ $data['Attribute']['private'] = false;
+ $data['Attribute']['cluster'] = false;
+ $data['Attribute']['pull'] = false;
+ break;
+ }
+ return $data;
+ }
+
public function beforeValidate() {
// remove leading and trailing blanks
$this->data['Attribute']['value'] = trim($this->data['Attribute']['value']);
@@ -682,10 +771,70 @@ IF (Attribute.category="External analysis", "j", "k"))))))))))'); // TODO hardc
}
}
+/**
+ * add_attachment method
+ *
+ * @return void
+ */
+ public function uploadAttachment($fileP, $realFileName, $malware, $eventId = null, $category = null, $extraPath = '', $fullFileName = '') {
+ // Check if there were problems with the file upload
+ // only keep the last part of the filename, this should prevent directory attacks
+ $filename = basename($fileP);
+ $tmpfile = new File($fileP);
+
+ // save the file-info in the database
+ $this->create();
+ $this->data['Attribute']['event_id'] = $eventId;
+ if ($malware) {
+ $this->data['Attribute']['category'] = $category ? $category : "Payload delivery";
+ $this->data['Attribute']['type'] = "malware-sample";
+ $this->data['Attribute']['value'] = $fullFileName ? $fullFileName . '|' . $tmpfile->md5() : $filename . '|' . $tmpfile->md5(); // TODO gives problems with bigger files
+ $this->data['Attribute']['to_ids'] = 1; // LATER let user choose to send this to IDS
+ } else {
+ $this->data['Attribute']['category'] = $category ? $category : "Artifacts dropped";
+ $this->data['Attribute']['type'] = "attachment";
+ $this->data['Attribute']['value'] = $fullFileName ? $fullFileName : $realFileName;
+ $this->data['Attribute']['to_ids'] = 0;
+ }
+
+ if ($this->save($this->data)) {
+ // attribute saved correctly in the db
+ } else {
+ // do some?
+ }
+
+ // no errors in file upload, entry already in db, now move the file where needed and zip it if required.
+ // no sanitization is required on the filename, path or type as we save
+ // create directory structure
+ $rootDir = APP . DS . "files" . DS . $eventId;
+ $dir = new Folder($rootDir, true);
+ // move the file to the correct location
+ $destpath = $rootDir . DS . $this->getId(); // id of the new attribute in the database
+ $file = new File ($destpath);
+ $zipfile = new File ($destpath . '.zip');
+ $fileInZip = new File($rootDir . DS . $extraPath . $filename); // FIXME do sanitization of the filename
+
+ // zip and password protect the malware files
+ if ($malware) {
+ // TODO check if CakePHP has no easy/safe wrapper to execute commands
+ $execRetval = '';
+ $execOutput = array();
+ exec("zip -j -P infected " . $zipfile->path . ' "' . addslashes($fileInZip->path) . '"', $execOutput, $execRetval);
+ if ($execRetval != 0) { // not EXIT_SUCCESS
+ // do some?
+ };
+ $fileInZip->delete(); // delete the original not-zipped-file
+ rename($zipfile->path, $file->path); // rename the .zip to .nothing
+ } else {
+ $fileAttach = new File($fileP);
+ rename($fileAttach->path, $file->path);
+ }
+ }
+
private function __afterSaveCorrelation($attribute) {
$this->__beforeDeleteCorrelation($attribute);
// re-add
- $this->setRelatedAttributes($attribute, array('Attribute.id', 'Attribute.event_id', 'Event.date'));
+ $this->setRelatedAttributes($attribute, array('Attribute.id', 'Attribute.event_id', 'Attribute.private', 'Event.date', 'Event.org'));
}
private function __beforeDeleteCorrelation($attribute) {
@@ -741,7 +890,7 @@ IF (Attribute.category="External analysis", "j", "k"))))))))))'); // TODO hardc
$params = array(
'conditions' => array('Event.id' => $relatedAttribute['Attribute']['event_id']),
'recursive' => 0,
- 'fields' => array('Event.date')
+ 'fields' => array('Event.date', 'Event.org')
);
$eventDate = $this->Event->find('first', $params);
$this->Correlation = ClassRegistry::init('Correlation');
@@ -750,6 +899,8 @@ IF (Attribute.category="External analysis", "j", "k"))))))))))'); // TODO hardc
'Correlation' => array(
'1_event_id' => $attribute['event_id'], '1_attribute_id' => $attribute['id'],
'event_id' => $relatedAttribute['Attribute']['event_id'], 'attribute_id' => $relatedAttribute['Attribute']['id'],
+ 'org' => $eventDate['Event']['org'],
+ 'private' => $relatedAttribute['Attribute']['private'],
'date' => $eventDate['Event']['date']))
);
}
diff --git a/app/Model/Event.php b/app/Model/Event.php
old mode 100755
new mode 100644
index 25b5bb0dc..801825d72
--- a/app/Model/Event.php
+++ b/app/Model/Event.php
@@ -8,6 +8,14 @@ App::uses('AppModel', 'Model');
*/
class Event extends AppModel {
+ public $name = 'Event'; // TODO general
+
+ public $actsAs = array('SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
+ 'userModel' => 'User',
+ 'userKey' => 'user_id',
+ 'change' => 'full'
+ ));
+
/**
* Display field
*
@@ -15,6 +23,8 @@ class Event extends AppModel {
*/
public $displayField = 'id';
+ public $virtualFields = array();
+
/**
* Description field
*
@@ -23,7 +33,8 @@ class Event extends AppModel {
public $fieldDescriptions = array(
'risk' => array('desc' => 'Risk levels: *low* means mass-malware, *medium* means APT malware, *high* means sophisticated APT malware or 0-day attack', 'formdesc' => 'Risk levels: low: mass-malware medium: APT malware high: sophisticated APT malware or 0-day attack'),
'private' => array('desc' => 'This field tells if the event should be shared with other CyDefSIG servers'),
- 'classification' => array('desc' => 'Set the Traffic Light Protocol classification.
TLP:AMBER - Share only within the organization on a need-to-know basisTLP:GREEN:NeedToKnow - Share within your constituency on the need-to-know basis.TLP:GREEN - Share within your constituency. ')
+ 'classification' => array('desc' => 'Set the Traffic Light Protocol classification. TLP:AMBER - Share only within the organization on a need-to-know basisTLP:GREEN:NeedToKnow - Share within your constituency on the need-to-know basis.TLP:GREEN - Share within your constituency. '),
+ 'submittedfile' => array('desc' => 'GFI sandbox: export upload', 'formdesc' => 'GFI sandbox: export upload'),
);
/**
@@ -80,6 +91,16 @@ class Event extends AppModel {
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
+ 'user_id' => array(
+ 'numeric' => array(
+ 'rule' => array('numeric'),
+ //'message' => 'Your custom message here',
+ //'allowEmpty' => false,
+ //'required' => false,
+ //'last' => false, // Stop validation after this rule
+ //'on' => 'create', // Limit validation to 'create' or 'update' operations
+ ),
+ ),
'published' => array(
'boolean' => array(
'rule' => array('boolean'),
@@ -120,6 +141,52 @@ class Event extends AppModel {
//),
);
+ public function __construct($id = false, $table = null, $ds = null) {
+ parent::__construct($id, $table, $ds);
+
+ if ('true' == Configure::read('CyDefSIG.private')) {
+
+ $this->virtualFields = Set::merge($this->virtualFields,array(
+ 'sharing' => 'IF (Event.private=true, "Org", IF (Event.cluster=true, "Server", IF (Event.pull=true, "Pull only", "All")))',
+ ));
+
+ $this->fieldDescriptions = Set::merge($this->fieldDescriptions,array(
+ 'sharing' => array('desc' => 'This field tells how and if the event should be shared with other CyDefSIG users'),
+ ));
+
+ $this->validate = Set::merge($this->validate,array(
+ 'cluster' => array(
+ 'boolean' => array(
+ 'rule' => array('boolean'),
+ //'message' => 'Your custom message here',
+ //'allowEmpty' => false,
+ 'required' => false,
+ //'last' => false, // Stop validation after this rule
+ //'on' => 'create', // Limit validation to 'create' or 'update' operations
+ ),
+ ),
+ 'pull' => array(
+ 'boolean' => array(
+ 'rule' => array('boolean'),
+ //'message' => 'Your custom message here',
+ //'allowEmpty' => false,
+ 'required' => false,
+ //'last' => false, // Stop validation after this rule
+ //'on' => 'create', // Limit validation to 'create' or 'update' operations
+ ),
+ ),
+ 'sharing' => array(
+ 'rule' => array('inList', array('Org', 'Server', 'Pull only')),
+ //'message' => 'Your custom message here',
+ 'allowEmpty' => false,
+ 'required' => false,
+ //'last' => false, // Stop validation after this rule
+ //'on' => 'create', // Limit validation to 'create' or 'update' operations
+ ),
+ ));
+ }
+ }
+
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
@@ -165,13 +232,67 @@ class Event extends AppModel {
)
);
+ public function beforeDelete() {
+ // delete event from the disk
+ $this->read(); // first read the event from the db
+ // FIXME secure this filesystem access/delete by not allowing to change directories or go outside of the directory container.
+ // only delete the file if it exists
+ $filepath = APP . "files" . DS . $this->data['Event']['id'];
+ App::uses('Folder', 'Utility');
+ $file = new Folder ($filepath);
+ if (is_dir($filepath)) {
+ if (!$this->destroyDir($filepath)) {
+ throw new InternalErrorException('Delete of event file directory failed. Please report to administrator.');
+ }
+ }
+ }
+
+ public function destroyDir($dir) {
+ if (!is_dir($dir) || is_link($dir)) return unlink($dir);
+ foreach (scandir($dir) as $file) {
+ if ($file == '.' || $file == '..') continue;
+ if (!$this->destroyDir($dir . DS . $file)) {
+ chmod($dir . DS . $file, 0777);
+ if (!$this->destroyDir($dir . DS . $file)) return false;
+ };
+ }
+ return rmdir($dir);
+ }
+
public function beforeValidate() {
+ parent::beforeValidate();
// generate UUID if it doesn't exist
if (empty($this->data['Event']['uuid'])) {
$this->data['Event']['uuid'] = String::uuid();
}
}
+ public function massageData(&$data) {
+ switch ($data['Event']['sharing']) {
+ case 'Org':
+ $data['Event']['private'] = true;
+ $data['Event']['cluster'] = false;
+ $data['Event']['pull'] = false;
+ break;
+ case 'Server':
+ $data['Event']['private'] = false;
+ $data['Event']['cluster'] = true;
+ $data['Event']['pull'] = false;
+ break;
+ case 'Pull only':
+ $data['Event']['private'] = false;
+ $data['Event']['cluster'] = false;
+ $data['Event']['pull'] = true;
+ break;
+ case 'All':
+ $data['Event']['private'] = false;
+ $data['Event']['cluster'] = false;
+ $data['Event']['pull'] = false;
+ break;
+ }
+ return $data;
+ }
+
public function isOwnedByOrg($eventid, $org) {
return $this->field('id', array('id' => $eventid, 'org' => $org)) === $eventid;
}
@@ -239,9 +360,12 @@ class Event extends AppModel {
* @return bool true if success, error message if failed
*/
public function uploadEventToServer($event, $server, $HttpSocket=null) {
- if (true == $event['Event']['private']) { // never upload private events
+ if (('true' != Configure::read('CyDefSIG.private')) && (true == $event['Event']['private'])) { // never upload private events
return "Event is private and non exportable";
}
+ if (('true' == Configure::read('CyDefSIG.private')) && (true == $event['Event']['pull'])) {
+ return "Event is pull only and non exportable";
+ }
$url = $server['Server']['url'];
$authkey = $server['Server']['authkey'];
diff --git a/app/Model/Group.php b/app/Model/Group.php
new file mode 100755
index 000000000..0cf91d66f
--- /dev/null
+++ b/app/Model/Group.php
@@ -0,0 +1,62 @@
+ array(
+ 'notempty' => array(
+ 'rule' => array('notempty'),
+ //'message' => 'Your custom message here',
+ //'allowEmpty' => false,
+ //'required' => false,
+ //'last' => false, // Stop validation after this rule
+ //'on' => 'create', // Limit validation to 'create' or 'update' operations
+ ),
+ ),
+ );
+
+/**
+ * hasMany associations
+ *
+ * @var array
+ */
+ public $hasMany = array(
+ 'User' => array(
+ 'className' => 'User',
+ 'foreignKey' => 'group_id',
+ 'dependent' => false,
+ 'conditions' => '',
+ 'fields' => '',
+ 'order' => '',
+ 'limit' => '',
+ 'offset' => '',
+ 'exclusive' => '',
+ 'finderQuery' => '',
+ 'counterQuery' => ''
+ )
+ );
+
+/**
+ * TODO ACL: 1: be requester to CakePHP ACL system
+ *
+ * @var unknown_type
+ */
+ public $actsAs = array('Acl' => array('type' => 'requester'), 'MagicTools.OrphansProtectable');
+
+/**
+ * TODO ACL: 2: hook Group into CakePHP ACL system (so link to aros)
+ */
+ public function parentNode() {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/app/Model/Log.php b/app/Model/Log.php
new file mode 100755
index 000000000..168ec5e90
--- /dev/null
+++ b/app/Model/Log.php
@@ -0,0 +1,31 @@
+ array(
+ 'rule' => array('inList', array(
+ 'login',
+ 'logout',
+ 'add',
+ 'edit',
+ 'delete',
+ 'publish' // FIXME remove this once all attributes have a category. Otherwise sigs without category are not shown in the list
+ )),
+ 'message' => 'Options : ...'
+ )
+ );
+
+ public $actionDefinitions = array(
+ 'login' => array('desc' => 'Login action', 'formdesc' => "Login action"),
+ 'logout' => array('desc' => 'Logout action', 'formdesc' => "Logout action"),
+ 'add' => array('desc' => 'Add action', 'formdesc' => "Add action"),
+ 'edit' => array('desc' => 'Edit action', 'formdesc' => "Edit action"),
+ 'delete' => array('desc' => 'Delete action', 'formdesc' => "Delete action"),
+ 'publish' => array('desc' => "Publish action", 'formdesc' => "Publish action")
+ );
+}
\ No newline at end of file
diff --git a/app/Model/Server.php b/app/Model/Server.php
old mode 100644
new mode 100755
index b16b6f7d9..29af76cd8
--- a/app/Model/Server.php
+++ b/app/Model/Server.php
@@ -6,6 +6,14 @@ App::uses('AppModel', 'Model');
*/
class Server extends AppModel {
+ public $name = 'Server'; // TODO general
+
+ public $actsAs = array('SysLogLogable.SysLogLogable' => array( // TODO Audit, logable, check: 'userModel' and 'userKey' can be removed given default
+ 'userModel' => 'User',
+ 'userKey' => 'user_id',
+ 'change' => 'full'
+ ));
+
/**
* Display field
*
@@ -94,4 +102,4 @@ class Server extends AppModel {
public function isOwnedByOrg($serverid, $org) {
return $this->field('id', array('id' => $serverid, 'org' => $org)) === $serverid;
}
-}
\ No newline at end of file
+}
diff --git a/app/Model/User.php b/app/Model/User.php
index 3956d8b7b..39ea0b654 100755
--- a/app/Model/User.php
+++ b/app/Model/User.php
@@ -17,6 +17,14 @@ class User extends AppModel {
*/
public $displayField = 'email';
+ public $orgField = 'org'; // TODO Audit, LogableBehaviour + org
+/**
+ * Model Name
+ *
+ * @var string
+ */
+ public $name = 'User'; // TODO general
+
/**
* Validation rules
*
@@ -69,6 +77,16 @@ class User extends AppModel {
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
+ 'org_id' => array(
+ 'notempty' => array(
+ 'rule' => array('notempty'),
+ 'message' => 'Please specify the organisation ID where you are working.', // TODO ACL, org_id in Users
+ //'allowEmpty' => false,
+ //'required' => false,
+ //'last' => false, // Stop validation after this rule
+ //'on' => 'create', // Limit validation to 'create' or 'update' operations
+ ),
+ ),
'email' => array(
'email' => array(
'rule' => array('email'),
@@ -162,6 +180,21 @@ class User extends AppModel {
//The Associations below have been created with all possible keys, those that are not needed can be removed
+/**
+ * belongsTo associations
+ *
+ * @var array
+ */
+ public $belongsTo = array(
+ 'Group' => array(
+ 'className' => 'Group',
+ 'foreignKey' => 'group_id',
+ 'conditions' => '',
+ 'fields' => '',
+ 'order' => ''
+ )
+ );
+
/**
* hasMany associations
*
@@ -183,6 +216,38 @@ class User extends AppModel {
)
);
+/**
+ * TODO ACL: 1: be requester to CakePHP ACL system
+ */
+ public $actsAs = array('Acl' => array('type' => 'requester', 'enabled' => false)); // TODO ACL, + 'enabled' => false
+
+/**
+ * TODO ACL: 2: hook User into CakePHP ACL system (so link to aros)
+ */
+ public function parentNode() {
+ if (!$this->id && empty($this->data)) {
+ return null;
+ }
+ if (isset($this->data['User']['group_id'])) {
+ $groupId = $this->data['User']['group_id'];
+ } else {
+ $groupId = $this->field('group_id');
+ }
+ if (!$groupId) {
+ return null;
+ } else {
+ return array('Group' => array('id' => $groupId));
+ }
+ }
+
+/**
+ * TODO ACL: 3: rights on Groups: http://stackoverflow.com/questions/6154285/aros-table-in-cakephp-is-still-including-users-even-after-bindnode
+ */
+ public function bindNode($user) {
+ // return array('model' => 'Group', 'foreign_key' => $user['User']['group_id']);
+ return array('Group' => array('id' => $user['User']['group_id']));
+ }
+
public function beforeSave() {
if (isset($this->data[$this->alias]['password'])) {
$this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password']);
diff --git a/app/Plugin/MagicTools/Model/Behavior/OrphansProtectableBehavior.php b/app/Plugin/MagicTools/Model/Behavior/OrphansProtectableBehavior.php
new file mode 100644
index 000000000..399c935b1
--- /dev/null
+++ b/app/Plugin/MagicTools/Model/Behavior/OrphansProtectableBehavior.php
@@ -0,0 +1,125 @@
+_deletionError = null; // Stores the deletion error message
+ $Model->orphansProtectableOptions = array_merge(array(
+ 'listPossibleOrphans' => true,
+ 'htmlError' => false
+ ), $settings);
+ }
+
+ /**
+ * Checks if there would be orphaned record left behind after deletion of this record; if so, deletion is prevented.
+ *
+ * @param $model Model
+ * @param $cascade boolean
+ * @return boolean
+ */
+ function beforeDelete(&$Model, $cascade) {
+ if($cascade) return true;
+ return !$Model->wouldLeaveOrphanedRecordsBehind();
+ }
+
+ /**
+ * Checks if deletion of this record would leave orphaned associated records behind.
+ *
+ * @param $model Model
+ * @return boolean
+ */
+ function wouldLeaveOrphanedRecordsBehind(&$Model) {
+ $possibleOrphans = array();
+
+ foreach($Model->hasMany as $model => $settings) {
+ // Is relationship is dependent?
+ if($settings['dependent']){ // Yes! Possible orphans are deleted, too!
+ // Do nothing
+ } else { // No! Possible orphans should be protected!
+ // Is there a possible orphan for this relation?
+ $Model->{$model}->recursive = -1;
+ $objects = $Model->{$model}->find('all', array('conditions' => array($settings['className'].'.'.$settings['foreignKey'] => $Model->id), 'order' => 'id asc'));
+ if(count($objects) > 0) { // Yes, there is at least one possible orphan!
+ $objectIds = array();
+ foreach($objects as $object) {
+ $objectIds[] = $object[$model]['id'];
+ }
+ $possibleOrphans[$model] = $objectIds;
+ }
+ }
+ }
+
+ // Would orphans be left behind?
+ if(count($possibleOrphans) > 0) { // Yes! Create deletion error message!
+ $Model->_deletionError = $Model->createDeletionError($possibleOrphans);
+ return true;
+ } else { // No!
+ return false;
+ }
+ }
+
+ /**
+ * Returns the deletion error message (if there is one).
+ *
+ * @param $model Model
+ * @return string
+ */
+ function getDeletionError(&$Model) {
+ return $Model->_deletionError;
+ }
+
+ /**
+ * Creates the deletion error message and returns it.
+ *
+ * @param $model Model
+ * @param $possibleOrphans array
+ * @return string
+ */
+ function createDeletionError(&$Model, $possibleOrphans) {
+ $errorParts = array();
+ foreach($possibleOrphans as $model => $ids) {
+ $count = count($ids);
+ $modelName = $count > 1 ? Inflector::pluralize($model) : $model;
+ $errorParts[] = $count.' '.__($modelName, true).' (ID: '.$Model->createDeletionErrorIds($model, $ids).')';
+ }
+ return __('it has the following dependent items', true).': '.implode($errorParts, ', ');
+ }
+
+ /**
+ * Creates a string containing HTML-links to comma separated IDs of the potentially orphaned records of the specified model.
+ *
+ * @param $model Model
+ * @param $orphanModel string
+ * @param $ids array
+ * @return string
+ */
+ function createDeletionErrorIds(&$Model, $orphanModel, $ids) {
+ $messageParts = array();
+ if($Model->orphansProtectableOptions['htmlError']) {
+ foreach($ids as $id) {
+ $messageParts[] = ''.$id.' '; // TODO: Noch unschön! --zivi-muh
+ }
+ } else {
+ $messageParts = $ids;
+ }
+ return implode($messageParts, ', ');
+ }
+}
+?>
\ No newline at end of file
diff --git a/app/Plugin/SysLogLogable/Model/Behavior/SysLogLogableBehavior.php b/app/Plugin/SysLogLogable/Model/Behavior/SysLogLogableBehavior.php
new file mode 100644
index 000000000..560b5f9ee
--- /dev/null
+++ b/app/Plugin/SysLogLogable/Model/Behavior/SysLogLogableBehavior.php
@@ -0,0 +1,220 @@
+settings[$Model->alias]['enabled']) {
+ return true;
+ }
+ if (isset($this->settings[$Model->alias]['skip']['add']) && $this->settings[$Model->alias]['skip']['add'] && $created) {
+ return true;
+ } elseif (isset($this->settings[$Model->alias]['skip']['edit']) && $this->settings[$Model->alias]['skip']['edit'] && !$created) {
+ return true;
+ }
+ $keys = array_keys($Model->data[$Model->alias]);
+ $diff = array_diff($keys, $this->settings[$Model->alias]['ignore']);
+ if (sizeof($diff) == 0 && empty($Model->logableAction)) {
+ return false;
+ }
+ if ($Model->id) {
+ $id = $Model->id;
+ } elseif ($Model->insertId) {
+ $id = $Model->insertId;
+ }
+ if (isset($this->schema[$this->settings[$Model->alias]['foreignKey']])) {
+ $logData['Log'][$this->settings[$Model->alias]['foreignKey']] = $id;
+ }
+ if (isset($this->schema['description'])) {
+ $logData['Log']['description'] = $Model->alias . ' ';
+ if (isset($Model->data[$Model->alias][$Model->displayField]) && $Model->displayField != $Model->primaryKey) {
+ $logData['Log']['description'] .= '"' . $Model->data[$Model->alias][$Model->displayField] . '" ';
+ }
+
+ if ($this->settings[$Model->alias]['description_ids']) {
+ $logData['Log']['description'] .= '(' . $id . ') ';
+ }
+
+ if ($created) {
+ $logData['Log']['description'] .= __('added', TRUE);
+ } else {
+ $logData['Log']['description'] .= __('updated', TRUE);
+ }
+ }
+ if (isset($this->schema['action'])) {
+ if ($created) {
+ $logData['Log']['action'] = 'add';
+ } else {
+ $logData['Log']['action'] = 'edit';
+ }
+
+ }
+ if (isset($this->schema['change'])) {
+ $logData['Log']['change'] = '';
+ $db_fields = array_keys($Model->schema());
+ $changed_fields = array();
+ foreach ( $Model->data[$Model->alias] as $key => $value ) {
+ if (isset($Model->data[$Model->alias][$Model->primaryKey]) && !empty($this->old) && isset($this->old[$Model->alias][$key])) {
+ $old = $this->old[$Model->alias][$key];
+ } else {
+ $old = '';
+ }
+ // TODO Audit, removed 'revision' as well
+ if ($key != 'revision' && $key != 'modified' && !in_array($key, $this->settings[$Model->alias]['ignore']) && $value != $old && in_array($key, $db_fields)) {
+ if ($this->settings[$Model->alias]['change'] == 'full') {
+ $changed_fields[] = $key . ' (' . $old . ') => (' . $value . ')';
+ } else if ($this->settings[$Model->alias]['change'] == 'serialize') {
+ $changed_fields[$key] = array(
+ 'old' => $old,
+ 'value' => $value);
+ } else {
+ $changed_fields[] = $key;
+ }
+ }
+ }
+ $changes = sizeof($changed_fields);
+ if ($changes == 0) {
+ return true;
+ }
+ if ($this->settings[$Model->alias]['change'] == 'serialize') {
+ $logData['Log']['change'] = serialize($changed_fields);
+ } else {
+ $logData['Log']['change'] = implode(', ', $changed_fields);
+ }
+ $logData['Log']['changes'] = $changes;
+ }
+ $this->_saveLog($Model, $logData);
+ }
+
+ function _saveLog(&$Model, $logData, $title = null) {
+
+ if ($title !== NULL) {
+ $logData['Log']['title'] = $title;
+ } elseif ($Model->displayField == $Model->primaryKey) {
+ $logData['Log']['title'] = $Model->alias . ' (' . $Model->id . ')';
+ } elseif (isset($Model->data[$Model->alias][$Model->displayField])) {
+ $logData['Log']['title'] = $Model->data[$Model->alias][$Model->displayField];
+ } else {
+ $logData['Log']['title'] = $Model->field($Model->displayField);
+ }
+
+ if (isset($this->schema[$this->settings[$Model->alias]['classField']])) {
+ // by miha nahtigal
+ $logData['Log'][$this->settings[$Model->alias]['classField']] = $Model->name;
+ }
+
+ if (isset($this->schema[$this->settings[$Model->alias]['foreignKey']]) && !isset($logData['Log'][$this->settings[$Model->alias]['foreignKey']])) {
+ if ($Model->id) {
+ $logData['Log'][$this->settings[$Model->alias]['foreignKey']] = $Model->id;
+ } elseif ($Model->insertId) {
+ $logData['Log'][$this->settings[$Model->alias]['foreignKey']] = $Model->insertId;
+ }
+ }
+
+ if (!isset($this->schema['action'])) {
+ unset($logData['Log']['action']);
+ } elseif (isset($Model->logableAction) && !empty($Model->logableAction)) {
+ $logData['Log']['action'] = implode(',', $Model->logableAction); // . ' ' . $logData['Log']['action'];
+ unset($Model->logableAction);
+ }
+
+ if (isset($this->schema['version_id']) && isset($Model->version_id)) {
+ $logData['Log']['version_id'] = $Model->version_id;
+ unset($Model->version_id);
+ }
+
+ if (isset($this->schema['ip']) && $this->userIP) {
+ $logData['Log']['ip'] = $this->userIP;
+ }
+
+ if (isset($this->schema[$this->settings[$Model->alias]['userKey']]) && $this->user) {
+ $logData['Log'][$this->settings[$Model->alias]['userKey']] = $this->user[$this->UserModel->alias][$this->UserModel->primaryKey];
+ }
+
+ if (isset($this->schema['description'])) {
+ if ($this->user && $this->UserModel) {
+ $logData['Log']['description'] .= ' by ' . $this->settings[$Model->alias]['userModel'] . ' "' . $this->user[$this->UserModel->alias][$this->UserModel->displayField] . '"';
+ if ($this->settings[$Model->alias]['description_ids']) {
+ $logData['Log']['description'] .= ' (' . $this->user[$this->UserModel->alias][$this->UserModel->primaryKey] . ')';
+ }
+
+ } else {
+ // UserModel is active, but the data hasnt been set. Assume system action.
+ $logData['Log']['description'] .= ' by System';
+ }
+ $logData['Log']['description'] .= '.';
+ }
+ if (isset($this->schema['email'])) { // TODO Audit, LogableBehevior email
+ if ($this->user && $this->UserModel) {
+ $logData['Log']['email'] = $this->user[$this->UserModel->alias][$this->UserModel->displayField];
+ } else {
+ // UserModel is active, but the data hasnt been set. Assume system action.
+ $logData['Log']['email'] = 'SYS';
+ }
+ }
+ if (isset($this->schema['org'])) { // TODO Audit, LogableBehevior org CHECK!!!
+ if ($this->user && $this->UserModel) {
+ $logData['Log']['org'] = $this->user[$this->UserModel->alias][$this->UserModel->orgField];
+ } else {
+ // UserModel is active, but the data hasnt been set. Assume system action.
+ $logData['Log']['org'] = 'SYS';
+ }
+ }
+ if (isset($this->schema['title'])) { // TODO LogableBehevior title
+ if ($this->user && $this->UserModel) { // $Model->data[$Model->alias][$Model->displayField]
+ switch ($Model->alias) {
+ case "User": // TODO Audit, not used here but done in UsersController
+ $title = 'User ('. $Model->data[$Model->alias]['id'].') '. $Model->data[$Model->alias]['email'];
+ break;
+ case "Event":
+ $this->Events = new EventsController();
+ $this->Events->constructClasses();
+ $title = 'Event ('. $Model->data[$Model->alias]['id'].'): '.$this->Events->getName($Model->data[$Model->alias]['id']);
+ $logData['Log']['title'] = $title;
+ break;
+ case "Attribute":
+ if (isset($Model->combinedKeys)) {
+ if (is_array($Model->combinedKeys)) {
+ $title = 'Attribute ('. $Model->data[$Model->alias]['id'].') '.'from Event ('. $Model->data[$Model->alias]['event_id'].'): '. $Model->data[$Model->alias][$Model->combinedKeys[1]].'/'. $Model->data[$Model->alias][$Model->combinedKeys[2]].' '. $Model->data[$Model->alias]['value1'];
+ $logData['Log']['title'] = $title;
+ }
+ }
+ break;
+ case "Server":
+ $this->Servers = new ServersController();
+ $this->Servers->constructClasses();
+ $title = 'Server ('. $Model->data[$Model->alias]['id'].'): '. $this->Servers->getName($Model->data[$Model->alias]['id']);
+ $logData['Log']['title'] = $title;
+ break;
+ default:
+ if (isset($Model->combinedKeys)) {
+ if (is_array($Model->combinedKeys)) {
+ $title = '';
+ foreach ($Model->combinedKeys as $combinedKey) {
+ $title .= '/'. $Model->data[$Model->alias][$combinedKey];
+ }
+ $title = substr($title ,1);
+ $logData['Log']['title'] = $title;
+ }
+ }
+ }
+ }
+ }
+ $this->Log->create($logData);
+ $this->Log->save(null, array(
+ 'validate' => false,
+ 'callbacks' => false));
+
+ // write to syslogd as well
+ $syslog = new SysLog();
+ if (isset($logData['Log']['change'])) {
+ $syslog->write('notice', $logData['Log']['description'].' -- '.$logData['Log']['change']);
+ } else {
+ $syslog->write('notice', $logData['Log']['description']);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/README.txt b/app/README.txt
index 4e24c94ee..9bc174af2 100755
--- a/app/README.txt
+++ b/app/README.txt
@@ -1,14 +1,25 @@
-
-TODOs
+TODOs v0.2.2 to v0.2.3
-----
+DB Update
+- UpdateShell with in/out
+
Auth
- Prevent bruteforce auth attempts
-implement auditing/logging system
-- add / edit events and signatures
-- failed / success logins (with source IP, headers,...)
+Acl
+- inactive buttons
+ - must be non-clickable.
+ - JavaScript include.
+ - DOM read and disable button_offXX.
+- clean-up to first cut.
+ - saveAcl, from GroupsController to AppController and inherit to *Controllers.
+
+auditing/logging system
+- logins
+ - add source IP (headers,...);
+ - failed logins.
Security
- force cookie reset after login
@@ -18,7 +29,7 @@ INSTALLATION INSTRUCTIONS
-------------------------
Install the following libraries:
apt-get install zip
-apt-get install pear
+apt-get install php-pear
pear install Crypt_GPG # need version >1.3.0
pear install Net_GeoIP
# ideally make sure geoip database is updated using crontab
@@ -80,6 +91,17 @@ Don't forget to change the email, password and authentication key after installa
+UPDATE INSTRUCTIONS
+-------------------
+
+To be sure, dump your database before updating.
+
+CyDefSIG from 0.2.2 to 0.2.3 needs a database migration and population.
+This is done executing /var/www/cydefsig/app/Console/shell/migrate-0.2.2-0.2.3.sh
+and answer (y)es to all the questions asked.
+
+
+
Recommended patches
-------------------
By default CakePHP exposes his name and version in email headers. Apply a patch to remove this behavior.
diff --git a/app/README.ubuntu.txt b/app/README.ubuntu.txt
new file mode 100755
index 000000000..c7b3bef46
--- /dev/null
+++ b/app/README.ubuntu.txt
@@ -0,0 +1,34 @@
+INSTALLATION INSTRUCTIONS
+-------------------------
+If on Ubuntu, besides the DocumentRoot,
+you have to change the AllowOverride from None to All as well.
+
+ DocumentRoot /var/www/cydefsig/app/webroot/
+
+ Options FollowSymLinks
+ AllowOverride All
+
+
+ Options Indexes FollowSymLinks MultiViews
+ AllowOverride All
+ Order allow,deny
+ allow from all
+
+
+Find the original below, for reference.
+
+ DocumentRoot /var/www
+
+
+ Options FollowSymLinks
+ AllowOverride None
+
+
+ Options Indexes FollowSymLinks MultiViews
+ AllowOverride None
+ Order allow,deny
+ allow from all
+
+
+Now /etc/init.d/apache2 restart
+and you are done, and now able to use the application.
\ No newline at end of file
diff --git a/app/View/Attributes/add.ctp b/app/View/Attributes/add.ctp
index 8ac677f89..782093bec 100755
--- a/app/View/Attributes/add.ctp
+++ b/app/View/Attributes/add.ctp
@@ -14,9 +14,15 @@ echo $this->Form->input('type', array(
'empty' => '(first choose category)'
));
if ('true' == Configure::read('CyDefSIG.sync')) {
- echo $this->Form->input('private', array(
- 'before' => $this->Html->div('forminfo', isset($attrDescriptions['private']['formdesc']) ? $attrDescriptions['private']['formdesc'] : $attrDescriptions['private']['desc']),
- ));
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ echo $this->Form->input('sharing', array('label' => 'Private',
+ 'before' => $this->Html->div('forminfo', isset($attrDescriptions['sharing']['formdesc']) ? $attrDescriptions['sharing']['formdesc'] : $attrDescriptions['sharing']['desc']),
+ ));
+ } else {
+ echo $this->Form->input('private', array(
+ 'before' => $this->Html->div('forminfo', isset($attrDescriptions['private']['formdesc']) ? $attrDescriptions['private']['formdesc'] : $attrDescriptions['private']['desc']),
+ ));
+ }
}
echo $this->Form->input('to_ids', array(
'checked' => true,
diff --git a/app/View/Attributes/add_attachment.ctp b/app/View/Attributes/add_attachment.ctp
index affc7a2bc..e729e4dbd 100755
--- a/app/View/Attributes/add_attachment.ctp
+++ b/app/View/Attributes/add_attachment.ctp
@@ -14,8 +14,13 @@ echo $this->Form->input('malware', array(
'after' => ' Tick this box to neutralize the sample. Every malware sample will be zipped with the password "infected"',
));
if ('true' == Configure::read('CyDefSIG.sync')) {
- echo $this->Form->input('private', array(
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ echo $this->Form->input('sharing', array('label' => 'Private',
+ 'before' => $this->Html->div('forminfo', isset($attrDescriptions['sharing']['formdesc']) ? $attrDescriptions['sharing']['formdesc'] : $attrDescriptions['sharing']['desc']),));
+ } else {
+ echo $this->Form->input('private', array(
'before' => $this->Html->div('forminfo', isset($attrDescriptions['private']['formdesc']) ? $attrDescriptions['private']['formdesc'] : $attrDescriptions['private']['desc']),));
+ }
}
// link an onchange event to the form elements
$this->Js->get('#AttributeType')->event('change', 'showFormInfo("#AttributeType")');
diff --git a/app/View/Attributes/edit.ctp b/app/View/Attributes/edit.ctp
index 7af48bcef..f291de012 100755
--- a/app/View/Attributes/edit.ctp
+++ b/app/View/Attributes/edit.ctp
@@ -1,3 +1,7 @@
+
Form->create('Attribute');?>
@@ -12,9 +16,15 @@ if ($attachment) {
echo $this->Form->input('type', array('between' => $this->Html->div('forminfo', '', array('id' => 'AttributeTypeDiv'))));
}
if ('true' == Configure::read('CyDefSIG.sync')) {
- echo $this->Form->input('private', array(
- 'before' => $this->Html->div('forminfo', isset($attrDescriptions['private']['formdesc']) ? $attrDescriptions['private']['formdesc'] : $attrDescriptions['private']['desc']),
- ));
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ echo $this->Form->input('sharing', array('label' => 'Private',
+ 'before' => $this->Html->div('forminfo', isset($attrDescriptions['sharing']['formdesc']) ? $attrDescriptions['sharing']['formdesc'] : $attrDescriptions['sharing']['desc']),
+ ));
+ } else {
+ echo $this->Form->input('private', array(
+ 'before' => $this->Html->div('forminfo', isset($attrDescriptions['private']['formdesc']) ? $attrDescriptions['private']['formdesc'] : $attrDescriptions['private']['desc']),
+ ));
+ }
}
echo $this->Form->input('to_ids', array(
'before' => $this->Html->div('forminfo', isset($attrDescriptions['signature']['formdesc']) ? $attrDescriptions['signature']['formdesc'] : $attrDescriptions['signature']['desc']),
@@ -38,7 +48,10 @@ $this->Js->get('#AttributeType')->event('change', 'showFormInfo("#AttributeType"
- Form->postLink(__('Delete'), array('action' => 'delete', $this->Form->value('Attribute.id')), null, __('Are you sure you want to delete # %s?', $this->Form->value('Attribute.id'))); ?>
+ findById($this->Form->value('Attribute.id')); // TODO ACL $attribute??
+ if ($isAclModify || $attribute['Event']['user_id'] == $me['id']) echo $this->Form->postLink(__('Delete'), array('action' => 'delete', $this->Form->value('Attribute.id')), null, __('Are you sure you want to delete # %s?', $this->Form->value('Attribute.id')));
+ else echo $this->Html->link(__('Delete'), array('action' => 'delete', $this->Form->value('Attribute.id')), array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus)); ?>
element('actions_menu'); ?>
@@ -95,8 +108,8 @@ function showFormInfo(id) {
// LATER use nice animations
//$(idDiv).hide('fast');
// change the content
- var value = $(id).val(); // get the selected value
- $(idDiv).html(formInfoValues[value]); // search in a lookup table
+ var value = $(id).val(); // get the selected value
+ $(idDiv).html(formInfoValues[value]); // search in a lookup table
// show it again
$(idDiv).fadeIn('slow');
@@ -111,4 +124,12 @@ formCategoryChanged("#AttributeCategory");
$('#AttributeType').val(type_value);
-Js->writeBuffer(); // Write cached scripts
\ No newline at end of file
+Js->writeBuffer(); // Write cached scripts ?>
+
+
+
+Js->writeBuffer(); // Write cached scripts
diff --git a/app/View/Attributes/index.ctp b/app/View/Attributes/index.ctp
index 3d2c67a4a..26699d622 100755
--- a/app/View/Attributes/index.ctp
+++ b/app/View/Attributes/index.ctp
@@ -1,3 +1,7 @@
+
@@ -37,8 +41,9 @@ if ('attachment' == $attribute['Attribute']['type'] || 'malware-sample' == $attr
Html->link(__('Edit'), array('action' => 'edit', $attribute['Attribute']['id']));
- echo $this->Form->postLink(__('Delete'), array('action' => 'delete', $attribute['Attribute']['id']), null, __('Are you sure you want to delete this attribute?'));
+ echo $this->Html->link(__('Edit'), array('action' => 'edit', $attribute['Attribute']['id']), $isAclModify || ($attribute['Event']['user_id'] == $me['id']) ? null : array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus));
+ if ($isAclModify || $attribute['Event']['user_id'] == $me['id']) echo $this->Form->postLink(__('Delete'), array('action' => 'delete', $attribute['Attribute']['id']), null, __('Are you sure you want to delete this attribute?'));
+ else echo $this->Html->link(__('Delete'), array('action' => 'delete', $attribute['Attribute']['id']), array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus));
}
echo $this->Html->link(__('View'), array('controller' => 'events', 'action' => 'view', $attribute['Attribute']['event_id']));
?>
@@ -65,4 +70,401 @@ echo $this->Html->link(__('View'), array('controller' => 'events', 'action' => '
element('actions_menu'); ?>
-
\ No newline at end of file
+
+
+
+
\ No newline at end of file
diff --git a/app/View/Attributes/xml/index.ctp b/app/View/Attributes/xml/index.ctp
index 249d8d9aa..257402f4c 100755
--- a/app/View/Attributes/xml/index.ctp
+++ b/app/View/Attributes/xml/index.ctp
@@ -10,6 +10,10 @@ foreach ($attributes as $key => $attribute) {
if ('true' != Configure::read('CyDefSIG.sync')) {
unset($attributes[$key]['private']);
}
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ unset($attributes[$key]['sharing']);
+ unset($attributes[$key]['cluster']);
+ }
}
diff --git a/app/View/Elements/actions_menu.ctp b/app/View/Elements/actions_menu.ctp
index d29b69ee8..727c845ba 100755
--- a/app/View/Elements/actions_menu.ctp
+++ b/app/View/Elements/actions_menu.ctp
@@ -1,4 +1,5 @@
- Html->link(__('New Event', true), array('controller' => 'events', 'action' => 'add')); ?>
+
+ Html->link(__('New Event', true), array('controller' => 'events', 'action' => 'add'), array('id' => $buttonAddStatus,'class' => $buttonAddStatus)); ?>
Html->link(__('List Events', true), array('controller' => 'events', 'action' => 'index')); ?>
Html->link(__('List Attributes', true), array('controller' => 'attributes', 'action' => 'index')); ?>
Html->link(__('Search Attributes', true), array('controller' => 'attributes', 'action' => 'search')); ?>
@@ -25,4 +26,10 @@
Html->link(__('New User', true), array('controller' => 'users', 'action' => 'add', 'admin' => true)); ?>
Html->link(__('List Users', true), array('controller' => 'users', 'action' => 'index', 'admin' => true)); ?>
+ Html->link(__('New Group', true), array('controller' => 'groups', 'action' => 'add', 'admin' => true)); ?>
+ Html->link(__('List Groups', true), array('controller' => 'groups', 'action' => 'index', 'admin' => true)); ?>
+
+
+ Html->link(__('List Logs', true), array('controller' => 'logs', 'action' => 'index', 'admin' => true)); ?>
+ Html->link(__('Search Logs', true), array('controller' => 'logs', 'action' => 'admin_search', 'admin' => true)); ?>
-Form->create('Event');?>
+Form->create('Event', array('type' => 'file'));?>
Form->input('date');
if ('true' == Configure::read('CyDefSIG.sync')) {
- echo $this->Form->input('private', array(
- 'before' => $this->Html->div('forminfo', isset($eventDescriptions['private']['formdesc']) ? $eventDescriptions['private']['formdesc'] : $eventDescriptions['private']['desc']),));
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ echo $this->Form->input('sharing', array('label' => 'Private',
+ 'before' => $this->Html->div('forminfo', isset($eventDescriptions['sharing']['formdesc']) ? $eventDescriptions['sharing']['formdesc'] : $eventDescriptions['sharing']['desc']),));
+ } else {
+ echo $this->Form->input('private', array(
+ 'before' => $this->Html->div('forminfo', isset($eventDescriptions['private']['formdesc']) ? $eventDescriptions['private']['formdesc'] : $eventDescriptions['private']['desc']),));
+ }
}
echo $this->Form->input('risk', array(
'before' => $this->Html->div('forminfo', isset($eventDescriptions['risk']['formdesc']) ? $eventDescriptions['risk']['formdesc'] : $eventDescriptions['risk']['desc'])));
echo $this->Form->input('info');
+echo $this->Form->input('Event.submittedfile', array(
+ 'label' => 'GFI sandbox ',
+ 'between' => ' ',
+ 'type' => 'file',
+ 'before' => $this->Html->div('forminfo', isset($eventDescriptions['submittedfile']['formdesc']) ? $eventDescriptions['submittedfile']['formdesc'] : $eventDescriptions['submittedfile']['desc'])));
?>
@@ -21,4 +31,4 @@ echo $this->Form->input('info');
element('actions_menu'); ?>
-
\ No newline at end of file
+
diff --git a/app/View/Events/edit.ctp b/app/View/Events/edit.ctp
index ff4654001..ebe34e7d8 100755
--- a/app/View/Events/edit.ctp
+++ b/app/View/Events/edit.ctp
@@ -8,8 +8,13 @@ echo $this->Form->input('date');
echo $this->Form->input('risk', array(
'before' => $this->Html->div('forminfo', isset($eventDescriptions['risk']['formdesc']) ? $eventDescriptions['risk']['formdesc'] : $eventDescriptions['risk']['desc'])));
if ('true' == Configure::read('CyDefSIG.sync')) {
- echo $this->Form->input('private', array(
- 'before' => $this->Html->div('forminfo', isset($eventDescriptions['private']['formdesc']) ? $eventDescriptions['private']['formdesc'] : $eventDescriptions['private']['desc']),));
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ echo $this->Form->input('sharing', array('label' => 'Private',
+ 'before' => $this->Html->div('forminfo', isset($eventDescriptions['sharing']['formdesc']) ? $eventDescriptions['sharing']['formdesc'] : $eventDescriptions['sharing']['desc']),));
+ } else {
+ echo $this->Form->input('private', array(
+ 'before' => $this->Html->div('forminfo', isset($eventDescriptions['private']['formdesc']) ? $eventDescriptions['private']['formdesc'] : $eventDescriptions['private']['desc']),));
+ }
}
echo $this->Form->input('info');
?>
diff --git a/app/View/Events/index.ctp b/app/View/Events/index.ctp
index a9992fcad..cf578a909 100755
--- a/app/View/Events/index.ctp
+++ b/app/View/Events/index.ctp
@@ -1,3 +1,9 @@
+
Events
@@ -51,13 +57,15 @@
Form->postLink('Publish Event', array('action' => 'alert', $event['Event']['id']), null, 'Are you sure this event is complete and everyone should be informed?');
+ if ($isAclPublish || $event['Event']['user_id'] == $me['id']) echo $this->Form->postLink('Publish Event', array('action' => 'alert', $event['Event']['id']), array('action' => 'alert', $event['Event']['id']), 'Are you sure this event is complete and everyone should be informed?');
+ else echo $this->Html->link('Publish Event', array('id' => $buttonPublishStatus . $buttonCounter++, 'class' => $buttonPublishStatus, 'action' => 'alert', $event['Event']['id']), array('id' => $buttonPublishStatus . $buttonCounter++, 'class' => $buttonPublishStatus, 'action' => 'alert', $event['Event']['id']));
elseif (0 == $event['Event']['published']) echo 'Not published';
?>
Html->link(__('Edit', true), array('action' => 'edit', $event['Event']['id']));
- echo $this->Form->postLink(__('Delete'), array('action' => 'delete', $event['Event']['id']), null, __('Are you sure you want to delete # %s?', $event['Event']['id']));
+ echo $this->Html->link(__('Edit', true), array('action' => 'edit', $event['Event']['id']), $isAclModify || ($event['Event']['user_id'] == $me['id']) ? null : array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus));
+ if ($isAclModify || $event['Event']['user_id'] == $me['id']) echo $this->Form->postLink(__('Delete'), array('action' => 'delete', $event['Event']['id']), null, __('Are you sure you want to delete # %s?', $event['Event']['id']));
+ else echo $this->Html->link(__('Delete'), array('action' => 'delete', $event['Event']['id']), array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus));
}
?>
Html->link(__('View', true), array('controller' => 'events', 'action' => 'view', $event['Event']['id'])); ?>
@@ -85,3 +93,580 @@ if ($isAdmin || $event['Event']['org'] == $me['org']) {
element('actions_menu'); ?>
+
+
+
diff --git a/app/View/Events/view.ctp b/app/View/Events/view.ctp
index 855e71873..d618c5e26 100755
--- a/app/View/Events/view.ctp
+++ b/app/View/Events/view.ctp
@@ -1,11 +1,24 @@
+
Form->postLink('Publish Event', array('action' => 'alert', $event['Event']['id']), null, 'Are you sure this event is complete and everyone should be informed?');
echo $this->Form->postLink('Publish (no email)', array('action' => 'publish', $event['Event']['id']), null, 'Publish but do NOT send alert email? Only for minor changes!');
+} else {
+ echo $this->Html->link('Publish Event', array('action' => 'alert', $event['Event']['id']), array('id' => $buttonPublishStatus . $buttonCounter++, 'class' => $buttonPublishStatus));
+ echo $this->Html->link('Publish (no email)', array('action' => 'publish', $event['Event']['id']), array('id' => $buttonPublishStatus . $buttonCounter++, 'class' => $buttonPublishStatus));
+}
?>
@@ -50,12 +63,20 @@
+
+
Private
+
+
+
+
+
Private
+
+
+
diff --git a/app/View/Events/xml/index.ctp b/app/View/Events/xml/index.ctp
index e654a5f8c..4191d6bc5 100644
--- a/app/View/Events/xml/index.ctp
+++ b/app/View/Events/xml/index.ctp
@@ -11,6 +11,10 @@ foreach ($events as $key => $event) {
if ('true' != Configure::read('CyDefSIG.sync')) {
unset($events[$key]['private']);
}
+ if ('true' == Configure::read('CyDefSIG.private')) {
+ unset($events[$key]['cluster']);
+ unset($events[$key]['sharing']);
+ }
// hide the org field is we are not in showorg mode
if ('true' != Configure::read('CyDefSIG.showorg') && !$isAdmin) {
unset($events[$key]['org']);
diff --git a/app/View/Events/xml/view.ctp b/app/View/Events/xml/view.ctp
index c34c5a433..4f24de28e 100755
--- a/app/View/Events/xml/view.ctp
+++ b/app/View/Events/xml/view.ctp
@@ -9,8 +9,18 @@ unset($event['Attribute']);
foreach ($event['Event']['Attribute'] as $key => $value) {
unset($event['Event']['Attribute'][$key]['value1']);
unset($event['Event']['Attribute'][$key]['value2']);
+ unset($event['Event']['Attribute'][$key]['category_order']);
}
+// hide the share fields is we are not in private mode
+if ('true' == Configure::read('CyDefSIG.private')) {
+ unset($event['Event']['cluster']);
+ unset($event['Event']['sharing']);
+ foreach ($event['Event']['Attribute'] as $key => $value) {
+ unset($event['Event']['Attribute'][$key]['cluster']);
+ unset($event['Event']['Attribute'][$key]['sharing']);
+ }
+}
// hide the private fields is we are not in sync mode
if ('true' != Configure::read('CyDefSIG.sync')) {
unset($event['Event']['private']);
diff --git a/app/View/Groups/add.ctp b/app/View/Groups/add.ctp
new file mode 100755
index 000000000..1e37e2b4f
--- /dev/null
+++ b/app/View/Groups/add.ctp
@@ -0,0 +1,19 @@
+
+Form->create('Group');?>
+
+
+ Form->input('name');
+ ?>
+
+Form->end(__('Submit'));?>
+
+
+
+
+
+ Html->link(__('List Groups'), array('action' => 'index'));?>
+ Html->link(__('List Users'), array('controller' => 'users', 'action' => 'index')); ?>
+ Html->link(__('New User'), array('controller' => 'users', 'action' => 'add')); ?>
+
+
diff --git a/app/View/Groups/admin_add.ctp b/app/View/Groups/admin_add.ctp
new file mode 100755
index 000000000..c1d0972e1
--- /dev/null
+++ b/app/View/Groups/admin_add.ctp
@@ -0,0 +1,19 @@
+
+Form->create('Group');?>
+
+
+ Form->input('name');
+ echo $this->Form->input('perm_add');
+ echo $this->Form->input('perm_modify');
+ echo $this->Form->input('perm_publish');
+ echo $this->Form->input('perm_full');
+ ?>
+
+Form->end(__('Submit'));?>
+
+
+
+ element('actions_menu'); ?>
+
+
diff --git a/app/View/Groups/admin_edit.ctp b/app/View/Groups/admin_edit.ctp
new file mode 100755
index 000000000..4d813b880
--- /dev/null
+++ b/app/View/Groups/admin_edit.ctp
@@ -0,0 +1,23 @@
+
+Form->create('Group');?>
+
+
+ Form->input('name');?>
+
+
+ Form->input('perm_add', array( 'label' => 'add'));
+ echo $this->Form->input('perm_modify', array( 'label' => 'modify'));
+ echo $this->Form->input('perm_publish', array( 'label' => 'publish'));
+ echo $this->Form->input('perm_full', array( 'label' => 'full'));
+ ?>
+
+
+Form->end(__('Submit'));?>
+
+
+
+ element('actions_menu'); ?>
+
+
diff --git a/app/View/Groups/admin_index.ctp b/app/View/Groups/admin_index.ctp
new file mode 100755
index 000000000..517d280f3
--- /dev/null
+++ b/app/View/Groups/admin_index.ctp
@@ -0,0 +1,88 @@
+
+
+
+
+ Paginator->sort('id');?>
+ Paginator->sort('name');?>
+ Paginator->sort('add');?>
+ Paginator->sort('modify');?>
+ Paginator->sort('publish');?>
+ Paginator->sort('full');?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Html->link(__('View'), array('admin' => true, 'action' => 'view', $group['Group']['id'])); ?>
+ Html->link(__('Edit'), array('admin' => true, 'action' => 'edit', $group['Group']['id'])); ?>
+ Form->postLink(__('Delete'), array('admin' => true, 'action' => 'delete', $group['Group']['id']), null, __('Are you sure you want to delete # %s?', $group['Group']['id'])); ?>
+
+
+
+
+
+ Paginator->counter(array(
+ 'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
+ ));
+ ?>
+
+
+ Paginator->prev('< ' . __('previous'), array(), null, array('class' => 'prev disabled'));
+ echo $this->Paginator->numbers(array('separator' => ''));
+ echo $this->Paginator->next(__('next') . ' >', array(), null, array('class' => 'next disabled'));
+ ?>
+
+
+
+
+ element('actions_menu'); ?>
+
+
+
+
\ No newline at end of file
diff --git a/app/View/Groups/admin_view.ctp b/app/View/Groups/admin_view.ctp
new file mode 100755
index 000000000..6e4c0bef8
--- /dev/null
+++ b/app/View/Groups/admin_view.ctp
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Html->link(__('Edit Group'), array('admin' => true, 'action' => 'edit', $group['Group']['id'])); ?>
+ Form->postLink(__('Delete Group'), array('admin' => true, 'action' => 'delete', $group['Group']['id']), null, __('Are you sure you want to delete # %s?', $group['Group']['id'])); ?>
+ Html->link(__('List Groups'), array('admin' => true, 'action' => 'index')); ?>
+ Html->link(__('New Group'), array('admin' => true, 'action' => 'add')); ?>
+
+
\ No newline at end of file
diff --git a/app/View/Groups/edit.ctp b/app/View/Groups/edit.ctp
new file mode 100755
index 000000000..75337df81
--- /dev/null
+++ b/app/View/Groups/edit.ctp
@@ -0,0 +1,21 @@
+
+Form->create('Group');?>
+
+
+ Form->input('id');
+ echo $this->Form->input('name');
+ ?>
+
+Form->end(__('Submit'));?>
+
+
+
+
+
+ Form->postLink(__('Delete'), array('action' => 'delete', $this->Form->value('Group.id')), null, __('Are you sure you want to delete # %s?', $this->Form->value('Group.id'))); ?>
+ Html->link(__('List Groups'), array('action' => 'index'));?>
+ Html->link(__('List Users'), array('controller' => 'users', 'action' => 'index')); ?>
+ Html->link(__('New User'), array('controller' => 'users', 'action' => 'add')); ?>
+
+
diff --git a/app/View/Groups/index.ctp b/app/View/Groups/index.ctp
new file mode 100755
index 000000000..ed37eddde
--- /dev/null
+++ b/app/View/Groups/index.ctp
@@ -0,0 +1,48 @@
+
+
+
+
+ Paginator->sort('id');?>
+ Paginator->sort('name');?>
+ Paginator->sort('created');?>
+ Paginator->sort('modified');?>
+
+
+
+
+
+
+
+
+
+ Html->link(__('View'), array('action' => 'view', $group['Group']['id'])); ?>
+ Html->link(__('Edit'), array('action' => 'edit', $group['Group']['id'])); ?>
+ Form->postLink(__('Delete'), array('action' => 'delete', $group['Group']['id']), null, __('Are you sure you want to delete # %s?', $group['Group']['id'])); ?>
+
+
+
+
+
+ Paginator->counter(array(
+ 'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
+ ));
+ ?>
+
+
+ Paginator->prev('< ' . __('previous'), array(), null, array('class' => 'prev disabled'));
+ echo $this->Paginator->numbers(array('separator' => ''));
+ echo $this->Paginator->next(__('next') . ' >', array(), null, array('class' => 'next disabled'));
+ ?>
+
+
+
+
+
+ Html->link(__('New Group'), array('action' => 'add')); ?>
+ Html->link(__('List Users'), array('controller' => 'users', 'action' => 'index')); ?>
+ Html->link(__('New User'), array('controller' => 'users', 'action' => 'add')); ?>
+
+
diff --git a/app/View/Groups/view.ctp b/app/View/Groups/view.ctp
new file mode 100755
index 000000000..7d3234f3a
--- /dev/null
+++ b/app/View/Groups/view.ctp
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ element('actions_menu'); ?>
+
+
\ No newline at end of file
diff --git a/app/View/Layouts/default.ctp b/app/View/Layouts/default.ctp
old mode 100644
new mode 100755
index 2a2e4ffcc..39c8378ab
--- a/app/View/Layouts/default.ctp
+++ b/app/View/Layouts/default.ctp
@@ -37,6 +37,8 @@
echo $this->Html->script('jquery-1.8.2.min'); // Include jQuery library
?>
+
+
diff --git a/app/View/Logs/admin_index.ctp b/app/View/Logs/admin_index.ctp
new file mode 100755
index 000000000..e7848b349
--- /dev/null
+++ b/app/View/Logs/admin_index.ctp
@@ -0,0 +1,59 @@
+
+
+
+
+ Paginator->sort('id');?>
+
+ Paginator->sort('email');?>
+ Paginator->sort('org');?>
+ Paginator->sort('created');?>
+ Paginator->sort('action');?>
+ Paginator->sort('title');?>
+ Paginator->sort('change');?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Html->link(__('View'), array('admin' => true, 'action' => 'view', $log['Log']['id'])); ?>
+
+
+
+
+
+ Paginator->counter(array(
+ 'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
+ ));
+ ?>
+
+
+ Paginator->prev('< ' . __('previous'), array(), null, array('class' => 'prev disabled'));
+ echo $this->Paginator->numbers(array('separator' => ''));
+ echo $this->Paginator->next(__('next') . ' >', array(), null, array('class' => 'next disabled'));
+ ?>
+
+
+
+
+ element('actions_menu'); ?>
+
+
diff --git a/app/View/Logs/admin_search.ctp b/app/View/Logs/admin_search.ctp
new file mode 100755
index 000000000..f0d024965
--- /dev/null
+++ b/app/View/Logs/admin_search.ctp
@@ -0,0 +1,53 @@
+
+Form->create('Log');?>
+
+
+ Form->input('email', array( 'label' => 'Email'));
+ echo $this->Form->input('org', array( 'label' => 'Org'));
+ echo $this->Form->input('action', array('between' => $this->Html->div('forminfo', '', array('id'=> 'LogActionDiv'))));
+
+ echo $this->Form->input('title', array( 'label' => 'Title'));
+ echo $this->Form->input('change', array( 'label' => 'Change'));
+ ?>
+
+Form->end(__('Search', true));?>
+
+
+
+ element('actions_menu'); ?>
+
+
+
+Js->writeBuffer(); // Write cached scripts ?>
diff --git a/app/View/Logs/admin_view.ctp b/app/View/Logs/admin_view.ctp
new file mode 100755
index 000000000..5654cb4f3
--- /dev/null
+++ b/app/View/Logs/admin_view.ctp
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Html->link(__('List Logs'), array('admin' => true, 'action' => 'index')); ?>
+
+
\ No newline at end of file
diff --git a/app/View/Logs/index.ctp b/app/View/Logs/index.ctp
new file mode 100755
index 000000000..e7848b349
--- /dev/null
+++ b/app/View/Logs/index.ctp
@@ -0,0 +1,59 @@
+
+
+
+
+ Paginator->sort('id');?>
+
+ Paginator->sort('email');?>
+ Paginator->sort('org');?>
+ Paginator->sort('created');?>
+ Paginator->sort('action');?>
+ Paginator->sort('title');?>
+ Paginator->sort('change');?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Html->link(__('View'), array('admin' => true, 'action' => 'view', $log['Log']['id'])); ?>
+
+
+
+
+
+ Paginator->counter(array(
+ 'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
+ ));
+ ?>
+
+
+ Paginator->prev('< ' . __('previous'), array(), null, array('class' => 'prev disabled'));
+ echo $this->Paginator->numbers(array('separator' => ''));
+ echo $this->Paginator->next(__('next') . ' >', array(), null, array('class' => 'next disabled'));
+ ?>
+
+
+
+
+ element('actions_menu'); ?>
+
+
diff --git a/app/View/Servers/index.ctp b/app/View/Servers/index.ctp
old mode 100644
new mode 100755
index 824958e0f..1f6cab5ca
--- a/app/View/Servers/index.ctp
+++ b/app/View/Servers/index.ctp
@@ -1,3 +1,10 @@
+
@@ -26,8 +33,9 @@
- Html->link(__('Edit'), array('action' => 'edit', $server['Server']['id'])); ?>
- Form->postLink(__('Delete'), array('action' => 'delete', $server['Server']['id']), null, __('Are you sure you want to delete # %s?', $server['Server']['id'])); ?>
+ Html->link(__('Edit'), array('action' => 'edit', $server['Server']['id']), $isAclModify || ($server['Server']['org'] == $me['org']) ? null : array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus)); ?>
+ Form->postLink(__('Delete'), array('action' => 'delete', $server['Server']['id']), null, __('Are you sure you want to delete # %s?', $server['Server']['id']));
+ else echo $this->Html->link(__('Delete'), array('action' => 'delete', $server['Server']['id']), array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus)); ?>
Form->postLink(__('Pull'), array('action' => 'pull', $server['Server']['id']) ); ?>
Form->postLink(__('Push'), array('action' => 'push', $server['Server']['id']) ); ?>
@@ -56,9 +64,404 @@
- Html->link(__('New Server'), array('controller' => 'servers', 'action' => 'add')); ?>
+ Html->link(__('New Server'), array('controller' => 'servers', 'action' => 'add'), array('id' => $buttonAddStatus . $buttonCounter++, 'class' => $buttonAddStatus)); ?>
Html->link(__('List Servers'), array('controller' => 'servers', 'action' => 'index'));?>
element('actions_menu'); ?>
+
diff --git a/app/View/Users/admin_add.ctp b/app/View/Users/admin_add.ctp
old mode 100644
new mode 100755
index 486a4042f..0e572614d
--- a/app/View/Users/admin_add.ctp
+++ b/app/View/Users/admin_add.ctp
@@ -7,6 +7,7 @@
echo $this->Form->input('password');
echo $this->Form->input('confirm_password', array('type' => 'password', 'div' => array('class' => 'input password required')));
echo $this->Form->input('org');
+ echo $this->Form->input('group_id');
echo $this->Form->input('autoalert');
echo $this->Form->input('authkey', array('value' => $authkey));
echo $this->Form->input('nids_sid');
diff --git a/app/View/Users/admin_edit.ctp b/app/View/Users/admin_edit.ctp
old mode 100644
new mode 100755
index 3148e7590..81ef66733
--- a/app/View/Users/admin_edit.ctp
+++ b/app/View/Users/admin_edit.ctp
@@ -7,6 +7,7 @@
echo $this->Form->input('password');
echo $this->Form->input('confirm_password', array('type' => 'password', 'div' => array('class' => 'input password required')));
echo $this->Form->input('org');
+ echo $this->Form->input('group_id'); // TODO ACL, User edit group_id.
echo $this->Form->input('autoalert');
echo $this->Form->input('authkey');
echo $this->Form->input('nids_sid');
diff --git a/app/View/Users/admin_index.ctp b/app/View/Users/admin_index.ctp
old mode 100644
new mode 100755
index 81411a0a5..4cdaf5c5f
--- a/app/View/Users/admin_index.ctp
+++ b/app/View/Users/admin_index.ctp
@@ -1,9 +1,16 @@
+
Paginator->sort('id');?>
Paginator->sort('org');?>
+ Paginator->sort('group_id');?>
Paginator->sort('email');?>
Paginator->sort('autoalert');?>
Paginator->sort('gpgkey');?>
@@ -20,6 +27,8 @@
+ Html->link($user['Group']['name'], array('controller' => 'groups', 'action' => 'view', $user['Group']['id'])); ?>
+
@@ -33,8 +42,10 @@
Html->link(__('View'), array('admin' => true, 'action' => 'view', $user['User']['id'])); ?>
- Html->link(__('Edit'), array('admin' => true, 'action' => 'edit', $user['User']['id'])); ?>
- Form->postLink(__('Delete'), array('admin' => true, 'action' => 'delete', $user['User']['id']), null, __('Are you sure you want to delete # %s?', $user['User']['id'])); ?>
+ Html->link(__('Edit'), array('admin' => true, 'action' => 'edit', $user['User']['id']), $isAclModify || ($user['User']['org'] == $me['org']) ? null : array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus)); ?>
+ Form->postLink(__('Delete'), array('admin' => true, 'action' => 'delete', $user['User']['id']), null, __('Are you sure you want to delete # %s?', $user['User']['id']));
+ else echo $this->Html->link(__('Delete'), array('admin' => true, 'action' => 'delete', $user['User']['id']), array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus));
+ ?>
@@ -59,3 +70,398 @@
element('actions_menu'); ?>
+
diff --git a/app/View/Users/admin_view.ctp b/app/View/Users/admin_view.ctp
old mode 100644
new mode 100755
index e974a2683..78ec41ce6
--- a/app/View/Users/admin_view.ctp
+++ b/app/View/Users/admin_view.ctp
@@ -1,6 +1,12 @@
+
-
Html->link(__('Edit Profile', true), array('admin' => true, 'action' => 'edit', $user['User']['id'])); ?>
+
Html->link(__('Edit Profile', true), array('admin' => true, 'action' => 'edit', $user['User']['id']), array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus)); ?>
@@ -19,6 +25,11 @@
+
+
+ Html->link($user['Group']['name'], array('controller' => 'groups', 'action' => 'view', $user['Group']['id'])); ?>
+
+
@@ -66,12 +77,15 @@
- Html->link(__('Edit User'), array('admin' => true, 'action' => 'edit', $user['User']['id'])); ?>
- Form->postLink(__('Delete User'), array('admin' => true, 'action' => 'delete', $user['User']['id']), null, __('Are you sure you want to delete # %s?', $user['User']['id'])); ?>
+ Html->link(__('Edit User'), array('admin' => true, 'action' => 'edit', $user['User']['id']), array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus)); ?>
+ Form->postLink(__('Delete User'), array('admin' => true, 'action' => 'delete', $user['User']['id']), null, __('Are you sure you want to delete # %s?', $user['User']['id']));
+ else echo $this->Html->link(__('Delete User'), array('admin' => true, 'action' => 'delete', $user['User']['id']), array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus));
+ ?>
Html->link(__('List Users'), array('admin' => true, 'action' => 'index')); ?>
- Html->link(__('New User'), array('admin' => true, 'action' => 'add')); ?>
+ Html->link(__('New User'), array('admin' => true, 'action' => 'add'), array('id' => $buttonAddStatus . $buttonCounter++, 'class' => $buttonAddStatus)); ?>
Html->link(__('List Events'), array('controller' => 'events', 'action' => 'index')); ?>
- Html->link(__('New Event'), array('controller' => 'events', 'action' => 'add')); ?>
+ Html->link(__('New Event'), array('controller' => 'events', 'action' => 'add'), array('id' => $buttonAddStatus . $buttonCounter++, 'class' => $buttonAddStatus)); ?>
@@ -103,8 +117,11 @@
Html->link(__('View'), array('controller' => 'events', 'action' => 'view', $event['id'])); ?>
- Html->link(__('Edit'), array('controller' => 'events', 'action' => 'edit', $event['id'])); ?>
- Form->postLink(__('Delete'), array('controller' => 'events', 'action' => 'delete', $event['id']), null, __('Are you sure you want to delete # %s?', $event['id'])); ?>
+ Html->link(__('Edit'), array('controller' => 'events', 'action' => 'edit', $event['id']), array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus)); ?>
+ Form->postLink(__('Delete'), array('controller' => 'events', 'action' => 'delete', $event['id']), null, __('Are you sure you want to delete # %s?', $event['id']));
+ else echo $this->Html->link(__('Delete'), array('controller' => 'events', 'action' => 'delete', $event['id']), array('id' => $buttonModifyStatus . $buttonCounter++, 'class' => $buttonModifyStatus));
+ ?>
@@ -112,3 +129,35 @@
+
\ No newline at end of file
diff --git a/app/View/Users/edit.ctp b/app/View/Users/edit.ctp
index b96f38bb3..8b864f41c 100755
--- a/app/View/Users/edit.ctp
+++ b/app/View/Users/edit.ctp
@@ -8,6 +8,7 @@
echo $this->Form->input('confirm_password', array('type' => 'password', 'div' => array('class' => 'input password required')));
if ($isAdmin) echo $this->Form->input('org');
else echo $this->Form->input('org', array('disabled' => 'disabled'));
+ echo $this->Form->input('group_id', array('disabled' => 'disabled')); // TODO ACL, check, My Profile not edit group_id.
echo $this->Form->input('autoalert');
echo $this->Form->input('nids_sid');
echo $this->Form->input('gpgkey');
@@ -22,4 +23,4 @@
element('actions_menu'); ?>
-
\ No newline at end of file
+
diff --git a/app/View/Users/news.ctp b/app/View/Users/news.ctp
old mode 100644
new mode 100755
index 393f77e42..7658aa57c
--- a/app/View/Users/news.ctp
+++ b/app/View/Users/news.ctp
@@ -1,5 +1,13 @@
News
+
June 2012
+
Audit
+There is now log on every login, logout, addition, change and deletion.
+
+
Access Control granulation
+There is Access Control, an user must be bound to a users-group,
+so we are able to grant global add, modify and publish rights.
+
April 2012
REST API (output)
From now on you can use the REST API that uses this XML export. For more information check out the export page.
diff --git a/app/View/Users/terms.ctp b/app/View/Users/terms.ctp
index a5d742888..57547e074 100644
--- a/app/View/Users/terms.ctp
+++ b/app/View/Users/terms.ctp
@@ -50,3 +50,8 @@ if (!$termsaccepted) {
element('actions_menu'); ?>
+
diff --git a/app/View/Users/view.ctp b/app/View/Users/view.ctp
index e115a5e4e..333767746 100755
--- a/app/View/Users/view.ctp
+++ b/app/View/Users/view.ctp
@@ -19,6 +19,11 @@
+
+
+
+
+
@@ -55,3 +60,36 @@
element('actions_menu'); ?>
+
+
\ No newline at end of file
diff --git a/app/technical_design/TD-ACL.txt b/app/technical_design/TD-ACL.txt
new file mode 100755
index 000000000..1b82f0358
--- /dev/null
+++ b/app/technical_design/TD-ACL.txt
@@ -0,0 +1,16 @@
+ACL Technical Design (TD)
+
+To use Access Control in CakePHP we use itś own AclComponent.
+
+http://book.cakephp.org/2.0/en/tutorials-and-examples/simple-acl-controlled-application/simple-acl-controlled-application.html
+http://book.cakephp.org/2.0/en/tutorials-and-examples/simple-acl-controlled-application/part-two.html
+
+ CakePHP example, just telling how to populate and connect the CakePHP AclController.
+
+http://stackoverflow.com/questions/6154285/aros-table-in-cakephp-is-still-including-users-even-after-bindnode
+
+ If ACL on Group level add this small correction, to just only add Groups to CakePHP ACL tables and not to add the Users.
+
+http://bakery.cakephp.org/articles/theshz/2006/11/28/user-permissions-and-cakephp-acl
+
+ Calling the ACL from within a controller.
diff --git a/app/technical_design/TD-Audit.txt b/app/technical_design/TD-Audit.txt
new file mode 100755
index 000000000..c4dd3e108
--- /dev/null
+++ b/app/technical_design/TD-Audit.txt
@@ -0,0 +1,28 @@
+Audit Technical Design (TD)
+
+To log in CakePHP we use an existing Model Behavior,
+to write to a log database table.
+
+https://github.com/eskil-saatvedt/CakePHP-Assets/blob/master/models/behaviors/LogableBehavior.php
+
+ Adds the logable Model Behavior.
+
+http://bakery.cakephp.org/articles/rikdc/2010/06/07/syslog-component
+
+ Ads the syslog capability.
+
+http://bakery.cakephp.org/articles/alkemann/2008/10/21/logablebehavior
+http://www.bitsntricks.com/cakephp-logable-behaviour/
+
+ Short explaination itś use.
+
+http://stackoverflow.com/questions/9791633/check-if-cakephp-update-changes-a-variable-in-update
+
+ This Logable Model Behavior seemed not to work in the UsersController,
+so the change checks are done manual coded in the UsersController.
+
+
+
+https://github.com/joebeeson/referee#readme
+
+ Can be handy lateron for log to db or syslog?
\ No newline at end of file
diff --git a/app/technical_design/TD-forum.txt b/app/technical_design/TD-forum.txt
new file mode 100755
index 000000000..993b44a26
--- /dev/null
+++ b/app/technical_design/TD-forum.txt
@@ -0,0 +1,12 @@
+Forum Technical Design (TD)
+
+We use a plugin giving Forum use in CakePHP.
+
+http://milesj.me/code/cakephp/forum
+
+Alternative PhpBB in conjunction with CakePHP Users and Groups tables.
+
+http://bakery.cakephp.org/articles/wilsonsheldon/2009/01/13/phpbb3-api-bridge
+http://www.phpbb.com/community/viewtopic.php?f=71&t=993475
+
+ CakePHP and a PhpBB3 forum.
\ No newline at end of file
diff --git a/app/tmp/cache/models/empty b/app/tmp/cache/models/empty
old mode 100644
new mode 100755
diff --git a/app/tmp/cache/persistent/empty b/app/tmp/cache/persistent/empty
old mode 100644
new mode 100755
diff --git a/app/tmp/cache/views/empty b/app/tmp/cache/views/empty
old mode 100644
new mode 100755
diff --git a/app/tmp/logs/empty b/app/tmp/logs/empty
old mode 100644
new mode 100755
diff --git a/app/tmp/sessions/empty b/app/tmp/sessions/empty
old mode 100644
new mode 100755
diff --git a/app/tmp/tests/empty b/app/tmp/tests/empty
old mode 100644
new mode 100755
diff --git a/app/webroot/css/cake.generic.css b/app/webroot/css/cake.generic.css
old mode 100644
new mode 100755
index 4b8e1eda2..1acfb3560
--- a/app/webroot/css/cake.generic.css
+++ b/app/webroot/css/cake.generic.css
@@ -772,3 +772,11 @@ pre {
#url-rewriting-warning {
display:none;
}
+
+/* to show a button as off/not-usable */
+a.button_off:link,a.button_off:visited, a.button_off:active {
+ color:#C1C1C1;
+ font-size:12px;
+ background-color:#ffffff;
+ text-decoration:none;
+}
diff --git a/app/webroot/js/deactivateButtons.js b/app/webroot/js/deactivateButtons.js
new file mode 100755
index 000000000..8e330f4d7
--- /dev/null
+++ b/app/webroot/js/deactivateButtons.js
@@ -0,0 +1,101 @@
+
\ No newline at end of file
diff --git a/plugins/AclExtras/Console/Command/AclExtrasShell.php b/plugins/AclExtras/Console/Command/AclExtrasShell.php
new file mode 100644
index 000000000..7ac1a36f2
--- /dev/null
+++ b/plugins/AclExtras/Console/Command/AclExtrasShell.php
@@ -0,0 +1,308 @@
+
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+
+App::uses('Controller', 'Controller');
+App::uses('ComponentCollection', 'Controller');
+App::uses('AclComponent', 'Controller/Component');
+App::uses('DbAcl', 'Model');
+
+/**
+ * Shell for ACO extras
+ *
+ * @package acl_extras
+ * @subpackage acl_extras.Console.Command
+ */
+class AclExtrasShell extends Shell {
+/**
+ * Contains instance of AclComponent
+ *
+ * @var AclComponent
+ * @access public
+ */
+ public $Acl;
+
+/**
+ * Contains arguments parsed from the command line.
+ *
+ * @var array
+ * @access public
+ */
+ public $args;
+
+/**
+ * Contains database source to use
+ *
+ * @var string
+ * @access public
+ */
+ public $dataSource = 'default';
+
+/**
+ * Root node name.
+ *
+ * @var string
+ **/
+ public $rootNode = 'controllers';
+
+/**
+ * Internal Clean Actions switch
+ *
+ * @var boolean
+ **/
+ public $_clean = false;
+
+/**
+ * Start up And load Acl Component / Aco model
+ *
+ * @return void
+ **/
+ public function startup() {
+ parent::startup();
+ $collection = new ComponentCollection();
+ $this->Acl = new AclComponent($collection);
+ $controller = null;
+ $this->Acl->startup($controller);
+ $this->Aco = $this->Acl->Aco;
+ }
+
+/**
+ * Sync the ACO table
+ *
+ * @return void
+ **/
+ function aco_sync() {
+ $this->_clean = true;
+ $this->aco_update();
+ }
+/**
+ * Updates the Aco Tree with new controller actions.
+ *
+ * @return void
+ **/
+ function aco_update() {
+ $root = $this->_checkNode($this->rootNode, $this->rootNode, null);
+ $controllers = $this->getControllerList();
+ $this->_updateControllers($root, $controllers);
+
+ $plugins = CakePlugin::loaded();
+ foreach ($plugins as $plugin) {
+ $controllers = $this->getControllerList($plugin);
+
+ $path = $this->rootNode . '/' . $plugin;
+ $pluginRoot = $this->_checkNode($path, $plugin, $root['Aco']['id']);
+ $this->_updateControllers($pluginRoot, $controllers, $plugin);
+ }
+ $this->out(__('Aco Update Complete '));
+ return true;
+ }
+
+/**
+ * Updates a collection of controllers.
+ *
+ * @param array $root Array or ACO information for root node.
+ * @param array $controllers Array of Controllers
+ * @param string $plugin Name of the plugin you are making controllers for.
+ * @return void
+ */
+ function _updateControllers($root, $controllers, $plugin = null) {
+ $dotPlugin = $pluginPath = $plugin;
+ if ($plugin) {
+ $dotPlugin .= '.';
+ $pluginPath .= '/';
+ }
+ $appIndex = array_search($plugin . 'AppController', $controllers);
+ if ($appIndex !== false) {
+ App::uses($plugin . 'AppController', $dotPlugin . 'Controller');
+ unset($controllers[$appIndex]);
+ }
+ // look at each controller
+ foreach ($controllers as $controller) {
+ App::uses($controller, $dotPlugin . 'Controller');
+ $controllerName = preg_replace('/Controller$/', '', $controller);
+
+ $path = $this->rootNode . '/' . $pluginPath . $controllerName;
+ $controllerNode = $this->_checkNode($path, $controllerName, $root['Aco']['id']);
+ $this->_checkMethods($controller, $controllerName, $controllerNode, $pluginPath);
+ }
+ if ($this->_clean) {
+ if (!$plugin) {
+ $controllers = array_merge($controllers, App::objects('plugin', null, false));
+ }
+ $controllerFlip = array_flip($controllers);
+
+ $this->Aco->id = $root['Aco']['id'];
+ $controllerNodes = $this->Aco->children(null, true);
+ foreach ($controllerNodes as $ctrlNode) {
+ $alias = $ctrlNode['Aco']['alias'];
+ $name = $alias . 'Controller';
+ if (!isset($controllerFlip[$name]) && !isset($controllerFlip[$alias])) {
+ if ($this->Aco->delete($ctrlNode['Aco']['id'])) {
+ $this->out(__(
+ 'Deleted %s and all children',
+ $this->rootNode . '/' . $ctrlNode['Aco']['alias']
+ ), 1, Shell::VERBOSE);
+ }
+ }
+ }
+ }
+ }
+
+/**
+ * Get a list of controllers in the app and plugins.
+ *
+ * Returns an array of path => import notation.
+ *
+ * @param string $plugin Name of plugin to get controllers for
+ * @return array
+ **/
+ function getControllerList($plugin = null) {
+ if (!$plugin) {
+ $controllers = App::objects('Controller', null, false);
+ } else {
+ $controllers = App::objects($plugin . '.Controller', null, false);
+ }
+ return $controllers;
+ }
+
+/**
+ * Check a node for existance, create it if it doesn't exist.
+ *
+ * @param string $path
+ * @param string $alias
+ * @param int $parentId
+ * @return array Aco Node array
+ */
+ function _checkNode($path, $alias, $parentId = null) {
+ $node = $this->Aco->node($path);
+ if (!$node) {
+ $this->Aco->create(array('parent_id' => $parentId, 'model' => null, 'alias' => $alias));
+ $node = $this->Aco->save();
+ $node['Aco']['id'] = $this->Aco->id;
+ $this->out(__('Created Aco node: %s', $path), 1, Shell::VERBOSE);
+ } else {
+ $node = $node[0];
+ }
+ return $node;
+ }
+
+/**
+ * Check and Add/delete controller Methods
+ *
+ * @param string $controller
+ * @param array $node
+ * @param string $plugin Name of plugin
+ * @return void
+ */
+ function _checkMethods($className, $controllerName, $node, $pluginPath = false) {
+ $baseMethods = get_class_methods('Controller');
+ $actions = get_class_methods($className);
+ $methods = array_diff($actions, $baseMethods);
+ foreach ($methods as $action) {
+ if (strpos($action, '_', 0) === 0) {
+ continue;
+ }
+ $path = $this->rootNode . '/' . $pluginPath . $controllerName . '/' . $action;
+ $this->_checkNode($path, $action, $node['Aco']['id']);
+ }
+
+ if ($this->_clean) {
+ $actionNodes = $this->Aco->children($node['Aco']['id']);
+ $methodFlip = array_flip($methods);
+ foreach ($actionNodes as $action) {
+ if (!isset($methodFlip[$action['Aco']['alias']])) {
+ $this->Aco->id = $action['Aco']['id'];
+ if ($this->Aco->delete()) {
+ $path = $this->rootNode . '/' . $controllerName . '/' . $action['Aco']['alias'];
+ $this->out(__('Deleted Aco node %s', $path), 1, Shell::VERBOSE);
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ public function getOptionParser() {
+ return parent::getOptionParser()
+ ->description(__("Better manage, and easily synchronize you application's ACO tree"))
+ ->addSubcommand('aco_update', array(
+ 'help' => __('Add new ACOs for new controllers and actions. Does not remove nodes from the ACO table.')
+ ))->addSubcommand('aco_sync', array(
+ 'help' => __('Perform a full sync on the ACO table.' .
+ 'Will create new ACOs or missing controllers and actions.' .
+ 'Will also remove orphaned entries that no longer have a matching controller/action')
+ ))->addSubcommand('verify', array(
+ 'help' => __('Verify the tree structure of either your Aco or Aro Trees'),
+ 'parser' => array(
+ 'arguments' => array(
+ 'type' => array(
+ 'required' => true,
+ 'help' => __('The type of tree to verify'),
+ 'choices' => array('aco', 'aro')
+ )
+ )
+ )
+ ))->addSubcommand('recover', array(
+ 'help' => __('Recover a corrupted Tree'),
+ 'parser' => array(
+ 'arguments' => array(
+ 'type' => array(
+ 'required' => true,
+ 'help' => __('The type of tree to recover'),
+ 'choices' => array('aco', 'aro')
+ )
+ )
+ )
+ ));
+ }
+
+/**
+ * Verify a Acl Tree
+ *
+ * @param string $type The type of Acl Node to verify
+ * @access public
+ * @return void
+ */
+ function verify() {
+ $type = Inflector::camelize($this->args[0]);
+ $return = $this->Acl->{$type}->verify();
+ if ($return === true) {
+ $this->out(__('Tree is valid and strong'));
+ } else {
+ $this->err(print_r($return, true));
+ return false;
+ }
+ }
+/**
+ * Recover an Acl Tree
+ *
+ * @param string $type The Type of Acl Node to recover
+ * @access public
+ * @return void
+ */
+ function recover() {
+ $type = Inflector::camelize($this->args[0]);
+ $return = $this->Acl->{$type}->recover();
+ if ($return === true) {
+ $this->out(__('Tree has been recovered, or tree did not need recovery.'));
+ } else {
+ $this->err(__('Tree recovery failed. '));
+ return false;
+ }
+ }
+}
diff --git a/plugins/Assets/models/behaviors/LogableBehavior.php b/plugins/Assets/models/behaviors/LogableBehavior.php
new file mode 100644
index 000000000..e17f0ba93
--- /dev/null
+++ b/plugins/Assets/models/behaviors/LogableBehavior.php
@@ -0,0 +1,535 @@
+ (Alek), age (28) => (29)] or [name, age]
+ *
+ * - "version_id" [int] : cooperates with RevisionBehavior to link the the shadow table (thus linking to old data)
+ *
+ * Remember that Logable behavior needs to be added after RevisionBehavior. In fact, just put it last to be safe.
+ *
+ * Optionally register what user was responisble for the activity :
+ *
+ * - Supply configuration only if defaults are wrong. Example given with defaults :
+ *
+ * class Apple extends AppModel {
+ * var $name = 'Apple';
+ * var $actsAs = array('Logable' => array('userModel' => 'User', 'userKey' => 'user_id'));
+ * [..]
+ *
+ * - In AppController (or single controller if only needed once) add these lines to beforeFilter :
+ *
+ * if (sizeof($this->uses) && $this->{$this->modelClass}->Behaviors->attached('Logable')) {
+ * $this->{$this->modelClass}->setUserData($this->activeUser);
+ * }
+ *
+ * This is not used any longer, as AuthComponent collect the user data instead.
+ *
+ * Where "$activeUser" should be an array in the standard format for the User model used :
+ *
+ * $activeUser = array( $UserModel->alias => array( $UserModel->primaryKey => 123, $UserModel->displayField => 'Alexander'));
+ * // any other key is just ignored by this behaviour.
+ *
+ * @author Alexander Morland (alexander#maritimecolours.no)
+ * @co-author Eskil Mjelva Saatvedt
+ * @co-author Ronny Vindenes
+ * @co-author Carl Erik Fyllingen
+ * @contributor Miha
+ * @category Behavior
+ * @version 2.3
+ * @modified 15.november 2011 by Eskil
+ */
+
+class LogableBehavior extends ModelBehavior {
+
+ public $user = NULL;
+
+ public $UserModel = FALSE;
+
+ public $settings = array();
+
+ public $defaults = array(
+ 'enabled' => true,
+ 'userModel' => 'User',
+ 'userKey' => 'user_id',
+ 'change' => 'list',
+ 'description_ids' => TRUE,
+ 'skip' => array(),
+ 'ignore' => array(),
+ 'classField' => 'model',
+ 'foreignKey' => 'model_id');
+
+ public $schema = array();
+
+ /**
+ * Cake called intializer
+ * Config options are :
+ * userModel : 'User'. Class name of the user model you want to use (User by default), if you want to save User in log
+ * userKey : 'user_id'. The field for saving the user to (user_id by default).
+ * change : 'list' > [name, age]. Set to 'full' for [name (alek) => (Alek), age (28) => (29)]
+ * description_ids : TRUE. Set to FALSE to not include model id and user id in the title field
+ * skip : array(). String array of actions to not log
+ *
+ * @param Object $Model
+ * @param array $config
+ */
+ function setup(&$Model, $config = array()) {
+
+ if (!is_array($config)) {
+ $config = array();
+ }
+ $this->settings[$Model->alias] = array_merge($this->defaults, $config);
+ $this->settings[$Model->alias]['ignore'][] = $Model->primaryKey;
+
+ $this->Log = & ClassRegistry::init('Log');
+ if ($this->settings[$Model->alias]['userModel'] != $Model->alias) {
+ $this->UserModel = & ClassRegistry::init($this->settings[$Model->alias]['userModel']);
+ } else {
+ $this->UserModel = $Model;
+ }
+ $this->schema = $this->Log->schema();
+ App::import('Component', 'Auth');
+ $this->user[$this->settings[$Model->alias]['userModel']] = AuthComponent::user();
+ }
+
+ function settings(&$Model) {
+
+ return $this->settings[$Model->alias];
+ }
+
+ function enableLog(&$Model, $enable = null) {
+
+ if ($enable !== null) {
+ $this->settings[$Model->alias]['enabled'] = $enable;
+ }
+ return $this->settings[$Model->alias]['enabled'];
+ }
+
+ /**
+ * Useful for getting logs for a model, takes params to narrow find.
+ * This method can actually also be used to find logs for all models or
+ * even another model. Using no params will return all activities for
+ * the models it is called from.
+ *
+ * Possible params :
+ * 'model' : mixed (NULL) String with className, NULL to get current or FALSE to get everything
+ * 'action' : string (NULL) String with action (add/edit/delete), NULL gets all
+ * 'order' : string ('created DESC') String with custom order
+ * 'conditions : array (array()) Add custom conditions
+ * 'model_id' : int (NULL) Add a int
+ *
+ * (remember to use your own user key if you're not using 'user_id')
+ * 'user_id' : int (NULL) Defaults to all users, supply id if you want for only one User
+ *
+ * @param Object $Model
+ * @param array $params
+ * @return array
+ */
+ function findLog(&$Model, $params = array()) {
+
+ $defaults = array(
+ $this->settings[$Model->alias]['classField'] => NULL,
+ 'action' => NULL,
+ 'order' => 'created DESC',
+ $this->settings[$Model->alias]['userKey'] => NULL,
+ 'conditions' => array(),
+ $this->settings[$Model->alias]['foreignKey'] => NULL,
+ 'fields' => array(),
+ 'limit' => 50);
+ $params = array_merge($defaults, $params);
+ $options = array(
+ 'order' => $params['order'],
+ 'conditions' => $params['conditions'],
+ 'fields' => $params['fields'],
+ 'limit' => $params['limit']);
+ if ($params[$this->settings[$Model->alias]['classField']] === NULL) {
+ $params[$this->settings[$Model->alias]['classField']] = $Model->alias;
+ }
+ if ($params[$this->settings[$Model->alias]['classField']]) {
+ if (isset($this->schema[$this->settings[$Model->alias]['classField']])) {
+ $options['conditions'][$this->settings[$Model->alias]['classField']] = $params[$this->settings[$Model->alias]['classField']];
+ } elseif (isset($this->schema['description'])) {
+ $options['conditions']['description LIKE '] = $params[$this->settings[$Model->alias]['classField']] . '%';
+ } else {
+ return FALSE;
+ }
+ }
+ if ($params['action'] && isset($this->schema['action'])) {
+ $options['conditions']['action'] = $params['action'];
+ }
+ if ($params[$this->settings[$Model->alias]['userKey']] && $this->UserModel && is_numeric($params[$this->settings[$Model->alias]['userKey']])) {
+ $options['conditions'][$this->settings[$Model->alias]['userKey']] = $params[$this->settings[$Model->alias]['userKey']];
+ }
+ if ($params[$this->settings[$Model->alias]['foreignKey']] && is_numeric($params[$this->settings[$Model->alias]['foreignKey']])) {
+ $options['conditions'][$this->settings[$Model->alias]['foreignKey']] = $params[$this->settings[$Model->alias]['foreignKey']];
+ }
+ return $this->Log->find('all', $options);
+ }
+
+ /**
+ * Get list of actions for one user.
+ * Params for getting (one line) activity descriptions
+ * and/or for just one model
+ *
+ * @example $this->Model->findUserActions(301,array('model' => 'BookTest'));
+ * @example $this->Model->findUserActions(301,array('events' => true));
+ * @example $this->Model->findUserActions(301,array('fields' => array('id','model'),'model' => 'BookTest');
+ * @param Object $Model
+ * @param int $user_id
+ * @param array $params
+ * @return array
+ */
+ function findUserActions(&$Model, $user_id, $params = array()) {
+
+ if (!$this->UserModel) {
+ return NULL;
+ }
+ // if logged in user is asking for her own log, use the data we allready have
+ if (isset($this->user) && isset($this->user[$this->UserModel->alias][$this->UserModel->primaryKey]) && $user_id == $this->user[$this->UserModel->alias][$this->UserModel->primaryKey] && isset($this->user[$this->UserModel->alias][$this->UserModel->displayField])) {
+ $username = $this->user[$this->UserModel->alias][$this->UserModel->displayField];
+ } else {
+ $this->UserModel->recursive = -1;
+ $user = $this->UserModel->find(array(
+ $this->UserModel->primaryKey => $user_id));
+ $username = $user[$this->UserModel->alias][$this->UserModel->displayField];
+ }
+ $fields = array();
+ if (isset($params['fields'])) {
+ if (is_array($params['fields'])) {
+ $fields = $params['fields'];
+ } else {
+ $fields = array(
+ $params['fields']);
+ }
+ }
+ $conditions = array(
+ $this->settings[$Model->alias]['userKey'] => $user_id);
+ if (isset($params[$this->settings[$Model->alias]['classField']])) {
+ $conditions[$this->settings[$Model->alias]['classField']] = $params[$this->settings[$Model->alias]['classField']];
+ }
+ $data = $this->Log->find('all', array(
+ 'conditions' => $conditions,
+ 'recursive' => -1,
+ 'fields' => $fields));
+ if (!isset($params['events']) || ( isset($params['events']) && $params['events'] == false )) {
+ return $data;
+ }
+ $result = array();
+ foreach ( $data as $key => $row ) {
+ $one = $row['Log'];
+ $result[$key]['Log']['id'] = $one['id'];
+ $result[$key]['Log']['event'] = $username;
+ // have all the detail models and change as list :
+ if (isset($one[$this->settings[$Model->alias]['classField']]) && isset($one['action']) && isset($one['change']) && isset($one[$this->settings[$Model->alias]['foreignKey']])) {
+ if ($one['action'] == 'edit') {
+ $result[$key]['Log']['event'] .= ' edited ' . $one['change'] . ' of ' . low($one[$this->settings[$Model->alias]['classField']]) . '(id ' . $one[$this->settings[$Model->alias]['foreignKey']] . ')';
+
+ // ' at '.$one['created'];
+ } elseif ($one['action'] == 'add') {
+ $result[$key]['Log']['event'] .= ' added a ' . low($one[$this->settings[$Model->alias]['classField']]) . '(id ' . $one[$this->settings[$Model->alias]['foreignKey']] . ')';
+ } elseif ($one['action'] == 'delete') {
+ $result[$key]['Log']['event'] .= ' deleted the ' . low($one[$this->settings[$Model->alias]['classField']]) . '(id ' . $one[$this->settings[$Model->alias]['foreignKey']] . ')';
+ }
+
+ } elseif (isset($one[$this->settings[$Model->alias]['classField']]) && isset($one['action']) && isset($one[$this->settings[$Model->alias]['foreignKey']])) { // have model,model_id and action
+ if ($one['action'] == 'edit') {
+ $result[$key]['Log']['event'] .= ' edited ' . low($one[$this->settings[$Model->alias]['classField']]) . '(id ' . $one[$this->settings[$Model->alias]['foreignKey']] . ')';
+
+ // ' at '.$one['created'];
+ } elseif ($one['action'] == 'add') {
+ $result[$key]['Log']['event'] .= ' added a ' . low($one[$this->settings[$Model->alias]['classField']]) . '(id ' . $one[$this->settings[$Model->alias]['foreignKey']] . ')';
+ } elseif ($one['action'] == 'delete') {
+ $result[$key]['Log']['event'] .= ' deleted the ' . low($one[$this->settings[$Model->alias]['classField']]) . '(id ' . $one[$this->settings[$Model->alias]['foreignKey']] . ')';
+ }
+ } else { // only description field exist
+ $result[$key]['Log']['event'] = $one['description'];
+ }
+
+ }
+ return $result;
+ }
+
+ /**
+ * Use this to supply a model with the data of the logged in User.
+ * Intended to be called in AppController::beforeFilter like this :
+ *
+ * if ($this->{$this->modelClass}->Behaviors->attached('Logable')) {
+ * $this->{$this->modelClass}->setUserData($activeUser);/
+ * }
+ *
+ * The $userData array is expected to look like the result of a
+ * User::find(array('id'=>123));
+ *
+ * @param Object $Model
+ * @param array $userData
+ */
+ function setUserData(&$Model, $userData = null) {
+
+ if ($userData) {
+ $this->user = $userData;
+ }
+ }
+
+ /**
+ * Used for logging custom actions that arent crud, like login or download.
+ *
+ * @example $this->Boat->customLog('ship', 66, array('title' => 'Titanic heads out'));
+ * @param Object $Model
+ * @param string $action name of action that is taking place (dont use the crud ones)
+ * @param int $id id of the logged item (ie model_id in logs table)
+ * @param array $values optional other values for your logs table
+ */
+ function customLog(&$Model, $action, $id, $values = array()) {
+
+ $logData['Log'] = $values;
+ /** @todo clean up $logData */
+ if (isset($this->schema[$this->settings[$Model->alias]['foreignKey']]) && is_numeric($id)) {
+ $logData['Log'][$this->settings[$Model->alias]['foreignKey']] = $id;
+ }
+ $title = NULL;
+ if (isset($values['title'])) {
+ $title = $values['title'];
+ unset($logData['Log']['title']);
+ }
+ $logData['Log']['action'] = $action;
+ $this->_saveLog($Model, $logData, $title);
+ }
+
+ function clearUserData(&$Model) {
+
+ $this->user = NULL;
+ }
+
+ function setUserIp(&$Model, $userIP = null) {
+
+ $this->userIP = $userIP;
+ }
+
+ function beforeDelete(&$Model) {
+
+ if (!$this->settings[$Model->alias]['enabled']) {
+ return true;
+ }
+ if (isset($this->settings[$Model->alias]['skip']['delete']) && $this->settings[$Model->alias]['skip']['delete']) {
+ return true;
+ }
+ $Model->recursive = -1;
+ $Model->read();
+ return true;
+ }
+
+ function afterDelete(&$Model) {
+
+ if (!$this->settings[$Model->alias]['enabled']) {
+ return true;
+ }
+ if (isset($this->settings[$Model->alias]['skip']['delete']) && $this->settings[$Model->alias]['skip']['delete']) {
+ return true;
+ }
+ $logData = array();
+ if (isset($this->schema['description'])) {
+ $logData['Log']['description'] = $Model->alias;
+ if (isset($Model->data[$Model->alias][$Model->displayField]) && $Model->displayField != $Model->primaryKey) {
+ $logData['Log']['description'] .= ' "' . $Model->data[$Model->alias][$Model->displayField] . '"';
+ }
+ if ($this->settings[$Model->alias]['description_ids']) {
+ $logData['Log']['description'] .= ' (' . $Model->id . ') ';
+ }
+ $logData['Log']['description'] .= __('deleted', TRUE);
+ }
+ $logData['Log']['action'] = 'delete';
+ $this->_saveLog($Model, $logData);
+ }
+
+ function beforeSave(&$Model) {
+
+ if (isset($this->schema['change']) && $Model->id) {
+ $this->old = $Model->find('first', array(
+ 'conditions' => array(
+ $Model->alias . '.' . $Model->primaryKey => $Model->id),
+ 'recursive' => -1));
+ }
+ return true;
+ }
+
+ function afterSave(&$Model, $created) {
+
+ if (!$this->settings[$Model->alias]['enabled']) {
+ return true;
+ }
+ if (isset($this->settings[$Model->alias]['skip']['add']) && $this->settings[$Model->alias]['skip']['add'] && $created) {
+ return true;
+ } elseif (isset($this->settings[$Model->alias]['skip']['edit']) && $this->settings[$Model->alias]['skip']['edit'] && !$created) {
+ return true;
+ }
+ $keys = array_keys($Model->data[$Model->alias]);
+ $diff = array_diff($keys, $this->settings[$Model->alias]['ignore']);
+ if (sizeof($diff) == 0 && empty($Model->logableAction)) {
+ return false;
+ }
+ if ($Model->id) {
+ $id = $Model->id;
+ } elseif ($Model->insertId) {
+ $id = $Model->insertId;
+ }
+ if (isset($this->schema[$this->settings[$Model->alias]['foreignKey']])) {
+ $logData['Log'][$this->settings[$Model->alias]['foreignKey']] = $id;
+ }
+ if (isset($this->schema['description'])) {
+ $logData['Log']['description'] = $Model->alias . ' ';
+ if (isset($Model->data[$Model->alias][$Model->displayField]) && $Model->displayField != $Model->primaryKey) {
+ $logData['Log']['description'] .= '"' . $Model->data[$Model->alias][$Model->displayField] . '" ';
+ }
+
+ if ($this->settings[$Model->alias]['description_ids']) {
+ $logData['Log']['description'] .= '(' . $id . ') ';
+ }
+
+ if ($created) {
+ $logData['Log']['description'] .= __('added', TRUE);
+ } else {
+ $logData['Log']['description'] .= __('updated', TRUE);
+ }
+ }
+ if (isset($this->schema['action'])) {
+ if ($created) {
+ $logData['Log']['action'] = 'add';
+ } else {
+ $logData['Log']['action'] = 'edit';
+ }
+
+ }
+ if (isset($this->schema['change'])) {
+ $logData['Log']['change'] = '';
+ $db_fields = array_keys($Model->schema());
+ $changed_fields = array();
+ foreach ( $Model->data[$Model->alias] as $key => $value ) {
+ if (isset($Model->data[$Model->alias][$Model->primaryKey]) && !empty($this->old) && isset($this->old[$Model->alias][$key])) {
+ $old = $this->old[$Model->alias][$key];
+ } else {
+ $old = '';
+ }
+ if ($key != 'modified' && !in_array($key, $this->settings[$Model->alias]['ignore']) && $value != $old && in_array($key, $db_fields)) {
+ if ($this->settings[$Model->alias]['change'] == 'full') {
+ $changed_fields[] = $key . ' (' . $old . ') => (' . $value . ')';
+ } else if ($this->settings[$Model->alias]['change'] == 'serialize') {
+ $changed_fields[$key] = array(
+ 'old' => $old,
+ 'value' => $value);
+ } else {
+ $changed_fields[] = $key;
+ }
+ }
+ }
+ $changes = sizeof($changed_fields);
+ if ($changes == 0) {
+ return true;
+ }
+ if ($this->settings[$Model->alias]['change'] == 'serialize') {
+ $logData['Log']['change'] = serialize($changed_fields);
+ } else {
+ $logData['Log']['change'] = implode(', ', $changed_fields);
+ }
+ $logData['Log']['changes'] = $changes;
+ }
+ $this->_saveLog($Model, $logData);
+ }
+
+ /**
+ * Does the actual saving of the Log model. Also adds the special field if possible.
+ *
+ * If model field in table, add the Model->alias
+ * If action field is NOT in table, remove it from dataset
+ * If the userKey field in table, add it to dataset
+ * If userData is supplied to model, add it to the title
+ *
+ * @param Object $Model
+ * @param array $logData
+ */
+ function _saveLog(&$Model, $logData, $title = null) {
+
+ if ($title !== NULL) {
+ $logData['Log']['title'] = $title;
+ } elseif ($Model->displayField == $Model->primaryKey) {
+ $logData['Log']['title'] = $Model->alias . ' (' . $Model->id . ')';
+ } elseif (isset($Model->data[$Model->alias][$Model->displayField])) {
+ $logData['Log']['title'] = $Model->data[$Model->alias][$Model->displayField];
+ } else {
+ $logData['Log']['title'] = $Model->field($Model->displayField);
+ }
+
+ if (isset($this->schema[$this->settings[$Model->alias]['classField']])) {
+ // by miha nahtigal
+ $logData['Log'][$this->settings[$Model->alias]['classField']] = $Model->name;
+ }
+
+ if (isset($this->schema[$this->settings[$Model->alias]['foreignKey']]) && !isset($logData['Log'][$this->settings[$Model->alias]['foreignKey']])) {
+ if ($Model->id) {
+ $logData['Log'][$this->settings[$Model->alias]['foreignKey']] = $Model->id;
+ } elseif ($Model->insertId) {
+ $logData['Log'][$this->settings[$Model->alias]['foreignKey']] = $Model->insertId;
+ }
+ }
+
+ if (!isset($this->schema['action'])) {
+ unset($logData['Log']['action']);
+ } elseif (isset($Model->logableAction) && !empty($Model->logableAction)) {
+ $logData['Log']['action'] = implode(',', $Model->logableAction); // . ' ' . $logData['Log']['action'];
+ unset($Model->logableAction);
+ }
+
+ if (isset($this->schema['version_id']) && isset($Model->version_id)) {
+ $logData['Log']['version_id'] = $Model->version_id;
+ unset($Model->version_id);
+ }
+
+ if (isset($this->schema['ip']) && $this->userIP) {
+ $logData['Log']['ip'] = $this->userIP;
+ }
+
+ if (isset($this->schema[$this->settings[$Model->alias]['userKey']]) && $this->user) {
+ $logData['Log'][$this->settings[$Model->alias]['userKey']] = $this->user[$this->UserModel->alias][$this->UserModel->primaryKey];
+ }
+
+ if (isset($this->schema['description'])) {
+ if ($this->user && $this->UserModel) {
+ $logData['Log']['description'] .= ' by ' . $this->settings[$Model->alias]['userModel'] . ' "' . $this->user[$this->UserModel->alias][$this->UserModel->displayField] . '"';
+ if ($this->settings[$Model->alias]['description_ids']) {
+ $logData['Log']['description'] .= ' (' . $this->user[$this->UserModel->alias][$this->UserModel->primaryKey] . ')';
+ }
+
+ } else {
+ // UserModel is active, but the data hasnt been set. Assume system action.
+ $logData['Log']['description'] .= ' by System';
+ }
+ $logData['Log']['description'] .= '.';
+ }
+ $this->Log->create($logData);
+ $this->Log->save(null, array(
+ 'validate' => false,
+ 'callbacks' => false));
+ }
+}
\ No newline at end of file
diff --git a/plugins/SysLog/Lib/SysLog.php b/plugins/SysLog/Lib/SysLog.php
new file mode 100644
index 000000000..3116ffcd3
--- /dev/null
+++ b/plugins/SysLog/Lib/SysLog.php
@@ -0,0 +1,91 @@
+isWindows()) {
+ $default_facility = LOG_USER;
+ } else {
+ $default_facility= LOG_LOCAL0;
+ }
+ $options += array('ident' => LOGS, 'facility' => $default_facility);
+ $this->_ident = $options['ident'];
+ $this->_facility = $options['facility'];
+ }
+
+/**
+ * Utilty method to identify if we're running on a Windows box.
+ *
+ * @return boolean if running on windows.
+ */
+ function isWindows() {
+ return (DIRECTORY_SEPARATOR == '\\' ? true : false);
+ }
+
+/**
+ * Implements writing to the specified syslog
+ *
+ * @param string $type The type of log you are making.
+ * @param string $message The message you want to log.
+ * @return boolean success of write.
+ */
+ function write($type, $message) {
+ $debugTypes = array('notice', 'info', 'debug');
+ $priority = LOG_INFO;
+ if ($type == 'error' || $type == 'warning') {
+ $priority = LOG_ERR;
+ } elseif (in_array($type, $debugTypes)) {
+ $priority = LOG_DEBUG;
+ }
+ $output = date('Y-m-d H:i:s') . ' ' . ucfirst($type) . ': ' . $message . "\n";
+ if (!openlog($this->_ident, LOG_PID | LOG_PERROR, $this->_facility)) {
+ return false;
+ }
+ $result = syslog($priority, $output);
+ closelog();
+ return $result;
+ }
+}
+?>
\ No newline at end of file
diff --git a/plugins/index.txt b/plugins/index.txt
new file mode 100644
index 000000000..96470e1ca
--- /dev/null
+++ b/plugins/index.txt
@@ -0,0 +1,4 @@
+https://github.com/markstory/acl_extras
+https://github.com/eskil-saatvedt/CakePHP-Assets (LogableBehavior)
+http://bakery.cakephp.org/articles/rikdc/2010/06/07/syslog-component
+http://xp-dev.com/trac/cakephp/browser/cakephp/libs/magic_tools
\ No newline at end of file
diff --git a/plugins/magic_tools/models/behaviors/orphans_protectable.php b/plugins/magic_tools/models/behaviors/orphans_protectable.php
new file mode 100644
index 000000000..c4e2d61f4
--- /dev/null
+++ b/plugins/magic_tools/models/behaviors/orphans_protectable.php
@@ -0,0 +1,126 @@
+_deletionError = null; // Stores the deletion error message
+ $Model->orphansProtectableOptions = array_merge(array(
+ 'listPossibleOrphans' => true,
+ 'htmlError' => false
+ ), $settings);
+ }
+
+ /**
+ * Checks if there would be orphaned record left behind after deletion of this record; if so, deletion is prevented.
+ *
+ * @param $model Model
+ * @param $cascade boolean
+ * @return boolean
+ */
+ function beforeDelete(&$model, $cascade) {
+ if($cascade) return true;
+ return !$Model->wouldLeaveOrphanedRecordsBehind();
+ }
+
+ /**
+ * Checks if deletion of this record would leave orphaned associated records behind.
+ *
+ * @param $model Model
+ * @return boolean
+ */
+ function wouldLeaveOrphanedRecordsBehind(&$model) {
+ $possibleOrphans = array();
+
+ foreach($Model->hasMany as $model => $settings) {
+ // Is relationship is dependent?
+ if($settings['dependent']){ // Yes! Possible orphans are deleted, too!
+ // Do nothing
+ } else { // No! Possible orphans should be protected!
+ // Is there a possible orphan for this relation?
+ $Model->{$model}->recursive = -1;
+ $objects = $Model->{$model}->find('all', array('conditions' => array($settings['className'].'.'.$settings['foreignKey'] => $Model->id), 'order' => 'id asc'));
+ if(count($objects) > 0) { // Yes, there is at least one possible orphan!
+ $objectIds = array();
+ foreach($objects as $object) {
+ $objectIds[] = $object[$model]['id'];
+ }
+ $possibleOrphans[$model] = $objectIds;
+ }
+ }
+ }
+
+ // Would orphans be left behind?
+ if(count($possibleOrphans) > 0) { // Yes! Create deletion error message!
+ $Model->_deletionError = $Model->createDeletionError($possibleOrphans);
+ return true;
+ } else { // No!
+ return false;
+ }
+ }
+
+ /**
+ * Returns the deletion error message (if there is one).
+ *
+ * @param $model Model
+ * @return string
+ */
+ function getDeletionError(&$model) {
+ return $Model->_deletionError;
+ }
+
+ /**
+ * Creates the deletion error message and returns it.
+ *
+ * @param $model Model
+ * @param $possibleOrphans array
+ * @return string
+ */
+ function createDeletionError(&$model, $possibleOrphans) {
+ $errorParts = array();
+ foreach($possibleOrphans as $model => $ids) {
+ $count = count($ids);
+ $modelName = $count > 1 ? Inflector::pluralize($model) : $model;
+ $errorParts[] = $count.' '.__($modelName, true).' (ID: '.$Model->createDeletionErrorIds($model, $ids).')';
+ }
+ return __('it has the following dependent items', true).': '.implode($errorParts, ', ');
+ }
+
+ /**
+ * Creates a string containing HTML-links to comma separated IDs of the potentially orphaned records of the specified model.
+ *
+ * @param $model Model
+ * @param $orphanModel string
+ * @param $ids array
+ * @return string
+ */
+ function createDeletionErrorIds(&$model, $orphanModel, $ids) {
+ $messageParts = array();
+ if($Model->orphansProtectableOptions['htmlError']) {
+ foreach($ids as $id) {
+ $messageParts[] = ''.$id.' '; // TODO: Noch unschön! --zivi-muh
+ }
+ } else {
+ $messageParts = $ids;
+ }
+ return implode($messageParts, ', ');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tools/curl/input/event.xml b/tools/curl/input/event.xml
index ab5e7dd75..48523c8ad 100644
--- a/tools/curl/input/event.xml
+++ b/tools/curl/input/event.xml
@@ -1,11 +1,11 @@
14
- NCIRC
+ ORG
2012-04-12
Medium
- TT6666: malixioious XLS (EDIT 234..5)
- 3
+ info
+ 1
0
4f8c2c4e-00dc-42c9-83ad-76e9ff32448e
0
@@ -31,8 +31,7 @@
4f8c2d08-7e6c-4648-8730-50a7ff32448e
1
0
- Summary_report_Vienna_2012 27 March
- ok_z.doc|b34a8fcf8e5c81de3f6f177bb6171929
+ A.doc|3f6f1aaab6171925c81de9b34a8fcf8e
c
@@ -45,22 +44,22 @@
4f8c2c69-9bf8-4279-8d03-2138ff32448e
1
0
- CVE-2010-3333
+ CVE-XXXX-XXXX
c
11
- 2012-04-03
+ 2011-01-03
4f8812ff-ded0-4592-9227-0615ff32448e
9
- 2012-04-02
+ 2011-02-02
4f85981e-d044-4b16-bc16-0a35ff32448e
6
- 2012-03-22
+ 2011-03-01
4f7a9faa-91d4-4c91-8ec6-0878ff32448e