diff --git a/.env.example.ini b/.env.example.ini
new file mode 100644
index 0000000..2a85ab7
--- /dev/null
+++ b/.env.example.ini
@@ -0,0 +1 @@
+LOG_ENABLED = true
\ No newline at end of file
diff --git a/.env.ini b/.env.ini
new file mode 100644
index 0000000..ac1b58f
--- /dev/null
+++ b/.env.ini
@@ -0,0 +1 @@
+LOG_ENABLED = false
\ No newline at end of file
diff --git a/assets/css/pages/dashboard.css b/assets/css/pages/dashboard.css
new file mode 100644
index 0000000..c08c9c4
--- /dev/null
+++ b/assets/css/pages/dashboard.css
@@ -0,0 +1,5 @@
+vv-shell {
+ display: grid;
+ justify-items: center;
+ align-items: center;
+}
\ No newline at end of file
diff --git a/assets/css/pages/index.css b/assets/css/pages/index.css
new file mode 100644
index 0000000..c08c9c4
--- /dev/null
+++ b/assets/css/pages/index.css
@@ -0,0 +1,5 @@
+vv-shell {
+ display: grid;
+ justify-items: center;
+ align-items: center;
+}
\ No newline at end of file
diff --git a/assets/css/shell.css b/assets/css/shell.css
index 4a9ef43..0703b47 100644
--- a/assets/css/shell.css
+++ b/assets/css/shell.css
@@ -59,6 +59,10 @@ button {
}
}
+dialog {
+ margin: auto;
+}
+
/* Sections */
vv-shell {
@@ -71,7 +75,7 @@ vv-shell {
border-radius: 9px;
background-color: white;
- &[vv-loading="true"] {
+ &[vv-loading="true"] ::not(dialog) {
pointer-events: none;
}
diff --git a/assets/js/modules/Logger.js b/assets/js/modules/Logger.js
new file mode 100644
index 0000000..97ad174
--- /dev/null
+++ b/assets/js/modules/Logger.js
@@ -0,0 +1,99 @@
+const MOUSE_MOVE_TIMEOUT_MS = 100;
+
+globalThis.Logger = class Logger {
+ #abort;
+ #mouseMoveTimeout;
+
+ static get url() {
+ const url = new URL(window.location);
+ url.pathname = "/log";
+
+ return url;
+ }
+
+ /**
+ * Return a best-effort unique string that identifies this client
+ * @returns {String}
+ */
+ static async #fingerprint() {
+ // Create a hash from various identifying browser data
+ const buffer = await window.crypto.subtle.digest("SHA-1", new TextEncoder().encode(JSON.stringify([
+ navigator.userAgent,
+ navigator.buildId,
+ navigator.languages
+ ])));
+
+ return new DataView(buffer).getBigUint64().toString();
+ }
+
+ /**
+ * Extract desired MouseEvent data into an object literal
+ * @param {MouseEvent} event
+ * @returns {Object}
+ */
+ static #mouseEvent(event) {
+ return {
+ e: event.type,
+ w: window.innerWidth,
+ h: window.innerHeight,
+ x: event.x,
+ y: event.y
+ }
+ }
+
+ /**
+ * Extract desired KeyboardEvent data into an object literal
+ * @param {KeyboardEvent} event
+ * @returns {Object}
+ */
+ static #keyEvent(event) {
+ return {
+ e: event.type,
+ c: event.key,
+ s: event.shiftKey
+ }
+ }
+
+ constructor() {}
+
+ /**
+ * Start logging user activities
+ */
+ start() {
+ this.#abort = new AbortController();
+
+ document.addEventListener("keyup", (event) => this.log(Logger.#keyEvent(event)), { signal: this.#abort.signal });
+ document.addEventListener("keydown", (event) => this.log(Logger.#keyEvent(event)), { signal: this.#abort.signal });
+ document.addEventListener("click", (event) => this.log(Logger.#mouseEvent(event)), { signal: this.#abort.signal });
+ document.addEventListener("mousemove", (event) => {
+ // Throttle mousemove events
+ clearTimeout(this.#mouseMoveTimeout);
+ //this.#mouseMoveTimeout = setTimeout(() => this.#log(mouseEvent(event)), MOUSE_MOVE_TIMEOUT_MS);
+ }, { signal: this.#abort.signal });
+ }
+
+ /**
+ * Stop logging user activitiers
+ */
+ stop() {
+ this.#abort.abort();
+ }
+
+ /**
+ * Log user data
+ * @param {Object} data
+ * @returns {Response}
+ */
+ async log(data) {
+ return await fetch(Logger.url, {
+ body: JSON.stringify({
+ client: data,
+ fingerprint: (await Logger.#fingerprint())
+ }),
+ method: "POST",
+ headers: Object.assign({
+ "Content-Type": "application/json"
+ }, VV.header)
+ });
+ };
+}
\ No newline at end of file
diff --git a/assets/js/pages/dashboard.js b/assets/js/pages/dashboard.js
new file mode 100644
index 0000000..06f766e
--- /dev/null
+++ b/assets/js/pages/dashboard.js
@@ -0,0 +1,5 @@
+// Clear all content and display the loading spinner for now. I want to add more stuff here later!
+setTimeout(() => {
+ VV.shell.innerHTML = "";
+ VV.shell.setAttribute("vv-loading", true);
+}, VV.delay);
\ No newline at end of file
diff --git a/assets/js/pages/login.js b/assets/js/pages/login.js
index bd6b5fd..d0d3588 100644
--- a/assets/js/pages/login.js
+++ b/assets/js/pages/login.js
@@ -1,23 +1,57 @@
-const WHITELIST_USERNAMES = [
- "user",
- "root",
- "admin",
- "mydlink"
-];
-const WHITELIST_PASSWORDS = [
- "root",
- "admin",
- "12345",
- "mydlink",
- "password",
- "123456789"
-]
+// Simulate a fake login page
+{
+ const WHITELIST_USERNAMES = [
+ "user",
+ "root",
+ "admin",
+ "mydlink"
+ ];
+ const WHITELIST_PASSWORDS = [
+ "root",
+ "admin",
+ "12345",
+ "mydlink",
+ "password",
+ "123456789"
+ ];
+ const INPUT_NAME_USERNAME = "username";
+ const INPUT_NAME_PASSWORD = "password";
+
+ document.querySelector("form button").addEventListener("click", (event) => {
+ event.preventDefault();
+
+ VV.shell.setAttribute("vv-loading", true);
+ const form = new FormData(event.target.closest("form"));
-document.querySelector("form button").addEventListener("click", (event) => {
- event.preventDefault();
+ // Invalid fake username or password derp
+ if (
+ !WHITELIST_USERNAMES.includes(form.get(INPUT_NAME_USERNAME))
+ || !WHITELIST_PASSWORDS.includes(form.get(INPUT_NAME_PASSWORD))
+ ) {
+ // Show "incorrect credentials" dialog after global Vegvisir delay
+ setTimeout(() => {
+ VV.shell.setAttribute("vv-loading", false);
+ document.querySelector("dialog").showModal();
+ }, VV.delay);
- VV.shell.setAttribute("vv-loading", true);
- const form = new FormData(event.target.closest("form"));
+ return;
+ }
- console.log("Hello");
-});
\ No newline at end of file
+ new VV().navigate("/dashboard");
+ });
+}
+
+// Only start logging if the user does something with the input fields
+{
+ const abortInitialInputChange = new AbortController();
+
+ const startLogging = () =>{
+ abortInitialInputChange.abort();
+ new globalThis.Logger().start();
+ };
+
+ document.querySelector("button").addEventListener("click", () => startLogging(), { signal: abortInitialInputChange.signal });
+ document.querySelectorAll("input").forEach(element => element.addEventListener("click", () => startLogging(), { signal: abortInitialInputChange.signal }));
+ document.querySelectorAll("input").forEach(element => element.addEventListener("keydown", () => startLogging(), { signal: abortInitialInputChange.signal }));
+ document.querySelectorAll("input").forEach(element => element.addEventListener("change", () => startLogging(), { signal: abortInitialInputChange.signal }));
+}
\ No newline at end of file
diff --git a/assets/js/shell.js b/assets/js/shell.js
index bb067c5..c3df959 100644
--- a/assets/js/shell.js
+++ b/assets/js/shell.js
@@ -1,73 +1,30 @@
-// Set a global delay to simulate crappy web software
-VV.delay = 200;
+const LOGIN_PAGE = "/login";
+const STORAGE_KEY_LOGGEDIN = "mydlink_dashboard_login";
-// Log user activities
-{
- const MOUSE_MOVE_TIMEOUT_MS = 100;
+// Set a generous global navigation delay to simulate crappy web software
+VV.delay = 3500;
- const logUrl = new URL(window.location);
- logUrl.pathname = "/log";
+// Redirect the user to the login page if session storage key is not set
+if (!sessionStorage.getItem(STORAGE_KEY_LOGGEDIN) && window.location.pathname !== LOGIN_PAGE) {
+ const getRandomString = (length = 16) => {
+ const CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ let string = "";
- let mouseMoveTimeout;
-
- // Return a fingerprint for this browser
- const fingerprint = async () => {
- const buffer = await window.crypto.subtle.digest("SHA-1", new TextEncoder().encode(JSON.stringify([
- navigator.userAgent,
- navigator.buildId,
- navigator.languages
- ])));
-
- let fingerprint;
-
- for (let i = 0; i < buffer.byteLength; i++) {
- fingerprint += buffer[i];
- }
-
- return fingerprint;
- };
-
- // Log data
- const log = async (data) => {
- console.log(JSON.stringify({
- data: data,
- fingerprint: await fingerprint()
- }));
-
- return await fetch(logUrl, {
- body: JSON.stringify({
- data: data,
- fingerprint: await fingerprint()
- }),
- method: "POST",
- headers: VV.header
- });
+ for (let i = 0; i < length; i++) string += CHARSET[Math.floor(Math.random() * CHARSET.length)];
+
+ return string;
};
- const mouseEvent = (event) => {
- return {
- e: event.type,
- w: window.innerWidth,
- h: window.innerHeight,
- x: event.x,
- y: event.y
- }
- }
+ const url = new URL(window.location);
- const keyEvent = (event) => {
- return {
- e: event.type,
- c: event.key,
- s: event.shiftKey
- }
- }
+ // Set some legit looking overcomplicated search parameters
+ url.searchParams.set("mydl_sid", getRandomString());
+ // This is our fake "user is logged in" Storage API key
+ url.searchParams.set("action", STORAGE_KEY_LOGGEDIN);
+ url.searchParams.set(`mydl_${getRandomString(3)}`, "dashboard");
+ url.searchParams.set(`mydl_asas_${getRandomString(4)}_${getRandomString(8)}`, "login_cgi");
+
+ url.pathname = LOGIN_PAGE;
- document.addEventListener("keyup", (event) => log(keyEvent(event)));
- document.addEventListener("keydown", (event) => log(keyEvent(event)));
- document.addEventListener("click", (event) => log(mouseEvent(event)));
- document.addEventListener("mousemove", (event) => {
- // Throttle mousemove events
- clearTimeout(mouseMoveTimeout);
- //mouseMoveTimeout = setTimeout(() => log(mouseEvent(event)), MOUSE_MOVE_TIMEOUT_MS);
- });
-}
+ new VV().navigate(url);
+}
\ No newline at end of file
diff --git a/logs/.gitkeep b/logs/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/public/dashboard.php b/public/dashboard.php
new file mode 100644
index 0000000..29e0ad3
--- /dev/null
+++ b/public/dashboard.php
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/public/error.php b/public/error.php
new file mode 100644
index 0000000..96d8eaa
--- /dev/null
+++ b/public/error.php
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/log.php b/public/log.php
index 9296dc1..90cecb0 100644
--- a/public/log.php
+++ b/public/log.php
@@ -5,7 +5,7 @@
require_once VV::root("src/Log.php");
if ($_SERVER["REQUEST_METHOD"] === "POST" && !empty($_POST)) {
- save_log($_POST);
+ save_log((object) $_POST);
}
?>
\ No newline at end of file
diff --git a/public/login.php b/public/login.php
index 09c90e9..1c4741c 100644
--- a/public/login.php
+++ b/public/login.php
@@ -2,11 +2,11 @@
@@ -16,9 +16,9 @@
Please follow these steps in order to register your mdlink-enabled product and get access to both mydlink.com and our mobile apps. Learn more details here.
- \ No newline at end of file + \ No newline at end of file diff --git a/public/shell.php b/public/shell.php index 76f1240..0d59f9d 100644 --- a/public/shell.php +++ b/public/shell.php @@ -2,14 +2,15 @@ -
+ DIR-880L