[pmg-devel] [PATCH pmg-gui 3/3] add Attachment Quarantine

Dominik Csapak d.csapak at proxmox.com
Thu Sep 26 12:28:17 CEST 2019


the Quarantine part is mostly copied from VirusQuarantine and adapted
the AttachmentGrid is inspired by the SpamScore list

this adds a new quarantine type 'Attachment' in the gui, where the admins
can review and control the mails in the attachment quarantine

it also shows a list of attachment/parts and a link where they can
be downloaded (in case the admin want to only forward a single
attachment or review the file in detail)

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 js/AttachmentGrid.js       |  61 ++++++++++++
 js/AttachmentQuarantine.js | 185 +++++++++++++++++++++++++++++++++++++
 js/Makefile                |   2 +
 js/NavigationTree.js       |   6 ++
 4 files changed, 254 insertions(+)
 create mode 100644 js/AttachmentGrid.js
 create mode 100644 js/AttachmentQuarantine.js

diff --git a/js/AttachmentGrid.js b/js/AttachmentGrid.js
new file mode 100644
index 0000000..e31bd12
--- /dev/null
+++ b/js/AttachmentGrid.js
@@ -0,0 +1,61 @@
+Ext.define('PMG.grid.AttachmentGrid',{
+    extend: 'Ext.grid.GridPanel',
+    xtype: 'pmgAttachmentGrid',
+
+    store: {
+	autoDestroy: true,
+	fields: [ 'name', 'content-type', 'size' ],
+	proxy: {
+	    type: 'proxmox',
+	}
+    },
+
+    setID: function(rec) {
+	var me = this;
+	if (!rec || !rec.data || !rec.data.id) {
+	    me.getStore().removeAll();
+	    return;
+	}
+	var url = '/api2/json/quarantine/listattachments?id=' + rec.data.id;
+	me.mailid = rec.data.id;
+	me.store.proxy.setUrl(url);
+	me.store.load();
+    },
+
+    emptyText: gettext('No Attachments'),
+
+    download: function() {
+	alert(arguments);
+    },
+
+    columns: [
+	{
+	    text: gettext('Filename'),
+	    dataIndex: 'name',
+	    flex: 1,
+	},
+	{
+	    text: gettext('Filetype'),
+	    dataIndex: 'content-type',
+	    renderer: PMG.Utils.render_filetype,
+	    flex: 1,
+	},
+	{
+	    text: gettext('Size'),
+	    renderer: Proxmox.Utils.format_size,
+	    dataIndex: 'size',
+	    flex: 1,
+	},
+	{
+	    header: gettext('Download'),
+	    renderer: function(value, mD, rec) {
+		var me = this;
+		let url = '/api2/json/quarantine/download';
+		url += '?mailid=' + me.mailid;
+		url += '&attachmentid=' + rec.data.id;
+		return "<a target='_blank' class='download' download='"+ rec.data.name +"' href='" +
+		url + "'><i class='fa fa-fw fa-download'</i></a>";
+	    },
+	}
+    ]
+});
diff --git a/js/AttachmentQuarantine.js b/js/AttachmentQuarantine.js
new file mode 100644
index 0000000..18a270e
--- /dev/null
+++ b/js/AttachmentQuarantine.js
@@ -0,0 +1,185 @@
+/*global Proxmox*/
+/*jslint confusion: true*/
+/*format is a string and a function*/
+Ext.define('pmg-attachment-list', {
+    extend: 'Ext.data.Model',
+    fields: [ 'id', 'envelope_sender', 'from', 'sender', 'receiver', 'subject',
+	{ type: 'integer', name: 'bytes' },
+	{ type: 'date', dateFormat: 'timestamp', name: 'time' },
+	{
+	    type: 'string',
+	    name: 'day',
+	    convert: function(v, rec) {
+		return Ext.Date.format(rec.get('time'), 'Y-m-d');
+	    }, depends: ['time']
+	}
+    ],
+    proxy: {
+        type: 'proxmox',
+	url: "/api2/json/quarantine/attachment"
+    },
+    idProperty: 'id'
+});
+
+Ext.define('PMG.AttachmentQuarantine', {
+    extend: 'Ext.container.Container',
+    xtype: 'pmgAttachmentQuarantine',
+
+    border: false,
+    layout: { type: 'border' },
+
+    defaults: { border: false },
+
+    controller: {
+
+	xclass: 'Ext.app.ViewController',
+
+	updatePreview: function(raw, rec) {
+	    var preview = this.lookupReference('preview');
+
+	    if (!rec || !rec.data || !rec.data.id)  {
+		preview.update('');
+		preview.setDisabled(true);
+		return;
+	    }
+
+	    var url = '/api2/htmlmail/quarantine/content?id=' + rec.data.id + ((raw)?'&raw=1':'');
+	    preview.setDisabled(false);
+	    preview.update("<iframe frameborder=0 width=100% height=100% sandbox='allow-same-origin' src='" + url +"'></iframe>");
+	},
+
+	toggleRaw: function(button) {
+	    var me = this;
+	    var list = this.lookupReference('list');
+	    var rec = list.getSelection()[0] || {};
+	    me.raw = !me.raw;
+	    me.updatePreview(me.raw, rec);
+	},
+
+	btnHandler: function(button, e) {
+	    var list = this.lookupReference('list');
+	    var selected = list.getSelection();
+	    if (!selected.length) {
+		return;
+	    }
+
+	    var action = button.reference;
+
+	    PMG.Utils.doQuarantineAction(action, selected[0].data.id, function() {
+		list.getController().load();
+	    });
+	},
+
+	onSelectMail: function() {
+	    var me = this;
+	    var list = this.lookupReference('list');
+	    var rec = list.getSelection()[0] || {};
+
+	    me.updatePreview(me.raw || false, rec);
+	    this.lookupReference('attachmentlist').setID(rec);
+	},
+
+	control: {
+	    'button[reference=raw]': {
+		click: 'toggleRaw'
+	    },
+	    'pmgQuarantineList': {
+		selectionChange: 'onSelectMail'
+	    }
+	}
+
+    },
+
+    items: [
+	{
+	    title: gettext('Virus Quarantine'),
+	    xtype: 'pmgQuarantineList',
+	    emptyText: gettext('No data in database'),
+	    emailSelection: false,
+	    reference: 'list',
+	    region: 'west',
+	    width: 500,
+	    split: true,
+	    collapsible: false,
+	    store: {
+		model: 'pmg-attachment-list',
+		groupField: 'day',
+		groupDir: 'DESC',
+		sorters: [{
+		    property: 'time',
+		    direction: 'DESC'
+		}]
+	    },
+
+	    columns: [
+		{
+		    header: gettext('Sender/Subject'),
+		    dataIndex: 'subject',
+		    renderer: PMG.Utils.sender_renderer,
+		    flex: 1
+		},
+		{
+		    header: gettext('Size') + ' (KB)',
+		    renderer: function(v) { return Ext.Number.toFixed(v/1024, 0); },
+		    dataIndex: 'bytes',
+		    align: 'right',
+		    width: 90
+		},
+		{
+		    header: gettext('Date'),
+		    dataIndex: 'day',
+		    hidden: true
+		},
+		{
+		    xtype: 'datecolumn',
+		    header: gettext('Time'),
+		    dataIndex: 'time',
+		    format: 'H:i:s'
+		}
+	    ]
+	},
+	{
+	    title: gettext('Selected Mail'),
+	    border: false,
+	    region: 'center',
+	    split: true,
+	    reference: 'preview',
+	    disabled: true,
+	    dockedItems: [
+		{
+		    xtype: 'toolbar',
+		    dock: 'top',
+		    items: [
+			{
+			    xtype: 'button',
+			    reference: 'raw',
+			    text: gettext('Toggle Raw'),
+			    enableToggle: true,
+			    iconCls: 'fa fa-file-code-o'
+			},
+			'->',
+			{
+			    reference: 'deliver',
+			    text: gettext('Deliver'),
+			    iconCls: 'fa fa-paper-plane-o',
+			    handler: 'btnHandler'
+			},
+			{
+			    reference: 'delete',
+			    text: gettext('Delete'),
+			    iconCls: 'fa fa-trash-o',
+			    handler: 'btnHandler'
+			}
+		    ]
+		},
+		{
+		    xtype: 'pmgAttachmentGrid',
+		    minHeight: 50,
+		    maxHeight: 250,
+		    scrollable: true,
+		    reference: 'attachmentlist',
+		}
+	    ]
+	}
+    ]
+});
diff --git a/js/Makefile b/js/Makefile
index 6f4d449..d377c32 100644
--- a/js/Makefile
+++ b/js/Makefile
@@ -55,6 +55,8 @@ JSSRC=							\
 	VirusDetectorOptions.js				\
 	VirusQuarantineOptions.js			\
 	VirusQuarantine.js				\
+	AttachmentQuarantine.js				\
+	AttachmentGrid.js				\
 	ClamAVDatabase.js				\
 	VirusDetectorConfiguration.js			\
 	LDAPConfig.js					\
diff --git a/js/NavigationTree.js b/js/NavigationTree.js
index 342c715..b14cf1f 100644
--- a/js/NavigationTree.js
+++ b/js/NavigationTree.js
@@ -106,6 +106,12 @@ Ext.define('PMG.store.NavigationStore', {
 			path: 'pmgVirusQuarantine',
 			leaf: true
 		    },
+		    {
+			text: gettext('Attachment Quarantine'),
+			iconCls: 'fa fa-paperclip',
+			path: 'pmgAttachmentQuarantine',
+			leaf: true
+		    },
 		    {
 			text: gettext('User Whitelist'),
 			iconCls: 'fa fa-file-o',
-- 
2.20.1




More information about the pmg-devel mailing list