From c89db1bc4c5674cd60292f98b43c56e9a785f1c8 Mon Sep 17 00:00:00 2001
From: Eugen Neuber <eugen.neuber@tugraz.at>
Date: Wed, 20 May 2020 13:10:36 +0200
Subject: [PATCH] Deny files not matching required mime types

See issue #2
---
 packages/file-handling/README.md         |  5 +++++
 packages/file-handling/src/demo.js       | 15 +++++++--------
 packages/file-handling/src/fileupload.js | 23 +++++++++++++++++++----
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/packages/file-handling/README.md b/packages/file-handling/README.md
index 9b30f26a..7b610c14 100644
--- a/packages/file-handling/README.md
+++ b/packages/file-handling/README.md
@@ -19,6 +19,11 @@
 - `deferred` (optional): if set files will not be uploaded immediately but only queued
     - use method `uploadFile` or `uploadOneQueuedFile` to really upload the queued file  
     - example `<vpu-fileupload deferred></vpu-fileupload>`
+- `allowed-mime-types` (optional): if set accept only files matching mime types
+    - example `<vpu-fileupload allowed-mime-types='application/pdf'></vpu-fileupload>` ... PDFs only
+    - example `<vpu-fileupload allowed-mime-types='image/*'></vpu-fileupload>` ... images (of all sub types) only
+    - example `<vpu-fileupload allowed-mime-types='image/png,text/plain'></vpu-fileupload>` ... PNGs or TXTs only
+    - example `<vpu-fileupload allowed-mime-types='*/*'></vpu-fileupload>` ... all file types (default)
 
 ## Local development
 
diff --git a/packages/file-handling/src/demo.js b/packages/file-handling/src/demo.js
index cdbb663a..8089e76f 100644
--- a/packages/file-handling/src/demo.js
+++ b/packages/file-handling/src/demo.js
@@ -80,18 +80,17 @@ class FileUploadDemo extends ScopedElementsMixin(LitElement) {
                 <div class="content">
                     <h2 class="subtitle">Send any File to Server</h2>
                     <p>There is no restriction for a specific file type:</p>
-                    <vpu-fileupload lang="de" url="${this.url}"></vpu-fileupload>
+                    <vpu-fileupload lang="de" url="${this.url}" allowed-mime-types="*/*"></vpu-fileupload>
                     <p>Only images are allowed here (JPG, PNG, GIF, TIF, ...):</p>
-                    <vpu-fileupload lang="de" url="${this.url}" accept="image/*"
+                    <vpu-fileupload lang="de" url="${this.url}" allowed-mime-types="image/*"
                         text="Abgabe nur für Bilder "></vpu-fileupload>
                     <p>This is for PDF only:</p>
-                    <vpu-fileupload lang="de" url="${this.url}" accept="application/pdf"
+                    <vpu-fileupload lang="de" url="${this.url}" allowed-mime-types="application/pdf"
                         text="Einreichung als PDF" button-label="PDF auswählen"></vpu-fileupload>
-                </div>
-                <div class="content">
-                    <h2>Log of uploads</h2>
-                    <ul id="log"></ul>
-                </div>
+                     <p>Text and images (JPG, PNG, GIF, TIF, ...) :</p>
+                    <vpu-fileupload lang="de" url="${this.url}" allowed-mime-types="text/plain,image/*"
+                        text="Abgabe für Text und Bilder "></vpu-fileupload>
+               </div>
             </section>
         `;
     }
diff --git a/packages/file-handling/src/fileupload.js b/packages/file-handling/src/fileupload.js
index 88e825aa..de0aeb67 100644
--- a/packages/file-handling/src/fileupload.js
+++ b/packages/file-handling/src/fileupload.js
@@ -17,7 +17,7 @@ export class FileUpload extends ScopedElementsMixin(VPULitElement) {
         this.lang = 'de';
         this.url = '';
         this.dropArea = null;
-        this.accept = '';
+        this.allowedMimeTypes = '';
         this.text = '';
         this.buttonLabel = '';
         this.uploadInProgress = false;
@@ -42,7 +42,7 @@ export class FileUpload extends ScopedElementsMixin(VPULitElement) {
         return {
             lang: { type: String },
             url: { type: String },
-            accept: { type: String },
+            allowedMimeTypes: { type: String, attribute: 'allowed-mime-types' },
             text: { type: String },
             buttonLabel: { type: String, attribute: 'button-label'},
             uploadInProgress: { type: Boolean, attribute: false},
@@ -150,9 +150,24 @@ export class FileUpload extends ScopedElementsMixin(VPULitElement) {
         let tempFilesToHandle = [];
         await commonUtils.asyncArrayForEach(files, async (file) => {
             if (file.size === 0) {
-                console.log('file ' + file.name + ' has size=0 and is denied!')
+                console.log('file \'' + file.name + '\' has size=0 and is denied!')
                 return;
             }
+            if (this.allowedMimeTypes) {
+                // check if file is allowed
+                const [fileMainType, fileSubType] = file.type.split('/');
+                const mimeTypes = this.allowedMimeTypes.split(',');
+                let deny = true;
+                mimeTypes.forEach((str) => {
+                    const [mainType, subType] = str.split('/');
+                    deny = deny && ((mainType !== '*' && mainType !== fileMainType) || (subType !== '*' && subType !== fileSubType));
+                });
+                if (deny) {
+                    console.log(`mime type ${file.type} of file '${file.name}' is not compatible with ${this.allowedMimeTypes}`);
+                    return;
+                }
+            }
+
             tempFilesToHandle.push(file);
         });
 
@@ -326,7 +341,7 @@ export class FileUpload extends ScopedElementsMixin(VPULitElement) {
             <div id="dropArea">
                 <div class="my-form" title="${this.uploadInProgress ? i18n.t('upload-disabled-title') : ''}">
                     <p>${this.text || i18n.t('intro')}</p>
-                    <input ?disabled="${this.uploadInProgress}" type="file" id="fileElem" multiple accept="${ifDefined(this.accept)}" name='file'>
+                    <input ?disabled="${this.uploadInProgress}" type="file" id="fileElem" multiple name='file'>
                     <label class="button is-primary" for="fileElem"><vpu-icon style="display: ${this.uploadInProgress ? "inline-block" : "none"}" name="lock"></vpu-icon> ${this.buttonLabel || i18n.t('upload-label')}</label>
                     <vpu-mini-spinner style="display: ${this.multipleUploadInProgress ? "inline-block" : "none"}"></vpu-mini-spinner>
                 </div>
-- 
GitLab