diff --git a/main b/main index 5d08dda..531bfb2 100644 --- a/main +++ b/main @@ -76,6 +76,15 @@ def get_session(id): return "error" return post +def get_session_from_sessionid(id): + conn = get_db_connection() + post = conn.execute("SELECT * FROM sessions WHERE sessionid = ?", + (id,)).fetchone() + conn.close() + if post is None: + return "error" + return post + def check_username_taken(username): conn = get_db_connection() post = conn.execute("SELECT * FROM users WHERE lower(username) = ?", @@ -148,8 +157,8 @@ def apisignup(): randomCharacters = secrets.token_hex(512) conn = get_db_connection() - conn.execute("INSERT INTO sessions (session, id) VALUES (?, ?)", - (randomCharacters, userID)) + conn.execute("INSERT INTO sessions (session, id, device) VALUES (?, ?, ?)", + (randomCharacters, userID, request.headers.get("user-agent"))) conn.commit() conn.close() @@ -178,8 +187,8 @@ def apilogin(): randomCharacters = secrets.token_hex(512) conn = get_db_connection() - conn.execute("INSERT INTO sessions (session, id) VALUES (?, ?)", - (randomCharacters, userID)) + conn.execute("INSERT INTO sessions (session, id, device) VALUES (?, ?, ?)", + (randomCharacters, userID, request.headers.get("user-agent"))) conn.commit() conn.close() @@ -374,6 +383,59 @@ def apideleteaccount(): return {}, 200 +@app.route("/api/sessions/list", methods=("GET", "POST")) +def apisessionslist(): + if request.method == "POST": + data = request.get_json() + secretKey = data["secretKey"] + + userCookie = get_session(secretKey) + user = get_user(userCookie["id"]) + + conn = get_db_connection() + sessions = conn.execute("SELECT * FROM sessions WHERE id = ? ORDER BY id DESC;", (user["id"],)).fetchall() + conn.close() + + datatemplate = [] + + for x in sessions: + device = x["device"] + thisSession = False + if (x["session"] == secretKey): + thisSession = True + sessiontemplate = { + "id": x["sessionid"], + "thisSession": thisSession, + "device": device + } + datatemplate.append(sessiontemplate) + + return datatemplate, 200 + +@app.route("/api/sessions/remove", methods=("GET", "POST")) +def apisessionsremove(): + if request.method == "POST": + data = request.get_json() + secretKey = data["secretKey"] + sessionId = data["sessionId"] + + userCookie = get_session(secretKey) + user = get_user(userCookie["id"]) + + session = get_session_from_sessionid(sessionId) + + if (session != "error"): + if (user["id"] == session["id"]): + conn = get_db_connection() + conn.execute("DELETE FROM sessions WHERE sessionid = ?", (session["sessionid"],)) + conn.commit() + conn.close() + + return {}, 200 + else: + return {}, 403 + else: + return {}, 422 @app.route("/listusers/", methods=("GET", "POST")) def listusers(secretkey): @@ -397,6 +459,10 @@ def apilogout(): def burger(e): return {}, 500 +@app.errorhandler(404) +def burger(e): + return render_template("error.html", errorCode=404, errorMessage="Page not found"), 404 + # Start server if __name__ == "__main__": print("[INFO] Server started") diff --git a/schema.sql b/schema.sql index 2181626..f4cb36d 100644 --- a/schema.sql +++ b/schema.sql @@ -19,6 +19,8 @@ CREATE TABLE notes ( ); CREATE TABLE sessions ( - session TEXT PRIMARY KEY NOT NULL, - id INTEGER NOT NULL + sessionid INTEGER PRIMARY KEY AUTOINCREMENT, + session TEXT NOT NULL, + id INTEGER NOT NULL, + device TEXT NOT NULL DEFAULT "?" ); \ No newline at end of file diff --git a/static/css/style.css b/static/css/style.css index c1bcebf..43aefbc 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -273,6 +273,33 @@ body { margin-bottom: 10px; } +.sessionDiv div { + background-color: #f4f4f4; + border-radius: 8px; + margin-bottom: 5px; + padding: 10px; + height: 35px; +} +.sessionDiv div p { + display: inline; + position: absolute; + transform: translateY(-7.5px); +} +.sessionDiv div button { + position: absolute; + border-radius: 99px; + right: 15px; + width: 40px; + height: 40px; + font-size: 16px; + transform: translateY(-2px); +} +.sessionDiv img { + display: inline; + filter: none; + height: 100%; +} + /* Sign up/log in div */ .inoutdiv { diff --git a/static/js/main.js b/static/js/main.js index 2dc02b7..19ecb87 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -11,6 +11,14 @@ if (localStorage.getItem("DONOTSHARE-password") === null) { function formatBytes(a, b = 2) { if (!+a) return "0 Bytes"; const c = 0 > b ? 0 : b, d = Math.floor(Math.log(a) / Math.log(1000)); return `${parseFloat((a / Math.pow(1000, d)).toFixed(c))} ${["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"][d]}` } +function truncateString(str, num) { + if (str.length > num) { + return str.slice(0, num) + "..."; + } else { + return str; + } +} + let secretkey = localStorage.getItem("DONOTSHARE-secretkey") let password = localStorage.getItem("DONOTSHARE-password") @@ -23,6 +31,10 @@ let closeErrorButton = document.getElementById("closeErrorButton") let cancelErrorButton = document.getElementById("cancelErrorButton") let errorInput = document.getElementById("errorInput") let exitThing = document.getElementById("exitThing") +let exitSessionsThing = document.getElementById("exitSessionsThing") +let sessionManagerButton = document.getElementById("sessionManagerButton") +let sessionManagerDiv = document.getElementById("sessionManagerDiv") +let sessionDiv = document.getElementById("sessionDiv") let deleteMyAccountButton = document.getElementById("deleteMyAccountButton") let storageThing = document.getElementById("storageThing") let storageProgressThing = document.getElementById("storageProgressThing") @@ -45,6 +57,7 @@ if (/Android|iPhone/i.test(navigator.userAgent)) { notesBar.style.width = "calc(100% - 10px)" noteBox.readOnly = true noteBox.style.fontSize = "18px" + noteBox.classList.add("hidden") notesBar.addEventListener("touchstart", function (event) { touchstartX = event.changedTouches[0].screenX; @@ -69,19 +82,25 @@ if (/Android|iPhone/i.test(navigator.userAgent)) { }, false); function handleGesture() { - if (touchendX > touchstartX) { - notesBar.style.width = "calc(100% - 30px)"; - noteBox.style.width = "30px" - noteBox.readOnly = true + if (touchendX > touchstartX + 75) { + notesBar.style.width = "calc(100% - 10px)"; + noteBox.style.width = "10px" + if (selectedNote != 0) { + noteBox.readOnly = true + } notesDiv.classList.remove("hidden") + noteBox.classList.add("hidden") newNote.classList.remove("hidden") } - if (touchendX < touchstartX) { + if (touchendX < touchstartX - 75) { noteBox.style.width = "calc(100% - 30px)"; - notesBar.style.width = "30px" - noteBox.readOnly = false + notesBar.style.width = "10px" + if (selectedNote != 0) { + noteBox.readOnly = false + } notesDiv.classList.add("hidden") + noteBox.classList.remove("hidden") newNote.classList.add("hidden") } } @@ -104,7 +123,6 @@ closeErrorButton.addEventListener("click", (event) => { optionsCoverDiv.classList.add("hidden") }); - function displayPrompt(message, callback) { errorMessageThing.innerText = message errorInput.value = "" @@ -160,13 +178,22 @@ function updateUserInfo() { .then((response) => response) .then((response) => { async function doStuff() { - let responseData = await response.json() - usernameBox.innerText = responseData["username"] - usernameThing.innerText = "logged in as " + responseData["username"] - storageThing.innerText = "you've used " + formatBytes(responseData["storageused"]) + " out of " + formatBytes(responseData["storagemax"]) - storageProgressThing.value = responseData["storageused"] - storageProgressThing.max = responseData["storagemax"] - noteCount = responseData["notecount"] + if (response.status == 500) { + displayError("Something went wrong. Signing you out..") + closeErrorButton.classList.add("hidden") + usernameBox.innerText = "" + setTimeout(function() { + window.location.replace("/api/logout") + }, 2500); + } else { + let responseData = await response.json() + usernameBox.innerText = responseData["username"] + usernameThing.innerText = "logged in as " + responseData["username"] + storageThing.innerText = "you've used " + formatBytes(responseData["storageused"]) + " out of " + formatBytes(responseData["storagemax"]) + storageProgressThing.value = responseData["storageused"] + storageProgressThing.max = responseData["storagemax"] + noteCount = responseData["notecount"] + } } doStuff() }); @@ -177,7 +204,7 @@ usernameBox.addEventListener("click", (event) => { updateUserInfo() }); logOutButton.addEventListener("click", (event) => { - window.location.href = "/api/logout" + window.location.replace("/api/logout") }); exitThing.addEventListener("click", (event) => { optionsDiv.classList.add("hidden") @@ -204,6 +231,85 @@ deleteMyAccountButton.addEventListener("click", (event) => { }) } }); +sessionManagerButton.addEventListener("click", (event) => { + optionsDiv.classList.add("hidden") + sessionManagerDiv.classList.remove("hidden") + + fetch("/api/sessions/list", { + method: "POST", + body: JSON.stringify({ + secretKey: secretkey + }), + headers: { + "Content-type": "application/json; charset=UTF-8" + } + }) + .then((response) => response) + .then((response) => { + async function doStuff() { + let responseData = await response.json() + document.querySelectorAll(".burgerSession").forEach((el) => el.remove()); + for (let i in responseData) { + let sessionElement = document.createElement("div") + let sessionText = document.createElement("p") + let sessionImage = document.createElement("img") + let sessionRemoveButton = document.createElement("button") + sessionText.classList.add("w300") + if (responseData[i]["thisSession"] == true) { + sessionText.innerHTML = "current" + truncateString(responseData[i]["device"], 18) + } else { + sessionText.innerHTML = truncateString(responseData[i]["device"], 27) + } + sessionText.title = responseData[i]["device"] + sessionRemoveButton.innerText = "X" + + sessionImage.src = "/static/svg/device_other.svg" + + ua = responseData[i]["device"] + + if (ua.includes("NT") || ua.includes("Linux")) { + sessionImage.src = "/static/svg/device_computer.svg" + } + if (ua.includes("iPhone" || ua.includes("Android"))) { + sessionImage.src = "/static/svg/device_smartphone.svg" + } + + sessionRemoveButton.addEventListener("click", (event) => { + fetch("/api/sessions/remove", { + method: "POST", + body: JSON.stringify({ + secretKey: secretkey, + sessionId: responseData[i]["id"] + }), + headers: { + "Content-type": "application/json; charset=UTF-8" + } + }) + .then((response) => response) + .then((response) => { + if (responseData[i]["thisSession"] == true) { + window.location.replace("/api/logout") + } + }); + sessionElement.remove() + }); + + sessionElement.append(sessionImage) + sessionElement.append(sessionText) + sessionElement.append(sessionRemoveButton) + + sessionElement.classList.add("burgerSession") + + sessionDiv.append(sessionElement) + } + } + doStuff() + }); +}); +exitSessionsThing.addEventListener("click", (event) => { + optionsDiv.classList.remove("hidden") + sessionManagerDiv.classList.add("hidden") +}); updateUserInfo() @@ -342,7 +448,6 @@ updateNotes() newNote.addEventListener("click", (event) => { let noteName = displayPrompt("note name? :3", burgerFunction) - //let noteName = prompt("note name? :3") function burgerFunction(noteName) { if (noteName != null) { let encryptedName = CryptoJS.AES.encrypt(noteName, password).toString(); @@ -410,7 +515,6 @@ function exportNotes() { responseData[i]["content"] = originalContent } let jsonString = JSON.parse(JSON.stringify(responseData)) - console.log(jsonString) exportNotesButton.innerText = "export notes" downloadObjectAsJson(jsonString, "data") diff --git a/static/svg/device_computer.svg b/static/svg/device_computer.svg new file mode 100644 index 0000000..5981880 --- /dev/null +++ b/static/svg/device_computer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/svg/device_other.svg b/static/svg/device_other.svg new file mode 100644 index 0000000..f8b0038 --- /dev/null +++ b/static/svg/device_other.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/svg/device_smartphone.svg b/static/svg/device_smartphone.svg new file mode 100644 index 0000000..100f589 --- /dev/null +++ b/static/svg/device_smartphone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/svg/list.svg b/static/svg/list.svg new file mode 100644 index 0000000..339b1f5 --- /dev/null +++ b/static/svg/list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/app.html b/templates/app.html index 5177c73..c5fdd83 100644 --- a/templates/app.html +++ b/templates/app.html @@ -39,8 +39,17 @@

account managment

+ +