Added password changing
This commit is contained in:
parent
b1f854b70b
commit
0c35db92ba
|
@ -7,6 +7,7 @@
|
|||
<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" />
|
||||
<script type="text/javascript" src="/static/js/hash-wasm.js"></script>
|
||||
<script type="text/javascript" src="/static/js/crypto-js.js"></script>
|
||||
<script type="text/javascript" src="/static/js/marked.js"></script>
|
||||
<script type="text/javascript" src="/static/js/purify.js"></script>
|
||||
|
@ -14,18 +15,16 @@
|
|||
</head>
|
||||
|
||||
<noscript>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; url=/login"/>
|
||||
</head>
|
||||
<meta http-equiv="refresh" content="0; url=/login"/>
|
||||
</noscript>
|
||||
|
||||
<body>
|
||||
<div class="topBar" id="topBar">
|
||||
<div class="modernToolbar">
|
||||
<button class="usernameBox hidden" onclick="handleGesture()" id="backButton"><div class="vcenter"><img src="/static/svg/arrow-back.svg"></div></button>
|
||||
<button class="usernameBox hidden" onclick="handleGesture()" id="backButton"><div class="vcenter"><img alt="Back arrow" src="/static/svg/arrow-back.svg"></div></button>
|
||||
<button class="count" id="wordCountBox">0 words</button>
|
||||
<button onclick="toggleMarkdown()" class="usernameBox"><div class="vcenter"><img src="/static/svg/markdown.svg"></div></button>
|
||||
<button id="usernameBox" class="usernameBox"><div class="vcenter"><img src="/static/svg/acct-settings.svg"></div></button>
|
||||
<button onclick="toggleMarkdown()" class="usernameBox"><div class="vcenter"><img alt="Enable markdown" src="/static/svg/markdown.svg"></div></button>
|
||||
<button id="usernameBox" class="usernameBox"><div class="vcenter"><img alt="Account settings" src="/static/svg/acct-settings.svg"></div></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -33,10 +32,8 @@
|
|||
<button id="newNote" class="newNote" style="margin-left: 5px;">
|
||||
<div class="vcenter"><img id="newNoteImage" draggable="false" alt="" src="/static/svg/add.svg"></div>
|
||||
</button>
|
||||
<!--<button class="newNote" style="margin-left: 37.5px; background-color: var(--bar) !important;">-->
|
||||
</button>
|
||||
<button id="removeBox" class="newNote remove">
|
||||
<div class="vcenter"><img id="newNoteImage" draggable="false" alt="" src="/static/svg/delete.svg"></div>
|
||||
<div class="vcenter"><img id="deleteNoteImage" draggable="false" alt="" src="/static/svg/delete.svg"></div>
|
||||
</button>
|
||||
<div id="notesDiv" class="notesDiv">
|
||||
<button class="loadingStuff" id="loadingStuff">Meow :3</button>
|
||||
|
@ -61,8 +58,9 @@
|
|||
<progress id="storageProgressThing" value="0" max="100"></progress><br>
|
||||
<p id="storageThing">Cannot connect to the server</p>
|
||||
<div class="section"></div>
|
||||
<p>Account managment</p>
|
||||
<p>Account management</p>
|
||||
<button id="deleteMyAccountButton"><img src="/static/svg/delete_forever.svg" alt="">Delete account</button>
|
||||
<button id="changePasswordButton"><img src="/static/svg/password.svg" alt="">Change password</button>
|
||||
<button id="exportNotesButton"><img src="/static/svg/download.svg" alt="">Export notes</button>
|
||||
<button id="importNotesButton"><img src="/static/svg/upload.svg" alt="">Import notes</button>
|
||||
<button id="sessionManagerButton"><img src="/static/svg/list.svg" alt="">View sessions</button>
|
||||
|
|
|
@ -34,6 +34,7 @@ let closeErrorButton = document.getElementById("closeErrorButton")
|
|||
let cancelErrorButton = document.getElementById("cancelErrorButton")
|
||||
let errorInput = document.getElementById("errorInput")
|
||||
let exitThing = document.getElementById("exitThing")
|
||||
let exitImportThing = document.getElementById("exitImportThing")
|
||||
let exitSessionsThing = document.getElementById("exitSessionsThing")
|
||||
let sessionManagerButton = document.getElementById("sessionManagerButton")
|
||||
let importNotesButton = document.getElementById("importNotesButton")
|
||||
|
@ -41,6 +42,7 @@ let sessionManagerDiv = document.getElementById("sessionManagerDiv")
|
|||
let importNotesDiv = document.getElementById("importDiv")
|
||||
let sessionDiv = document.getElementById("sessionDiv")
|
||||
let deleteMyAccountButton = document.getElementById("deleteMyAccountButton")
|
||||
let changePasswordButton = document.getElementById("changePasswordButton")
|
||||
let storageThing = document.getElementById("storageThing")
|
||||
let storageProgressThing = document.getElementById("storageProgressThing")
|
||||
let usernameThing = document.getElementById("usernameThing")
|
||||
|
@ -112,16 +114,6 @@ if (/Android|iPhone|iPod/i.test(navigator.userAgent)) {
|
|||
touchstartY = event.changedTouches[0].screenY;
|
||||
}, false);
|
||||
|
||||
noteBox.addEventListener("touchend", function (event) {
|
||||
touchendX = event.changedTouches[0].screenX;
|
||||
touchendY = event.changedTouches[0].screenY;
|
||||
if (touchendX > touchstartX + 75) {
|
||||
handleGesture();
|
||||
} else if (touchendX < touchstartX - 75) {
|
||||
enableMarkdown();
|
||||
}
|
||||
}, false);
|
||||
|
||||
markdown.addEventListener("touchstart", function (event) {
|
||||
touchstartX = event.changedTouches[0].screenX;
|
||||
touchstartY = event.changedTouches[0].screenY;
|
||||
|
@ -214,14 +206,14 @@ async function checknetwork() {
|
|||
})
|
||||
.then((response) => response)
|
||||
.then((response) => {
|
||||
if (response.status == 400) {
|
||||
if (response.status === 400) {
|
||||
displayError("Something went wrong! Signing you out...")
|
||||
closeErrorButton.classList.add("hidden")
|
||||
//usernameBox.innerText = ""
|
||||
setTimeout(function () {
|
||||
window.location.replace("/logout")
|
||||
}, 2500);
|
||||
} else if (response.status == 200) {
|
||||
} else if (response.status === 200) {
|
||||
updateUserInfo()
|
||||
} else {
|
||||
noteBox.readOnly = true
|
||||
|
@ -320,6 +312,129 @@ deleteMyAccountButton.addEventListener("click", () => {
|
|||
})
|
||||
}
|
||||
});
|
||||
async function waitForConfirm() {
|
||||
let resolvePromise;
|
||||
const promise = new Promise(resolve => resolvePromise = resolve);
|
||||
closeErrorButton.addEventListener("click", () => {
|
||||
resolvePromise();
|
||||
});
|
||||
await promise;
|
||||
}
|
||||
|
||||
async function hashpass(pass) {
|
||||
let key = pass
|
||||
for (let i = 0; i < 128; i++) {
|
||||
key = await hashwasm.sha3(key)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
changePasswordButton.addEventListener("click", () => {
|
||||
optionsDiv.classList.add("hidden")
|
||||
async function doStuff() {
|
||||
async function fatalError(notes, passwordBackup) {
|
||||
displayError("Something went wrong! Your password change has failed. Attempting to revert changes...")
|
||||
password = passwordBackup
|
||||
localStorage.setItem("DONOTSHARE-password", password)
|
||||
let changePasswordBackResponse = await fetch(remote + "/api/changepassword", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
secretKey: secretkey,
|
||||
newPassword: await hashpass(oldPass)
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8",
|
||||
"X-Burgernotes-Version": "200"
|
||||
}
|
||||
})
|
||||
if (changePasswordBackResponse.status === 200) {
|
||||
let responseStatus = await importNotes(notes)
|
||||
if (responseStatus === 500) {
|
||||
closeErrorButton.classList.remove("hidden")
|
||||
displayError("Failed to revert changes. Please delete this user account and sign-up again, then re-import the notes. Click Ok to download the notes to import later.")
|
||||
await waitForConfirm()
|
||||
downloadObjectAsJson(notes, "data")
|
||||
} else {
|
||||
closeErrorButton.classList.remove("hidden")
|
||||
displayError("Password change failed! Changes have been reverted.")
|
||||
updateNotes()
|
||||
}
|
||||
} else {
|
||||
displayError("Failed to revert changes. Please delete this user account and sign-up again, then re-import the notes. Click Ok to download the notes to import later.")
|
||||
downloadObjectAsJson(notes, "data")
|
||||
}
|
||||
}
|
||||
displayError("Confirm your current password to change it")
|
||||
errorInput.type = "password"
|
||||
errorInput.classList.remove("hidden")
|
||||
await waitForConfirm()
|
||||
const oldPass = errorInput.value
|
||||
errorInput.classList.add("hidden")
|
||||
if (await hashwasm.sha512(oldPass) !== password) {
|
||||
displayError("Incorrect password!")
|
||||
} else {
|
||||
errorInput.value = ""
|
||||
displayError("Enter your new password")
|
||||
errorInput.classList.remove("hidden")
|
||||
await waitForConfirm()
|
||||
errorInput.classList.add("hidden")
|
||||
const newPass = errorInput.value
|
||||
errorInput.type = "text"
|
||||
errorInput.value = ""
|
||||
if (newPass.length < 8) {
|
||||
displayError("Password must be at least 8 characters!")
|
||||
} else {
|
||||
displayError("Changing your password. This process may take up to 5 minutes. Do NOT close the tab!")
|
||||
closeErrorButton.classList.add("hidden")
|
||||
const response = await fetch(remote + "/api/changepassword", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
secretKey: secretkey,
|
||||
newPassword: await hashpass(newPass)
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8",
|
||||
"X-Burgernotes-Version": "200"
|
||||
}
|
||||
})
|
||||
if (response.status === 200) {
|
||||
let notes = await exportNotes()
|
||||
let passwordBackup = password
|
||||
password = await hashwasm.sha512(newPass)
|
||||
localStorage.setItem("DONOTSHARE-password", password)
|
||||
let purgeNotes = await fetch(remote + "/api/purgenotes", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
secretKey: secretkey
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
if (purgeNotes.status !== 200) {
|
||||
fatalError(notes, passwordBackup)
|
||||
} else {
|
||||
let responseStatus = await importNotes(notes)
|
||||
errorDiv.classList.add("hidden")
|
||||
if (responseStatus !== 200) {
|
||||
fatalError(notes, passwordBackup)
|
||||
} else {
|
||||
closeErrorButton.classList.remove("hidden")
|
||||
displayError("Password changed!")
|
||||
updateNotes()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
closeErrorButton.classList.remove("hidden")
|
||||
const data = await response.json()
|
||||
console.log(data)
|
||||
displayError(data["error"])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
doStuff()
|
||||
})
|
||||
importNotesButton.addEventListener("click", () => {
|
||||
optionsDiv.classList.add("hidden")
|
||||
importNotesDiv.classList.remove("hidden")
|
||||
|
@ -523,7 +638,7 @@ function updateNotes() {
|
|||
async function doStuff() {
|
||||
noteBox.readOnly = true
|
||||
selectedNote = 0
|
||||
if (selectLatestNote == false) {
|
||||
if (selectLatestNote === false) {
|
||||
noteBox.placeholder = ""
|
||||
}
|
||||
noteBox.value = ""
|
||||
|
@ -538,18 +653,17 @@ function updateNotes() {
|
|||
let highestID = 0
|
||||
|
||||
// First decrypt note data, then render
|
||||
let noteData;
|
||||
for (let i in responseData) {
|
||||
noteData = responseData[i]
|
||||
|
||||
let bytes = CryptoJS.AES.decrypt(noteData["title"], password);
|
||||
let decryptedTitle = bytes.toString(CryptoJS.enc.Utf8);
|
||||
|
||||
noteData["title"] = decryptedTitle
|
||||
noteData["title"] = bytes.toString(CryptoJS.enc.Utf8)
|
||||
|
||||
if (noteData["id"] > highestID) {
|
||||
highestID = noteData["id"]
|
||||
}
|
||||
|
||||
|
||||
decryptedResponseData.push(noteData)
|
||||
console.log(noteData)
|
||||
}
|
||||
|
@ -564,7 +678,7 @@ function updateNotes() {
|
|||
|
||||
console.log(noteData["title"])
|
||||
|
||||
if (noteData["title"] == "") {
|
||||
if (noteData["title"] === "") {
|
||||
console.log(noteData["title"])
|
||||
console.log("case")
|
||||
noteData["title"] = "New note"
|
||||
|
@ -598,7 +712,7 @@ function updateNotes() {
|
|||
}
|
||||
document.querySelectorAll(".loadingStuff").forEach((el) => el.remove());
|
||||
|
||||
if (selectLatestNote == true) {
|
||||
if (selectLatestNote === true) {
|
||||
selectNote(highestID)
|
||||
selectLatestNote = false
|
||||
}
|
||||
|
@ -621,7 +735,7 @@ newNote.addEventListener("click", () => {
|
|||
noteButton.classList.add("noteButton")
|
||||
notesDiv.append(noteButton)
|
||||
noteButton.innerText = "New note"
|
||||
noteButton.style.order = -1
|
||||
noteButton.style.order = "-1"
|
||||
noteButton.classList.add("selected")
|
||||
noteBox.placeholder = "Type something!"
|
||||
|
||||
|
@ -650,7 +764,7 @@ newNote.addEventListener("click", () => {
|
|||
});
|
||||
});
|
||||
function downloadObjectAsJson(exportObj, exportName) {
|
||||
let dataStr = "data:text/json;charset=utf-8," + DOMPurify.sanitize(JSON.stringify(exportObj));
|
||||
let dataStr = "data:text/json;charset=utf-8," + JSON.stringify(exportObj);
|
||||
let downloadAnchorNode = document.createElement("a");
|
||||
downloadAnchorNode.setAttribute("href", dataStr);
|
||||
downloadAnchorNode.setAttribute("download", exportName + ".json");
|
||||
|
@ -659,8 +773,8 @@ function downloadObjectAsJson(exportObj, exportName) {
|
|||
downloadAnchorNode.remove();
|
||||
}
|
||||
|
||||
function exportNotes() {
|
||||
fetch(remote + "/api/exportnotes", {
|
||||
async function exportNotes() {
|
||||
let exportNotesFetch = await fetch(remote + "/api/exportnotes", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
secretKey: secretkey
|
||||
|
@ -669,38 +783,28 @@ function exportNotes() {
|
|||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
async function doStuff() {
|
||||
let responseData = await response.json()
|
||||
for (let i in responseData) {
|
||||
exportNotes.innerText = "Decrypting " + i + "/" + noteCount
|
||||
let responseData = await exportNotesFetch.json()
|
||||
for (let i in responseData) {
|
||||
exportNotes.innerText = "Decrypting " + i + "/" + noteCount
|
||||
|
||||
let bytes = CryptoJS.AES.decrypt(responseData[i]["title"], password);
|
||||
responseData[i]["title"] = bytes.toString(CryptoJS.enc.Utf8)
|
||||
let bytes = CryptoJS.AES.decrypt(responseData[i]["title"], password);
|
||||
responseData[i]["title"] = bytes.toString(CryptoJS.enc.Utf8)
|
||||
|
||||
let bytesd = CryptoJS.AES.decrypt(responseData[i]["content"], password);
|
||||
responseData[i]["content"] = bytesd.toString(CryptoJS.enc.Utf8)
|
||||
}
|
||||
let jsonString = JSON.parse(JSON.stringify(responseData))
|
||||
downloadObjectAsJson(jsonString, "data")
|
||||
optionsDiv.classList.add("hidden")
|
||||
displayError("Exported notes!")
|
||||
}
|
||||
doStuff()
|
||||
})
|
||||
let bytesd = CryptoJS.AES.decrypt(responseData[i]["content"], password);
|
||||
responseData[i]["content"] = bytesd.toString(CryptoJS.enc.Utf8)
|
||||
}
|
||||
return responseData
|
||||
}
|
||||
|
||||
function importNotes(plaintextNotes) {
|
||||
async function importNotes(plaintextNotes) {
|
||||
for (let i in plaintextNotes) {
|
||||
let originalTitle = plaintextNotes[i]["title"];
|
||||
let encryptedTitle = CryptoJS.AES.encrypt(originalTitle, password).toString();
|
||||
plaintextNotes[i]["title"] = encryptedTitle;
|
||||
plaintextNotes[i]["title"] = CryptoJS.AES.encrypt(originalTitle, password).toString();
|
||||
|
||||
let originalContent = plaintextNotes[i]["content"];
|
||||
let encryptedContent = CryptoJS.AES.encrypt(originalContent, password).toString();
|
||||
plaintextNotes[i]["content"] = encryptedContent;
|
||||
plaintextNotes[i]["content"] = CryptoJS.AES.encrypt(originalContent, password).toString();
|
||||
}
|
||||
fetch(remote + "/api/importnotes", {
|
||||
let importNotesFetch = await fetch(remote + "/api/importnotes", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
"secretKey": localStorage.getItem("DONOTSHARE-secretkey"),
|
||||
|
@ -710,21 +814,7 @@ function importNotes(plaintextNotes) {
|
|||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
async function doStuff() {
|
||||
if (response.status === 500) {
|
||||
optionsDiv.classList.add("hidden")
|
||||
importNotesDiv.classList.add("hidden")
|
||||
displayError("Something went wrong! Perhaps your note file was invalid?")
|
||||
} else {
|
||||
optionsDiv.classList.add("hidden")
|
||||
importNotesDiv.classList.add("hidden")
|
||||
displayError("Notes uploaded!")
|
||||
updateNotes()
|
||||
}
|
||||
}
|
||||
doStuff()
|
||||
})
|
||||
return importNotesFetch.status
|
||||
}
|
||||
|
||||
function firstNewVersion() {
|
||||
|
@ -757,16 +847,31 @@ function disableMarkdown() {
|
|||
}
|
||||
|
||||
exportNotesButton.addEventListener("click", () => {
|
||||
exportNotes()
|
||||
let responseData = exportNotes()
|
||||
downloadObjectAsJson(responseData, "data")
|
||||
optionsDiv.classList.add("hidden")
|
||||
displayError("Exported notes!")
|
||||
});
|
||||
|
||||
importFile.addEventListener('change', function(e) {
|
||||
importFile.addEventListener('change', function() {
|
||||
let fileread = new FileReader()
|
||||
fileread.addEventListener(
|
||||
"load",
|
||||
() => {
|
||||
let decrypted = JSON.parse(fileread.result)
|
||||
let decrypted = JSON.parse(fileread.result.toString())
|
||||
importNotes(decrypted)
|
||||
.then((responseStatus) => {
|
||||
if (responseStatus === 500) {
|
||||
optionsDiv.classList.add("hidden")
|
||||
importNotesDiv.classList.add("hidden")
|
||||
displayError("Something went wrong! Perhaps your note file was invalid?")
|
||||
} else {
|
||||
optionsDiv.classList.add("hidden")
|
||||
importNotesDiv.classList.add("hidden")
|
||||
displayError("Notes uploaded!")
|
||||
updateNotes()
|
||||
}
|
||||
})
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="40px" viewBox="0 -960 960 960" width="40px" fill="#000000"><path d="M80-200v-67.33h800V-200H80Zm40.67-250-44-24.67 38-65.33H40v-50h74.67l-38-64.67 44-24.66 36.66 64 36.67-64 44 24.66L200-590h74.67v50H200l38 65.33L194-450l-36.67-64.67L120.67-450Zm322.66 0-44-26 38-65.33h-74.66v-50h74.66l-38-64.67 44-24.67 36.67 64 36.67-64 44 24.67-38 64.67h74.66v50h-74.66l38 65.33-44 26L480-514.67 443.33-450ZM766-450l-44-26 38-65.33h-74.67v-50H760L722-656l44-24.67 36.67 64 36.66-64 44 24.67-38 64.67H920v50h-74.67l38 65.33-44 26-36.66-64.67L766-450Z"/></svg>
|
After Width: | Height: | Size: 594 B |
Reference in New Issue