From 8c511833b8637581e4242e5e793b0908e15f62ef Mon Sep 17 00:00:00 2001
From: alice grosch <a.grosch@fz-juelich.de>
Date: Wed, 29 Jan 2020 16:16:51 +0100
Subject: [PATCH] Add encryption

---
 dicom_upload/widget_upload.py |   2 +
 examples/introduction.ipynb   | 129 ++++++++++++++++++++++++----------
 package-lock.json             |   7 +-
 package.json                  |   4 +-
 src/widget.ts                 |  10 ++-
 5 files changed, 108 insertions(+), 44 deletions(-)

diff --git a/dicom_upload/widget_upload.py b/dicom_upload/widget_upload.py
index 5664759..6a66aaa 100644
--- a/dicom_upload/widget_upload.py
+++ b/dicom_upload/widget_upload.py
@@ -59,6 +59,8 @@ class Uploader(DescriptionWidget, ValueWidget):
     token = Unicode(help='Jupyter API token').tag(sync=True)
     upload_url = Unicode('http://localhost:8888/api/contents/',
                         help='http(s)://notebook_url/api/contents/').tag(sync=True)
+    password = Unicode(None, allow_none=True, 
+        help="If set, encrypts DICOM files with the password.").tag(sync=True)
 
     # Variables set on the JavaScript side.
     files = List().tag(sync=True)
diff --git a/examples/introduction.ipynb b/examples/introduction.ipynb
index 08a7ac0..0e495ff 100644
--- a/examples/introduction.ipynb
+++ b/examples/introduction.ipynb
@@ -4,12 +4,14 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "# Introduction"
+    "# Upload DICOM file(s)\n",
+    "\n",
+    "Header tags starting with 0008 and 0010 are removed on the JS side before the data is transferred."
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -19,14 +21,15 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
     "# Upload to the examples subdirectory.\n",
     "upload_url = 'http://localhost:8888/api/contents/examples/'\n",
-    "token = 'c13dac305e39982bb3236b508fda269b2b79daeaafd07d80'\n",
+    "token = '<token>'\n",
     "\n",
+    "# The button can be styled like a ipywidget button widget\n",
     "uploader = dicom_upload.Uploader(upload_url=upload_url,\n",
     "                          token=token,\n",
     "                          button_style='primary', \n",
@@ -35,7 +38,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -59,38 +62,9 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "application/vnd.jupyter.widget-view+json": {
-       "model_id": "be486335a3fb40d8a1c3af9326da53bd",
-       "version_major": 2,
-       "version_minor": 0
-      },
-      "text/plain": [
-       "Uploader(value=None, button_style='primary', description='Upload', layout=Layout(border='solid blue 1px'), tok…"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "application/vnd.jupyter.widget-view+json": {
-       "model_id": "20eb44ff6efb40228d316f854b21445c",
-       "version_major": 2,
-       "version_minor": 0
-      },
-      "text/plain": [
-       "Output()"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    }
-   ],
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
     "display(uploader)\n",
     "display(out)"
@@ -98,7 +72,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -124,6 +98,83 @@
     "ds = pydicom.dcmread('./IM000001')\n",
     "ds"
    ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Upload encrypted DICOM file(s)\n",
+    "\n",
+    "If a password is passed, the file(s) will be encrypted before being sent to the server."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import dicom_upload"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Upload to the examples subdirectory.\n",
+    "upload_url = 'http://localhost:8888/api/contents/examples/'\n",
+    "token = '<token>'\n",
+    "password = '<password>'\n",
+    "\n",
+    "uploader = dicom_upload.Uploader(upload_url=upload_url, token=token, password=password)\n",
+    "display(uploader)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "uploader.upload()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Decrypt the file"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "!openssl aes-256-cbc -d -md md5 -in IM000001 -k $password | base64 -d > IM000001.decoded"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Check decryption"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import pydicom\n",
+    "\n",
+    "ds = pydicom.dcmread('./IM000001.decoded')\n",
+    "ds"
+   ]
   }
  ],
  "metadata": {
@@ -146,5 +197,5 @@
   }
  },
  "nbformat": 4,
- "nbformat_minor": 2
+ "nbformat_minor": 4
 }
diff --git a/package-lock.json b/package-lock.json
index a882035..e20badd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "dicom-upload",
-  "version": "0.1.1",
+  "version": "0.1.2",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -1504,6 +1504,11 @@
         "randomfill": "^1.0.3"
       }
     },
+    "crypto-js": {
+      "version": "3.1.9-1",
+      "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz",
+      "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg="
+    },
     "css-loader": {
       "version": "3.4.2",
       "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.4.2.tgz",
diff --git a/package.json b/package.json
index a3e6a8f..ad99f49 100644
--- a/package.json
+++ b/package.json
@@ -10,8 +10,7 @@
   ],
   "files": [
     "lib/**/*.js",
-    "dist/*.js",
-    "css/*.css"
+    "dist/*.js"
   ],
   "homepage": "https://gitlab.version.fz-juelich.de/jupyter4jsc/j4j_extras/dicom-upload",
   "bugs": {
@@ -50,6 +49,7 @@
   },
   "dependencies": {
     "@jupyter-widgets/base": "^1.1.10 || ^2",
+    "crypto-js": "^3.1.9-1",
     "dicom-parser": "^1.8.4",
     "lodash": "^4.17.15",
     "spark-md5": "^3.0.0",
diff --git a/src/widget.ts b/src/widget.ts
index 661371e..3d89ef6 100644
--- a/src/widget.ts
+++ b/src/widget.ts
@@ -13,6 +13,7 @@ import * as _ from 'lodash';
 import { parseDicom } from 'dicom-parser';
 import { clone } from 'underscore';
 
+import CryptoJS = require('crypto-js');
 import SparkMD5 = require('spark-md5');
 
 export
@@ -248,12 +249,17 @@ class UploaderView extends DOMWidgetView {
             that.touch();
             return;
           }
-          let b64Array = Uint8ToBase64(slicedByteArray);
+          let b64String = Uint8ToBase64(slicedByteArray);
 
           let model = { name: file.name, path: file.name }
           model["type"] = 'file';
           model["format"] = 'base64';
-          model["content"] = b64Array;
+          if (that.model.get('password') == null) {
+            model["content"] = b64String;
+          } else { // Encrypt
+            let key = that.model.get('password');
+            model["content"] = CryptoJS.AES.encrypt(b64String, key).toString();
+          }
 
           fetch(upload_url + file.name, {
             method: "PUT",
-- 
GitLab