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