document.addEventListener("DOMContentLoaded", async () => { "use strict";
const secure = location.protocol === "https:";
const $ = (s,c) => (c||document).querySelector(s);
function $$(x,y,z,a){a=(z||document).querySelectorAll(x);if(typeof y=="function")[].forEach.call(a,y);return a}
function m(a,b,c){c=document;b=c.createElement(b||"p");b.innerHTML=a.trim();for(a=c.createDocumentFragment();c=b.firstChild;)a.appendChild(c);return a.firstChild}
function debounce(fn, delay) {
let timeout = null;
return (...args) => {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
timeout = null;
fn.apply(null, args);
}, delay||500);
}
}
//sock.init(`ws${secure?"s":""}://${location.host}/ws`);
//sock.on("hello", e => {
// console.log("hello", e);
// sock.send("world", {foo:"bar"});
//});
//if ("serviceWorker" in navigator) {
// navigator.serviceWorker.register("sw.js")
// .then(() => console.log("Service worker registered"));
//}
function drawNote(note) {
const el = m(`
${note.id}
`);
$("textarea", el).addEventListener("input",
debounce(() => { saveNote(note.id, $("textarea", el).value); }, 500));
$("#notes").appendChild(el);
}
async function getNote(id) {
const res = await fetch(`${id}`);
const note = await res.json();
console.log(note);
drawNote(note);
}
async function getList() {
const res = await fetch("/list");
const list = await res.json();
console.log(list);
for (let i=0;i {
const res = await fetch("/login", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
username: $("#username").value,
password: $("#password").value,
keepSession: $("#keep-session").checked,
})
});
// TODO check return code
const json = await res.json();
console.log(json);
// TODO "Must Change Password" flow
getUserData();
getList();
});
$("#change-password").addEventListener("click", async () => {
const res = await fetch("/change-password", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
username: $("#username").value,
password: $("#password").value,
newPassword: $("#new-password").value,
keepSession: $("#keep-session").checked,
})
});
const json = await res.json();
console.log(json);
getUserData();
});
$("#change-username").addEventListener("click", async () => {
const res = await fetch("/change-username", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
newUsername: $("#new-username").value,
password: $("#password").value,
})
});
const json = await res.json();
console.log(json);
getUserData();
});
$("#logout").addEventListener("click", async () => {
const res = await fetch("/logout", {
method: "POST",
});
//const json = await res.json();
//console.log(json);
console.log("Logged out");
$("#uid").value = "";
});
$("#logout-everywhere").addEventListener("click", async () => {
const res = await fetch("/deauth-all", {
method: "POST",
});
console.log("Logged out everywhere");
$("#uid").value = "";
});
try { getUserData(); getList(); getUserSessions(); } catch(e) {}
// TODO make sure to save unsynced delta even if token has expired, then sync when logged in
// TODO Cookie consent on signup; "only necessary for maintaining user session and cached data"
// TODO "Review sessions" popup client-side when relogin required on a token which shouldn't have expired yet
// TODO prevent data: and javascript: links?
// Also embedding of external content?
// encodeURI *AND* encode for attribute (quote marks etc)
// https://github.com/cure53/DOMPurify
//
// elem.textContent = dangerVariable; !!!!!!!!!
// elem.insertAdjacentText(dangerVariable);
// elem.className = dangerVariable;
// elem.setAttribute(safeName, dangerVariable);
// formfield.value = dangerVariable;
// document.createTextNode(dangerVariable);
// document.createElement(dangerVariable);
// elem.innerHTML = DOMPurify.sanitize(dangerVar);
// https://github.com/cure53/DOMPurify/blob/main/src/attrs.js
// https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
});