diff --git a/src/main.ts b/src/main.ts
new file mode 100644
index 0000000..7052132
--- /dev/null
+++ b/src/main.ts
@@ -0,0 +1,451 @@
+import command from "../config.json" assert { type: "json" };
+import { HELP } from "./commands/help";
+import { BANNER } from "./commands/banner";
+import { ABOUT } from "./commands/about";
+import { DEFAULT } from "./commands/default";
+import { createWhoami } from "./commands/whoami";
+import config from "../config.json";
+
+let mutWriteLines = document.getElementById("write-lines");
+let historyIdx = 0;
+let tempInput = "";
+let userInput: string;
+let isRoot = false;
+let isPasswordInput = false;
+let passwordCounter = 0;
+let bareMode = false;
+
+const WRITELINESCOPY = mutWriteLines;
+const TERMINAL = document.getElementById("terminal");
+const USERINPUT = document.getElementById("user-input") as HTMLInputElement;
+const INPUT_HIDDEN = document.getElementById("input-hidden");
+const PASSWORD = document.getElementById("password-input");
+const PASSWORD_INPUT = document.getElementById(
+ "password-field"
+) as HTMLInputElement;
+const PRE_HOST = document.getElementById("pre-host");
+const PRE_USER = document.getElementById("pre-user");
+const HOST = document.getElementById("host");
+const USER = document.getElementById("user");
+const PROMPT = document.getElementById("prompt");
+const COMMANDS = [
+ "help",
+ "about",
+ "whoami",
+ "banner",
+ "clear",
+ "key",
+ "linkedin",
+ "youtube",
+ "nagini",
+ "email",
+];
+const HISTORY: string[] = [];
+const ROOT_PASSWORD = command.password;
+
+const scrollToBottom = () => {
+ const MAIN = document.getElementById("main");
+ if (!MAIN) return;
+
+ MAIN.scrollTop = MAIN.scrollHeight;
+};
+
+function userInputHandler(e: KeyboardEvent) {
+ const key = e.key;
+
+ switch (key) {
+ case "Enter":
+ e.preventDefault();
+ if (!isPasswordInput) {
+ enterKey();
+ } else {
+ passwordHandler();
+ }
+
+ scrollToBottom();
+ break;
+ case "Escape":
+ USERINPUT.value = "";
+ break;
+ case "ArrowUp":
+ arrowKeys(key);
+ e.preventDefault();
+ break;
+ case "ArrowDown":
+ arrowKeys(key);
+ break;
+ case "Tab":
+ tabKey();
+ e.preventDefault();
+ break;
+ }
+}
+
+function enterKey() {
+ if (!mutWriteLines || !PROMPT) return;
+ const resetInput = "";
+ let newUserInput;
+ userInput = USERINPUT.value;
+
+ if (bareMode) {
+ newUserInput = userInput;
+ } else {
+ newUserInput = `${userInput}`;
+ }
+
+ HISTORY.push(userInput);
+ historyIdx = HISTORY.length;
+
+ if (userInput === "clear") {
+ commandHandler(userInput.toLowerCase().trim());
+ USERINPUT.value = resetInput;
+ userInput = resetInput;
+ return;
+ }
+
+ const div = document.createElement("div");
+ div.innerHTML = `${PROMPT.innerHTML} ${newUserInput}`;
+
+ if (mutWriteLines.parentNode) {
+ mutWriteLines.parentNode.insertBefore(div, mutWriteLines);
+ }
+
+ if (userInput.trim().length !== 0) {
+ commandHandler(userInput.toLowerCase().trim());
+ }
+
+ USERINPUT.value = resetInput;
+ userInput = resetInput;
+}
+
+function tabKey() {
+ let currInput = USERINPUT.value;
+
+ for (const ele of COMMANDS) {
+ if (ele.startsWith(currInput)) {
+ USERINPUT.value = ele;
+ return;
+ }
+ }
+}
+
+function arrowKeys(e: string) {
+ switch (e) {
+ case "ArrowDown":
+ if (historyIdx !== HISTORY.length) {
+ historyIdx += 1;
+ USERINPUT.value = HISTORY[historyIdx];
+ if (historyIdx === HISTORY.length) USERINPUT.value = tempInput;
+ }
+ break;
+ case "ArrowUp":
+ if (historyIdx === HISTORY.length) tempInput = USERINPUT.value;
+ if (historyIdx !== 0) {
+ historyIdx -= 1;
+ USERINPUT.value = HISTORY[historyIdx];
+ }
+ break;
+ }
+}
+
+function commandHandler(input: string) {
+ if (input.startsWith("rm -rf") && input.trim() !== "rm -rf") {
+ if (isRoot) {
+ if (input === "rm -rf /" && !bareMode) {
+ bareMode = true;
+
+ setTimeout(() => {
+ if (!TERMINAL || !WRITELINESCOPY) return;
+ TERMINAL.innerHTML = "";
+ TERMINAL.appendChild(WRITELINESCOPY);
+ mutWriteLines = WRITELINESCOPY;
+ });
+
+ easterEggStyles();
+ setTimeout(() => {
+ writeLines(["What made you think that was a good idea?", "
"]);
+ }, 200);
+
+ setTimeout(() => {
+ writeLines(["Now everything is ruined.", "
"]);
+ }, 1200);
+ } else if (input === "rm -rf /" && bareMode) {
+ writeLines(["there's no more / folder.", "
"]);
+ } else {
+ if (bareMode) {
+ writeLines(["What else are you trying to delete?", "
"]);
+ } else {
+ writeLines([
+ "
",
+ "Directory not found.",
+ "type 'ls' for a list of directories.",
+ "
",
+ ]);
+ }
+ }
+ } else {
+ writeLines(["Permission not granted.", "
"]);
+ }
+ return;
+ }
+
+ switch (input) {
+ case "clear":
+ setTimeout(() => {
+ if (!TERMINAL || !WRITELINESCOPY) return;
+ TERMINAL.innerHTML = "";
+ TERMINAL.appendChild(WRITELINESCOPY);
+ mutWriteLines = WRITELINESCOPY;
+ });
+ break;
+
+ case "pwd":
+ writeLines(["/home/guest", "
"]);
+ break;
+
+ case "banner":
+ writeLines(bareMode ? ["Joshua SystemV", "
"] : BANNER);
+ break;
+
+ case "help":
+ writeLines(
+ bareMode
+ ? ["maybe restarting your browser will fix this.", "
"]
+ : HELP
+ );
+ break;
+
+ case "whoami":
+ writeLines(bareMode ? [`${command.username}`, "
"] : createWhoami());
+ break;
+
+ case "about":
+ writeLines(bareMode ? ["Nothing to see here.", "
"] : ABOUT);
+ break;
+
+ case "key":
+ writeLines([`Downloading to key/${config.social["pgp-key"]}...`, "
"]);
+ setTimeout(() => {
+ window.open(
+ `https://src.panahifar.ir/pgp/C86437BFC43196C6.asc`,
+ "_blank"
+ );
+ }, 500);
+ break;
+
+ case "linkedin":
+ const linkedinUrl = `https://linkedin.com/in/${config.social.linkedin}`;
+ writeLines([
+ `Redirecting to Linkedin/${config.social.linkedin}...`,
+ "
",
+ ]);
+ setTimeout(() => {
+ window.open(linkedinUrl, "_blank");
+ }, 500);
+ break;
+
+ case "youtube":
+ const youtubeUrl = `https://www.youtube.com/@${config.social.youtube}`;
+ writeLines([
+ `Redirecting to Linkedin/${config.social.linkedin}...`,
+ "
",
+ ]);
+ setTimeout(() => {
+ window.open(youtubeUrl, "_blank");
+ }, 500);
+ break;
+
+ case "nagini":
+ writeLines([`Redirecting to negini/${config.social.git}...`, "
"]);
+ setTimeout(() => {
+ window.open(
+ `https://src.panahifar.ir/${config.social.git}`,
+ "_blank"
+ );
+ }, 500);
+ break;
+
+ case "email":
+ writeLines([`Redirecting to ${config.social.email}...`, "
"]);
+ setTimeout(() => {
+ window.open(`mailto:${config.social.email}`, "_blank");
+ }, 500);
+ break;
+
+ case "rm -rf":
+ if (bareMode) {
+ writeLines(["don't try again.", "
"]);
+ break;
+ }
+ if (isRoot) {
+ writeLines([
+ "Usage: 'rm -rf <dir>'",
+ "
",
+ ]);
+ } else {
+ writeLines(["Permission not granted.", "
"]);
+ }
+ break;
+ case "su":
+ if (bareMode) {
+ writeLines(["no.", "
"]);
+ break;
+ }
+ if (!PASSWORD) return;
+ isPasswordInput = true;
+ USERINPUT.disabled = true;
+
+ if (INPUT_HIDDEN) INPUT_HIDDEN.style.display = "none";
+ PASSWORD.style.display = "block";
+ setTimeout(() => {
+ PASSWORD_INPUT.focus();
+ }, 100);
+
+ break;
+ case "ls":
+ if (bareMode) {
+ writeLines(["there's nothing to see here.", "
"]);
+ break;
+ }
+
+ if (isRoot) {
+ writeLines(["/", "
"]);
+ } else {
+ writeLines(["Permission not granted.", "
"]);
+ }
+ break;
+ default:
+ if (bareMode) {
+ writeLines(["type 'help'", "
"]);
+ break;
+ }
+
+ writeLines(DEFAULT);
+ break;
+ }
+}
+
+function writeLines(message: string[]) {
+ message.forEach((item, idx) => {
+ displayText(item, idx);
+ });
+}
+
+function displayText(item: string, idx: number) {
+ setTimeout(() => {
+ if (!mutWriteLines) return;
+ const p = document.createElement("p");
+ p.innerHTML = item;
+ mutWriteLines.parentNode!.insertBefore(p, mutWriteLines);
+ scrollToBottom();
+ }, 40 * idx);
+}
+
+function revertPasswordChanges() {
+ if (!INPUT_HIDDEN || !PASSWORD) return;
+ PASSWORD_INPUT.value = "";
+ USERINPUT.disabled = false;
+ INPUT_HIDDEN.style.display = "block";
+ PASSWORD.style.display = "none";
+ isPasswordInput = false;
+
+ setTimeout(() => {
+ USERINPUT.focus();
+ }, 200);
+}
+
+function passwordHandler() {
+ if (passwordCounter === 2) {
+ if (!INPUT_HIDDEN || !mutWriteLines || !PASSWORD) return;
+ writeLines([
+ "
",
+ "INCORRECT PASSWORD.",
+ "PERMISSION NOT GRANTED.",
+ "
",
+ ]);
+ revertPasswordChanges();
+ passwordCounter = 0;
+ return;
+ }
+
+ if (PASSWORD_INPUT.value === ROOT_PASSWORD) {
+ if (!mutWriteLines || !mutWriteLines.parentNode) return;
+ writeLines([
+ "
",
+ "PERMISSION GRANTED.",
+ "Try 'rm -rf'",
+ "
",
+ ]);
+ revertPasswordChanges();
+ isRoot = true;
+ return;
+ } else {
+ PASSWORD_INPUT.value = "";
+ passwordCounter++;
+ }
+}
+
+function easterEggStyles() {
+ const bars = document.getElementById("bars");
+ const body = document.body;
+ const main = document.getElementById("main");
+ const span = document.getElementsByTagName("span");
+
+ if (!bars) return;
+ bars.innerHTML = "";
+ bars.remove();
+
+ if (main) main.style.border = "none";
+
+ body.style.backgroundColor = "black";
+ body.style.fontFamily = "VT323, monospace";
+ body.style.fontSize = "20px";
+ body.style.color = "white";
+
+ for (let i = 0; i < span.length; i++) {
+ span[i].style.color = "white";
+ }
+
+ USERINPUT.style.backgroundColor = "black";
+ USERINPUT.style.color = "white";
+ USERINPUT.style.fontFamily = "VT323, monospace";
+ USERINPUT.style.fontSize = "20px";
+ if (PROMPT) PROMPT.style.color = "white";
+}
+
+const initEventListeners = () => {
+ if (HOST) {
+ HOST.innerText = command.hostname;
+ }
+
+ if (USER) {
+ USER.innerText = command.username;
+ }
+
+ if (PRE_HOST) {
+ PRE_HOST.innerText = command.hostname;
+ }
+
+ if (PRE_USER) {
+ PRE_USER.innerText = command.username;
+ }
+
+ window.addEventListener("load", () => {
+ writeLines(BANNER);
+ });
+
+ USERINPUT.addEventListener("keypress", userInputHandler);
+ USERINPUT.addEventListener("keydown", userInputHandler);
+ PASSWORD_INPUT.addEventListener("keypress", userInputHandler);
+
+ window.addEventListener("click", () => {
+ USERINPUT.focus();
+ });
+
+ console.log(
+ `%cPassword: ${command.password}`,
+ "color: red; font-size: 20px;"
+ );
+};
+
+initEventListeners();