diff options
Diffstat (limited to 'client/src/components/Editor')
-rw-r--r-- | client/src/components/Editor/Editor.jsx | 164 |
1 files changed, 138 insertions, 26 deletions
diff --git a/client/src/components/Editor/Editor.jsx b/client/src/components/Editor/Editor.jsx index 868036f..e1675fc 100644 --- a/client/src/components/Editor/Editor.jsx +++ b/client/src/components/Editor/Editor.jsx @@ -4,11 +4,16 @@ import Prism from "prismjs"; import styles from "./Editor.module.css"; import "../prism-themes/prism-gruvbox-dark.css"; import "../prism-themes/prism-line-numbers.css"; -import { - BASE_URL, - URL_REGEX, -} from "../../utils/constants"; +import { BASE_URL, URL_REGEX } from "../../utils/constants"; import Header from "../Header/Header"; +import { + generateAESKey, + keyToString, + stringToKey, + encryptAES, + decryptAES, +} from "../../utils/encryption"; +import Modal from "../Modal/Modal"; const Editor = () => { const { id } = useParams(); @@ -16,8 +21,10 @@ const Editor = () => { const location = useLocation(); const [text, setText] = useState(""); const [language, setLanguage] = useState("none"); + const [openModal, setOpenModal] = useState(false); const textareaRef = useRef(null); const lineNumberRef = useRef(null); + const queryParams = new URLSearchParams(location.search); const handleTextChange = (event) => { setText(event.target.value); @@ -29,11 +36,56 @@ const Editor = () => { } }; - const handleClick = async () => { + const handleSaveClick = async () => { if (!text) { alert("Please enter some text!"); return; } + if (URL_REGEX.test(text)) { + const response = await fetch(`${BASE_URL}/bin`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + language, + content: text, + }), + }); + const data = await response.json(); + if (response.ok) { + navigator.clipboard + .writeText(`${window.location.origin}/r/${data.id}`) + .then( + function () { + alert("Short URL copied to clipboard!"); + }, + function () { + try { + document.execCommand("copy"); + alert("Short URL copied to clipboard!"); + } catch (err) { + console.log("Oops, unable to copy"); + } + }, + ); + } + navigate(`/${data.id}`); + return; + } + setOpenModal(true); + }; + + const handleSuccessClick = async () => { + setOpenModal(false); + const key = await generateAESKey(); + const keyString = await keyToString(key); + const { encrypted, iv } = await encryptAES(text, key); + const encryptedBase64 = btoa( + String.fromCharCode.apply(null, new Uint8Array(encrypted)), + ); + const ivBase64 = btoa(String.fromCharCode.apply(null, iv)); + const response = await fetch(`${BASE_URL}/bin`, { method: "POST", headers: { @@ -41,42 +93,68 @@ const Editor = () => { }, body: JSON.stringify({ language, - content: text, + content: encryptedBase64, + iv: ivBase64, }), }); const data = await response.json(); if (response.ok) { - const isURL = URL_REGEX.test(text); - if (isURL) { - navigator.clipboard.writeText(`${BASE_URL}/r/${data.id}`).then( + navigator.clipboard + .writeText(`${window.location.origin}/${data.id}?key=${keyString}`) + .then( function () { - alert("Short URL copied to clipboard!"); + navigator.clipboard.writeText( + `${window.location.origin}/${data.id}?key=${keyString}`, + ); + alert("URL copied to clipboard!"); }, - function (err) { + function () { try { - var successful = document.execCommand("copy"); - alert("Short URL copied to clipboard!"); + document.execCommand("copy"); + alert("URL copied to clipboard!"); } catch (err) { console.log("Oops, unable to copy"); } }, ); - } else { - navigator.clipboard.writeText(`${BASE_URL}/r/${data.id}`).then( + navigate(`/${data.id}?key=${keyString}`); + } else { + console.error(data); + } + }; + + const handleCancelClick = async () => { + setOpenModal(false); + const response = await fetch(`${BASE_URL}/bin`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + language, + content: text, + }), + }); + const data = await response.json(); + if (response.ok) { + navigator.clipboard + .writeText(`${window.location.origin}/${data.id}`) + .then( function () { - navigator.clipboard.writeText(`${BASE_URL}/${data.id}`); + navigator.clipboard.writeText( + `${window.location.origin}/${data.id}`, + ); alert("URL copied to clipboard!"); }, - function (err) { + function () { try { - var successful = document.execCommand("copy"); - alert("URL copied to clipboard!"); + document.execCommand("copy"); + alert("URL copied to clip`board!"); } catch (err) { console.log("Oops, unable to copy"); } }, ); - } navigate(`/${data.id}`); } else { console.error(data); @@ -96,12 +174,30 @@ const Editor = () => { const response = await fetch(`${BASE_URL}/bin/${id}`); const data = await response.json(); if (response.ok) { - const isURL = URL_REGEX.test(data.content); - if (isURL) { - setText(`Your shortened URL: ${BASE_URL}/r/${id}`); - } else { + if (data.iv) { + const keyString = queryParams.get("key"); + const key = await stringToKey(keyString); + const encrypted = new Uint8Array( + atob(data.content) + .split("") + .map((char) => char.charCodeAt(0)), + ).buffer; + const ivArray = new Uint8Array( + atob(data.iv) + .split("") + .map((char) => char.charCodeAt(0)), + ); + const decryptedContent = await decryptAES(encrypted, key, ivArray); setLanguage(data.language); - setText(data.content); + setText(decryptedContent); + } else { + const isURL = URL_REGEX.test(data.content); + if (isURL) { + setText(`Your shortened URL: ${window.location.origin}/r/${id}`); + } else { + setLanguage(data.language); + setText(data.content); + } } } }; @@ -117,9 +213,24 @@ const Editor = () => { return ( <> <Header isSelectVisible={!id} onLanguageChange={handleLanguageChange} /> + <Modal + openModal={openModal} + setOpenModal={setOpenModal} + onSuccessClick={() => { + handleSuccessClick(); + }} + onCancelClick={() => { + handleCancelClick(); + }} + /> <div className={styles.container}> {!id && ( - <button className={styles.btn__save} onClick={handleClick}> + <button + className={styles.btn__save} + onClick={() => { + handleSaveClick(); + }} + > <img src="assets/icons/save.svg" className={styles.btn__icon} /> </button> )} @@ -150,3 +261,4 @@ const Editor = () => { }; export default Editor; + |