This commit is contained in:
parent
a8f721eab6
commit
52cff35cd2
74
main
74
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/<secretkey>", 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")
|
||||
|
|
|
@ -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 "?"
|
||||
);
|
|
@ -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 {
|
||||
|
|
|
@ -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 = "<span style='background-color: #157efb; color: white; padding: 8px; border-radius: 8px; margin-right: 5px;'>current</span>" + 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")
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M70-120q-12.75 0-21.375-8.675Q40-137.351 40-150.175 40-163 48.625-171.5T70-180h820q12.75 0 21.375 8.675 8.625 8.676 8.625 21.5 0 12.825-8.625 21.325T890-120H70Zm70-120q-24 0-42-18t-18-42v-480q0-24 18-42t42-18h680q24 0 42 18t18 42v480q0 24-18 42t-42 18H140Zm0-60h680v-480H140v480Zm0 0v-480 480Z"/></svg>
|
After Width: | Height: | Size: 399 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M140-160q-24 0-42-18t-18-42v-520q0-24 18-42t42-18h680q24 0 42 18t18 42v520q0 24-18 42t-42 18H140Zm0-60h680v-436H140v436Zm160-72-42-42 103-104-104-104 43-42 146 146-146 146Zm190 4v-60h220v60H490Z"/></svg>
|
After Width: | Height: | Size: 300 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M260-40q-24 0-42-18t-18-42v-760q0-24 18-42t42-18h440q24 0 42 18t18 42v760q0 24-18 42t-42 18H260Zm0-90v30h440v-30H260Zm0-60h440v-580H260v580Zm0-640h440v-30H260v30Zm0 0v-30 30Zm0 700v30-30Z"/></svg>
|
After Width: | Height: | Size: 293 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M290-620v-60h550v60H290Zm0 170v-60h550v60H290Zm0 170v-60h550v60H290ZM150-620q-12 0-21-9t-9-21.5q0-12.5 9-21t21.5-8.5q12.5 0 21 8.625T180-650q0 12-8.625 21T150-620Zm0 170q-12 0-21-9t-9-21.5q0-12.5 9-21t21.5-8.5q12.5 0 21 8.625T180-480q0 12-8.625 21T150-450Zm0 170q-12 0-21-9t-9-21.5q0-12.5 9-21t21.5-8.5q12.5 0 21 8.625T180-310q0 12-8.625 21T150-280Z"/></svg>
|
After Width: | Height: | Size: 455 B |
|
@ -39,8 +39,17 @@
|
|||
<p>account managment</p>
|
||||
<button id="deleteMyAccountButton"><img src="/static/svg/delete_forever.svg">delete my account</button>
|
||||
<button id="exportNotesButton"><img src="/static/svg/download.svg">export notes</button>
|
||||
<button id="sessionManagerButton"><img src="/static/svg/list.svg">session manager</button>
|
||||
<button class="lastButton" id="logOutButton"><img src="/static/svg/logout.svg">log out</button>
|
||||
</div>
|
||||
<div id="sessionManagerDiv" class="optionsDiv hidden">
|
||||
<button class="exit" id="exitSessionsThing">X</button>
|
||||
<h3 class="w300">session manager</h3>
|
||||
<p>manage your sessions</p>
|
||||
<div class="section"></div>
|
||||
<div class="sessionDiv" id="sessionDiv">
|
||||
</div>
|
||||
</div>
|
||||
<div id="errorDiv" class="optionsDiv hidden">
|
||||
<p id="errorMessageThing"></p>
|
||||
<input class="hidden" id="errorInput" type="text" placeholder="e.g. shopping list"><br></input>
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>burgernotes</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2 class="w300">{{ errorMessage }}</h2>
|
||||
{{ errorCode }} | {{ errorMessage }}
|
||||
</body>
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin-left: 15px;
|
||||
}
|
||||
</style>
|
||||
|
||||
</html>
|
|
@ -21,6 +21,12 @@
|
|||
<ul>
|
||||
<li>Username, and your password hashed</li>
|
||||
<li>Date of creating account</li>
|
||||
<li>Web browser "User Agent"</li>
|
||||
</ul>
|
||||
<h2 class="w300">Information collected when logging in</h2>
|
||||
<p>When logging back in to your account, we collect and store the following information:</p>
|
||||
<ul>
|
||||
<li>Web browser "User agent"</li>
|
||||
</ul>
|
||||
<h2 class="w300">Information we collect while using our services</h2>
|
||||
<p>When you create an note, we collect and use this information:</p>
|
||||
|
|
Loading…
Reference in New Issue