aboutsummaryrefslogtreecommitdiff
path: root/client/src/components/Editor/Editor.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/components/Editor/Editor.jsx')
-rw-r--r--client/src/components/Editor/Editor.jsx164
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;
+