From 6efbf8515142f90db7eaeeec131601a30a9a13c0 Mon Sep 17 00:00:00 2001 From: Theresa Nguyen Date: Wed, 5 Feb 2025 00:30:47 -0800 Subject: [PATCH 1/5] implementing file basic file encryption --- client/src/components/DataUpload.js | 13 +++++- client/src/components/EncryptionUpload.js | 48 +++++++++++++++++++++++ package-lock.json | 18 ++++++++- 3 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 client/src/components/EncryptionUpload.js diff --git a/client/src/components/DataUpload.js b/client/src/components/DataUpload.js index b3f3f5f..64136b7 100755 --- a/client/src/components/DataUpload.js +++ b/client/src/components/DataUpload.js @@ -8,11 +8,13 @@ import { Paper, Container, } from "@mui/material"; +import { EncryptionUpload } from "./EncryptionUpload"; const DataUpload = () => { const [fileData, setFileData] = useState(null); const [price, setPrice] = useState(""); const [loading, setLoading] = useState(false); + const encryptionUpload = new EncryptionUpload(); const handleFileChange = (event) => { const file = event.target.files[0]; @@ -25,13 +27,20 @@ const DataUpload = () => { try { // Here add the blockchain integration later - console.log("File:", fileData); + // Encrypting file before uploading + const encryptingFile = await encryptionUpload.encryptFile(fileData); + + console.log("Encrypted Package:", { + filename: encryptingFile.filename, + contentType: encryptingFile.contentType, + encryptedSize: encryptingFile.encrypted.byteLength, + }); console.log("Price:", price); // Mock API call for now await new Promise((resolve) => setTimeout(resolve, 1000)); - alert("Data uploaded successfully!"); + alert("Data encrypted and ploaded successfully!"); setFileData(null); setPrice(""); } catch (error) { diff --git a/client/src/components/EncryptionUpload.js b/client/src/components/EncryptionUpload.js new file mode 100644 index 0000000..2841dd2 --- /dev/null +++ b/client/src/components/EncryptionUpload.js @@ -0,0 +1,48 @@ +// EncryptionUpload.js +export class EncryptionUpload { + async generateEncryptionKey() { + return await crypto.subtle.generateKey( + { + name: 'AES-GCM', + length: 256 + }, + true, + ['encrypt', 'decrypt'] + ); + } + + async exportKey(key) { + const rawKey = await crypto.subtle.exportKey('raw', key); + return btoa(String.fromCharCode(...new Uint8Array(rawKey))); + } + + async encryptFile(file) { + try { + const initialVector = crypto.getRandomValues(new Uint8Array(16)); + const key = await this.generateEncryptionKey(); + const fileBuffer = await file.arrayBuffer(); + + const encryptedFile = await crypto.subtle.encrypt( + { + name: 'AES-GCM', + iv: initialVector + }, + key, + fileBuffer + ); + + const base64 = await this.exportKey(key); + + return { + encrypted: encryptedFile, + initialVector: Array.from(initialVector), + key: base64, + filename: file.name, + contentType: file.type + }; + } catch (err) { + console.error('Encryption error:', err); + throw new Error('Failed to encrypt the file you are uploading.'); + } + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 64b0cd7..067073d 100755 --- a/package-lock.json +++ b/package-lock.json @@ -2384,6 +2384,7 @@ "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", + "optional": true, "dependencies": { "buffer": "^6.0.3", "catering": "^2.0.0", @@ -3339,6 +3340,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "optional": true, "engines": { "node": ">=6" } @@ -4171,6 +4173,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.4.1.tgz", "integrity": "sha512-r4eRSeStEGf6M5SKdrQhhLK5bOwOBxQhIE3YSTnZE3GpKiLfnnhE+tPtrJE79+eDJgm39BM6LSoI8SCx4HbwlQ==", + "optional": true, "engines": { "node": ">=6" } @@ -9874,6 +9877,7 @@ "url": "https://feross.org/support" } ], + "optional": true, "engines": { "node": ">=4" } @@ -10343,6 +10347,7 @@ "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", + "optional": true, "dependencies": { "catering": "^2.1.0" }, @@ -10471,6 +10476,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", + "optional": true, "engines": { "node": ">=10" } @@ -10536,6 +10542,7 @@ "integrity": "sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ==", "deprecated": "Superseded by classic-level (https://github.com/Level/community#faq)", "hasInstallScript": true, + "optional": true, "dependencies": { "abstract-leveldown": "~6.2.1", "napi-macros": "~2.0.0", @@ -10550,6 +10557,7 @@ "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz", "integrity": "sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==", "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", + "optional": true, "dependencies": { "buffer": "^5.5.0", "immediate": "^3.2.3", @@ -10579,6 +10587,7 @@ "url": "https://feross.org/support" } ], + "optional": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -10589,6 +10598,7 @@ "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz", "integrity": "sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw==", "deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)", + "optional": true, "engines": { "node": ">=6" } @@ -10597,6 +10607,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz", "integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==", + "optional": true, "dependencies": { "xtend": "^4.0.2" }, @@ -10608,6 +10619,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.1.1.tgz", "integrity": "sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ==", + "optional": true, "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -11493,7 +11505,8 @@ "node_modules/napi-macros": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", - "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==" + "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", + "optional": true }, "node_modules/negotiator": { "version": "0.6.3", @@ -12565,7 +12578,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "optional": true }, "node_modules/quick-lru": { "version": "5.1.1", From caefef7b80ec75fdf3ca6d2577d94222883316f5 Mon Sep 17 00:00:00 2001 From: Theresa Nguyen Date: Wed, 5 Feb 2025 01:08:27 -0800 Subject: [PATCH 2/5] updating to add file type validation --- client/src/components/EncryptionUpload.js | 32 ++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/client/src/components/EncryptionUpload.js b/client/src/components/EncryptionUpload.js index 2841dd2..2037dc3 100644 --- a/client/src/components/EncryptionUpload.js +++ b/client/src/components/EncryptionUpload.js @@ -1,5 +1,31 @@ // EncryptionUpload.js export class EncryptionUpload { + + // accepted file types + acceptedFileTypes = { + 'application/pdf': ['.pdf'] + }; + + validContentType(file){ + const fileExtension = '.' + file.name.split('.').pop().toLowerCase(); + + const isValidFile = Object.entries(this.acceptedFileTypes).some(([mimeType, extensions]) => { + return file.type === mimeType || extensions.includes(fileExtension); + }); + + if (!isValidFile) { + const validExtension = Object.values(this.acceptedFileTypes).flat(); + throw new Error( + `Invalid file type. Valid file types are: ${validExtensions.join(',')}` + ); + } + + if (file.size > 10 * 1024 * 1024) { + throw new Error('File size must be 10MB or less'); + } + return true; + } + async generateEncryptionKey() { return await crypto.subtle.generateKey( { @@ -38,11 +64,15 @@ export class EncryptionUpload { initialVector: Array.from(initialVector), key: base64, filename: file.name, - contentType: file.type + contentType: file.type, + fileSize: file.size }; } catch (err) { console.error('Encryption error:', err); throw new Error('Failed to encrypt the file you are uploading.'); } } + getAcceptedFileTypes() { + return Object.values(this.acceptedFileTypes).flat(); + } } \ No newline at end of file From 4e728333f546eab36fb9d53a1488826a23410093 Mon Sep 17 00:00:00 2001 From: Theresa Nguyen Date: Wed, 5 Feb 2025 01:27:04 -0800 Subject: [PATCH 3/5] file type validation, errors not showing up with inserting invalid file types --- client/src/components/DataUpload.js | 22 +++++++++++++++++++++- client/src/components/EncryptionUpload.js | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/client/src/components/DataUpload.js b/client/src/components/DataUpload.js index 64136b7..9d2ecf9 100755 --- a/client/src/components/DataUpload.js +++ b/client/src/components/DataUpload.js @@ -7,6 +7,7 @@ import { Typography, Paper, Container, + Alert, } from "@mui/material"; import { EncryptionUpload } from "./EncryptionUpload"; @@ -14,18 +15,35 @@ const DataUpload = () => { const [fileData, setFileData] = useState(null); const [price, setPrice] = useState(""); const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); const encryptionUpload = new EncryptionUpload(); const handleFileChange = (event) => { const file = event.target.files[0]; - setFileData(file); + //setFileData(file); + setError(""); + + try { + if (file) { + encryptionUpload.validContentType(file); + setFileData(file); + } + } catch (err) { + setError(err.message); + event.target.value = ''; + setFileData(null); + } }; const handleSubmit = async (event) => { event.preventDefault(); setLoading(true); + setError(""); try { + if (!fileData) { + throw new Error("Please select a file"); + } // Here add the blockchain integration later // Encrypting file before uploading const encryptingFile = await encryptionUpload.encryptFile(fileData); @@ -51,6 +69,8 @@ const DataUpload = () => { } }; + const acceptedTypes = encryptionUpload.getAcceptedFileTypes().join(', '); + return ( diff --git a/client/src/components/EncryptionUpload.js b/client/src/components/EncryptionUpload.js index 2037dc3..c04c538 100644 --- a/client/src/components/EncryptionUpload.js +++ b/client/src/components/EncryptionUpload.js @@ -16,7 +16,7 @@ export class EncryptionUpload { if (!isValidFile) { const validExtension = Object.values(this.acceptedFileTypes).flat(); throw new Error( - `Invalid file type. Valid file types are: ${validExtensions.join(',')}` + `Invalid file type. Valid file types are: ${validExtension.join(',')}` ); } From 116fb1da41c53188613d028b0f045029e6c55793 Mon Sep 17 00:00:00 2001 From: Theresa Nguyen Date: Fri, 7 Feb 2025 12:29:26 -0800 Subject: [PATCH 4/5] committing files with encryption --- client/src/components/DataUpload.js | 2 +- client/src/components/EncryptionUpload.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/DataUpload.js b/client/src/components/DataUpload.js index 9d2ecf9..8f29365 100755 --- a/client/src/components/DataUpload.js +++ b/client/src/components/DataUpload.js @@ -58,7 +58,7 @@ const DataUpload = () => { // Mock API call for now await new Promise((resolve) => setTimeout(resolve, 1000)); - alert("Data encrypted and ploaded successfully!"); + alert("Data encrypted and uploaded successfully!"); setFileData(null); setPrice(""); } catch (error) { diff --git a/client/src/components/EncryptionUpload.js b/client/src/components/EncryptionUpload.js index c04c538..775ceb1 100644 --- a/client/src/components/EncryptionUpload.js +++ b/client/src/components/EncryptionUpload.js @@ -1,7 +1,7 @@ // EncryptionUpload.js export class EncryptionUpload { - // accepted file types + // accepted file types acceptedFileTypes = { 'application/pdf': ['.pdf'] }; From a52fe3c13198ceb705892bd3376d74aff840baa7 Mon Sep 17 00:00:00 2001 From: Theresa Nguyen Date: Fri, 7 Feb 2025 13:19:42 -0800 Subject: [PATCH 5/5] including file upload encryption --- client/src/components/EncryptionUpload.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/EncryptionUpload.js b/client/src/components/EncryptionUpload.js index 775ceb1..d4322dc 100644 --- a/client/src/components/EncryptionUpload.js +++ b/client/src/components/EncryptionUpload.js @@ -21,7 +21,7 @@ export class EncryptionUpload { } if (file.size > 10 * 1024 * 1024) { - throw new Error('File size must be 10MB or less'); + throw new Error('File size must be within 10MB or less'); } return true; }