2024-10-30 12:24:59 +00:00
|
|
|
const loadingDialog = {
|
|
|
|
dialog: document.querySelector("dialog#loading-dialog"),
|
|
|
|
init() {
|
|
|
|
this.dialog.addEventListener("cancel", (ev) => {
|
2024-10-29 23:08:11 +00:00
|
|
|
ev.preventDefault();
|
2024-10-30 12:24:59 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
show() {
|
|
|
|
this.dialog.showModal();
|
|
|
|
},
|
|
|
|
close() {
|
|
|
|
this.dialog.close();
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const errorDialog = {
|
|
|
|
dialog: document.querySelector("dialog#error-dialog"),
|
|
|
|
error: document.querySelector("textarea#error"),
|
|
|
|
reload: document.querySelector("button#error-reload"),
|
|
|
|
init() {
|
|
|
|
this.dialog.addEventListener("close", (ev) => {
|
|
|
|
window.location.reload();
|
|
|
|
});
|
2024-10-29 23:08:11 +00:00
|
|
|
|
2024-10-30 12:24:59 +00:00
|
|
|
this.reload.addEventListener("click", (ev) => {
|
|
|
|
window.location.href = "/";
|
|
|
|
});
|
|
|
|
},
|
|
|
|
show(err) {
|
|
|
|
this.error.value = err;
|
|
|
|
console.error(err);
|
|
|
|
this.dialog.showModal();
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const urlDialog = {
|
|
|
|
dialog: document.querySelector("dialog#url-dialog"),
|
|
|
|
url: document.querySelector("input#url"),
|
|
|
|
urlCopy: document.querySelector("button#url-copy"),
|
|
|
|
close: document.querySelector("button#url-close"),
|
|
|
|
init() {
|
|
|
|
this.dialog.addEventListener("close", (ev) => {});
|
|
|
|
|
|
|
|
this.urlCopy.addEventListener("click", (ev) => {
|
|
|
|
this.url.select();
|
|
|
|
this.url.setSelectionRange(0, 99999);
|
|
|
|
navigator.clipboard.writeText(this.url.value);
|
|
|
|
});
|
2024-10-29 23:08:11 +00:00
|
|
|
|
2024-10-30 12:24:59 +00:00
|
|
|
this.close.addEventListener("click", (ev) => {
|
|
|
|
this.dialog.close();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
show(url) {
|
|
|
|
this.url.value = url;
|
|
|
|
this.dialog.showModal();
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const notFoundDialog = {
|
|
|
|
dialog: document.querySelector("dialog#not-found"),
|
|
|
|
close: document.querySelector("button#not-found-close"),
|
|
|
|
init() {
|
|
|
|
this.dialog.addEventListener("close", (ev) => {
|
2024-11-04 21:52:00 +00:00
|
|
|
window.location.hash = "";
|
|
|
|
window.location.reload();
|
2024-10-30 12:24:59 +00:00
|
|
|
});
|
2024-10-29 23:08:11 +00:00
|
|
|
|
2024-10-30 12:24:59 +00:00
|
|
|
this.close.addEventListener("click", (ev) => {
|
2024-11-04 21:52:00 +00:00
|
|
|
window.location.hash = "";
|
|
|
|
window.location.reload();
|
2024-10-30 12:24:59 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
show() {
|
|
|
|
this.dialog.showModal();
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const viewDialog = {
|
|
|
|
dialog: document.querySelector("dialog#view-dialog"),
|
|
|
|
password: document.querySelector("textarea#view-password"),
|
|
|
|
close: document.querySelector("button#view-close"),
|
|
|
|
init() {
|
|
|
|
this.dialog.addEventListener("close", (ev) => {
|
2024-11-04 21:52:00 +00:00
|
|
|
window.location.hash = "";
|
|
|
|
window.location.reload();
|
2024-10-30 12:24:59 +00:00
|
|
|
});
|
2024-10-29 23:08:11 +00:00
|
|
|
|
2024-10-30 12:24:59 +00:00
|
|
|
this.close.addEventListener("click", (ev) => {
|
|
|
|
this.dialog.close();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
show(password) {
|
|
|
|
this.password.value = password;
|
|
|
|
this.dialog.showModal();
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const confirmViewDialog = {
|
|
|
|
dialog: document.querySelector("dialog#confirm-view-dialog"),
|
|
|
|
cancel: document.querySelector("button#view-cancel"),
|
|
|
|
confirm: document.querySelector("button#view-confirm"),
|
|
|
|
resolve: null,
|
|
|
|
reject: null,
|
|
|
|
init() {
|
|
|
|
this.dialog.addEventListener("cancel", (ev) => {
|
|
|
|
this.dialog.close();
|
|
|
|
this.resolve(false);
|
|
|
|
});
|
2024-10-29 23:08:11 +00:00
|
|
|
|
2024-10-30 12:24:59 +00:00
|
|
|
this.cancel.addEventListener("click", (ev) => {
|
|
|
|
this.dialog.close();
|
|
|
|
this.resolve(false);
|
|
|
|
});
|
2024-10-29 23:08:11 +00:00
|
|
|
|
2024-10-30 12:24:59 +00:00
|
|
|
this.confirm.addEventListener("click", (ev) => {
|
|
|
|
this.dialog.close();
|
|
|
|
this.resolve(true);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
show() {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
this.resolve = resolve;
|
|
|
|
this.reject = reject;
|
|
|
|
this.dialog.showModal();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
};
|
2024-10-29 23:49:30 +00:00
|
|
|
|
2024-10-30 12:24:59 +00:00
|
|
|
async function viewPassword() {
|
2024-10-29 23:49:30 +00:00
|
|
|
try {
|
2024-10-30 12:24:59 +00:00
|
|
|
loadingDialog.show();
|
2024-10-29 23:49:30 +00:00
|
|
|
|
2024-11-04 21:52:00 +00:00
|
|
|
let id, key, iv;
|
|
|
|
|
|
|
|
// We need to be backwards compatible with old links that still use the query
|
|
|
|
if (window.location.search.trim() != "") {
|
|
|
|
const params = new URLSearchParams(window.location.search);
|
|
|
|
id = params.get("id");
|
|
|
|
key = params.get("key");
|
|
|
|
iv = params.get("iv");
|
|
|
|
} else {
|
|
|
|
// Need to remove leading "#"
|
|
|
|
const hash = window.location.hash.substring(1);
|
|
|
|
const split = hash.split(":");
|
|
|
|
id = split[0];
|
|
|
|
key = split[1];
|
|
|
|
iv = split[2];
|
|
|
|
}
|
2024-10-29 23:49:30 +00:00
|
|
|
|
2024-10-30 12:24:59 +00:00
|
|
|
const exists = await hasPassword(id);
|
|
|
|
if (!exists) {
|
|
|
|
notFoundDialog.show();
|
2024-10-29 23:49:30 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-10-30 12:24:59 +00:00
|
|
|
const shouldView = await confirmViewDialog.show();
|
|
|
|
if (!shouldView) {
|
|
|
|
// This is needed for the redirect, otherwise the user won't get redirected
|
2024-11-04 21:52:00 +00:00
|
|
|
setTimeout(() => {
|
|
|
|
window.location.hash = "";
|
|
|
|
window.location.reload();
|
|
|
|
}, 0);
|
2024-10-30 12:24:59 +00:00
|
|
|
return;
|
2024-10-29 23:49:30 +00:00
|
|
|
}
|
2024-10-30 12:24:59 +00:00
|
|
|
|
|
|
|
const encrypted = await getPassword(id);
|
|
|
|
const password = await decryptPassword(encrypted, key, iv);
|
|
|
|
|
|
|
|
viewDialog.show(password);
|
2024-10-29 23:49:30 +00:00
|
|
|
} catch (error) {
|
2024-10-30 12:24:59 +00:00
|
|
|
errorDialog.show(error);
|
2024-10-29 23:49:30 +00:00
|
|
|
} finally {
|
2024-10-30 12:24:59 +00:00
|
|
|
loadingDialog.close();
|
2024-10-29 23:49:30 +00:00
|
|
|
}
|
2024-10-29 23:08:11 +00:00
|
|
|
}
|
|
|
|
|
2024-10-30 12:24:59 +00:00
|
|
|
const enterPassword = document.querySelector("form#enter-password");
|
2024-10-29 23:08:11 +00:00
|
|
|
|
2024-10-30 12:24:59 +00:00
|
|
|
enterPassword.addEventListener("submit", async (ev) => {
|
2024-10-29 23:08:11 +00:00
|
|
|
try {
|
2024-10-30 12:24:59 +00:00
|
|
|
loadingDialog.show();
|
|
|
|
ev.preventDefault();
|
|
|
|
const data = new FormData(ev.target);
|
|
|
|
|
|
|
|
const password = await encryptPassword(data.get("password"));
|
|
|
|
const id = await uploadPassword(
|
|
|
|
password.password,
|
|
|
|
parseInt(data.get("expires-in")),
|
2024-10-29 23:08:11 +00:00
|
|
|
);
|
|
|
|
|
2024-10-30 12:24:59 +00:00
|
|
|
const url = new URL(window.location);
|
2024-11-04 21:52:00 +00:00
|
|
|
url.hash = [id, password.key, password.iv].join(":");
|
2024-10-30 12:24:59 +00:00
|
|
|
urlDialog.show(url.toString());
|
2024-10-29 23:08:11 +00:00
|
|
|
} catch (error) {
|
2024-10-30 12:24:59 +00:00
|
|
|
errorDialog.show(error);
|
2024-10-29 23:08:11 +00:00
|
|
|
} finally {
|
|
|
|
loadingDialog.close();
|
|
|
|
}
|
2024-10-30 12:24:59 +00:00
|
|
|
});
|
2024-10-29 23:08:11 +00:00
|
|
|
|
2024-10-30 12:24:59 +00:00
|
|
|
loadingDialog.init();
|
|
|
|
errorDialog.init();
|
|
|
|
urlDialog.init();
|
|
|
|
notFoundDialog.init();
|
|
|
|
viewDialog.init();
|
|
|
|
confirmViewDialog.init();
|
2024-10-29 23:08:11 +00:00
|
|
|
|
2024-11-04 21:52:00 +00:00
|
|
|
const hash = window.location.hash;
|
|
|
|
if (hash.trim() != "") {
|
|
|
|
viewPassword();
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to be backwards compatible with the old links
|
2024-10-30 12:24:59 +00:00
|
|
|
const query = window.location.search;
|
|
|
|
if (query.trim() != "") {
|
|
|
|
viewPassword();
|
|
|
|
}
|