From cf71fcb8929d5e730816b0675ff5043e7ae41718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Tu=C8=99inean?= Date: Wed, 3 Jul 2024 12:14:32 +0300 Subject: [PATCH] experimental editor --- components/cryptForm.js | 189 ++++++++++++++++++++++++++++++++-------- components/editor.js | 53 +++++++++-- pages/index.js | 2 - 3 files changed, 198 insertions(+), 46 deletions(-) diff --git a/components/cryptForm.js b/components/cryptForm.js index 6ecee91..297da63 100644 --- a/components/cryptForm.js +++ b/components/cryptForm.js @@ -2,6 +2,7 @@ import { Box, Button, Text, + Link, Checkbox, useToast, Modal, @@ -16,6 +17,7 @@ import { import { FaDownload, FaEdit } from 'react-icons/fa'; import { useRef, useState } from 'react'; import dynamic from 'next/dynamic'; +import NextLink from 'next/link'; import crypto from 'crypto'; const Editor = dynamic(() => import('./editor'), { ssr: false }); @@ -24,6 +26,15 @@ function isGzip(data) { return data[0] == 0x1F && data[1] == 0x8B; } +function isJSON(data) { + try { + JSON.parse(data.toString()); + } catch (e) { + return false; + } + return true; +} + async function pipeThrough(data, stream) { let piped = Buffer.from(''); const reader = new Blob([data]).stream() @@ -41,10 +52,38 @@ async function pipeThrough(data, stream) { return piped; } +async function cryptData(data, password, isEncryption, shouldGzip) { + let wasGunzipped = false; + if (isEncryption) { + if (shouldGzip) + data = await pipeThrough(data, new CompressionStream('gzip')); + + if (password) { + const iv = crypto.randomBytes(16); + const cipher = crypto.createCipheriv('aes-128-cbc', crypto.pbkdf2Sync(password, iv, 100, 16, 'sha1'), iv); + data = Buffer.concat([iv, cipher.update(data), cipher.final()]); + } + } else { + if (password) { + const iv = data.subarray(0, 16); + const decipher = crypto.createDecipheriv('aes-128-cbc', crypto.pbkdf2Sync(password, iv, 100, 16, 'sha1'), iv); + data = Buffer.concat([decipher.update(data.subarray(16)), decipher.final()]); + } + + if (isGzip(data)) { + wasGunzipped = true; + data = await pipeThrough(data, new DecompressionStream('gzip')); + } + } + + return { wasGunzipped, cryptedData: data }; +} + export default function CryptForm({ isEncryption, isLoading, setIsLoading, password }) { const toast = useToast(); const saveFileRef = useRef(); const [data, setData] = useState(null); + const [editorData, setEditorData] = useState(null); const [shouldGzip, setShouldGzip] = useState(false); const [isEncryptionWarning, setIsEncryptionWarning] = useState(false); const { isOpen, onOpen: _onOpen, onClose: _onClose } = useDisclosure(); @@ -62,6 +101,13 @@ export default function CryptForm({ isEncryption, isLoading, setIsLoading, passw setIsEncryptionWarning(false); }; + const setDownloadData = (data, fileName) => { + const blobUrl = window.URL.createObjectURL(new Blob([data], { type: 'binary/octet-stream' })); + const downloader = document.getElementById('downloader'); + downloader.href = blobUrl; + downloader.download = fileName; + }; + const download = () => { setData(null); saveFileRef.current.value = ''; @@ -79,8 +125,10 @@ export default function CryptForm({ isEncryption, isLoading, setIsLoading, passw ref={saveFileRef} disabled={isLoading} onChange={changeEvent => { - if (!changeEvent.target.files.length) + if (!changeEvent.target.files.length) { + setData(null); return; + } const fileReader = new FileReader(); fileReader.onload = loadEvent => setData(Buffer.from(loadEvent.target.result)); @@ -117,7 +165,74 @@ export default function CryptForm({ isEncryption, isLoading, setIsLoading, passw
{!isEncryption && ( - + )} - + + diff --git a/pages/index.js b/pages/index.js index c73b59f..c9fd35c 100644 --- a/pages/index.js +++ b/pages/index.js @@ -6,7 +6,6 @@ import { Heading, Input, Text, - Link, Button, Modal, ModalOverlay, @@ -20,7 +19,6 @@ import { } from '@chakra-ui/react'; import { CloseIcon } from '@chakra-ui/icons'; import { useEffect, useState } from 'react'; -import NextLink from 'next/link'; import Head from 'next/head'; import CryptForm from '../components/cryptForm';